Ruby, adding methods to a Module, Class or Object -
i noticed odd while adding methods kernel
make them available globally. it's interesting, , i'm looking documentation or explanation.
let's @ code:
file: ./demo.rb
# example 1 module kernel def foo puts "i'm defined inside module!" end end # example 2 module bar def bar puts "i'm included! (bar)" end end kernel.send :include, bar # example 3 module baz def baz puts "i'm included! (baz)" end end module kernel include baz end
then, in bash , irb
$ irb -r ./demo.rb > foo # i'm defined inside module! > bar # nameerror: undefined local variable or method `bar' main:object > baz # nameerror: undefined local variable or method `baz' main:object > > self.class.ancestors # => [object, kernel, basicobject] > > include kernel > > self.class.ancestors # => [object, kernel, baz, bar, basicobject] > > foo # i'm defined inside module! > bar # i'm included! (bar) > baz # i'm included! (baz)
foo
works expected, , available objects include kernel
. bar
, baz
, on other hand, not available.
imagine it's because evaluation context of irb (an object
) includes kernel
, , including module inside module b not "reload" previous inclusions of b.
ok, makes perfect sense, , in fact re-including kernel
add other 2 methods.
then, questions are:
- why opening
kernel
work? (example 1) - if opening module treated differently, why isn't 3rd example working well?
what happens call foo.bar
in ruby? this:
foo.class.ancestors.each |klass| if klass.public_instance_methods.include? :bar return klass.instance_method(:bar).bind(foo).call end end raise nameerror
i.e. ruby searches through ancestors find matching instance method.
and happens when call a.include b
in ruby? this:
b.ancestors.each |mod| a.ancestors << mod unless a.ancestors.include? mod end
b
, of ancestors become ancestors of a
. these 2 behaviors explain everything:
- opening
kernel
works because it's included inobject
, ancestor of every object, meaning methods (including new ones) can searched whenever call method on object. - opening module isn't treated differently. second , third examples same. both don't work because
kernel
's ancestors searched when included, before added new ancestors it.
Comments
Post a Comment