Stefan
Stefan

Reputation: 9339

Ruby: Extending hash constructor

I'm new to Ruby, so apologies if my terminology is incorrect here.

I'm trying to make a subclass of hash, but am having trouble with initialising it. I want to be able to initialise it with an existing hash, and also some additional parameters, e.g.:

x = NewHash[{:a => b}, extra_param]

I tried to do that by overriding the static Hash [] operator:

class NewHash < Hash
  def self.[](hash_values, backend = nil)
    @backend = backend
    super(hash_values)
  end
end

This doesn't work, because the [] operator is static and I can't access non-static member variables, i.e. @backend is lost.

Is there anything I can do? The alternative is to use new, but that doesn't give me a nice way to accept the initial hash.

Upvotes: 0

Views: 332

Answers (1)

Chris Heald
Chris Heald

Reputation: 62668

This is slightly hacky, because [] isn't the hash constructor; it's a factory method. So, there's no real clean way to get private scope to the new hash.

You can do something like this:

class NewHash < Hash
  def self.[](hash_values, backend = nil)
    super(hash_values).tap do |hash|
      hash.instance_variable_set("@backend", backend)
    end
  end
end

This requires the use of instance_variable_set, which is generally considered smelly, but it works. An alternate would be to create public accessors:

class NewHash < Hash
  attr_accessor :backend
  def self.[](hash_values, backend = nil)
    super(hash_values).tap do |hash|
      hash.backend = backend
    end
  end
end

This, of course, is public, so if you're trying to hide it, the smellier first version might be better.

Upvotes: 1

Related Questions