在Ruby中我可以在initialize方法中以某种方式自动填充实例变量吗?

Gre*_*reg 16 ruby ruby-on-rails

在Ruby中我可以在initialize方法中以某种方式自动填充实例变量吗?

例如,如果我有:

class Weekend
  attr_accessor :start_date, :end_date, :title, :description, :location

  def initialize(params)
    # SOMETHING HERE TO AUTO POPULATE INSTANCE VARIABLES WITH APPROPRIATE PARAMS
  end

end
Run Code Online (Sandbox Code Playgroud)

Mis*_*cha 16

你可以instance_variable_set像这样使用:

params.each do |key, value|
  self.instance_variable_set("@#{key}".to_sym, value)
end
Run Code Online (Sandbox Code Playgroud)


apn*_*ing 7

为了简单起见:

class Weekend
  attr_accessor :start_date, :end_date, :title, :description, :location

  def initialize(params)
    @start_date = params[:start_date] # I don't really know the structure of params but you have the idea
    @end_date   = params[:end_date]
  end
end
Run Code Online (Sandbox Code Playgroud)

你可以通过元编程的方式做一些更聪明的事情,但这真的有必要吗?

  • 我理解避免不必要的metaprog的愿望,但这并不是OP所要求的简洁代码.您必须手动指定每个字段名称. (3认同)

Kel*_*vin 5

Ruby 有时可能非常简单。看不到循环!

class Weekend < Struct.new(:start_date, :end_date, :title, :description, :location)
  # params: Hash with symbols as keys
  def initialize(params)
    # arg splatting to the rescue
    super( * params.values_at( * self.class.members ) )
  end
end
Run Code Online (Sandbox Code Playgroud)

请注意,您甚至不需要使用继承 -Struct可以在创建过程中自定义新的:

Weekend = Struct.new(:start_date, :end_date, :title, :description, :location) do
  def initialize(params)
    # same as above
  end
end
Run Code Online (Sandbox Code Playgroud)

测试:

weekend = Weekend.new(
  :start_date => 'start_date value',
  :end_date => 'end_date value',
  :title => 'title value',
  :description => 'description value',
  :location => 'location value'
)

p [:start_date , weekend.start_date  ]
p [:end_date   , weekend.end_date    ]
p [:title      , weekend.title       ]
p [:description, weekend.description ]
p [:location   , weekend.location    ]
Run Code Online (Sandbox Code Playgroud)

请注意,这实际上并没有设置实例变量。你的类将有不透明的 getter 和 setter。如果您不想公开它们,您可以围绕它包装另一个类。这是一个例子:

# this gives you more control over readers/writers
require 'forwardable'
class Weekend
  MyStruct = ::Struct.new(:start_date, :end_date, :title, :description, :location)
  extend Forwardable
  # only set up readers
  def_delegators :@struct, *MyStruct.members

  # params: Hash with symbols as keys
  def initialize(params)
    # arg splatting to the rescue
    @struct = MyStruct.new( * params.values_at( * MyStruct.members ) )
  end
end
Run Code Online (Sandbox Code Playgroud)