From: Josh Cheek Date: 2011-01-18T22:04:51+09:00 Subject: Re: Current class --0016e64f47ce366425049a1e8a64 Content-Type: text/plain; charset=ISO-8859-1 On Tue, Jan 18, 2011 at 6:37 AM, Josh Cheek wrote: > On Sun, Jan 16, 2011 at 7:59 AM, Josh Cheek wrote: > >> My questions are: >> 1. Is any other situation where this information is relevant? >> > > I found one more situation where this knowledge is relevant. > > When you are in your main object, and you define methods (here, they feel > like functions), they become available to all objects. The reason for this > is because the current class is set to Object, so defining methods in main > defines them as instance methods of Object, which is an ancestor of most > classes, so most objects can now invoke this method. > > To test this, I went to Ruby 1.9, which has BasicObject that does not > inherit from Object, and showed that you can invoke f from an instance of > Object, but not an instance of BasicObject. > > > > RUBY_VERSION # => "1.9.1" > > # create a new function in the main object > self # => main > defined? f # => nil > def f > 'you see f' > end > > > # current class is Object, so it defines the method on object > method :f # => # > Object.instance_method :f # => # > > > # Object inherits from BasicObject > # BasicObject inherits from nothing > Object.ancestors # => [Object, Kernel, BasicObject] > BasicObject.ancestors # => [BasicObject] > > > # so if f exists on instances of Object, > # but not instances of BasicObject, > # then the explanation of top-level "functions" is that > # current class is Object, so def keyword defines methods in Object > # and almost everything inherits from Object, so it is visible everywhere > Array.new.instance_eval { f } # => "you see f" > begin > BasicObject.new.instance_eval { f } # => > rescue > $!.to_s # => "undefined local variable or method `f' for > #" > end > > > # But the main object must be declared privately, > # to which prevent it from showing up in objects' methods lists > # or being able to do stupid things like this > begin > Array.new.f # => > rescue > $!.to_s # => "private method `f' called for []:Array" > end > > > # to test this, the above code should work if we make f public > public :f > Array.new.f # => "you see f" > > Okay, and this, then, explains, why you can include modules into the general namespace, and then the methods become available. Because you are actually including them on Object, so they become available everywhere. Which is actually dangerous! require 'fileutils' require 'digest' class User def initialize(attributes) @attributes = attributes end def method_missing(meth) @attributes[meth] end def password_hash Digest::MD5.hexdigest(pwd) end end bill = User.new :name => 'bill' , :pwd => 'a19532SDjkl' # store the password hash before and after including FileUtils before = bill.password_hash include FileUtils after = bill.password_hash # compare them before == after # => false before # => "baa0396a6b57358e05e48e66be123288" after # => "badfb5b273616983aa8bea8b099bf343" # so what happened? str = 'a19532SDjkl' # => "a19532SDjkl" Digest::MD5.hexdigest(str) # => "baa0396a6b57358e05e48e66be123288" before # => "baa0396a6b57358e05e48e66be123288" pwd # => "/Users/joshuacheek" Digest::MD5.hexdigest(pwd) # => "badfb5b273616983aa8bea8b099bf343" after # => "badfb5b273616983aa8bea8b099bf343" So what you should actually do is `extend FileUtils` instead of `include FileUtils`, because Extend will put the module on the main object's singleton class, and it won't be visible to any other objects. --0016e64f47ce366425049a1e8a64--