* 20 end end m...">

Module methods in Ruby

Here is my code:

module Star
  def Star.line
    puts '*' * 20
  end
end

module Dollar
  def Star.line
    puts '$' * 20
  end
end

module At
  def line
    puts '@' * 20
  end
end

include At
Dollar::line # => "@@@@@@@@@@@@@@@@@@@@"
Star::line   # => "$$$$$$$$$$$$$$$$$$$$"
Dollar::line # => "@@@@@@@@@@@@@@@@@@@@"
line         # => "@@@@@@@@@@@@@@@@@@@@"

      

Can someone explain how I get this result? I don't understand the flow of looking for a method here.

+3


source to share


3 answers


This is how I see it:

Dollar::line

This module does not have a method to call At::line

because you included this module.

Star::line

It uses the latest definition from the module Dollar

(it comes after the original definition Star

, so it is overridden).



Dollar::line

The third call is the same as the first.

line

And the last one is At::line

because you did include.

+7


source


Is an

module Dollar
   def Star.line

      



intentional or typo?

It looks like it Dollar.line

is undefined and the method line

in the At

.

+1


source


First, you need to understand that Ruby looks for constants that are somewhat similar to methods. It starts by looking for a constant in the current lexical scope. If he doesn't find a constant, it goes up one level and looks there, etc. If it can't find the constant elsewhere, it ends up looking for the top level, so you can access modules like Kernel

, from anywhere in your code.

module Star
end
Star.object_id # 20

module Dollar
  Star.object_id # 20. No Star in current scope, so gets the top-level star
end

module At
  module Star
  end
  Star.object_id # 10. There is now a Star in this scope, so we don't get the top-level one
end

      

The next thing to understand is that methods defined at the top level in Ruby are instantiated methods Object

. Since everything in Ruby is an instance Object

, such methods can always be called.

Finally, let's look at what it does include

: it takes instance methods from the module and makes them instances in the current scope. So, if you are include

something at the top level, all these methods are added to Object

!

So your code is essentially equivalent to this:

module Star
  def self.line
    puts '*' * 20
  end

  # this overwrites the previous definition
  def self.line
    puts '$' * 20
  end
end

# because of the way constants are looked up, the def ends up in Star
module Dollar
end

module At
  def line
    puts '@' * 20
  end
end

# the include does this, so now every object (including Dollar) can call line
def line
  puts '@' * 20
end

# except Star already has its own line method, so the one from Object won't be called for it
Star.line # "$$$$$$$$$$$$$$$$$$$$"

      

+1


source







All Articles