【问题标题】:Set ruby 2.0 keyword arguments with attr_accessor on initialize在初始化时使用 attr_accessor 设置 ruby​​ 2.0 关键字参数
【发布时间】:2013-09-18 15:37:27
【问题描述】:

我怎样才能动态设置而不必从头到尾写相同的代码。

现在代码如下所示:

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

【问题讨论】:

    标签: ruby


    【解决方案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
    

    或遵循 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
    

    【讨论】:

    • 不错。不知道 local_variables 存在。
    • 您还可以查看self.method(:initialize).parameters,它还会告诉您参数的类型(例如,可选、必需、键、全局...)
    • @JohnLedbetter 实际上,这可能比我的回答要好。
    • @JohnLedbetter 优雅!可以使用__method__ 代替initialize
    • John Ledbetter 和 Cary Swoveland 的建议不太适合继承。如果我是从初始化第二种方法的类继承的 - 如果我尝试传递任何东西,我会在子类上得到 zilch。与 local_variables 一起使用 - 我实际上都尝试过 - 请参阅下面的答案
    【解决方案2】:

    这是一个基于 Sawa 回答的工作示例。选项编号 #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 
    

    现在孩子将使用正确的文件夹和文件前缀进行初始化。如果我使用第二个选项 - 它们将被初始化为 nil。

    【讨论】:

      【解决方案3】:

      如果您使用 Ruby v2.5 或更高版本,请考虑使用Struct

      MyClass = Struct.new(:foo, :bar, keyword_init: true)
      MyClass.new(foo: 1, bar: 2)
      

      https://ruby-doc.org/core-2.5.0/Struct.html#method-c-new

      【讨论】:

        猜你喜欢
        • 2017-05-26
        • 1970-01-01
        • 2018-03-03
        • 2022-12-30
        • 2010-10-23
        • 2022-06-17
        • 2010-12-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多