Need assistance understanding Ruby code - ruby

I was working on a coding problem at codewars.com. This is the answer to said problem:
class Conjurer
def self.conjure(name, lambda)
define_method name, lambda
end
end
I would like to articulate the way I am reading it, and receive criticism that helps me better understand the meaning of this code.
The class Conjurer is created.
An instance method of the class is called, representing the class itself.
It is given permanent parameters name and lambda.
Unsure what define_method name, lambda means.

define_method makes a method named name and passes it a block lambda. So if you call the method name, it runs the block represented by the variable lamba.
The self.conjure is allowing you do define a method within the class: the name parameter becomes the name of the method, the lambda becomes the body of the method itself.

The class Conjurer is created.
Yes. More accurately, the Conjurer class is opened, meaning that it's being opened for modification. In this case, the conjure method is being added.
In Ruby, you can open a class many times:
class Conjurer
def self.something
# code
end
end
class Conjurer
def self.other_thing
# code
end
end
This is the same as doing
class Conjurer
def self.something
# code
end
def self.other_thing
# code
end
end
An instance method of the class is called, representing the class itself.
No. It's not a method call, it's a method definition. The def keyword defines a new method. The def self. defines a method for the Conjurer class rather than a Conjurer.new instance.
It is given permanent parameters name and lambda.
Almost. The parameters are name and lambda, but they're not arguments of a call (see here for the difference between argument and parameter), because that isn't a method call, is a method definition.
Unsure what define_method name, lambda means.
define_method is part of the Ruby language. It does what is says, it defines a method with the name name that when called, executes lambda. See the docs here.

Related

Ruby methods called at top of classes

I've seen this a lot in Ruby (started using Ruby for the first time a couple years ago):
class MyAwesomeClass
another_method
def initialize; end
end
And I can't get my head around what type of method another_method is...
Looking at examples, it's sometimes declared as a class method, but usually you call class methods in your code like this:
AnotherClass.another_method
And most importantly you call your methods regardless if they are from another class, module, or inherited class inside another method of your class you use them. For example:
module SomeModule
def some_method; end
end
class AnotherClass
private
def another_method; end
end
class YetAnotherClass
self.yet_another_method; end
end
class MyAwesomeClass < AnotherClass
include SomeModule
def initialize
some_method # method from my included module
another_method # method inherited from AnotherClass
YetAnotherClass.yet_another_method # class method called directly
end
end
So what are these methods that can be called at the top of a class and NOT called inside of another method as my examples above?
Are you able to just call class methods inside another class (that it inherits from) outside of your method calls?
I can't get my head around what type of method another_method is...
There is only one type of method in Ruby: every method in Ruby is an instance method of some module. There is no other type of method.
We may sometimes talk about "class methods" or "singleton methods", but that is just a convenient way of talking about a particular way to use methods. The methods themselves are no different.
Every method in Ruby is an instance method of some module. The question is simply: which module?
We are sometimes talking about class methods, but class methods don't really exist. Class methods are simply singleton methods of an object that happens to be an instance of the Class class.
There is absolutely no difference between
Foo = ''
def Foo.bar; end
and
class Foo; end
def Foo.bar; end
and
module Foo; end
def Foo.bar; end
We call the first one a "singleton method", the second one a "class method", and the third one a "module function", but there is actually no difference between the three. The only difference is that the first object is an instance of the String class, the second object is an instance of the Class class, and the third object is an instance of the Module class, that's it.
Actually, I must confess something: I lied. I wrote that class methods are simply singleton methods of an object that happens to be an instance of the Class class, but in reality … singleton methods don't exist either.
A singleton method is simply a boring old normal instance method of the singleton class.
There is no difference between
foo = ''
def foo.bar; end
and
foo = ''
class << foo
def bar; end
end
There you have it: singleton methods are actually just instance methods of the singleton class, class methods are actually just instance methods of the singleton class of an object that is an instance of the Class class, module functions are actually just instance methods of the singleton class of an object that is an instance of the Module class.
It's just that "instance method of the singleton class of an object that is an instance of the Class class" is annoying to say and write all the time, so we say "class method" instead, knowing full well that there is no such thing.
Looking at examples, it's sometimes declared as a class method, but usually you call class methods in your code like this:
AnotherClass.another_method
Again, there is no such thing as a class method. There is exactly one kind of method, and they are always called the same way:
receiver.method(args)
If the receiver is self, then you can leave it out, and if you have no arguments, you can leave them out, too.
And most importantly you call your methods regardless if they are from another class, module, or inherited class inside another method of your class you use them.
That is not true.
In fact, in your own example, you are calling two methods outside of a method body: Module#private and Module#include, and you seem to have no trouble with those. Other methods that I am sure you have already called outside of a method body are Module#attr_accessor, Kernel#require, or Kernel#puts. In fact, in simple scripts, there is often not a single method definition body at all.
So what are these methods that can be called at the top of a class and NOT called inside of another method as my examples above?
They are instance methods just like any other instance methods, there is absolutely nothing special about them.
Are you able to just call class methods inside another class (that it inherits from) outside of your method calls?
Since class methods don't exist, and these are simply instance methods just like every other instance method, the method lookup algorithm is of course also just the method lookup algorithm for instance methods:
Start with the private internal hidden __klass__ pointer of the receiver. If you can't find the method there …
Get the private internal hidden __superklass__ pointer and repeat.
And that's it. (Yes, okay, there is a tiny bit more to it: if you come to a point where there is no __superklass__ pointer, then you try again with method_missing and the name of the method as an argument, and if you also cannot find that, then you raise a NoMethodError.)
So, let's try that in your example:
class MyAwesomeClass
another_method
end
Okay, first off: what is the receiver? Well, if no receiver is given, then the receiver is always implicitly self. Now, what is self here?
A ha! That is actually the most important question in Ruby, always. At any point in Ruby, you must always know what self is.
Well, we know that inside of a method body, self is the receiver of the message send. So, we can guess: what would make the most sense for self inside of a class definition. The class itself, of course! Let's test that:
what_is_self = class MyAwesomeClass
self
end
p what_is_self
# MyAwesomeClass
Well, looks like we're right. Okay, we know the receiver of the message send is MyAwesomeClass, so what is the first step in our algorithm? We get the private internal hidden __klass__ pointer.
We cannot actually do that in Ruby (it is a private internal hidden implementation detail of the Ruby implementation). But let me assure you that is pretty much always going to be the singleton class. (There are some objects which cannot have singleton classes, and some Ruby implementations optimize the creation of singleton classes so that they are only created when needed, but for all intents and purposes, we can assume that the __klass__ pointer is always the singleton class.)
We look inside the singleton class, and we find no definition of the method another_method. So, we move to the second step of the algorithm: we get the __superklass__ of the singleton class.
The __superklass__ of the singleton class is usually going to be the class of the object. So, in this case, the object is MyAwesomeClass, which is a class, so the class of MyAwesomeClass and the __superklass__ of the singleton class is going to be Class.
Again, we look inside Class and we don't find another_method. Ergo, we get Class's __superklass__, which is Module. We also don't find another_method here, so we move on to Object, which also doesn't have another_method.
Now, it gets interesting again, because Object's __superklass__ pointer is actually Kernel and not BasicObject as you might have thought. (More precisely, it is an include class which shares its method table with the Kernel module, since Kernel is not a class at all and thus cannot be a superclass.)
Kernel also doesn't have a method named another_method, so we get Kernel's __superklass__ (again, technically we are talking about an include class that proxies Kernel and not Kernel itself), which is BasicObject. Finally, BasicObject does not have a __superklass__.
Which means we start aaaaaaaaaaaall the way back from step #1 again, but this time as-if you had written
class MyAwesomeClass
method_missing(:another_method)
end
We do the whole song-and-dance again, and we also never find a method until we get to the very top, to BasicObject, which has a method_missing that roughly looks like this:
class BasicObject
def method_missing(meth, *args)
raise NoMethodError, "undefined method `#{meth}' for #{inspect}", meth, args, receiver: self
end
end
So, if you want your call to another_method to not fail, it needs to be defined anywhere along the whole chain we just walked up:
In MyAwesomeClass's singleton class
In a module that MyAwesomeClass extends
In Class
In a module that Class includes
Or in a module included by that module
In Module
In a module that Module includes
Or in a module included by that module
In Object
In Kernel
Or another module that Object includes
Or in a module that Kernel includes
In BasicObject
In a module that BasicObject includes
Or in a module included by that module
Or maybe the Ruby implementation you are using has an implementation-specific superclass of BasicObject (e.g. MacRuby has Objective-C's NSObject as the superclass of BasicObject)
To illustrate difference between different type of methods, consider this example:
class Foo
puts 'method called outside of method'
def initialize
puts 'initialize called'
end
def instanse_method
puts 'instance method called'
end
def self.clazz_method
puts 'class method called'
end
end
Foo
foo = Foo.new
foo.instanse_method
Foo.clazz_method
What will be the output?
method called outside of method
initialize called
instance method called
class method called
So what are these methods that can be called at the top of a class and NOT called inside of another method as my examples above?
As you can see, any method can be called before initialize method. It's executed when class is loaded.
Just calling
Foo
would be sufficient enough to output:
method called outside of method
(but notice that it was not called multiple times)
Looking at examples, it's sometimes declared as a class method, but usually you call class methods in your code like this: AnotherClass.another_method
It's like static function in PHP. In my example, it's Foo#clazz_method.
And most importantly you call your methods regardless if they are from another class, module, or inherited class inside another method of your class you use them
Usually, you have to include a file that define another class before using its method. But most frameworks like Ruby on Rails, have already built-in autoloading system, so it looks like it's working magically without explicit require or include. But there are times when RoR does not know where your custom classes are. In this case, you have to require the file explicitly before you use it. Well, usually in the beginning of the file.
It'll be easier to understand by looking at it in action.
# Step 1
# Run this in IRB
class MyClass
def self.another_method
puts "Executed when class is loaded to memory"
end
end
# Step 2
# Now when you run the following in IRB after that, its going to execute the
# class method which was defined in its parent class (MyClass)
class MyAwesomeClass < MyClass
another_method # Executed ONCE when the class is loaded to memory for the first
def initialize; end
end
# Now if you instantiate MyAwesomeClass though, it will not print the same as of
# Step 2 as class method :another_method already has been executed when class
# was loaded
awesome1 = MyAwesomeClass.new
The body of a class will be interpreted and executed sequentially & behaves much like you'd expect it inside an instance method. Try putting a puts "Hello World" in the body of your class definition like so:
class MyClass
# Executes when the class is defined in IRB(Loaded to memory)
puts "Hello World"
end

Why use 'instance_eval' instead of creating a method?

Here's a code sample:
class Book
def initialize
#v = "abc"
end
end
b = Book.new
b.instance_eval do
def book_name
end
end
Why do we use instance_eval to create a method (book_name) instead of adding book_name method inside class Book? The method (book_name) created using instance_eval will be accessible only by object b in the case above. Is there any particular use case?
instance_eval is very useful when some kind of metaprogramming is needed, like when defining methods during instance initialization or inside frameworks.
Why use it? It's usually faster than calling define_method in these cases and, if adding a bunch of methods at the same time, invalidates the method cache just once.
On your specific example the method is being created only on the b instance, making it what is called a singleton method, meaning it only exists for this particular instance. The author could have used eval but since it evaluate code on a more global scope, it's considered unsafe.
Edit:
The same effect would be produced if you defined the method using b as the receiver
def b.book_name
end
The author of this codes wanted book_name to be a method which belongs only to b. If he had created inside the class definition, it would belong to every object of class Book.

Method is executed without calling it?

I came across this solution for a Proxy class in the Ruby koans:
class Proxy
attr_accessor :messages
def initialize(target_object)
#object = target_object
#messages = []
end
def method_missing(method_name, *args, &block)
#messages << method_name
#object.send(method_name, *args, &block)
end
end
I can create an object from this proxy class by passing another class as an argument. For instance, the following code will result in "Do something", without having to type thing.method_missing(:do_thing):
class Thing
def do_thing
puts "Doing something."
end
end
thing = Proxy.new(Thing.new)
thing.do_thing
Why is the code in method_missing executed even without having to call said method?
There are methods that are called implicitly (i.e., called even when you don't write it in the code) when a certain event happens or a certain method is called. I call these methods hooks, borrowing the terminology of e-lisp. As far as I know, Ruby has the following hooks:
Ruby hooks
at_exit
set_trace_func
initialize
method_missing
singleton_method_added
singleton_method_removed
singleton_method_undefined
respond_to_missing?
extended
included
method_added
method_removed
method_undefined
const_missing
inherited
initialize_copy
initialize_clone
initialize_dup
prepend
append_features
extend_features
prepend_features
And method_missing is one of them. For this particular one, it is automatically called when Ruby cannot find a defined method. Or in other words, method_missing is the most default method that is called with the least priority, for any method call.
method_missing is one of the amazing aspects of metaprogramming in ruby. With proper use of this method, you can gracefully handle exceptions and whatnot. In your case it is called because the method you are calling on the object doesn't exist obviously.
But one should be careful of its use too. While you are at it do look at responds_to method too.
An example regarding ActiveRecord will make you understand better. When we write:
User.find_by_email_and_age('me#example.com', 20)
There isn't actually a method by that name. This call goes to the method_missing and then this fancyfindmethod is broken down into pieces and you are served what you asked for. I hope that helps.

Sending method to child in Ruby class? Inheritance confusion

I have the following code:
class Bike
attr_reader :chain
def initialize
#chain = default_chain
end
def default_chain
raise 'SomeError'
end
end
class MountainBike < Bike
def initialize
super
end
def default_chain
4
end
end
mb = MountainBike.new
p mb.chain
When in the initialization we call super, I would expect the default_chain of the super class to be called, and therefore the Exception to be launched. However, it seems that the Bike class actually goes and calls the default_chain method of the original caller. Why is that?
As said #BorisStitnicky you need to use singleton_class. For more understanding, in this post you may find info: Understanding the singleton class when aliasing a instance method
The point of putting a same-named method in a sub-class is to overload that method.
ie to replace it with your new version.
The code will look at the calling sub-class's version of any method - before it starts looking up the ancestry chain for a method, because the sub-class is the context of the current code.
So even though the method is referred-to in the superclass... the ruby interpreter will still first look at your sub-class's set of method as the main context.
If you also want to call the parent's one - you must use super in your default_chain method too.
Alternatively rename the one in the parent class to something else and call it from your superclass only.
In object oriented programming, which method is called is solely determined by the receiver and the method name.
Method name initialize is called on the receiver: MountainBike instance, for which MountainBike#initialize matches, and is executed.
Within the execution, super is called, for which Bike#initialize matches, and is executed.
Within the execution, method name default_chain is called on the implicit receiver self, which is the MountainBike instance. MountainBike#default_chain matches, and is executed.
If Bike#default_chain were to be called in the last step on the receiver (MountainBike instance), it would mean that method calling would depend not only on the receiver and the method name, but also on the context. That would make it too complicated, and would defeat the purpose of object oriented programming. Again, the idea of object oriented programming is that method call is solely determined by the receiver and the method name, not the context.

Why use extend/include instead of simply defining method in main object?

RSpec adds a "describe" method do the top-level namespace. However, instead of simply defining the method outside of any classes/modules, they do this:
# code from rspec-core/lib/rspec/core/dsl.rb
module RSpec
module Core
# Adds the `describe` method to the top-level namespace.
module DSL
def describe(*args, &example_group_block)
RSpec::Core::ExampleGroup.describe(*args, &example_group_block).register
end
end
end
end
extend RSpec::Core::DSL
Module.send(:include, RSpec::Core::DSL)
What is the benefit of using this technique as opposed to simply defining describe outside any modules and classes? (From what I can tell, the DSL module isn't used anywhere else in rspec-core.)
I made this change a few months ago so that describe is no longer added to every object in the system. If you defined it at the top level:
def describe(*args)
end
...then every object in the system would have a private describe method. RSpec does not own every object in the system and should not be adding describe willy-nilly to every object. We only want the describe method available in two scopes:
describe MyClass do
end
(at the top-level, off of the main object)
module MyModule
describe MyClass do
end
end
(off of any module, so you nest your describes in a module scope)
Putting it in a module makes it easy to extend onto the main object (to add it to only that object, and not every object) and include it in Module (to add it to all modules).
Actually, if that's all there is in the code, I don't really believe it to be much better — if at all. A common argument is that you can easily check that RSpec is responsible for addinng this method in the global namespace by checking the method owner. Somehow it never felt this was needed, as the location of the method already stores that information.
Defining the method outside of any scope would have be equivalent to defining a private instance method in Object:
class Object
private
def double(arg)
arg * 2
end
end
double(3) # OK
3.double(3) # Error: double is private
self.double(3) # Error: double is private
I think privateness is a useful aspect, because it prevents from making certain method calls that have no meaning, that the code shown in the question lacks.
There's an advantge to defining the method in a module, though, but the RSpec code doesn't seem to make use of it: using module_function, not only do you preserve privateness of the instance method, but you also get a public class method. This means that if you have an instance method of the same name, you will still be able to refer to the one defined by the module, by using the class method version.
A common example of module_function is the Kernel module, which contains most function-like core methods like puts (another one is Math). If you're in a class that redefines puts, you can still use Kernel#puts explicitly if you need:
class LikeAnIO
def puts(string)
#output << string
end
def do_work
puts "foo" # inserts "foo" in #output
Kernel.puts "foo" # inserts "foo" in $stdout
end
end

Resources