views:

150

answers:

3

ActiveSupport offers the nice method to_sentence. Thus,

require 'active_support'
[1,2,3].to_sentence  # gives "1, 2, and 3"
[1,2,3].to_sentence(:last_word_connector => ' and ')  # gives "1, 2 and 3"

it's good that you can change the last word connector, because I prefer not to have the extra comma. but it takes so much extra text: 44 characters instead of 11!

the question: what's the most ruby-like way to change the default value of :last_word_connector to ' and '?

+6  A: 

Well, it's localizable so you could just specify a default 'en' value of ' and ' for support.array.last_word_connector

See:

from: conversion.rb

def to_sentence(options = {})
...
   default_last_word_connector = I18n.translate(:'support.array.last_word_connector', :locale => options[:locale])
...
end

Step by step guide:

First, Create a rails project

rails i18n
Next, edit your en.yml file: vim config/locales/en.yml
en:
  support:
    array:
      last_word_connector: " and "

Finally, it works:

 
Loading development environment (Rails 2.3.3)
>> [1,2,3].to_sentence
=> "1, 2 and 3"
Sam Saffron
How would you do this if you are using activesupport without rails (eg just for a shell script)?
nanothief
Rake tasks load the whole environment, for a shell script outside of rails you can always do I18n.load_path << "filename_with_localization.yml"
Sam Saffron
A: 
 class Array
   alias_method :old_to_sentence, :to_sentence
   def to_sentence(args={})
     a = {:last_word_connector => ' and '}
     a.update(args) if args
     old_to_sentence(a)
   end
 end
Martin DeMello
the trouble with monkey patching is that you are building a house of cards, next time someone monkey patches this in the same way you will have an infinite loop. In this particular case monkey patching is not really needed, cause there is a supported way of achieving the same goal.
Sam Saffron
true, didn't know activesupport did something to support super. that's definitely the best way, then.
Martin DeMello
A: 

As an answer to how to override a method in general, a post here gives a nice way of doing it. It doesn't suffer from the same problems as the alias technique, as there isn't a leftover "old" method.

Here how you could use that technique with your original problem (tested with ruby 1.9)

class Array
  old_to_sentence = instance_method(:to_sentence)
  define_method(:to_sentence) { |options = {}|

    options[:last_word_connector] ||= " and "
    old_to_sentence.bind(self).call(options)
  }
end

You might also want read up on UnboundMethod if the above code is confusing. Note that old_to_sentence goes out of scope after the end statement, so it isn't a problem for future uses of Array.

nanothief