2009-05-09 12 views
16

Die Rails Methode Array#to_sentence die folgenden erlaubt:Redefining Rails Methoden

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

Ich möchte diese Methode erweitern, um es zu ermöglichen, einen Block zu nehmen, so dass Sie so etwas wie die folgenden (wo die Menschen tun können ist ein Array von Person-Objekte, die den Namen Attribut):

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

ich mit dem Schreiben die Erweiterungsmethode ein Problem nicht haben. Aber ich kann nicht herausfinden, wo ich es hinstellen soll. Die Rails-Core-Erweiterungen werden irgendwo in den Tiefen von ActiveSupport geladen. Mein Bedarf ist für einen Platz, wo benutzerdefinierter Code immer geladen wird und vor jedem Anwendungscode geladen wird.

Antwort

23

Erstellen config/initializers/super_to_sentence.rb. Alle Dateien in diesem Verzeichnis werden nach dem Laden von Rails geladen, sodass Sie die Rails-Definition von Array#to_sentence überschreiben können.

Für Code, den Sie laden möchten, bevor Rails geladen wird, fügen Sie ihn zu config/environment.rb hinzu.

+0

Wie erwähnt wurde, fügen Sie alle Ihre benutzerdefinierten Erweiterungen zu einer Config/Initializers/*. RB-Datei – cpjolicoeur

+0

Vielen Dank. Wird es überprüfen. – dcw

14

Ich mag, dies zu tun:

# 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

Danke. Übrigens denke ich, es ist eine gute Übung, sich an das vorherige defn zu erinnern, d. h., vor dem Definieren der neuen Methode und deren Aliasing ein "alias alt_zu_sende zu to_sentence" hinzuzufügen. – dcw

14

Ich denke, das eine hässliche Idee. Warum nicht Sie schreiben gerade

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

Das sieht fast gleich und verwirren nicht andere Leute Code zu lesen (wie Sie selbst in 2 Jahren)

+2

Und jetzt wird es noch kürzer: 'people.map (&: name) .to_sentence' – sawa

1

gleich um die Web-Suche, scheint wie gute Praxis hinzufügen es in lib/

also, wenn Sie wollen etwas Rubin Klasse erweitern (in meinem Fall, Datetime), nur den Code in .rb setzen und dann in config/environment.rb:

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

meine super_datetime.rb sieht wie folgt aus (Code aus 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 

den Server neu starten und Sie werden für alle Datetime-Objekte Zugriff auf das neue Verfahren haben.

Verwandte Themen