3

I have this class:

class PriceChange
  attr_accessor :distributor_id, :product_id, :value, :price_changed_at, :realm

  def initialize(data = {})
    @distributor_id   = data[:distributor_id]
    @product_id       = data[:product_id]
    @value            = data[:value]
    @price_changed_at = data[:price_changed_at]
    @realm            = data[:realm]
  end
end

And I want to avoid the mapping inside the method body. I want a transparent and elegant way to set the instance attributes values. I know I can iterate through the data keys and use something like define_method. I don't want this. I want to do this in a clean way.

Andrey Deineko
  • 51,333
  • 10
  • 112
  • 145
Leantraxxx
  • 4,506
  • 3
  • 38
  • 56

1 Answers1

5

I want to do this in a clean way.

You won't get attr_accessors and instance variables without defining them. The below is using some simple metaprogramming (does it qualify for "clean"?)

class PriceChange
  def initialize(data = {})
    data.each_pair do |key, value|
      instance_variable_set("@#{key}", value)
      self.class.instance_eval { attr_accessor key.to_sym }
    end
  end
end

Usage:

price_change = PriceChange.new(foo: :foo, bar: :bar)
#=> #<PriceChange:0x007fb3a1755178 @bar=:bar, @foo=:foo>
price_change.foo
#=> :foo
price_change.foo = :baz
#=> :baz
price_change.foo
#=> :baz
Andrey Deineko
  • 51,333
  • 10
  • 112
  • 145
  • Your code is undoubtedly very clean but, as I said: "I know I can iterate through the data keys and use something like define_method". I'm looking for a "transparent" way. Maybe does not exist. – Leantraxxx Apr 04 '17 at 20:10
  • 2
    @Leantraxxx it does not exist, AFAICT – Andrey Deineko Apr 04 '17 at 20:15