Mod_ruby and include statements (mixins)

(Matthew Thill) #1

Perhaps someone can explain this behaviour to me.

This is on an OpenBSD system. Ruby 1.8.2 and mod_ruby 1.2.4 installed successfully. Apache runs in a chroot environment. To avoid starting Apache with the -u flag (to turn chroot off) I copied the ruby installation into the chroot environment (/var/www) so things would work. Things do work as expected, except for this bit of strange behaviour. Any insight anyone can offer would be appreciated.

I have replicated the problem with a few small files.

The first file, call it ruby1.rb, is created and I run it from the shell, using the command "ruby ruby1.rb".

*********** Start ruby1.rb *******************
module M
   def some_method
   end
end

class T
   include M

   def T.main
     puts methods.include?('some_method').to_s
   end
   def main
     puts methods.include?('some_method').to_s
   end
end
T.main
t = T.new
t.main
include M
puts methods.include?('some_method').to_s
*********** End ruby1.rb *******************

The output is as expected:
false
true

If I put this file somewhere Apache can see it and run it through mod_ruby, I get an internal server error. In Apache's error log I see this:
`append_features': cyclic include detected (ArgumentError)

So, mod_ruby is doing something weird with include statements (read: I don't understand what it's doing).

To work around this, I put the module M definition into a file (call it m.rb).

************* Start m.rb *******************
module M
   def some_method
   end
end
************ End m.rb **********************

The code put in m.rb is removed from ruby1.rb (the first 4 lines), and is replaced with "load {path/to/m.rb}".

I then run ruby1.rb through Apache and mod_ruby again, and receive this output (I put the linefeeds in to make it easier to read):
false
true
false

The first two are as expected, but the last "false" is not expected. Apparently, with mod_ruby, only a class can include (or mix-in) a module. When I try to include a module in a script and run it through mod_ruby, the methods defined in the module are not available. I can only access the methods from the module if I have a class include the module.

A posibly related issue is the cyclic include error. I would appear as though defining a module in the same file as a class results in the module being "automatically" included. To test this, I put ruby1.rb in its original form back and removed the "include M" statement. This did fix the cyclic include error, but the module methods were still not available and the output was:
false
true
false

Can anyone provide me with an explanation for this behaviour? Is this just the way mod_ruby works? Should it work this way? I would think a script that runs in the shell environment should work exactly the same in the mod_ruby environment. Or is all this related to the chroot environment, and if so, why?