class String
# Selects the part based upon count. Giving you control over the syntax.
#
# The syntax:
# * "{$N}".pluralize_for(int)
# * "{post|posts}".pluralize_for(int)
# * "one post ~~ more posts".pluralize_for(int)
# * "no posts ~~ one post ~~ more posts".pluralize_for(int)
# * "no posts ~~ one post ~~$N<6: more posts ~~else: large amount".pluralize_for(int)
# * "click {1:here} for more info".pluralize_for(int) { |array| array[1] = link_to(array[i], url) if array[i]
#
# Tip: ~~$N>=3:-syntax is eval'ed, so check your source code! Also, if you decide to use it, it's better to specify it everywhere, not just the last parts.
def pluralize_for(count)
# get the value properly, so we can manipulate it
str = self.to_s.clone
# examine which part of it we need to fetch
str = __get_partialized_string(str, count)
# replace the count value, if any left
str.gsub!("{$N}", count.to_s) if str.include?("{$N}")
# replace {single|plural} with either single or plural
if str =~ /\{([^|\{]*)\|([^\}]*)\}/
single = $1.clone
plural = $2.clone
str.gsub!(/\{([^|\{]*)\|([^\}]*)\}/, (count == 1 ? single : plural))
end
# do some replacements with {1:foo}
if block_given?
# find the substitution parts
matched = str.scan(/\{(\d+):([^\}]+)\}/)
# do some reordering
array = []
matched.each do |x|
array[x[0].to_i] = x[1].to_s
end
# let the others edit it if they like
yield array
# replace the block with the new values
array.size.times do |x|
str.gsub!(/\{#{x}:([^\}]+)\}/,array[x].to_s)
end
end
str
end
private
def __get_partialized_string(str, count)
parts = str.split('~~')
if parts.size > 1
array = case parts.size
when 2 then ['$N==1:', 'else:']
when 3 then ['$N==0:', '$N==1:', 'else:']
else
['$N==1:','$N!=1:']
end
parts.size.times do |i|
parts[i] = array[i] + parts[i] unless parts[i] =~ /^\S*:/
c = parts[i].split(/:\s*/,2)
if c[0] == 'else'
return c[1]
else
return c[1] if eval(c[0].gsub('$N',count.to_s))
end
end
end
return str
end
end