Richard Stokes
Richard Stokes

Reputation: 3552

Hash constructor parameter in 1.9.*

I seem to be having problems with using a hash parameter to my constructor in Ruby 1.9.2. I note that what I'm trying to do works in 1.8.7. Here is my example code:

def initialize(*params)
    @attr1 = params[:attr1] or nil
    @attr2 = params[:attr2] or nil
end

However, when I try to instantiate an object of this example class, I get an error message on the line where the first instance variable is set: in '[]': can't convert Symbol into Integer (TypeError)

Why does this not work in 1.9.2? And how do I work around it?

Upvotes: 2

Views: 1034

Answers (2)

Emily
Emily

Reputation: 18203

You don't need the splat (*) to capture a single hash argument. It's used to capture an unknown number of arguments. Change your function definition to

def initialize(params = {})
    @attr1 = params[:attr1] or nil
    @attr2 = params[:attr2] or nil
end

and everything should work the way you'd expect. Edit: The params = {} makes the params argument optional, and sets it to an empty hash when nothing is provided.

What's actually being captured in params with the function definion you have now, would be like this:

Whatever.new(:foo => 'foo', :bar => 'bar')
# params contains [{:foo => 'foo', :bar => 'bar'}]

so you'd need to reach into the array first to get the hash, then use the hash keys.

When Ruby sees a set of hash key/value pairs as the last argument to a function, it's automatically wrapped into a Hash. So even though it looks like you're supplying multiple arguments to the function, the interpreter is actually only receiving a single argument.

Upvotes: 5

WarHog
WarHog

Reputation: 8710

Because from splat * symbol you turn your hash actual parameter into array:

class Test
  def initialize(*params)
    p params
  end
end

Test.new(attr1: 1, attr2: 2)  # => [{:attr1=>1, :attr2=>2}]

Remove * from initialize method:

class Test
  def initialize(params)
    @attr1 = params[:attr1] or nil
    @attr2 = params[:attr2] or nil
  end

  attr_accessor :attr1, :attr2
end

test = Test.new(attr1: 1, attr2: 2)
test.attr1  #= > 1

Upvotes: 5

Related Questions