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

      

+3


source to share


3 answers


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

+5


source


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

.

+7


source


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
}

      

But I want to focus on what I noticed about this code example. Each method starts with envelope

, which probably means that. If you extract this data into an 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

      

Surely the real code will be more complex than this, just food for thought.

+1


source







All Articles