Re: mod_ruby and include statements (mixins)
Brian Candler <[email protected]> Sun, 4 Sep 2005 14:35:29 +0100
| Newsgroups | gmane.comp.apache.mod-ruby |
|---|---|
| Message-ID | <[email protected]> |
On Wed, Aug 24, 2005 at 07:35:19PM -0600, Matthew Thill wrote:
> 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
> 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.
In the mod_ruby environment, each file to be executed is loaded inside an
anonymous module, kind-of as if wrapped by:
module FOOBARrandom123456
... code goes here
end
This is to minimise the interactions between unrelated code for different
applications which are all run within the mod_ruby interpreter.
You can get the same effect using "load(filename,true)" - see ri Kernel#load
Now this lets us replicate your problem without using mod_ruby:
$ cat ruby2.rb
load 'ruby1.rb', true
$ ruby ruby2.rb
false
true
./ruby1.rb:19:in `append_features': cyclic include detected (ArgumentError)
from ./ruby1.rb:19:in `include'
from ./ruby1.rb:19
from ruby2.rb:1:in `load'
from ruby2.rb:1
I hope this gives you a starting point for tracking down the problem
further. You can minimise your test case to:
$ cat ruby3.rb
load 'ruby4.rb', true
$ cat ruby4.rb
module M
def some_method
end
end
include M
$ ruby ruby3.rb
./ruby4.rb:6:in `append_features': cyclic include detected (ArgumentError)
from ./ruby4.rb:6:in `include'
from ./ruby4.rb:6
from ruby3.rb:1:in `load'
from ruby3.rb:1
and you can always post this onto the ruby-talk mailing list for further
explanation.
Regards,
Brian.