rubyruby-2.5

splat operator on hash for keyword arguments in ruby method definition


I have a class like this:

class AwesomeService
  attr_reader :a, :b

  def initialize(a: 30, b: 40)
    @a = a
    @b = b
  end
end

I am trying to do something like this:

class AwesomeService
  DEFAULTS = {
    a: 30,
    b: 40
  }

  attr_reader *DEFAULTS.keys

  def initialize(**DEFAULTS)
    @a = a
    @b = b
  end
end

so that I can keep the defaults in a separate hash.

But I am getting the error:

SyntaxError ((irb): syntax error, unexpected tCONSTANT, expecting ')')
  def initialize(**DEFAULTS)
                   ^~~~~~~~

It seems like the splat operator in the initialize is not working as I expected. But it seems to be the logical way of doing that. What am I doing wrong here?


Solution

  • Yeah... that's not a thing you can do.

    **foo in an argument list is how you collect a kwargs hash, so it can't also be how you inject one.

    More importantly, the main point of kwargs is that they explode the hash into local variables -- that can't work if it's expanding a hash at runtime.

    The closest you could get would be something like:

    def initialize(**values)
      values = DEFAULTS.merge(values)
      raise "..." unless (values.keys - DEFAULTS.keys).empty?
      @a = values[:a]
      @b = values[:b]
    end