I feel like this should exist, but I'm looking for a Rails helpers that handles listing a collection of items.
# Input and expected output
[1,2,3,4] # 1, 2, and 2 others.
[1,2,3] # 1, 2, and 3.
[1,2] # 1 and 2.
[1] # 1.
Does anything like this exist?
CodePudding user response:
Maybe this one?
[1,2,3].to_sentence
=> "1, 2 and 3"
CodePudding user response:
Archer answered the question, however my use case required a little more customization so I ended up (for better or worse) reinventing the wheel.
sig do
params(
items: T::Array[T.untyped],
count: Integer,
renderer: T.nilable(T.proc.params(arg0: T.untyped).returns(String)),
final_renderer:
T.nilable(T.proc.params(arg0: T.untyped).returns(String)),
)
.returns(T.untyped)
end
def listicle(items, count: 3, renderer: nil, final_renderer: nil)
SolidAssert.assert(items.size > 0, 'Must provide at least 1 item.')
buffer = ''
rendered_items =
items.first(count).map { |item| renderer ? renderer.call(item) : item }
if items.size <= count
# Case: All items can be inlined.
if rendered_items.size == 1
buffer = rendered_items.join
else
items_before_and = rendered_items.first(rendered_items.size - 1)
last_item = rendered_items.last
buffer = items_before_and.join(', ')
buffer << " and #{last_item}"
end
else
# Case: There are too many items so we render an "and 1 other..." item.
remaining_count = items.size - count
final_item =
if final_renderer
final_renderer.call(remaining_count)
else
"#{ApplicationController.helpers.pluralize(remaining_count, 'other')}"
end
buffer = rendered_items.join(', ')
buffer << " and #{final_item}"
end
buffer.html_safe
end