Make Ruby object respond to double splat operator **

272 Views Asked by At

I have a library that has an #execute method like this

def execute(query, **args)
  # ...
end

I have a class that generates the data for args (which has a lot of logic depending on user abilities)

class Abilities
  def to_h
    { user: user } # and a lot more data
  end
end

Now when I'm using #execute I always have to remember to use #to_h, which is pretty annoying and leads to mistakes when someone forgets it:

execute(query, abilities.to_h)

So I was wondering if my Abilities class could somehow respond to the ** (double splat) operator, so that I can simply pass the object:

execute(query, abilities)

When I try to call it like this, it throws an error:

ArgumentError: wrong number of arguments (given 2, expected 1)

So, is there any way to make my Abilities class behave like a Hash? I could derive it like this Abilities < Hash but then I have all the Hash logic on it, which seems pretty dirty.

2

There are 2 best solutions below

0
On BEST ANSWER

You can implement to_hash: (or define it as an alias for to_h)

class MyClass
  def to_hash
    { a: 1, b: 2 }
  end
end

def foo(**kwargs)
  p kwargs: kwargs
end

foo(MyClass.new)
#=> {:kwargs=>{:a=>1, :b=>2}}
1
On

If you specify the API to execute in such a way that it accepts anything that supports to_h, then you have a solution:

def execute(query, args = {})
  args = args.to_h
  ...
end