8

我有这样一行代码

"#{envelope_quantity} - envelope #{Budget::util_name(envelope_size)} #{Budget::util_name(envelope_paper)} #{Budget::util_name(envelope_color)} #{Budget::util_name(envelope_grammage)} #{Budget::util_name(envelope_model)} #{Budget::util_name(envelope_print)}"

太长了,读起来不好,这就是 RuboCop 用Metrics::LineLength警告我的原因。

我想将它重构为不长线。

我知道很多方法可以做到这一点,但我想知道哪一种是红宝石风格专家所期望的。

当我需要一个空字符串(如果它为 nil)时,需要该静态方法 util_name 来防止 nil。

def self.util_name(value)
  return '' if value.nil?
  value.name
end
4

3 回答 3

12

你可以试试这个

str = "#{envelope_quantity} - envelope #{Budget::util_name(envelope_size)} "\
      "#{Budget::util_name(envelope_paper)} #{Budget::util_name(envelope_color)} "\
      "#{Budget::util_name(envelope_grammage)} #{Budget::util_name(envelope_model)} "\
      "#{Budget::util_name(envelope_print)}"

这样,您将能够将字符串限制在最大行长度内,并且比使用它更易读join

于 2017-06-10T06:57:40.227 回答
7

您可能会尝试的一件事是不使用字符串插值,而是使用连接和构造字符串join

"#{envelope_quantity} - envelope " + 
[Budget::util_name(envelope_size), 
 Budget::util_name(envelope_paper),
 Budget::util_name(envelope_color),
 Budget::util_name(envelope_grammage),
 Budget::util_name(envelope_model),
 Budget::util_name(envelope_print)].join(' ')

更简洁地说,您可以使用map

"#{envelope_quantity} - envelope " + 
[envelope_size, 
 envelope_paper,
 envelope_color,
 envelope_grammage,
 envelope_model,
 envelope_print].map{|x| Budget::util_name(x)}.join(' ')

通过以正确的顺序定义具有所有信封属性的数组并将其应用于该数组,可以使这更简洁map

envelope_properties=[envelope_size, 
                     envelope_paper,
                     envelope_color,
                     envelope_grammage,
                     envelope_model,
                     envelope_print]

"#{envelope_quantity} - envelope " + 
envelope_properties.map{|x| Budget::util_name(x)}.join(' ')

当然,如果您碰巧对envelope_properties阵列有其他用途,这会有所帮助。

于 2017-06-10T02:56:53.067 回答
1

当我需要一个空字符串(如果它为 nil)时,需要该静态方法 util_name 来防止 nil。

def self.util_name(value)
  return '' if value.nil?
  value.name
end

好的,鉴于那一点上下文,您可以Budget::util_name完全删除该方法,因为它没有做任何有用的事情。有两种方法可以有条件地调用对象上的方法nil,一种由框架提供,另一种由语言提供。

如果您使用的是 Ruby 2.2 或更早版本,请使用try 方法

value.try(:name)

如果您使用的是 Ruby 2.3 或更高版本,则可以使用安全导航运算符

value&.name

无论哪种情况,您都不需要专门测试,nil因为它会在插值时自动强制转换为空字符串。

"#{envelope_quantity&.name} - envelope #{envelope_size&.name} #{envelope_paper&.name} #{envelope_color&.name} #{envelope_grammage&.name} #{envelope_model&.name} #{envelope_print&.name}"

这更合理,但可能还是有点太长了。您可以使用字符串模板:

"%{quantity} - envelope %{size} %{paper} %{color} %{grammage} %{model} %{print}" % {
  quantity: envelope_quantity&.name,
  size:     envelope_size&.name,
  paper:    envelope_paper&.name,
  color:    envelope_color&.name,
  grammage: envelope_grammage&.name,
  model:    envelope_model&.name,
  print:    envelope_print&.name
}

但我想重点关注我注意到的关于此代码示例的一些内容。每个方法都以envelope这可能意味着这些方法告诉您它们应该是一个单独的对象。如果您将这些数据提取到一个值对象中,那么这个辅助方法的自然位置就变得很明显了......

class Envelope < Struct.new(:quantity, :size, :paper, :color, :grammage, :model, :print)
  def to_s
    "#{quantity&.name} - envelope #{size&.name} #{paper&.name} #{color&.name} #{grammage&.name} #{model&.name} #{print&.name}"
  end
end

毫无疑问,真正的代码会比这更复杂,只是值得深思。

于 2017-06-13T02:34:13.140 回答