How Does Ruby Allow a Method and a Class with the Same Name

Refer to method in module with same name as class

If you don't want to look up the constant relative to the current scope, just use an absolute path:

::Pushover.configure

Local variables and methods with the same name in Ruby?

In ruby you can have local variables and methods with the same name. This has some complications for example with setter methods in classes:

class Test
def active
@active
end

def active=(value)
@active = value
end

def make_active
active = true
end
end

t1 = Test.new
t1.active = true
t1.active #=> true

t2 = Test.new
t2.make_active
t2.active #=> nil

Code for t1 object will return expected result, but code for t2 returns nil, because make_active method is actually creating local variable and not calling active= method. You need to write self.active = true to make this work.

When you write gen_class, ruby tries to access local variable, if it is not defined ruby tries to call method. You can call your method explicit by writing gen_class().

method's local variable with same name as another method

I think that the local variable is declared as soon as it's enunciated. In ruby the lookup is first to look for a local variable, if it exists it's used, and if not it looks for a method. This would mean that val = val declares the first val as local and the left-hand val then matches it (not sure about it I should check the ruby under microscope to be sure)

If you try

class A
def val
10
end

def test
back = []
x = val
back << x
val = x + 1
back << val
x = val
back << x
end
end

p A.new.test

then all is good, it prints [10, 11, 11] which means the first x = val calls the method, the second calls the local variable, presumably.

Method and variable name is the same

Try this:

puts hello()

Class context overrides Module methods with the same name?

Class context overrides Module methods with the same name?

Yes, that is how it works.

class C
include M
end

makes M the superclass of C, that's all it does.

Since M is the superclass of C (or looking at it from the other side C is a subclass of M), methods defined in C override methods defined in M, that's just how inheritance works.

If you want M's methods to override C's, you need to use prepend which puts M in front of the ancestors list.


More precisely, an include class M′ is created whose class variable table pointer, constant table pointer, and method table pointer point to M's class variable table, M's constant table, and M's method table. M′'s superclass pointer is set to C's superclass, then C's superclass pointer is set to M′. The Object#class and Class#superclass methods know to "skip" singleton classes and include classes, and Module#ancestors knows to return the corresponding module instead of the include class, so you don't see this working, but that's what happens.

This explains why methods defined in the class override methods defined in the included module. It also explains the behavior of super with modules. It's all just straightforward class inheritance.

Rails associated models with a method of the same name

Firstly, ActiveRecord::Concern can change a lot of behaviour and you've left out a lot of code, most crucially, I don't know where it's being injected, but I can make an educated guess.

For a Concern's methods to be available a given object, it must be include'd in the object's class's body.

If you have access to an instance of the Order object, at any point you can call the balance method:

order = Orders.last         # grab the last order in your database
order.balance # this will call Order#balance

And if you have the Order then you can also get the LineItem:

order.line_items.first.balance    # should call the Concerns:: LineItems::Aggregates#balance

You can open up a Rails console (with rails console) and run the above code to see if it works as you expect. You'll need a working database to get meaningful orders and balances, and you might need to poke around to find a completed order, but Ruby is all about exploration and a REPL is the place to go.

I'd also grep (or ag or ack) the codebase looking for calls to balance maybe doing something like grep -r "(^|\s)\w+\.balance" *, what you want to look for is the word before .balance, that is the receiver of the "balance" message, if that receiver is an Order object then it will call Order#balance and if it is a LineItem object then it will call Concerns:: LineItems::Aggregates#balance instead.

I get the feeling you're not familiar with Ruby's paradigm, and if that's the case then an example might help.

Let's define two simple Ruby objects:

class Doorman
def greet
puts "Good day to you sir!"
end
end

class Bartender
def greet
puts "What are you drinking?"
end
end

Doorman and Bartender both have a greet method, and which is called depends on the object we call greet on.

# Here we instantiate one of each
a_doorman = Doorman.new
a_bartender = Bartender.new

a_doorman.greet # outputs "Good day to you sir!"
a_bartender.greet # outputs "What are you drinking?"

We're still using a method called greet but the receiver is what determines which is called.

Ruby is a "message passing language" and each "method" is not a function but it's a message that is passed to an object and handled by that object.


References

  • How to use concerns in Rails 4
  • http://api.rubyonrails.org/classes/ActiveSupport/Concern.html
  • http://guides.rubyonrails.org/command_line.html#rails-console

Is it OK to use the same name for a Ruby method parameter and an accessor method?

It is totally safe to do this and I do it all the time. However, I think that's it's a better style to set your object attributes like this:

class Parser
attr_accessor :config, :html
def initialize(config, html)
self.config = config
self.html = html
end
...
end

When you do this, your code will use the setter methods provided by attr_acessor. This way you always have a consistent way that your variables are accessed.



Related Topics



Leave a reply



Submit