在初始化时使用attr_accessor设置ruby 2.0关键字参数

如何动态设置而无需全部编写相同的代码。

现在代码看起来像这样:

def initialize(keywords: keywords, title: title, url: url, adsetting: adsetting) self.keywords = keywords self.title = title self.url = url self.adsetting = adsetting end 

如果列表变长,这很快就会失控。

使用ruby 1.9我只是将哈希传递给方法。 像这样:

 def initialize(args) args.each do |k,v| instance_variable_set("@#{k}", v) unless v.nil? end end 

但我宁愿使用Ruby 2.0关键字参数。 可以实现类似的东西吗?

 def initialize(keywords: keywords, title: title, url: url, adsetting: adsetting) args.each do |k,v| instance_variable_set("@#{k}", v) unless v.nil? end end 

 def initialize(keywords: nil, title: nil, url: nil, adsetting: nil) local_variables.each do |k| v = eval(k.to_s) instance_variable_set("@#{k}", v) unless v.nil? end end 

或遵循John Ledbetter和Cary Swoveland的建议:

 def initialize(keywords: nil, title: nil, url: nil, adsetting: nil) method(__method__).parameters.each do |type, k| next unless type == :key v = eval(k.to_s) instance_variable_set("@#{k}", v) unless v.nil? end end 

这是一个基于Sawa答案的工作示例。 选项号#1无法正常inheritance。

 class CsvOutline def initialize( headers: [], body: [], folder: 'tmp', file_prefix: 'test', filename: "#{file_prefix}_#{Time.zone.now.strftime("%Y%m%d%H%M%S")}.csv", path: File.join(folder, filename)) # Set instance variables and attribute accessors based on named parameters in initialize local_variables.each do |k| class_eval do attr_accessor k end v = eval(k.to_s) instance_variable_set("@#{k}", v) unless v.nil? end end end 

现在如果我要创建一个子类

 class ReportCsv < CsvOutline def initialize super(folder: 'reports', file_prefix: 'Report') end end 

现在,子进程将使用正确的文件夹和file_prefix进行初始化。 如果我要使用第二个选项 - 它们将初始化为零。