Ответ Брайана отличный, но я хотел бы предложить некоторые модификации, чтобы сделать его в основном мета:
class Fruit
# Now this is the only thing you have to touch when adding defaults or properties
def set_defaults
@color ||= 'green'
@type ||= 'pear'
end
def initialize(params = {})
params.each { |key,value| instance_variable_set("@#{key}", value) }
set_defaults
instance_variables.each {|var| self.class.send(:attr_accessor, var.to_s.delete('@'))}
end
def to_s
instance_variables.inject("") {|vars, var| vars += "#{var}: #{instance_variable_get(var)}; "}
end
end
puts Fruit.new
puts Fruit.new :color => 'red', :type => 'grape'
puts Fruit.new :type => 'pomegranate'
puts Fruit.new :cost => 20.21
puts Fruit.new :foo => "bar"
f = Fruit.new :potato => "salad"
puts "f.cost.nil? #{f.cost.nil?}"
Какие выходы:
@color: green; @type: pear;
@color: red; @type: grape;
@color: green; @type: pomegranate;
@color: green; @type: pear; @cost: 20.21;
@color: green; @type: pear; @foo: bar;
f.cost.nil? true
Конечно, это не идеальное решение для всего, но оно дает вам некоторые идеи по повышению динамичности вашего кода.