Подтвердить что ты не робот

Задайте аргументы ключевого слова ruby ​​2.0 с помощью attr_accessor при инициализации

Как я могу динамически установить без необходимости писать один и тот же код.

В настоящий момент код выглядит следующим образом:

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
4b9b3361

Ответ 1

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

или следуя указаниям Джона Ледбеттера и Кейри Суволанда:

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

Ответ 2

Вот рабочий пример, основанный на ответе Саввы. Номер опции №1 работает неправильно с наследованием.

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. Если бы мне пришлось использовать второй вариант - они будут инициализированы нулем.