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.

1 Answer 1

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
Sign up to request clarification or add additional context in comments.

2 Comments

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 it does not exist, AFAICT

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.