How do you reproduce a method with forwarding parameters? - ruby

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.

Related

Ruby - how to intercept a block and modify it before eval-ing or yield-ing it?

I have been thinking about blocks in Ruby.
Please consider this code:
div {
h2 'Hello world!'
drag
}
This calls the method div(), and passes a block to it.
With yield I can evaluate the block.
h2() is also a method, and so is drag().
Now the thing is - h2() is defined in a module, which
is included. drag() on the other hand resides on an
object and also needs some additional information.
I can provide this at run-time, but not at call-time.
In other words, I need to be able to "intercept"
drag(), change it, and then call that method
on another object.
Is there a way to evaluate yield() line by line
or some other way? I don't have to call yield
yet, it would also be possible to get this
code as string, modify drag(), and then
eval() on it (although this sounds ugly, I
just need to have this available anyway
no mater how).
If I'm understanding you correctly, it seems that you're looking for the .tap method. Tap allows you to access intermediate results within a method chain. Of course, this would require you to restructure how this is set up.
You can kind of do this with instance_eval and a proxy object.
The general idea would be something like this:
class DSLProxyObject
def initialize(proxied_object)
#target = proxied_object
end
def drag
# Do some stuff
#target.drag
end
def method_missing(method, *args, &block)
#target.send(method, *args, &block)
end
end
DSLProxyObject.new(target_object).instance_eval(&block)
You could implement each of your DSL's methods, perform whatever modifications you need to when a method is called, and then call what you need to on the underlying object to make the DSL resolve.
It's difficult to answer your question completely without a less general example, but the general idea is that you would create an object context that has the information you need and which wraps the underlying DSL, then evaluate the DSL block in that context, which would let you intercept and modify individual calls on a per-usage basis.

What is the asterisk alone in the parameter list?

I found this in a Module that is supposed to extend some other class:
module Somemodule
def foo(*)
do_something_funny
super
end
end
I understand def foo(*args) construct. What is the purpose of an asterisk alone?
It's similar to *args but you get no reference to the arguments. They are, however, passed as provided to any super invocation to the parent's constructor (or same-name method), as long as no explicit parameters are specified in the super call.
It is a nice way to convey that you do not intend to process the provided arguments in any way.

Why use Rails public_method?

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.

Blocks and objects

I have an object like this
class SomeObject
def initialize &block
# do something
end
end
class AnotherObject < SomeObject
def initalize &block
super
# do something with block
end
end
When super is called in AnotherObject, the block seems to be passed to SomeObject. Is this the right behaviour and is there away round it?
According to rubyspec this is the correct behaviour, even if you pass explicit arguments to super (i.e. super('foo'))
If you don't want to pass that block, you could just pass a block that does nothing, although this isn't quite the same thing (e.g. if the method changes its behaviour based on block_given?)
It appears that
super(&nil)
is a way to pass no block at all to super, although I couldn't find this in ruby spec.

Dot syntax vs param passing syntax

Are only the core Ruby methods callable using object.functionName syntax? Is it possible to create methods on my own that are callable in the dot syntax fashion?
For this method:
def namechanger (name)
nametochange = name
puts "This is the name to change: #{nametochange}"
end
First one below works, the second does not.
namechanger("Steve")
"Steve".namechanger
I get an error on "Steve".namechanger
The error is:
rb:21:in `<main>': private method `namechanger' called for "Steve":String (NoMethodError)
Yes, you can add methods to the String class to achieve your desired effect; the variable "self" refers to the object which receives the method call.
class String
def namechanger
"This is the name to change: #{self}"
end
end
"Steve".namechanger # => This is the name to change: Steve
This practice is known as monkey patching and should be used carefully.
Instead of monkeypatching, you could alway subclass and thus:
Be precise about what you think the object really is.
Gain all the methods of String
For example:
class PersonName < String
def namechanger
puts "This is the name to change: #{self}"
end
end
s = PersonName.new( "Iain" )
s.namechanger
This is the name to change: Iain
=> nil
What you have here in the first form is a method which takes a parameter, which is very different than a method that doesn't take any parameters. Let me illustrate
ruby
namechanger("Steve")
Looks for a method named namechanger and passes a string argument to it. Straight forward. It looks up in some unknown context, probably the locals of another method which will look it up on the object that receives that method.
ruby
"Steve".namechanger
is a method that takes no arguments that exists on String. Typically these methods use the implicit self parameter to operate on some data.
If you want to be able to call "Steve".namechanger, you have to make namechanger a method of the String class like this:
class String
def namechanger
puts "This is the name to change: #{self}"
end
end
This is generally referred to as "monkey patching" and you might want to improve your general Ruby proficiency a bit before you get into the related considerations and discussions.
You could do
class String
def namechanger
puts "This is the name to change: #{self}"
end
end
The difference is that your first example is a method that's (basically) globally defined, which takes a string and operates on it. This code above however defines a method called "namechanger" which takes no parameters, and defines it directly on the String class. So any and all strings in your application will then have this method.
But as pst said, you should probably not dive into that style of programming until you get a little more familiar with Ruby, so that you can more easily see the upsides and downsides of doing monkeypatching like this. One of the considerations is that you probably have many strings that don't represent names, and it doesn't make a lot of sense for those strings to have a method called namechanger.
That said, if your goal is just to have a little fun with Ruby, to see what you can do, go for it, but remember to be more careful in projects that will have a longer lifespan.

Resources