I am reading through Avdi Grimm's book 'Objects in Rails' and he uses the method public_method and I dont understand why. Here is the code example:
class Blog
# ...
attr_writer :post_source
# ...
private
def post_source
#post_source ||= Post.public_method(:new)
end
end
Why would you call Post.public_method(:new) and not Post.new? Do these methods do anything different or are they exactly the same? Thanks for the help.
Post.new
is not equivalent to
Post.public_method(:new)
The former is an invocation of method new, which, by default, creates a new Post object. The latter, however, does not call new immediately. It merely prepares it to be called later. I haven't read that particular book, but if you look around in the associated source code, you'll see this line
#post_source.call # maybe some params are passed here
This is where Post#new finally gets called.
Documentation: Object#public_method, Object#method.
Post.public_method(:new) and Post.new are different things. The latter creates an instance of Post. The former creates an instance of Method, which is not the result of applying such method but is an abstraction of the method itself. You can take out the result of it by doing call on it later.
Post.public_method(:new) may be replaced by Post.method(:new), unless there is a private or protected method named new. It is just making sure not to refer to such methods if there are any.
Related
So, I'm currently learning about metaprogramming in Ruby and I want to fully understand what is happening behind the scenes.
I followed a tutorial where I included some of the methods in my own small project, an importer for CSV files and I have difficulties to wrap my hand around one of the methods used.
I know that the define_method method in Ruby exists to create methods "on the fly", which is great. Now, in the tutorial the method initialize to instantiate an object from a class is defined with this method, so basically it looks like this:
class Foo
def self.define_initialize(attributes)
define_method(:initialize) do |*args|
attributes.zip(args) do |attribute, value|
instance_variable_set("##{attribute}", value)
end
end
end
end
Next, in an initializer of the other class first this method is called with Foo.define_initialize(attributes), where attributes are the header row from the CSV file like ["attr_1", "attr_2", ...], so the *args are not provided yet.
Then in the next step a loop loops over the the data:
#foos = data[1..-1].map do |d|
Foo.new(*d)
end
So here the *d get passed as the *args to the initialize method respectively to the block.
So, is it right that when Foo.define_initialize gets called, the method is just "built" for later calls to the class?
So I theoretically get a class which now has this method like:
def initialize(*args)
... do stuff
end
Because otherwise, it had to throw an exception like "missing arguments" or something - so, in other words, it just defines the method like the name implies.
I hope that I made my question clear enough, cause as a Rails developer coming from the "Rails magic" I would really like to understand what is happening behind the scenes in some cases :).
Thanks for any helpful reply!
Short answer, yes, long answer:
First, let's start explaining in a really (REALLY) simple way, how metaprogramming works on Ruby. In Ruby, the definition of anything is never close, that means that you can add, update, or delete the behavior of anything (really, almost anything) at any moment. So, if you want to add a method to Object class, you are allowed, same for delete or update.
In your example, you are doing nothing more than update or create the initialize method of a given class. Note that initialize is not mandatory, because ruby builds a default "blank" one for you if you didn't create one. You may think, "what happens if the initialize method already exist?" and the answer is "nothing". I mean, ruby is going to rewrite the initialize method again, and new Foo.new calls are going to call the new initialize.
Some open source code I'm integrating in my application has some classes that include code to that effect:
class SomeClass < SomeParentClass
def self.new(options = {})
super().tap { |o|
# do something with `o` according to `options`
}
end
def initialize(options = {})
# initialize some data according to `options`
end
end
As far as I understand, both self.new and initialize do the same thing - the latter one "during construction" and the former one "after construction", and it looks to me like a horrible pattern to use - why split up the object initialization into two parts where one is obviously "The Wrong Think(tm)"?
Ideally, I'd like to see what is inside the super().tap { |o| block, because although this looks like bad practice, just maybe there is some interaction required before or after initialize is called.
Without context, it is possible that you are just looking at something that works but is not considered good practice in Ruby.
However, maybe the approach of separate self.new and initialize methods allows the framework designer to implement a subclass-able part of the framework and still ensure setup required for the framework is completed without slightly awkward documentation that requires a specific use of super(). It would be a slightly easier to document and cleaner-looking API if the end user gets functionality they expect with just the subclass class MyClass < FrameworkClass and without some additional note like:
When you implement the subclass initialize, remember to put super at the start, otherwise the magic won't work
. . . personally I'd find that design questionable, but I think there would at least be a clear motivation.
There might be deeper Ruby language reasons to have code run in a custom self.new block - for instance it may allow constructor to switch or alter the specific object (even returning an object of a different class) before returning it. However, I have very rarely seen such things done in practice, there is nearly always some other way of achieving the goals of such code without customising new.
Examples of custom/different Class.new methods raised in the comments:
Struct.new which can optionally take a class name and return objects of that dynamically created class.
In-table inheritance for ActiveRecord, which allows end user to load an object of unknown class from a table and receive the right object.
The latter one could possibly be avoided with a different ORM design for inheritance (although all such schemes have pros/cons).
The first one (Structs) is core to the language, so has to work like that now (although the designers could have chosen a different method name).
It's impossible to tell why that code is there without seeing the rest of the code.
However, there is something in your question I want to address:
As far as I understand, both self.new and initialize do the same thing - the latter one "during construction" and the former one "after construction"
They do not do the same thing.
Object construction in Ruby is performed in two steps: Class#allocate allocates a new empty object from the object space and sets its internal class pointer to self. Then, you initialize the empty object with some default values. Customarily, this initialization is performed by a method called initialize, but that is just a convention; the method can be called anything you like.
There is an additional helper method called Class#new which does nothing but perform the two steps in sequence, for the programmer's convenience:
class Class
def new(*args, &block)
obj = allocate
obj.send(:initialize, *args, &block)
obj
end
def allocate
obj = __MagicVM__.__allocate_an_empty_object_from_the_object_space__
obj.__set_internal_class_pointer__(self)
obj
end
end
class BasicObject
private def initialize(*) end
end
The constructor new has to be a class method since you start from where there is no instance; you can't be calling that method on a particular instance. On the other hand, an initialization routine initialize is better defined as an instance method because you want to do something specifically with a certain instance. Hence, Ruby is designed to internally call the instance method initialize on a new instance right after its creation by the class method new.
Currently reading a Ruby style guide and I came across an example:
def no_op; end
What is the purpose of empty body methods?
There are a number of reasons you might create an empty method:
Stub a method that you will fill in later.
Stub a method that a descendant class will override.
Ensure a class or object will #respond_to? a method without necessarily doing anything other than returning nil.
Undefine an inherited method's behavior while still allowing it to #respond_to? the message, as opposed to using undef foo on public methods and surprising callers.
There are possibly other reasons, too, but those are the ones that leapt to mind. Your mileage may vary.
There may be several reasons.
One case is when a class is expected to implement a specific interface (virtually speaking, given that in Ruby there are no interfaces), but in that specific class that method would not make sense. In this case, the method is left for consistency.
class Foo
def say
"foo"
end
end
class Bar
def say
"bar"
end
end
class Null
def say
end
end
In other cases, it is left as a temporary placeholder or reminder.
There are also cases where the method is left blank on purpose, as a hook for developers using that library. The method it is called somewhere at runtime, and developers using that library can override the blank method in order to execute some custom callback. This approach was used in the past by some Rails libraries.
I see many examples of *args and &blk being passed and cases of yield. But let's just say I want to clone (not the clone method, but the action of cloning) a method from one Object to another.
Example:
class String
def all?
self.split("").all?
end
end
How would I best handle all edge cases for optional parameters, or blocks, whatever the case may be. This is not the only case I need to use method cloning. I just figured since you see the method doing a modification before acting as a clone you would get the idea.
I don't want my method to bring up it's own errors. I want the cloned method that's being called to give it's own errors.
Methods can be passed arguments, keyword arguments and a block. All you have to do is forward all those parameters to the method you're calling.
class String
def all?(*arguments, **keyword_arguments, &block)
chars.all? *arguments, **keyword_arguments, &block
end
end
That will catch and forward everything to Enumerable#all?, ensuring the method can used in the same way. Note that String has a chars method to enumerate its individual characters. Since that's what you seem to be doing, I took the liberty of using it.
Why not just use delegate this avoids any additional method definitions unless you need to process the arguments in addition.
class String
extend Forwardable
delegate :all? => :chars
end
When you call String.all? to will now call String.chars.all? and you can pass the same arguments as if you had called the chained method directly.
There is apparently a ruby method called method and I can't find any docs or examples on it so far. Could someone please post a few useful annotated examples?
there is docs about that method in ruby api documentation
http://www.ruby-doc.org/core-1.9.3/Object.html#method-i-method
there is also method_defined? which could be also useful if you need method it self
http://www.ruby-doc.org/core-1.9.3/Module.html#method-i-method_defined-3F
I've mostly used it to look up source location of a specific method. (example run in irb on ruby-1.9.2-p290)
class Thing
def foo
end
end
Thing.new.method(:foo).source_location
=> ["(irb)", 2]
Thing.new.method(:foo).owner
=> Thing
It's part of Object and is documented here:
http://www.ruby-doc.org/core-1.9.3/Object.html#method-i-method
The class Method is documented here, and gives some examples:
http://www.ruby-doc.org/core-1.9.3/Method.html
One of the best uses of the bound method object returned by Object#method is for blocks. The return result of that method can be converted to a block argument. Imagine you have:
class Converter
def convert_item(item)
item.transmorph
end
end
Then you could do this
c = Converter.new
elements.map(&c.method(:convert_item))
or when you are within the convertor
elements.map(&method(:convert_item))
which IMO is more elegant than the explicit block creation syntax. It also supports to_proc so you can do this
some_object.callback = my_handler.method(:activate).to_proc
and then in some_object you can do
#callback.call(data)
Object#method, is this what you are looking for?
http://www.ruby-doc.org/core-1.9.3/Object.html#method-i-method