passing methods that accepts blocks - ruby

How is a good way of passing a method that accept a block?
I.e. to treat the method as a variable so it could be used in this way:
(#glob&.each || crawl_dir(#base_dir)) do |file|
puts "#{file}"
end
A simple example that can be tried out:
> require 'csv'
=> true
> CSV {|v|v}
=> <#CSV io_type:$stdout encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">
> a=CSV
=> CSV
> a==CSV
=> true
> a {|v|v}
Traceback (most recent call last):
1: from (irb):14
NoMethodError (undefined method `a' for main:Object)
Is this possible?

In your example, you are using different things which are all called CSV.
CSV {|v|v}
Here, you are calling the method named CSV with a block. You get the return value of that method back. Methods such as this are usually used as converters. E.g. there is the Integer() method which takes an argument (such as a String) which is converted to an Integer object. Usually, those methods are called the same as the class of object they return.
a=CSV
Here, you are assigning the value of the CSV constant (which is the CSV class) to the a variable. In your code, you can then either use the CSV constant or the a variable to refer to the class object.
In these cases where you have the same name refer to different things (a class and a method respectively), Ruby can distinguish which one to call / return based on how you use it. Only of you explicitly and unambiguously call the "thing" (i.e. by passing a block or any other arguments), Ruby will call the method.
In all other cases, if you refer to a thing with a name starting with a capital letter, Ruby expects it to a constant and returns its referred to object (which in this case is the CSV class object).
a {|v|v}
Here, you get an error since Ruby tries to call the method named a (which doesn't exist). Even if this would work, the a variable is at this point a reference to the CSV class (which can't be called directly).
(Note: to call a method whose name you have stored in a variable, you can use the send method, e.g. my_receiver.send(a).)
Now, to solve your initial issue, you could create a method object and use it to call the desired method, e.g.
method_proc = #glob&.method(:each) || method(:crawl_dir).curry(#base_dir)
method_proc.call do |file|
puts file
end
However, this is not very idiomatic Ruby. Here, method references are seldom carried around (rather than in Javascript or Python where you regularly do this with passed function objects). A more idiomatic implementation in Ruby could be:
def handle_file(file)
puts file
end
if #glob.respond_to(:each)
#glob.each { |file| handle_file(file) }
else
crawl_dir(#base_dir) { |file| handle_file(file) }
end
Even more idiomatic would be if your crawl_dir method would (optionally) return an Enumerator object, in which case you could simplify the calling code.
Here, I assume that #glob is either nil or an Enumerable object (such as an Array or an Enumerator which thus response directly to each). This allows us to simplify the code further.
def crawl_dir(directory)
# Return an Enumerator object for the current method invocation if no
# block was passed, similar to how the standard `Enumerable#each` method
# works.
return enum_for(__method__) unless block_given?
# the rest of the method here...
end
enumerable = #glob || crawl_dir(#base_dir)
enumerable.each do |file|
puts file
end
What happens here is that you either take #glob (which we assume to be an Enumerable object if it exists, and thus response do each) or crawl_dir(#base_dir) without a block. From your crawl_dir method, you will get then an Enumerator object back, which is again an Enumerable. You can then loop over this object with each. Both of your objects thus have the same return type can can thus be used similarly.

If you want to get a reference to a method, you can use the Object#method method. You can then call this method using the Method#call method, or the .() syntactic sugar:
require 'csv'
a = method(:CSV)
a.() {|v| v }
#=> #<CSV io_type:$stdout encoding:UTF-8 lineno:0 col_sep:"," row_sep:"\n" quote_char:"\"">

You can always use tap on any object:
a.tap do |v|
p v
end

Related

In Ruby, how do you write a simple method that can be used with &:symbol?

This article touches on the issues but doesn't give a solution.
This started when I wanted to write a method and optionally pass it an argument which could be null or a ???? (proc, lambda, method, block, ???). Lets call it, for now, a block because a block works. The block takes one required argument. An example of the method and a call to it would be:
#!/usr/bin/env ruby
def foo(&proc)
puts "before"
if proc
yield "passed to proc"
end
puts "after"
end
def add_message(s)
puts "from add_message #{s}"
end
foo { |s| add_message(s) }
foo
And the output is:
before
from add_message passed to proc
after
before
after
Great. But, what I'd like to do is be able to call foo like this: foo(&:add_message). But I can't. Changing line 15 above I get:
before
./temp.rb:11:in `add_message': wrong number of arguments (given 0, expected 1) (ArgumentError)
from ./temp.rb:6:in `foo'
from ./temp.rb:15:in `<main>'
And, as the article above mentions, the arity is now -2. So, how do I write a simple method like add_message that I can use with &:add_message. OR!!! as is the case 99.99% of the time, please set me on the proper track on how to do this.
The problem is that Symbol#to_proc does not create a proc that calls add_message method correctly.
# `yield` will pass its arguments to proc
>> :add_message.to_proc.call('passed to proc')
# => ArgumentError
This calls 'passed to proc'.add_message, because our method is defined in Object it works when called on String, however it is missing the required argument.
The solution is to make a proc that can accept the same arguments as add_message method and pass them along to that method. We can use Object#method that returns Method object that implements its own to_proc and has the same arity as the method.
>> method(:add_message).to_proc.arity
=> 1
>> method(:add_message).to_proc.call('passed to proc')
from add_message passed to proc
>> foo(&method(:add_message))
before
from add_message passed to proc
after
From the Ruby docs
Conversion of other objects to procs
Any object that implements the to_proc method can be converted into a proc by the & operator, and therefore can be consumed by iterators.
class Greeter
def initialize(greeting)
#greeting = greeting
end
def to_proc
proc {|name| "#{#greeting}, #{name}!" }
end
end
hi = Greeter.new("Hi")
hey = Greeter.new("Hey")
["Bob", "Jane"].map(&hi) #=> ["Hi, Bob!", "Hi, Jane!"]
["Bob", "Jane"].map(&hey) #=> ["Hey, Bob!", "Hey, Jane!"]
Of the Ruby core classes, this method is implemented by Symbol, Method, and Hash.
So when you pass an argument with a unary ampersand before it, to_proc gets called on it. The &: "syntax" is actually & being called on a symbol literal, i.e. &(:foobar), and Symbol.to_proc has the behavior of converting a symbol into a method call on its first argument, i.e. these two are roughly equivalent (modulo named argument forwarding)
:foobar.to_proc
proc { |x, *args| x.foobar(*args) }
Ruby's Method type also implements to_proc, so if you have a standalone method called foobar (on a module, say, Example), then you can call Example.method(:foobar) and get an &-compatible object. If you have a "top-level" method, then it's probably being defined on the main object and calling method with no explicit receiver will work.
The other type mentioned in that quote is hashes, which can be turned into a function mapping their keys to their values (and returning nil if no matching key exists). And, of course, you can always implement a method called to_proc on your own classes and it'll work just as well as any built-in type.
class Integer
def set
return self + 1
end
end
p [1,2,3,4,5,6].map(&:set)
I think when you can use &: syntax that a method have been defined for a class like above

What is being called in this Ruby method?

I need some help understanding what's going on here. It's a block inside of a method. Basically I get everything here except the call in the if statement wasABlock_nowAProc.call. This is not defined here, so what is it calling?
class Array
def eachEven(&wasABlock_nowAProc)
isEven = true # We start with "true" because arrays start with 0, which is even.
self.each do |object|
if isEven
wasABlock_nowAProc.call object
end
isEven = (not isEven) # Toggle from even to odd, or odd to even.
end
end
end
['apple', 'bad apple', 'cherry', 'durian'].eachEven do |fruit|
puts 'Yum! I just love '+fruit+' pies, don\'t you?'
end
# Remember, we are getting the even-numbered elements
# of the array, all of which happen to be odd numbers,
# just because I like to cause problems like that.
[1, 2, 3, 4, 5].eachEven do |oddBall|
puts oddBall.to_s+' is NOT an even number!'
end
def eachEven(&wasABlock_nowAProc) declares that the eachEven method accepts a block, which is the do ... end stuff from your two examples. It is then accessible within the method as a .callable Proc/Lambda object with the name wasABlock_nowAProc.
wasABlock_nowAProc.call object basically invokes the attached block from within the method and passes it one argument, object.
Do a google search for "ruby block to proc" and any of the first results should give you a thorough explanation.
Basically, when you define a method parameter with an & prefix (as in def eachEven(&wasABlock_nowAProc)), it tells Ruby that this method is expecting to receive a Proc object as an argument. In the method body you can then do stuff with Proc, such as use the #call method to run it or pass it on to another method.
Now, it's rare for Ruby programmer to manually create Proc objects. It's much more common to just use a block (less typing, easier to read, etc). If you try to pass a block to method that requires a Proc, well, Ruby handles that just fine. It magically converts the block to a Proc and uses that.
In this particular example, the only reason I can see to define the &wasABlock_nowAProc parameter is to tell Ruby to raise an error if the method is called with a block. You could remove the parameter and replace the #call line with yield to achieve the same functionality.

Accessing functions inside a Ruby block

I'm working inside a one-off Ruby script (so not inside an explicitly defined module or class) and I'm having a hard time accessing a function I've defined earlier in the script, from within a .each block.
def is_post?(hash)
if hash["data"]["post"] == "true" #yes, actually a string
true
else
false
end
end
#further down
threads["data"]["children"].each do |item|
puts item["data"]["title"] unless item.is_post?
end
Result:
in 'block in <top (required)>': private method `is_post?' called for #<Hash:0x007f9388008cf0\> (NoMethodError)
threads is a very, very nested hash. A hash, contaning a hash of arrays, the arrays contain a hash with header data, which contains another hash with the rest of the details. A bit messy, but I didn't write the module that generates that :P
The idea is to iterate through the arrays and retrieve the data from each one.
My questions are:
What manner of shenaniganery do I need to do to access my is_post? function from within the block?
Why is it coming up as a private method when I don't have any private declarations anywhere in my script?
Kernel vs instance method, self vs argument
def is_post?(hash)
...
end
By defining the methods in that way, you are defining a method for Kernel. You have the choice of either calling this method through Kernel.is_post?(hash), or is_post?(arg). Unless item is the Kernel object, you wont have defined the method is_post? for it.
Your method takes exactly one argument. In case item has a is_post? method, by doing item.is_post?, you are not providing an argument but only self to the method.
The solution
You probably should replace
item.is_post?
by
is_post?(item)
You don't want to call is_post? on the item (it's a Hash like the error message says).
What you want is the following:
threads["data"]["children"].each do |item|
puts item["data"]["title"] unless is_post?(item)
end

How does the "#map(&proc)" idiom work when introspecting module classes?

Presenting the Idiom
I found an interesting but unexplained alternative to an accepted answer. The code clearly works in the REPL. For example:
module Foo
class Bar
def baz
end
end
end
Foo.constants.map(&Foo.method(:const_get)).grep(Class)
=> [Foo::Bar]
However, I don't fully understand the idiom in use here. In particular, I don't understand the use of &Foo, which seems to be some sort of closure, or how this specific invocation of #grep operates on the result.
Parsing the Idiom
So far, I've been able to parse bits and pieces of this, but I'm not really seeing how it all fits together. Here's what I think I understand about the sample code.
Foo.constants returns an array of module constants as symbols.
method(:const_get) uses Object#method to perform a method lookup and return a closure.
Foo.method(:const_get).call :Bar is a closure that returns a qualified path to a constant within the class.
&Foo seems to be some sort of special lambda. The docs say:
The & argument preserves the tricks if a Proc object is given by & argument.
I'm not sure I fully understand what that means in this specific context, either. Why a Proc? What "tricks," and why are they necessary here?
grep(Class) is operating on the value of the #map method, but its features are not obvious.
Why is this #map construct returning a greppable Array instead of an Enumerator?
Foo.constants.map(&Foo.method(:const_get)).class
=> Array
How does grepping for a class named Class actually work, and why is that particular construction necessary here?
[Foo::Bar].grep Class
=> [Foo::Bar]
The Question, Restated
I'd really like to understand this idiom in its entirety. Can anyone fill in the gaps here, and explain how the pieces all fit together?
&Foo.method(:const_get) is the method const_get of the Foo object. Here's another example:
m = 1.method(:+)
#=> #<Method: Fixnum#+>
m.call(1)
#=> 2
(1..3).map(&m)
#=> [2, 3, 4]
So in the end this is just a pointfree way of saying Foo.constants.map { |c| Foo.const_get(c) }. grep uses === to select elements, so it would only get constants that refer to classes, not other values. This can be verified by adding another constant to Foo, e.g. Baz = 1, which will not get grepped.
If you have further questions please add them as comments and I'll try to clarify them.
Your parse of the idiom is pretty spot on, but I'll go through it and try to clear up any questions you mentioned.
1. Foo.constants
As you mentioned, this returns an array of module constant names as symbols.
2. Array#map
You obviously know what this does, but I want to include it for completeness. Map takes a block and calls that block with each element as an argument. It returns an Array of the results of these block calls.
3. Object#method
Also as you mentioned, this does a method lookup. This is important because a method without parentheses in Ruby is a method call of that method without any arguments.
4. &
This operator is for converting things to blocks. We need this because blocks are not first-class objects in Ruby. Because of this second-class status, we have no way to create blocks which stand alone, but we can convert Procs into blocks (but only when we are passing them to a function)! The & operator is our way of doing this conversion. Whenever we want to pass a Proc object as if it were a block, we can prepend it with the & operator and pass it as the last argument to our function. But & can actually convert more than just Proc objects, it can convert anything that has a to_proc method!
In our case, we have a Method object, which does have a to_proc method. The difference between a Proc object and a Method object lies in their context. A Method object is bound to a class instance and has access to the variables which belong to that class. A Proc is bound to the context in which it is created; that is, it has access to the scope in which it was created. Method#to_proc bundles up the context of the method so that the resulting Proc has access to the same variables. You can find more about the & operator here.
5. grep(Class)
The way Enumerable#grep works is that it runs argument === x for all x in the enumerable. The ordering of the arguments to === is very important in this case, since it's calling Class.=== rather than Foo::Bar.===. We can see the difference between these two by running:
irb(main):043:0> Class === Foo::Bar
=> true
irb(main):044:0> Foo::Bar === Class
=> false
Module#=== (Class inherits its === method from Method) returns True when the argument is an instance of Module or one of its descendants (like Class!), which will filter out constants which are not of type Module or Class.
You can find the documentation for Module#=== here.
The first thing to know is that:
& calls to_proc on the object succeeding it and uses the proc produced as the methods' block.
Now you have to drill down to how exactly the to_proc method is implemented in a specific class.
1. Symbol
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
Or something like this. From the above code you clearly see that the proc produced calls the method (with name == the symbol) on the object and passes the arguments to the method. For a quick example:
[1,2,3].reduce(&:+)
#=> 6
which does exactly that. It executes like this:
Calls :+.to_proc and gets a proc object back => #<Proc:0x007fea74028238>
It takes the proc and passes it as the block to the reduce method, thus instead of calling [1,2,3].reduce { |el1, el2| el1 + el2 } it calls
[1,2,3].reduce { |el1, el2| el1.send(:+, el2) }.
2. Method
class Method
def to_proc
Proc.new do |*args|
self.call(*args)
end
end
end
Which as you can see it has a different implementation of Symbol#to_proc. To illustrate this consider again the reduce example, but now let as see how it uses a method instead:
def add(x, y); x + y end
my_proc = method(:add)
[1,2,3].reduce(&my_proc)
#=> 6
In the above example is calling [1,2,3].reduce { |el1, el2| my_proc(el1, el2) }.
Now on why the map method returns an Array instead of an Enumerator is because you are passing it a block, try this instead:
[1,2,3].map.class
#=> Enumerator
Last but not least the grep on an Array is selecting the elements that are === to its argument. Hope this clarifies your concerns.
Your sequence is equivalent to:
c_names = Foo.constants #=> ["Bar"]
cs = c_names.map { |c_name| Foo.__send__(:const_get, c_name) } #=> [Foo::Bar]
cs.select{ |c| Class === c } #=> [Foo::Bar]
You can consider Object#method as (roughly):
class Object
def method(m)
lambda{ |*args| self.__send__(m, *args) }
end
end
grep is described here http://ruby-doc.org/core-1.9.3/Enumerable.html#method-i-grep
=== for Class (which is subclass of Module) is described here http://ruby-doc.org/core-1.9.3/Module.html#method-i-3D-3D-3D
UPDATE: And you need to grep because there can be other constants:
module Foo
PI = 3.14
...
end
and you probably don't need them.

Method pointers in ruby

I want to store several different methods in an array in Ruby. Suppose I want to store the type method twice:
[type, type]
doesn't store two entries of type in an array; it executes type twice, and stores the results in the array. how do I refer explicitly to the method object itself?
(this is just a simplified version of what I really want.)
EDIT: on second thoughts, it bothers me that the solution proposed below avoids the problem by passing the name of the method. how do you pass the method object itself? for example, what if you pass [:type, :type] to a method that has an alternative resolution for type? how can you pass the type method object itself?
If you want to store a method rather than the result of calling a method or just the message you'd send to invoke it, you need to use the method method on the owning object. So for example
"hello".method(:+)
will return the + method of the object "hello", so that if you call it with the argument " world", you'll get "hello world".
helloplus = "hello".method(:+)
helloplus.call " world" # => "hello world"
If you're thinking about doing method references in Ruby, you're doing it wrong.
There is a built-in method in Ruby called method. It will return a proc version of the method. It is not a reference to the original method, though; every call to method will create a new proc. Changing the method won't affect the proc, for example.
def my_method
puts "foo"
end
copy = method(:my_method)
# Redefining
def my_method
puts "bar"
end
copy.call
# => foo
When you want to store pieces of code, and don't want to use regular methods, use procs.
stack = [proc { do_this }, proc { do_that }]
stack.each {|s| s.call }
[:type, :type].collect { |method_name| self.send(method_name) }
Alternatively, if the method is part of an object:
method = obj.method(:type)
values = [method.call, method.call]

Resources