Module vs Binding Evaluation

I

Intransition

I am confused by the difference between using module_eval on a module,
vs. using eval on a binding extracted from a module.

Have a look at this gist:

http://gist.github.com/445263

When run, it produces:

s2::X uninitialized constant #<S:0x7fa6256160e8>::X
s3::X uninitialized constant #<S:0x7fa625615698>::X

Other than the lack of a local scope (which is not being used), why is
s1 and s2 behaving differently? I would expect the results to be
equivalent. And even more confusing to me, how is it that s3 can see
s2's method definitions even though it's a whole new module!?

Note the 'extend self' doesn't seem to make much of a difference. Take
it out and s1.x is no longer accessible as would be expected. But s2
and s3 seem unaffected.
 
B

Brian Candler

Thomas said:
I am confused by the difference between using module_eval on a module,
vs. using eval on a binding extracted from a module.

Have a look at this gist:

http://gist.github.com/445263

This looks rather odd to me: (1) you are subclassing Module, (2) you are
creating instances of [this subclass of] Module, and (3) you are
extending each instance of this class/module with itself. These seem to
be unusual things to do, although I'm sure you have a good reason.

If I rewrite the code to avoid this usage, it all looks OK:

# Sample 1

module M1
def self.__binding__
@binding ||= binding
end
end

M1.module_eval <<-END
X = 10
def self.x; 10; end
END

raise unless M1.x == 10 rescue puts "M1.x " + $!
raise unless M1::X == 10 rescue puts "M1::X " + $!


# Sample 2

module M2
def self.__binding__
@binding ||= binding
end
end

eval(<<-END, M2.__binding__)
X = 10
def self.x; 10; end
def self.y; 20; end
END

raise unless M2.x == 10 rescue puts "M2.x " + $!
raise unless M2.y == 20 rescue puts "M2.y " + $!
raise unless M2::X == 10 rescue puts "M2::X " + $!


My simplistic understanding is that there are two sorts of object
context in Ruby: the "current object", which is visible as 'self', and
the "current class", which is pretty well hidden but it's where 'def'
defines new instance methods, and is set by 'class' and 'class_eval'.


class C
end

C.send:)class_eval) do
def foo
puts "In foo"
end
end

C.foo rescue puts "foo is not a class method"
C.new.foo

C.send:)instance_eval) do
def bar
puts "In bar"
end
end

C.bar
C.new.bar rescue puts "bar is not an instance method"


However I don't understand this fully, because I can't see how your code
manages to define singleton methods on s2, just by using eval and a
binding. If I try a simpler example, it doesn't:


eval(<<EOS, C.send:)binding))
def baz
puts "In baz"
end
EOS

baz
C.baz rescue puts "baz is private global method"
C.new.baz rescue puts "baz is not an instance method"
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,825
Latest member
VernonQuy6

Latest Threads

Top