[Q] eval and binding with mod_ruby

Hi,

I have a question about eval and binding, with mod_ruby.
It is no problem to execute CGI program on command-line,
but an internal error happened when executing as mod_ruby script.

Here is the scripts.

viewloader.rb:
.--------------------
def output(filename, _binding=TOPLEVEL_BINDING)
s = nil
File.open(filename) do |file|
s = file.read
end
s.untaint
eval s, _binding
end
.--------------------

view.rb:
.--------------------
print “Hello #{username}!\n”
.--------------------

logic.rbx:
.--------------------
#!/usr/bin/ruby

require 'cgi’
cgi = CGI.new
print cgi.header

require 'viewloader’
username = 'Ruby’
output(‘view.rb’) # I prefer this rather than
# output(‘view.rb’, binding())
.--------------------

result(command-line): – No Problem.
.====================
$ ruby logic.rbx
(offline mode: enter name=value pairs on standard input)
Content-Type: text/html

Hello Ruby!
.====================

result(apache error_log): – INTERNAL ERROR!
.====================
[Thu May 1 11:41:59 2003] [error] mod_ruby: error in ruby
/home/httpd/html/sample/viewloader.rb:7:in eval': (eval):1: undefined local variable or methodusername’ for #Object:0x40b35c90
(NameError)
from /home/httpd/html/sample/viewloader.rb:7:in output' from /home/httpd/html/sample/logic.rbx:9 from /usr/lib/ruby/1.6/apache/ruby-run.rb:63:inload’
from /usr/lib/ruby/1.6/apache/ruby-run.rb:63:in `handler’
from ruby:0
.====================

I don’t know why the mod_ruby error happens.
Please give me an advice.

I can succeed if using output(‘view.rb’, binding)

instead of output(‘view.rb’) in logic.rbx,

but I want to use the former.

···


regards
kwatch

I think it’s because mod_ruby loads your code into an anonymous module, to
protect the top-level namespace which is shared by all the mod_ruby
applications running under the same interpreter. See

http://ruby-talk.org/65376
http://ruby-talk.org/56532

Regards,

Brian.

···

On Thu, May 01, 2003 at 12:59:22PM +0900, kwatch wrote:

I have a question about eval and binding, with mod_ruby.
It is no problem to execute CGI program on command-line,
but an internal error happened when executing as mod_ruby script.

Brian Candler B.Candler@pobox.com wrote in message news:20030501083010.GA41857@uk.tiscali.com

I think it’s because mod_ruby loads your code into an anonymous module, to
protect the top-level namespace which is shared by all the mod_ruby
applications running under the same interpreter. See

http://ruby-talk.org/65376
http://ruby-talk.org/56532

I got. Thanks for a good advice.
I must use binding() in conclusion.

But how ERuby can do ERuby::import() ?
I think ERuby may calls eval in itself, but it has no need to
call binding().

view.rhtml
.--------------------
Hello <%= username %>!
.--------------------

logic.rbx
.--------------------
require ‘cgi’
cgi = CGI.new
print cgi.header

require ‘eruby’
username = ‘Ruby’
ERuby::import(‘view.rhtml’) # no binding(), but evaled with no error.
.--------------------

I have read ERuby source code (eruby_load() in eruby_lib.c),
but I could not get understand how ERuby do.

Would you teach me if you know it?

Maybe, getting a binding() of anonymous package?

regards,
kwatch

I don’t :slight_smile: But I have just installed eruby now…

I’ve played with this a bit and have been unable to make the local variable
‘username’ available in viewloader.rb without passing a binding explicitly
as you did - having tried various combinations of instance_eval, passing in
‘self’ as a parameter etc.

The usual rule is that when you call a method, a new scope is started (so
local variables in the calling method are not visible in the called method).
I don’t understand how or why ERuby::import is able to see them when it
calls ‘eval’. The relevant function in eruby_lib.c looks like

static VALUE eruby_import(VALUE self, VALUE filename)
{
VALUE compiler, file, code;

compiler = eruby_compiler_new();
file = rb_file_open(STR2CSTR(filename), "r");
code = eruby_compiler_compile_file(compiler, file);
rb_funcall(ruby_top_self, rb_intern("eval"), 3, code, Qnil, filename);
return Qnil;

}

And the closest I can get to simulate that is:

···

On Fri, May 02, 2003 at 07:43:42AM +0900, kwatch wrote:

view.rhtml
.--------------------
Hello <%= username %>!
.--------------------

logic.rbx
.--------------------
require ‘cgi’
cgi = CGI.new
print cgi.header

require ‘eruby’
username = ‘Ruby’
ERuby::import(‘view.rhtml’) # no binding(), but evaled with no error.
.--------------------

I have read ERuby source code (eruby_load() in eruby_lib.c),
but I could not get understand how ERuby do.

Would you teach me if you know it?


TOP_SELF = self

module Foo
def Foo.output(code)
TOP_SELF.send( :eval, code )
end
end

username=“test”
Foo.output(“puts username”)

but this doesn’t work :frowning: Anybody else got any better ideas, or an
explanation of why ERuby doesn’t need you to pass in an explicit ‘binding’?

Thanks,

Brian.