Ruby: why are inputs passed to send() being wrapped in a Hash? - ruby

I'm using the send() method in Ruby to invoke a method I've defined. The method takes an OpenStruct.
Here's a snippet showing how I invoke my method using send:
my_open_struct = OpenStruct.new(foo: "foo")
result = #my_object.send(
:my_method_that_takes_an_openstruct,
name_of_openstruct_param: my_open_struct)
The problem is that inside my_method_that_takes_an_openstruct the OpenStruct param is getting wrapped in a Hash, resulting in logging output like this:
Just before calling send #<OpenStruct foo="foo">
Inside my_method_that_takes_an_openstruct: {:name_of_openstruct_param=>#<OpenStruct foo="foo">}
Why is this happening, and how can I prevent this wrapping behaviour?

I'm assuming my_method looks something like this
class Foo
def my_method(arg)
puts "#{arg}"
end
end
If you're coming from a Python background, you might think we can call my_method as either foo.my_method(1) or foo.my_method(arg: 1). But this isn't how it works in Ruby. In Ruby, arguments are either named or positional. To make an argument named, we put a colon after it.
class Foo
def my_method(arg:)
puts "#{arg}"
end
end
Now we can do Foo.new.my_method(arg: 1) or Foo.new.send(:my_method, arg: 1), but it's incorrect to do Foo.new.my_method(1).
The reason you're getting a hash is a compatibility trick. In old versions of Ruby, before we had named arguments, the convention was to take a single hash argument at the end
def foo(a, b, opts)
...
end
and then the following two calls would be equivalent (the former being syntax sugar for the latter)
foo(1, 2, foo: "bar", bar: "baz")
foo(1, 2, {foo: "bar", bar: "baz"})
Basically, if any named-looking arguments appeared in an argument list, they'd get converted to a single hash and passed as the final argument to the function.
This behavior is deprecated as of Ruby 2.7 and removed in Ruby 3.0. The correct convention now is to take explicit named arguments, and recent versions of Ruby support the double splat ** operator for converting a hash into named arguments, similar to the Python operator with the same name.

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

In Ruby, how do I assign a value to a class instance

I want to create a class instance that has a value such that I can do something like puts a = Example.new(1) where a's value is specified in initialize.
I expect that this is a simple problem since all predefined Ruby classes allow this, but I'm unable to figure out how to do it for my classes.
Class#new and Return Values
Your example doesn't quite work because Ruby treats Class#new as a special case, and is expected to invoke the #initialize method and return an object. If it didn't, calling #new on a class would surprise a lot of people by returning the last evaluation of the initializer from your class, or from Object#new if it's otherwise undefined for your class. In either case, this would violate the principle of least surprise.
However, you can do what you want pretty easily by simply creating an accessor method and then chaining off of Example#new. For example, in Ruby 3.1.0:
class Example
attr_reader :int
def initialize(int) = (#int = int)
end
# prints `1` to STDOUT and assigns the value to *a*,
# but returns nil because you're using Kernel#puts
# which always returns nil
puts a = Example.new(1).int
# shows that the local variable *a* is set to the value
# returned by the Example#int accessor for the class'
# #int instance variable
a
#=> 1
To avoid the confusion of having a nil return value (even though this is expected with Kernel#puts, just change your puts statement to use Kernel#p instead:
p a = Example.new(2).int
#=> 2
Refactoring the Example Class for Older Rubies
If you're using an older Ruby than 3.0, you can't use an endless method or the improved handling for them in Ruby 3.1. The only difference is that rather than an inline method, you need to specify it with the standard def...end syntax, e.g.:
class Example
attr_reader :int
def initialize(int)
#int = int
end
end
Otherwise, the points above are valid as far back as any currently-supported Ruby version.

Call of a method as a block

Beginner in ruby world, I would like to do something like:
[1,2.0,"a",2].select(&:is_a?(Integer))
but like this it definitely don't work...
Any ideas?
You can't do what you are asking for because when you use the & syntax you have to use a method that doesn't take parameters.
However, if you for some reason you really want to do something like that, you need to make a method that doesn't take parameters like so:
class Object
def is_an_integer?
is_a? Integer
end
end
You can then do:
[1,2.0,"a",2].select(&:is_an_integer)
&:method_name is syntactic sugar for &:method.to_proc. Enumerators like select and whatnot accept a block and yield each element of the enumerator to the passed block. That is:
[1,2,3].select &:even?
is equivalent to:
p = :even.to_proc
[1,2,3].select {|val| p.yield(val) }
Since only the parameters yielded by the enumerator are yielded to the proc, you would have to include them in the source list. That is, we might expect:
[[1, Integer]].select &:is_a?
to result in:
select {|*args|, p.yield(*args) }
However, remember that p isn't a method bound to any particular class! It's going to try to invoke the given method on the passed argument. So, it's going to try to invoke Array#is_a? with no arguments, rather than splatting the arguments out and invoking Integer#is_a?(Integer).
So, to accomplish this, we'll have to somehow create a proc that binds the passed arguments, and then calls the given method on the yielded receiver with the passed args. We can do this by adding a method to the Symbol class:
class Symbol
def with_args(*args)
proc {|receiver| receiver.send(self, *args) }
end
end
[1, "a"].select &:is_a?.with_args(Integer)
While it's perhaps not amazingly clean, it does work.

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.

Where does the variable "p" get it's value from in ruby if it's not defined explicitly?

Question: Where does p get it's value from below and why does it happen?
Consider this irb session:
me#somewhere:~$ irb
irb(main):001:0> a
NameError: undefined local variable or method `a' for main:Object
from (irb):1
irb(main):002:0> foo
NameError: undefined local variable or method `foo' for main:Object
from (irb):2
irb(main):003:0> p
=> nil
irb(main):004:0> p.class
=> NilClass
irb(main):005:0>
I never defined p - so why is it nil valued? Neither a nor foo were recognized so what's special about p? I also didn't find anything listed under Kernel#p
Context: I'm reading the so-called "28 bytes of ruby joy" and assumed p was a variable, as in: def p.method_missing *_ ...
(Don't worry: I'm not going to actually define method_missing on nil everywhere... just studying some ruby code...)
p is just a method on Kernel which calls inspect on its arguments, producing human-readable representations of those objects. If you give it no arguments, it prints nothing. Regardless of what you pass it, though, it returns nil. See Kernel#p and Object#inspect.
Power tip: In Ruby 1.9, when you have a method and you don't know where it came from, use the method method:
ruby-1.9.1-p378 > method(:p)
=> #<Method: Object(Kernel)#p>
Putting it together one step at a time, we read this as:
p # We found a method called p.
#p # It's an instance method.
Object ... #p # It's available on Object.
Object(Kernel)#p # It came from the Kernel module.
Update: The OP provided some context from this article, where the author claims that your life will be easier if you add a method_missing to nil, by doing the following:
def p.method_missing*_;p;end
This somewhat obfuscated code should be read as:
Define a new method (def), called method_missing. This overrides the default method_missing handler on Object, which simply raises a NoMethodError when it encounters a method it doesn't understand.
This method will live on something called p.
It accepts any number of arguments (*) and stores them in a variable called _.
The result of these arguments is something called p.
The second bullet is the tricky part here. def p.method_missing means one of two things, depending on context:
A previously defined object called p which is in scope here.
A method called p which is in scope, and which is passed no arguments.
With def p.method_missing, we mean, "this method is being defined on the object which is the result of calling p with no arguments". In this case, that is NilClass; if you call p with no arguments, you get nil. So this is just a short, hacky way to define a method on NilClass.
Note: I definitely recommend against defining a method_missing on nil. This is a silly and dangerous tactic to use for the sake of saving a few lines of code, because it changes the behavior of nil. Don't do it!
p is a method which prints the inspect value of its arguments and returns nil. Without arguments it simply does nothing.
Its documentation is under Kernel#p, not Kernel::p (because it's an instance method of Kernel).
p is a method of the Kernel module. It's good for debugging - it prints out the internal representation of whatever you give it, by calling inspect on it. If you don't pass it any arguments, it just prints out nil.
irb(main):001:0> p 11
11
=> 11
irb(main):002:0> Kernel::p [1,2] + [3,4]
[1, 2, 3, 4]
=> [1, 2, 3, 4]
The results are printed out twice here as it also returns the object, which irb then prints out too.

Resources