2013-02-08 11 views
10

Sto cercando un modo per 'mappare' un singolo oggetto in Ruby.Ruby map() per un singolo oggetto

Voglio chiamare questa funzione e passarla a un blocco, l'oggetto verrà restituito al blocco e quindi il risultato del blocco verrà restituito al chiamante. Esattamente ciò che fa la mappa, ma per un singolo elemento.

La motivazione è che a volte si generano oggetti che sono appena utilizzati per costruire qualcos'altro. L'oggetto originale non è più necessario. Sarebbe bello mettere la conversione in un blocco ed eliminare il temporaneo.

Come esempio forzato, supponiamo di voler creare un numero intero che rappresenti la combinazione mese/anno. Per la data odierna, il codice sarebbe simile:

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

Mi piacerebbe molto se avrei potuto fare qualcosa di simile:

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

Ma io non so che cosa è 'una_qualche_funzione' (o se esiste anche).

Se c'è un modo più rubino di gestire qualcosa di simile, sono tutto orecchie. Sono a conoscenza delle classi di patch di scimmia, ma sto cercando di gestire quei casi che sono un po 'più transitori.

+0

[ 'Object # tap'] (http://ruby-doc.org/core-1.9.3/Object.html#method-i-tap) è così vicino, ma doesn' t restituire il valore del blocco ... – maerics

+1

Qualcosa come? m = lambda {| d | d.anno * 100 + d.month} .call (Date.today) – Kaeros

+0

Vedere la risposta di @jondavidjohn. Built in e nessun overhead di binding proc. –

risposta

13

instance_eval è quello che stai cercando.

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

Il |d| è opzionale e self il default è il contesto di oggetto.

Questo può soddisfare le vostre esigenze in modo più compatto. incorporato Object#tap

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

Grazie! Questo è esattamente ciò di cui avevo bisogno. –

+0

Sembra che | | | è anche opzionale (auto sarà l'istanza durante l'esecuzione del blocco). Quindi funzionerà anche il seguente: Date.today.instance_eval {year * 100 + month} –

+0

Grazie, ha funzionato per me. –

3

di Ruby è vicino, ma non restituisce il valore del blocco.

Ecco un'idea:

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

Perché dovresti scimmia se non ne avevi la metà? vedi la mia risposta qui sotto. – jondavidjohn

+1

+1 per una sintassi bella e breve, ma penso che l'uso di _jondavidjohn di instance_eval sia più corretto in virtù del fatto di essere incorporato. –

+2

Mentre 'instance_eval' funziona in modo comparabile rivela anche le variabili membro dell'oggetto target, rompendo la barriera di interfaccia/implementazione. Questo non è tanto un problema di sicurezza quanto una possibilità di saltare accidentalmente il piede. In questo caso è giustificato il patching scimmia IMHO. – maerics

15

Utilizzando instance_eval come in risposta jondavidjohn s' è un modo per andare, ma ha in testa per la riassegnazione self. Tale funzione era una volta proposed in Ruby core, ma è stata respinta ed è stata ritirata. Utilizzando la soluzione presentata lì da uno degli sviluppatori KNU Ruby (Akinori Musha), si potrebbe scrivere in questo modo:

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

Utilizzando tap, l'unica cosa in più è necessario fare è mettere break all'inizio del blocco .


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 per la risposta che più probabilmente sarà favorita dal team principale. Sto ancora imparando alcuni dei dettagli di Ruby e il comportamento di rompere i blocchi è nuovo per me. In questo caso, trovo onestamente il comportamento del linguaggio scomodo. –

+1

+1 per il benchmark. Grazie! –

Problemi correlati