HiveBrain v1.2.0
Get Started
← Back to all entries
patternrubyMinor

Conditional string building in Ruby

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
stringbuildingconditionalruby

Problem

I can see a possible performance optimization with declaring 2 arrays and iterating the $fake_widgets only once, but how else can I make the following conditional string building more elegant in Ruby?

pending_coloring = $fake_widgets.select do |widget|
  widget[:status] == 'awaiting_coloring' && widget[:owner_color] == @owner.id
end

pending_processing = $fake_widgets.select do |widget|
  widget[:status] == 'awaiting_processing' && widget[:owner_color] == @owner.id
end

notification_text = "You have "

if pending_coloring.size == 1
  notification_text += "#{pending_coloring.size} widget to color"
elsif pending_coloring.size > 1
  notification_text += "#{pending_coloring.size} widgets to color"
end

if pending_coloring.size > 0 && pending_processing.size > 0
  notification_text += " and "
end

if pending_processing.size == 1
  notification_text += "#{pending_processing.size} widget to process"
elsif pending_processing.size > 1
  notification_text += "#{pending_processing.size} widgets to process"
end

notification_text += ". Go to widget dashboard"

Solution

First of all, you have weird behaviour if pending_coloring and pending_processing are both empty arrays. The output would then be

You have . Go to widget dashboard


I assume that in such a case, it should just say "Go to widget dashboard".

I think that pluralization ought to be treated as an i18n issue. Even if your application happens to be English-only for now, it's actually easier to generalize the solution, since pluralization is considered a solved problem in internationalization. In particular, you can use the i18n gem (which is included in Rails, and is a simple installation with no dependencies even if you aren't using Rails).

require 'i18n'

pending_coloring = …
pending_processing = …

I18n.backend.store_translations :en, 'widget' => {
:zero => nil,
:one => '1 widget to %{verb}',
:other => '%{count} widgets to %{verb}'
}
coloring_text = I18n.t 'widget', :count => pending_coloring.size, :verb => 'color'
processing_text = I18n.t 'widget', :count => pending_processing.size, :verb => 'process'

notification_text = if (!coloring_text && !processing_text) then
''
else
"You have #{[coloring_text, processing_text].compact.join(' and ')}. "
end + "Go to widget dashboard"

Context

StackExchange Code Review Q#109588, answer score: 3

Revisions (0)

No revisions yet.