Why does `send` fail with Ruby 2.0 refinement? - ruby

Why does this not work?
module StringRefinement
refine String do
def bar
length
end
end
end
using StringRefinement
"abcdefghijklmnopqrstuvwxyz".send(:bar)
#NoMethodError: undefined method 'bar' for "abcdefghijklmnopqrstuvwxyz":String
Can someone explain why send doesn't work here? And is there a way to dynamically call methods defined in a refinement? I can't seem to find a good, full explanation of how refinements work in Ruby 2.0.

Because the specification says so:
Indirect method accesses
Any indirect method access such as Kernel#send, Kernel#method, and Kernel#respond_to? shall not honor refinements in the caller context during method lookup.

I am tempted to say "This is by design". But again it's quite possible this design is not entirely stable. For example, the module and class scoping feature has been removed just a few months ago.
At the moment even on Ruby HEAD the only way is to use the root of all evil:
eval "puts 'abcdefghijklmnopqrstuvwxyz'.bar" # => 26
But really, this is just for the lab, right ? Do not unchain such code, kitten would die.

Related

"The simplest" way to use a method as a proc in Ruby

Obviously, method(:method_name).to_proc works but I'm looking for a more concise way to do it - or I will not be doing it even when it's technically the right thing to do.
I'm contemplating a mix-in defining to_proc (just proc would be nicer but some genius made it a private method in Kernel)
module ProcifiedMethods
def to_proc(sym)
method(sym).to_proc
end
end
and then call
to_proc(:method_name)[*args]
but one would think something like that already exists in Ruby core?
My general motivation is to use functional programming concepts interchangeably with OOP. Got a method in some mixin that has no side-effects? Well... use it as a proc! Curry it, compose it, all the other good stuff.
That's the general idea, anyway :)
QUESTION: is there a simpler, battle tested, ideally within-ruby-core way to convert methods to procs? (i.e. a more shorthand alias of method(:method_name).to_proc).
If you're using this proc as method argument, you could use & unary operator, like foo(&method(:method_name))
If method is defined on object, this works too: foo(&obj.method(:method_name))
Firstly, proc does something different from to_proc. to_proc gives you a proc representation of a method. proc creates a proc given a block (or using the block with which the method was invoked if no block is given).
Secondly, method(:name).to_proc is fairly simple. You can define a method that simplifies it a bit, but for what it does - I would say it is very straight forward.
So for the direct question - No, there is no such way.
An argument to be made as for why it has to be slightly more explicit is that unlike with purely functional languages, here the method (and hence the proc) is tied to the instance.
class Foo
attr_accessor :bar
def calculate(baz)
baz * bar
end
end
foo = Foo.new
pro = foo.method(:calculate).to_proc
foo.bar = 7
pro.call(6) # => 42
foo.bar = 9
pro.call(6) # => 54
Stefan gave a good response, a Method behaves like / answers to the same methods as a Proc, so the answer is that the simplest way of using a Method as a Proc is simply using the Method which answers to #call, #[], #curry and all other funny stuff that a Proc has.
This makes a Method useful for standard FP shennanigans. An example:
3.method(:+).curry[3] == 6
If anyone is interested, this is the use case

Ruby Monk - Understanding Inheritance - Alternate solution not accepted?

I have been coding for three or four months (started in Python) and I am just getting into Ruby on account of Rails popularity.
To help build my understanding of the Ruby language, I have been going through the problems on Ruby Monk. The Ruby Primer: Ascent 1.1 - Understanding Inheritance course has the following problem:
Write a method that takes a class and a subclass as arguments and returns a boolean regarding whether or not the subclass is an ancestor of the class.
Here is what I came up with (note: Ruby Monk decided to go with spelling "klass" for "class"):
def is_ancestor?(klass, subclass)
subclass.ancestors.map{ |ancestor| ancestor.to_s }.include? klass.to_s
end
This code passes all tests except for a special one that states doesn't use any other methods to solve the problem (yes, there's a shortcut :)).
I was really vexed as to how to solve this without using other methods, and so I looked at the proposed solution. Here is what Ruby Monk says that answer should be.
def is_ancestor?(klass, subclass)
current_class = subclass
while !current_class.superclass.nil? && current_class != klass
current_class = current_class.superclass
end
current_class == klass
end
I understand this code. What I don't understand is why this code passes the test requirement of not using methods while my code doesn't. After all, the Ruby Monk proposed answer does use methods (see !current_class.superclass.nil).
Am I missing something here? Perhaps I don't really understand what a method is. Perhaps my code does work and is only failing because Ruby Monk is performing tests that match code 1:1.
Maybe they don't want you to use map and include? since they are not methods of classes. They are methods of arrays.
I guess this shall pass the tests.
def is_ancestor?(klass, subclass)
subclass <= klass
end
Well, strictly speaking, <= is also a method.
BTW, if you can compare classes directly, don't compare their names. You original code can be optimized as
def is_ancestor?(klass, subclass)
subclass.ancestors.include? klass
end

DSL block without argument in ruby

I'm writing a simple dsl in ruby. Few weeks ago I stumbled upon some blog post, which show how to transform code like:
some_method argument do |book|
book.some_method_on_book
book.some_other_method_on_book :with => argument
end
into cleaner code:
some_method argument do
some_method_on_book
some_other_method_on_book :with => argument
end
I can't remember how to do this and I'm not sure about downsides but cleaner syntax is tempting. Does anyone have a clue about this transformation?
def some_method argument, &blk
#...
book.instance_eval &blk
#...
end
UPDATE: However, that omits book but don't let you use the argument. To use it transparently you must transport it someway. I suggest to do it on book itself:
class Book
attr_accessor :argument
end
def some_method argument, &blk
#...
book.argument = argument
book.instance_eval &blk
#...
end
some_method 'argument' do
some_method_on_book
some_other_method_on_book argument
end
Take a look at this article http://www.dan-manges.com/blog/ruby-dsls-instance-eval-with-delegation — there is an overview of the method (specifically stated in the context of its downsides and possible solution to them), plus there're several useful links for further reading.
Basically, it's about using instance_eval to execute the block in the desirable context.
Speaking about downside of this technique:
So what's the problem with it? Well, the problem is that blocks are
generally closures. And you expect them to actually be full closures.
And it's not obvious from the point where you write the block that
that block might not be a full closure. That's what happens when you
use instance_eval: you reset the self of that block into something
else - this means that the block is still a closure over all local
variables outside the block, but NOT for method calls. I don't even
know if constant lookup is changed or not.
Using instance_eval changes the rules for the language in a way that
is not obvious when reading a block. You need to think an extra step
to figure out exactly why a method call that you can lexically see
around the block can actually not be called from inside of the block.
Check out the docile gem. It takes care of all the sharp edges, making this very easy for you.

How can I splattify an anonymous object so I can use &method on it?

I'm wanting to use the &method(:method_name) idiom when there's more than one object required by method_name. Can I do this under Ruby 1.9?
For example, if I've got
def move_file(old_filename, new_filename)
STDERR.puts "Moving #{old_filename.inspect} to #{new_filename.inspect}"
# Implementation for careful moving goes here
end
old_filenames = ["foo.txt", "bar.txt", "hoge.ja.txt"]
new_filenames = ["foo_20110915.txt", "bar_20110915.txt", "hoge_20110915.ja.txt"]
the code
old_filenames.zip(new_filenames).each(&method(:move_file))
works under Ruby 1.8, but not under Ruby 1.9. Under Ruby 1.9, it's trying to do move_file(["foo.txt", "foo_20110915.txt"]) instead of move_file("foo.txt", "foo_20110915.txt").
How do I splattify it so it has the correct arity?
Workarounds I'm aware of:
Replace def move_file(old_filename, new_filename) with def move_file(*arguments)
Replace each(&method(:move_file)) with
each{|old_filename, new_filename| move_file(old_filename, new_filename)}
Instead
each{|old_filename, new_filename| move_file(old_filename, new_filename)}
you should be able to do
each{|pair| move_file(*pair)}
But I don't know how you'd pull off blockless variant (I needed it couple of times as well). I guess &-shorthand was made to make the syntax simpler, and is not meant to be clogged much (whether it will be passed an array as an array, or splatted, for example). :)
How do I splattify it so it has the correct arity?
I don't think there is a way to do this while being compatible to both Ruby versions. What you could do is wrap it into a lambda
move_from_to = Proc.new {|*both| move_files(*both) }
The thing is - block and proc arity is something that got addressed in Ruby 1.9 so there might be a difference in behavior there. Also see prc.lambda? here http://www.ruby-doc.org/core/classes/Proc.html for info on what it does to the arity.
This question is also related to what you want to do (the solution there is to resplat and unsplat manually): Inconsistency of arity between Hash.each and lambdas

When does Ruby know that a method exists?

One question that ran through my mind was how does the Ruby interpreter know that a method exists on a object if the definition is yet to be interpreted? Like, wouldn't it matter whether you define the method first than use it, rather than use it then define it?
It doesn't know, and it doesn't care - until execution. When a method call statement is executed, the interpreter looks to see if the class (object, not code!) has the named function. If it does not, it looks up the ancestor tree. If it does not find any, it calls the method_missing method. If that is not defined, you get your error.
If your function call does not get executed, you will not get any errors.
The interpreter doesn't know about undefined methods ahead of time, for example:
o = Object.new
o.foo # => Raises NoMethodError.
class Object
def foo
puts "Foo!"
end
end
o.foo # => prints "Foo!", since the method is defined.
However, Ruby has a neat feature called method_missing which let's the receiver of a method call take the method name and arguments as separate arguments and handle accordingly as long as no defined method already handles the call.
def o.method_missing(sym, *args)
puts "OK: #{sym}(#{args.inspect})"
# Do something depending on the value of 'sym' and args...
end
o.bar(1, 2, 3) #=> OK: bar(1, 2, 3)
"Method missing" is used by things like active record find methods and other places where it could make sense to have "dynamically defined" functions.
The problem is, the interpreter tried to find it when you use it, and since it won't be there, it may fail.
In ( some ) compiled languages, it doesn't matter, because while compiling, the compiler may say "I'll look for this on a second pass" but I don't think this is the case with Ruby.

Resources