在 ruby 中重构长字符串行的最佳方法是什么?
How is the best way to refactor a long string line in ruby?
我有这样一行代码
"#{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。
我想将其重构为不长的一行。
我知道很多方法,但我想知道 ruby 风格专家期望哪种方法。
当我需要一个空字符串(如果它是 nil)时,需要静态方法 util_name 来防止 nil。
def self.util_name(value)
return '' if value.nil?
value.name
end
您可以尝试的一件事是不使用字符串插值,而是使用连接和 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
数组有其他用途,那将会有所帮助。
你可以试试这个
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
更易读
that static method util_name is needed to prevent nil when I need an empty string if it's nil.
def self.util_name(value)
return '' if value.nil?
value.name
end
好的,考虑到这些上下文,您可以完全删除 Budget::util_name
方法,因为它没有做任何有用的事情。有两种方法可以有条件地调用可能 nil
的对象上的方法,一种由框架提供,一种由语言提供。
如果您使用的是 Ruby 2.2 或更早版本,请使用 try method.
value.try(:name)
如果您使用的是 Ruby 2.3 或更高版本,您可以使用 safe navigation operator
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
开头,这可能意味着 these methods are telling you they should be a separate object. If you extract this data into a value object,那么这个辅助方法的自然位置就变得显而易见了......
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
毫无疑问,真正的代码会比这更复杂,仅供思考。
我有这样一行代码
"#{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。
我想将其重构为不长的一行。
我知道很多方法,但我想知道 ruby 风格专家期望哪种方法。
当我需要一个空字符串(如果它是 nil)时,需要静态方法 util_name 来防止 nil。
def self.util_name(value)
return '' if value.nil?
value.name
end
您可以尝试的一件事是不使用字符串插值,而是使用连接和 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
数组有其他用途,那将会有所帮助。
你可以试试这个
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
that static method util_name is needed to prevent nil when I need an empty string if it's nil.
def self.util_name(value)
return '' if value.nil?
value.name
end
好的,考虑到这些上下文,您可以完全删除 Budget::util_name
方法,因为它没有做任何有用的事情。有两种方法可以有条件地调用可能 nil
的对象上的方法,一种由框架提供,一种由语言提供。
如果您使用的是 Ruby 2.2 或更早版本,请使用 try method.
value.try(:name)
如果您使用的是 Ruby 2.3 或更高版本,您可以使用 safe navigation operator
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
开头,这可能意味着 these methods are telling you they should be a separate object. If you extract this data into a value object,那么这个辅助方法的自然位置就变得显而易见了......
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
毫无疑问,真正的代码会比这更复杂,仅供思考。