What's the best way to reorganize a long string of a string in ruby?
I have a line of code like
"#{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)}"
too long, it's bad to read and that's why RuboCop warns me about this Metrics :: LineLength .
I would like to reorganize it so that it is not long.
I know of many ways to do this, but I am wondering which one would be expected by ruby ββstyle experts.
that the static method util_name is needed to prevent nil when I need an empty string if it is nil.
def self.util_name(value)
return '' if value.nil?
value.name
end
source to share
You can try this
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)}"
this way you will be able to constrain the line within the maximum line length and also make it slightly more readable than with join
source to share
One thing you can try is not to use string interpolation, instead construct a string using concatenation and 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(' ')
Even more succinctly, you can use map
:
"#{envelope_quantity} - envelope " +
[envelope_size,
envelope_paper,
envelope_color,
envelope_grammage,
envelope_model,
envelope_print].map{|x| Budget::util_name(x)}.join(' ')
This can be made more concise by specifying an array with all the envelope properties in the correct order and applying map
to that:
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(' ')
Of course it would help if you had other uses for the array envelope_properties
.
source to share
that the static method util_name is needed to prevent nil when I need an empty string if it is zero.
def self.util_name(value)
return '' if value.nil?
value.name
end
Ok, given this bit of context, you can remove the method entirely Budget::util_name
, because it doesn't do anything useful. There are two ways to conditionally call a method on an object, which may be nil
, one is provided by the framework and the other is provided by the language.
If you are using Ruby 2.2 or earlier, use the try method .
value.try(:name)
if you are using Ruby 2.3 or higher you can use the safe navigation operator
This is much more reasonable, but probably too long. You can use string templates:
"%{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
}
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
Surely the real code will be more complex than this, just food for thought.
source to share