2013-02-08 15 views
10

Szukam sposobu na "zmapowanie" pojedynczego przedmiotu w Ruby.Mapa Ruby() dla pojedynczego obiektu

Chcę wywołać tę funkcję i przekazać jej blok, obiekt zostanie oddany do bloku, a następnie wynik bloku zostanie zwrócony do osoby dzwoniącej. Dokładnie to, co robi mapa, ale dla pojedynczego elementu.

Motywacją jest to, że czasami generujesz obiekty, które są używane tylko do konstruowania czegoś innego. Oryginalny obiekt nie jest już potrzebny. Byłoby miło po prostu przekształcić konwersję w blok i wyeliminować tymczasowy.

Jako wymyślny przykład załóżmy, że chcę utworzyć liczbę całkowitą reprezentującą kombinację miesiąc/rok. Do dnia dzisiejszego, kod będzie wyglądał mniej więcej tak:

day = Date.today 
month_number = day.year * 100 + day.month 

bym naprawdę podoba, czy mogę zrobić coś takiego:

month_number = Date.today.some_function { |d| d.year * 100 + d.month } 

Ale nie wiem, co jest „some_function” (lub jeśli nawet istnieje).

Jeśli istnieje bardziej Rubinowy sposób radzenia sobie z czymś w tym stylu, jestem uszy. Jestem świadomy klas łatania małp, ale staram się poradzić sobie z przypadkami, które są nieco bardziej przejściowe.

+0

[ 'Obiekt # tap'] (http://ruby-doc.org/core-1.9.3/Object.html#method-i-tap) jest tak blisko, ale nie robi” t zwraca wartość bloku ... – maerics

+1

Coś jak? m = lambda {| d | d.rok * 100 + d.miesiąc} .call (Date.today) – Kaeros

+0

Zobacz odpowiedź @jondavidjohn. Wbudowany i bez obciążenia wiążącego proc. –

Odpowiedz

13

instance_eval jest tym, czego szukasz.

month_number = Date.today.instance_eval { |d| d.year * 100 + d.month } 

|d| jest również opcjonalny i self domyślnie kontekście obiektu.

To może zaspokoić Twoje potrzeby w bardziej zwarty sposób.

month_number = Date.today.instance_eval { year * 100 + month } 
+1

Dzięki! Dokładnie tego potrzebowałem. –

+0

Wygląda jak | | | jest opcjonalny (samo będzie instancją podczas wykonywania bloku). Tak więc będą działać również: Date.today.instance_eval {year * 100 + month} –

+0

Dzięki, to zadziałało dla mnie. –

3

Wbudowany w Ruby Object#tap jest blisko, ale nie zwraca wartości bloku.

Oto pomysł:

class Object 
    def sap 
    yield self 
    end 
end 

eleven = 10.sap { |x| x + 1 } # => 11 
month_number = Date.today.sap { |d| d.year * 100 + d.month } # => 201202 
+0

Dlaczego miałbyś łatać małpy, gdybyś nie miał połowy? zobacz moją odpowiedź poniżej. – jondavidjohn

+1

+1 dla ładnej, krótkiej składni, ale myślę, że użycie @ instancevidjohn przez instance_eval jest bardziej poprawne z racji bycia wbudowanym. –

+2

Podczas gdy 'instance_eval' działa w podobny sposób, ujawnia również zmienne składowe obiektu docelowego, łamanie bariera interfejsu/implementacji. To nie tyle kwestia bezpieczeństwa, ile szansa na przypadkowe zdmuchnięcie stopy. W tym przypadku usprawiedliwienie małp IMHO jest uzasadnione. – maerics

15

Korzystanie instance_eval jak w odpowiedzi jondavidjohn jest to jedna droga, ale ma narzutu na realokacja self. Taka funkcja była kiedyś proposed in Ruby core, ale została odrzucona i została wycofana. Korzystanie z rozwiązania przedstawionego tam przez jednego z Ruby deweloperów KNU (Akinori Musha), można napisać tak:

month_number = Date.today.tap{|d| break d.year * 100 + d.month} 

Korzystanie tap, jedyną dodatkową rzeczą, którą musisz zrobić, to umieścić break na początku bloku .


require 'benchmark' 

n = 500000 
Benchmark.bm do |x| 
    x.report{n.times{Date.today.instance_eval{year * 100 + month}}} 
    x.report{n.times{Date.today.instance_eval{|d| d.year * 100 + d.month}}} 
    x.report{n.times{Date.today.tap{|d| break d.year * 100 + d.month}}} 
end 

     user  system  total  real 
    2.130000 0.400000 2.530000 ( 2.524296) 
    2.120000 0.400000 2.520000 ( 2.527134) 
    1.410000 0.390000 1.800000 ( 1.799213) 
+1

+1 za odpowiedź, która najprawdopodobniej będzie faworyzowana przez główny zespół. Nadal uczę się tajników Ruby, a zachowanie łamania bloków jest dla mnie nowością. W tym przypadku uczciwie znajduję zachowanie dyskomfortu językowego. –

+1

+1 dla testu porównawczego. Dziękuję Ci! –

Powiązane problemy