分支条件赋值过高

7

我有一个简单的类,在初始化时需要1到8个参数。它将这些访问器设置为以后使用。Rubocop试图因ABC值过高而逮捕我,但我不确定我所做的是否真的有问题。这是我只需要在初始化中禁用检查的情况吗?

class Foo
  attr_accessor :one, :two, :three, :four
  attr_accessor :five, :six, :seven, :eight

  def initialize(p={})
    @one = p[:one] if p[:one].present?
    # ...
    @eight = p[:eight] if p[:eight].present?
  end
end

我觉得减小代码量的方法是在初始化时遍历所有的attr_accessor,查看是否在哈希表中有对应的符号,并将其赋值。

class Foo
  attr_accessor :one, :two, :three, :four
  attr_accessor :five, :six, :seven, :eight

  def initialize(p={})
    instance_variables.each do |variable|
      send("@#{variable}") = p["#{send(variable)}".to_sym] if p["#{send(variable)}".to_sym].present?
    end
  end
end

但这似乎有些虚弱。
2个回答

5
这是实现您想要做的其中一种方法:

以下是具体步骤:

class Foo
  attr_accessor(*%i[one two three four five six seven eight])

  def initialize(p = {})
    p.keys.each { |k| instance_variable_set("@#{k}", p.fetch(k, nil)) }
  end
end

请查看Hash#fetch方法。
如果您决定使用一个变量(@p)而不是8个变量,则可以使用它来访问p变量的键值对。

编辑

出于好奇,编写了这个版本(使用了一些元编程),它将动态添加attr_accessor以添加实例变量。
class Foo
  def initialize(p = {})
    p.keys.each do |k|
      instance_variable_set("@#{k}", p.fetch(k, nil))
      self.class.__send__(:attr_accessor, k)
    end
  end
end

发生的情况是,我们获取传递给initialize方法的参数(哈希p),从中获取键并创建实例变量,将每个变量赋值为相应的键的值。然后,我们为每个键定义attr_accessor
a = Foo.new(a: 2, b: 3)
#=> #<Foo:0x00000002d63ad8 @a=2, @b=3>

这看起来很像我认为可能是一种逃避责任的方式。双关语。虽然我同意这是解决问题的一种方式,但您能否指出一个参考资料,让我可以更多地了解为什么这是“正确”的方式?感谢您抽出时间回复! - CarlyL
@CarlyL 关于正确的方式 - Ruby 是一种非常灵活的语言,因此可以用多种方式完成任务。而且通常“正确的方式”是个人偏好的问题。我认为你可以阅读 Ruby 风格指南,了解什么是不应该做的,但我怀疑有人会声称某件事情是100%正确的 :) - Andrey Deineko
你也可以将属性名称放入一个冻结数组中,例如ATTR_NAMES = %i(one two three four five six seven eight).freeze常量,并调用attr_accessor(*ATTR_NAMES) - chad_

2

你不应该将它们分别分配为不同的变量。相反,你应该将它们保存到一个变量中作为单个哈希,并在需要值时访问哈希。实际上,你已经似乎有一个变量p。所以将其保留为@p = p


感谢您抽出时间回复。两个回答都表明我可以只有一个attr_accessor p,它是一个哈希,但这对我来说似乎有点奇怪。您有任何参考资料可以让我了解为什么这是最好的方法吗? - CarlyL

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接