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.