2009-05-09 15 views
16

The Rails metodo Array#to_sentence permette le seguenti:metodi Ridefinizione Rails'

['a', 'b', 'c'].to_sentence # gives: "a, b, and c" 

vorrei estendere questo metodo per consentire di prendere un blocco, in modo che si può fare qualcosa di simile al seguente (in cui la gente è un array di oggetti Person, che hanno l'attributo nome):

people.to_sentence { |person| person.name } 
# => "Bill, John, and Mark" 

non ho un problema con la scrittura il metodo di estensione. Ma non riesco a capire dove metterlo. Le estensioni core di Rails vengono caricate da qualche parte nelle profondità di ActiveSupport. La mia necessità è un luogo in cui il codice definito dall'utente viene sempre caricato ed è precaricato (prima di qualsiasi codice dell'applicazione).

risposta

23

Creare config/initializers/super_to_sentence.rb. Tutti i file in questa directory vengono caricati dopo aver caricato Rails, quindi avrai la possibilità di ignorare la definizione di Rails di Array#to_sentence.

Per il codice che si desidera caricare prima che Rails venga caricato, aggiungerlo a config/environment.rb.

+0

come è stato detto, aggiungere tutte le estensioni personalizzate a un config/inizializzatori/*. File rb – cpjolicoeur

+0

Grazie. Verificherò – dcw

14

mi piace fare questo:

# config/initializers/app.rb 
Dir[File.join(Rails.root, "lib", "core_ext", "*.rb")].each {|l| require l } 

# lib/core_ext/array.rb 
class Array 
    def to_sentence_with_block(*args, &block) 
    if block_given? 
     # do something... 
     # to_sentence_without_block(*args) perhaps? 
    else 
     to_sentence_without_block(*args) 
    end 
    end 
    alias_method_chain :to_sentence, :block 
end 
+0

Grazie. btw, penso che sia una buona pratica ricordare il defn precedente, cioè aggiungere un "alias old_to_sentence a_sentence" prima del defn del nuovo metodo e del suo aliasing. – dcw

14

Penso che questa sia una brutta idea. Perché non basta scrivere

people.collect { |person| person.name }.to_sentence 

Questo sembra quasi la stessa e non confondere le altre persone a leggere il codice (come te in 2 anni)

+2

E ormai diventa ancora più corto: 'people.map (&: name) .to_sentence' – sawa

1

solo cercando in giro per il web, sembra buona pratica è quella di aggiungere in lib/

quindi, se volete estendere qualche classe rubino (nel mio caso, DateTime), appena messo il codice in .RB e poi in config/environment.rb:

config.after_initialize do 
    require "lib/super_datetime.rb" 
    end 

il mio super_datetime.rb assomiglia a questo (codice da http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/140184):

class DateTime 
    def days_in_month 
    self::class.civil(year, month, -1).day 
    end 
    alias dim days_in_month 
    def weekdays 
    (1..dim).to_a 
    end 
end 

riavviare il server e avrete accesso al nuovo metodo per tutti gli oggetti DateTime.

Problemi correlati