I am really confused why the methods in modules B and C are mixed in to the class in module A when I use include C. Does include somehow recursively mix in with all classes below the namespace where it is called?
module A
class AClass
def a_method_
end
end
end
module B
extend self
def b_method_
end
end
module C
extend self
include B
def c_method_
puts A::AClass.new.methods.grep /_method_/
end
end
C.c_method_
puts "----"
include C
c_method_
With the result that before the include, the AClass instance correctly only has method a_method_, but after the include it has access to the other two methods as well.
a_method_
----
a_method_
c_method_
b_method_
Can someone please help explain this?
If you change the tail end of your code to this:
C.c_method_
puts self.inspect
puts "----"
include C
c_method_
you should help you see what's going on. That will give you this output:
a_method_
main
----
a_method_
c_method_
b_method_
So what is this main business? Chuck has a nice summary over in this answer:
Everything in Ruby occurs in the context of some object. The object at the top level is called "main". It's basically an instance of Object with the special property that any methods defined there are added as instance methods of Object (so they're available everywhere).
That means that saying this at the top level:
include C
is the same as saying:
Object.send(:include, C)
Adding things to Object pollutes everything.
You might find this illuminating:
puts Object.instance_methods.grep /_method_/
# c_method_
# b_method_
Your methods have been added to everything, not just AClass! And to really demonstrate the weirdness, try changing that last bit to:
class D
include C
puts Object.instance_methods.grep /_method_/
end
No more output! You've stumbled upon one of the weird, intentional behaviors of Ruby's main (the implicit receiver when nothing else is specified). The basic motivation is that if you define a method in main, you want to be able to call it anywhere:
def foo
end
# now all of these work:
class A
foo
end
module B
foo
end
A.new.instance_eval { foo }
A.singleton_class.class_eval { foo }
This isn't about scope resolution either; if you change that to foo = :bar you'll get NameErrors. This is for stuff like puts and gets where you generally don't care who the receiver is when you call them. But this behavior doesn't jive at all with Ruby's object model, so matz hacked it in: every method defined in main gets added to Object as an instance method. Since everything is an object, the rest works as expected.
Related
a1 is a method on A.
module A
def self.a1
puts "I am defined in A"
end
end
class Sample
include A
end
samp = Sample.new
How can I call samp.a1?
puts samp.a1
There's a couple of things to keep in mind here:
If you declare module methods with the self prefix that means they're able to be directly called on the module, like A.a1, but it also means they won't be imported with include. Those declared without self are "mix-in methods", or those that will automatically be imported on include.
If you include more than one module which defines a method then the last module included will be the one that actually gets called.
The fix here is either to change def self.a1 to def a1 in module A or instead call it directly with A.a1. If B also defines a1 then it will have precedence unless you include B first, making it lower priority.
If you know this sort of thing will happen ahead of time, you can use alias as you're including modules (note this changes the method definitions from def self.a1 to def a1 so that they are properly included as instance methods):
module A
def a1
puts "I am defined in A"
end
end
module B
def a1
puts "I am defined in B"
end
end
class Sample
include A
alias :a_a1 :a1
include B
alias :b_a1 :a1
end
samp = Sample.new
samp.a_a1
samp.b_a1
samp.a1
running this outputs:
I am defined in A
I am defined in B
I am defined in B
As a general rule, though, I would avoid this situation and rename one of the methods in the modules, if you're able to; though sometimes you're not able to for one reason or another.
If it's just for a1, then this should work:
class Sample
include A
def a1
self.class.a1
end
end
If you need it for all methods, you can try Catching the NoMethodError with a send-command for the class, but that is usually overkill.
Background:
Here is what I understand about the object model (relative to my question below):
self always references the receiver in the current stack frame.
When you are in the top level and you say def someMethod the implicit receiver is self and you are creating a method which sits in the anonymous class associated with self. This anonymous class happens to sit just under Object (self is an instance of the Object class) so when you call someMethod, Ruby "takes a step to the right", and it lands in the anonymous class, thus finding and invoking your method.
This is similar to what goes on when you define methods inside of class definitions. If, when inside a class definition, you say: def self.classMethod you are creating a method in an anonymous class that sits just underneath the Class class. Methods of this class, existing "to the right" of the class currently being defined will not be visible to instances of the new class.
My Question:
How does "defining a method in a class" happen in the first place? (semantically)
Class objects aren't supposed to be different from normal objects, right?
From what I understand about message handling, Class objects have a table as a part of their state, presumable meaning it is an instance variable, that has the names of all of its instance methods. This is how the method look up works. (If Ruby doesn't find it , it goes up one and again, presumably the directions to the next link up the chain are a part of the state of the current Class object.)
Since Ruby doesn't really care about object type, I presume it doesn't care that it's looking in Class objects specifically when doing method look up. Rather, it's just following references and looking for bits of state with certain names. So, could I create my own "class objects" without using the class keyword that don't inherit from the Class class?
If that question doesn't make any sense, then I apologize. I just want to know what happens when the interpreter encounters the def keyword.
When you write 'def something' in ruby you are adding a method to a module. Sometimes that module is a 'class' (a type of module). It all depends on what 'self' is at the time:
class Foo
# right now self is 'Foo'
class << self
# right now self is 'Class:Foo'
end
def self.bar
# right now self is 'Foo'
end
end
def Foo.buz
# right now self is 'Foo'
end
obj = Foo.new
def obj.baz
# right now self is 'Foo:0x007fe8a632fa78' (an instance)
end
A class is just a type of module. Subclassing is one way of creating a pointer from One module up to another:
class Foo
end
class Bar < Foo
end
> Bar.ancestors
=> [Bar, Foo, Object, Kernel, BasicObject]
Another way is including mixins:
module Mixin
end
class Foo
include Mixin
end
> Foo.ancestors
=> [Foo, Mixin, Object, Kernel, BasicObject]
Method dispatch works on what exists in the inheritance chain. It's a list (not a tree) of parent modules and is ordered based on when the inheritance was created:
# bar.rb
module MixinA
def something
puts "MixinA"
super
end
end
module MixinB
def something
puts "MixinB"
end
end
class Base
def something
puts "Base"
super
end
end
class Sub < Base
include MixinB
include MixinA
def something
puts "Sub"
super
end
end
obj = Sub.new
obj.something
Run:
$ ruby bar.rb
Sub
MixinA
MixinB
Inspecting the chain:
> Sub.ancestors
=> [Sub, MixinA, MixinB, Base, Object, Kernel, BasicObject]
When a method call happens in walks this list looking for the method in question. If none of the modules in the chain have the method then the search starts over at the top but instead calls method_missing. In either case, the first resolution found wins.
Yehuda Katz wrote a good article on this stuff in 2009:
http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-the-self/
When you include module in class with method name conflict, it would use method defined by the class. Is there a way to choose which one I want to run?
module B
def self.hello
"hello B"
end
end
class A
include B
def self.hello
"hello A"
end
end
A.hello #=> this prints "hello A", what if I want "hello B"?
Ben, when you call a method (say it's hello) in Ruby, this is what happens:
If the receiver's eigenclass has a method called hello, it will be called. If not:
If the receiver's class has an instance method called hello, it will be called. If not:
If any module included by the receiver's class has an instance method called hello, it will be called. If there are more than one, the most recently included module will "win". Otherwise:
If the superclass of the receiver's class has an instance method called hello, it will be called. If not:
If any module included by the superclass of the receiver's class...
(And so on for the superclass of the superclass, all the way to BasicObject...)
If no method called hello is found, the same process is repeated with method_missing, starting from the eigenclass, then the class, then included modules, then the superclass, then modules included by the superclass... this search always succeeds, because Kernel defines a default implementation of method_missing.
So to answer your question, if there is more than one method called hello, you can't choose which one will be invoked. The method lookup rules described above decide which one will be invoked.
HOWEVER: Ruby is a very flexible language, and if you post more details about what you want to do and why, I can probably help you think of a way to simulate the desired effect.
Another point: if you want to add class methods from a module to a class, you can do this:
module B; def hello; "hello B"; end end
A.extend(B)
A.hello
=> "hello B"
Do you see? When a class includes a module, the module's instance methods become instance methods on the class. When a class extends a module, the module's instance methods become class methods on the class.
The way it's set up it'd never call the included module's method anyway. Try leaving out the hello method in A and see what happens when you call A.hello.
This will include the method from B. There's probably a more succinct way to do this. I just cribbed it from my codebase:
module B
def self.included(base)
base.extend Greetings
end
module Greetings
def hello
"hello B"
end
end
end
The module's method will always override the included module's method. That's the way it's supposed to work. However, you could conditionally return A's hello value like this:
module A
include B
def self.hello
if show_hello_a?
"hello A"
else
super
end
end
def self.show_hello_a?
false # insert an actual condition statement here
end
end
When you call A.Hello all that is happening is the message "hello" is being passed to the A object. The A object then must determine how to handle that message. It will first look at it's own methods to determine if it has one called "hello" before looking to it's parents and included modules for a "hello" method.
While you could technically use A.ancestors to see that B is an ancestor of A, and call it's hello method, this would be violating the abstraction of A as an object.
The correct way to allow both methods to be called would be to create another method in A that calls B.hello, or to name A.hello something else so that it wouldn't override the functionality of B.hello.
Edit: Because you have included B in A, creating a method that calls B's hello within A is as simple as adding a method that calls B.hello
def self.hello2
B.hello
end
I'm trying to learn ruby by building a basic Campfire bot to screw around with at work. I've gotten pretty far (it works!) and learned a lot (it works!), but now I'm trying to make it a bit more complex by separating the actions to be performed out into their own classes, so that they can be easier to write / fix when broken. If you're interested in seeing all the (probably crappy) code, it's all up on GitHub. But for the sake of this question, I'll narrow the scope a bit.
Ideally, I would like to be able to create plugins easily, name them the same as the class name, and drop them into an "actions" directory in the root of the project, where they will be instantiated at runtime. I want the plugins themselves to be as simple as possible to write, so I want them all to inherit some basic methods and properties from an action class.
Here is action.rb as it currently exists:
module CampfireBot
class Action
#handlers = {}
def initialize(room)
#room = room
end
class << self
attr_reader :handlers
attr_reader :room
def hear(pattern, &action)
Action.handlers[pattern] = action
end
end
end
end
Where #room is the room object, and #handlers is a hash of patterns and blocks. I kind of don't understand why I have to do that class << self call, but that's the only way I could get the child plugin classes to see that hear method.
I then attempt to create a simple plugin like so (named Foo.rb):
class Foo < CampfireBot::Action
hear /foo/i do
#room.speak "bar"
end
end
I then have my plugins instantiated inside bot.rb like so:
def load_handlers(room)
actions = Dir.entries("#{BOT_ROOT}/actions").delete_if {|action| /^\./.match(action)}
action_classes = []
# load the source
actions.each do |action|
load "#{BOT_ROOT}/actions/#{action}"
action_classes.push(action.chomp(".rb"))
end
# and instantiate
action_classes.each do |action_class|
Kernel.const_get(action_class).new(room)
end
#handlers = Action.handlers
end
The blocks are then called inside room.rb when the pattern is matched by the following:
handlers.each do |pattern, action|
if pattern.match(msg)
action.call($~)
end
end
If I do puts #room inside the initialization of Action, I see the room object printed out in the console. And if I do puts "foo" inside Foo.rb's hear method, I see foo printed out on the console (so, the pattern match is working). But, I can't read that #room object from the parent class (it comes out as a nil object). So obviously I'm missing something about how this is supposed to be working.
Furthermore, if I do something to make the plugin a bit cleaner (for larger functions) and rewrite it like so:
class Foo < CampfireBot::Action
hear /foo/i do
say_bar
end
def say_bar
#room.speak "bar"
end
end
I get NoMethodError: undefined method 'say_bar' for Foo:Class.
The definition of hear can be pulled out of the class << self block and changed to:
def self.hear(pattern, &action)
Action.handlers[pattern] = action
end
to yield the exact same result. That also immediately explains the problem. hear Is a class method. say_bar is an instance method. You can't call an instance method from a class method, because there simply isn't an instance of the class available.
To understand the class << self bit, you'll have to do your own reading and experiments: I won't try to improve on what has already been said. I'll only say that within the class << self .. end block, self refers to the eigenclass or metaclass of the CampfireBot::Action class. This is the instance of the Class class that holds the definition of the CampfireBot::Action class.
I'm writing a Ruby library which has a module with a bunch of classes inside it. Many of these classes need to be usable and modifiable by calling scripts, but I don't want (some of) the initializers to be visible/callable:
module MyLib
class Control
def initialize
# They can use this
end
def do_stuff
Helper.new('things')
end
end
class Helper
# Shouldn't be visible
def initialize(what)
#what = what
end
def shout
#what
end
end
end
c = MyLib::Control.new
h = c.do_stuff
p h.shout
# => "things"
# ^ All of this is desired
# v This is undesirable
p MyLib::Helper.new('!')
# => <MyLib::Helper #what='!'>
If it's a simple thing, then I'd also appreciate the generated RDoc not even include the .new method for the Helper class either. Any ideas?
Thanks for reading!
My original answer was completely wrong, as #Matthew pointed out. But there are other workarounds. For instance, you can assign an anonymous class to a class variable on Control, and still define methods as normal by using class_eval:
module MyLib
class Control
def initialize
end
def do_stuff
##helper.new('things')
end
##helper = Class.new
##helper.class_eval do
def initialize(what)
#what = what
end
def shout
#what
end
end
end
end
The snippet
c = MyLib::Control.new
h = c.do_stuff
p h.shout
still writes "things", but now there's no way to access ##helper except through the class variable. If someone really wants to access it my reopening the Control class or using class_eval, there's nothing to stop them, but that's just something you have to deal with in a dynamic language.
I chose to assign the anonymous class to a class variable so that it would only be created once; but if you don't care about redefining the anonymous class many times, there's no reason it couldn't be an instance variable.
Ruby has access control.