GSP
GSP

Reputation: 3789

Elegant way to add to_hash (or to_h) method to Struct?

I'm using a Struct as opposed to a simple Hash in a project to provide a semantic name to a collection of key value pairs. Once I've built the structure, however, I need to output a hash value. I'm in Ruby 1.9.3. Example:

MyMeaninfulName = Struct.new(:alpha, :beta, :gamma) do
  def to_hash
    self.members.inject({}) {|h,m| h[m] = self[m]; h}
  end
end

my_var = MyMeaningfulName.new
my_var.to_hash # -> { :alpha=>nil, :beta=>nil, :gamma=>nil } 

Is there a reason why Struct does not include a to_hash method? It seems like a natural fit, but perhaps there's an underlying reason why it's not included.

Second, is there a more elegant way to build a generic to_hash method into Struct (either generally, via monkeypatching, or through a module or inheritance).

Upvotes: 5

Views: 4123

Answers (4)

Jaffa
Jaffa

Reputation: 12719

I know the question is about ruby 1.9.3, but starting from ruby 2.0.0, Struct has a to_h method which does the job.

MyMeaningfulName = Struct.new(:alpha, :beta, :gamma)

my_var = MyMeaningfulName.new
my_var.to_h # -> { :alpha=>nil, :beta=>nil, :gamma=>nil } 

Upvotes: 3

Linuxios
Linuxios

Reputation: 35788

Try this:

class Struct
  old_new = self.method(:new)
  def self.new(*args) 
    obj = old_new.call(*args)
    obj.class_exec do
      def to_hash
        self.members.inject({}) {|h,m| h[m] = self[m]; h}
      end
    end
    return obj
  end
end

Upvotes: 0

Joshua Cheek
Joshua Cheek

Reputation: 31776

I don't know why, it does seem obvious. Fortunately, you can use it as a hash in many places since it implements bracket operators.

Anyway, this is fairly elegant:

MyMeaningfulName = Struct.new :alpha, :beta, :gamma do
  def to_hash
    Hash[members.zip values]
  end
end

my_var = MyMeaningfulName.new 1, 2, 3
my_var.to_hash # => {:alpha=>1, :beta=>2, :gamma=>3}

Upvotes: 2

froderik
froderik

Reputation: 4808

or this:

class Struct
  def to_hash
    self.class.members.inject({}) {|h,m| h[m] = self[m]}
  end
end

(note the extra class to get to the members)

Upvotes: 2

Related Questions