Enumerable#lazy
si affida al numero enumerabile fornendo un metodo #each
. Se il tuo enumerable non ha un metodo #each
non è possibile utilizzare #lazy
. Ora Kernel#enum_for
e #to_enum
offrono la flessibilità di specificare un metodo di enumerazione diverso #each
:Qual è il modo migliore per restituire un Enumeratore :: Lazy quando la classe non definisce #each?
Kernel#enum_for(method = :each, *args)
Ma #enum_for
e amici costruiscono sempre semplici enumeratori (non pigri), mai Enumerator::Lazy
.
vedo che Enumerator
in Ruby 1.9.3 offre questa forma simile di #new:
Enumerator#new(obj, method = :each, *args)
Purtroppo questo costruttore è stato completamente rimosso in Ruby 2.0. Inoltre, non penso che sia mai stato disponibile su Enumerator::Lazy
. Quindi mi sembra che se ho una classe con un metodo voglio restituire un enumeratore pigro, se quella classe non ha #each
allora devo definire qualche classe helper che definisce #each
.
Ad esempio, ho una classe Calendar
. Non ha senso per me offrire di elencare ogni data dall'inizio di tutti i tempi. Un #each
sarebbe inutile. Invece offro un metodo che enumera (pigramente) da una data di inizio:
class Calendar
...
def each_from(first)
if block_given?
loop do
yield first if include?(first)
first += step
end
else
EachFrom.new(self, first).lazy
end
end
end
E che EachFrom
classe assomiglia a questo:
class EachFrom
include Enumerable
def initialize(cal, first)
@cal = cal
@first = first
end
def each
@cal.each_from(@first) do |yielder, *vals|
yield yielder, *vals
end
end
end
funziona ma ci si sente pesante. Forse dovrei sottoclasse Enumerator::Lazy
e definire un costruttore come quello deprecato da Enumerator
. Cosa ne pensi?
Mi hai appena fatto impazzire Marc-André. Il mio codice passò da idiota a idiomatico. Non ho capito che Ruby vuole che ci occupiamo sempre del traffico in Enumeratori e non Enumeratore :: Lazy. Ovunque sia necessario qualcosa per essere pigri, chiediamo a quell'enumeratore la versione #lazy. Il lato negativo è forse che gli utenti delle nostre astrazioni devono davvero capire quando chiamare #lazy (ad esempio prima di chiamare #drop (n)). Il lato positivo è il codice pulito e nitido. –
Ho avuto così tanti problemi con (e ho imparato tanto da) #drop (n). Ora che sto restituendo "semplici" Enumeratori ovunque ho dovuto cospargere alcuni ... lazy.drop (n) ... circa. Così ho definito un metodo drop-like che fa avanzare semplicemente l'Enumeratore, lasciandomi cambiare a ... skip (n) ... –
Giusto. Si può sicuramente definire un metodo come "Enumerable # skip (n)" che restituisce un 'Enumerator' invece di un array come' drop' fa e gioca con quello. –