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
kernelwork? (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
kernelworks 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