Domanda

Sto cercando di imparare un po 'di rubino. Immagina di fare un ciclo continuo e di fare un lungo processo, e in questo processo voglio ottenere un filatore per il tempo necessario.

Quindi potrei fare:

a=['|','/','-','\\']
aNow=0
# ... skip setup a big loop
print a[aNow]
aNow += 1
aNow = 0 if aNow == a.length
# ... do next step of process
print "\b"

Ma ho pensato che sarebbe stato più pulito fare:

def spinChar
  a=['|','/','-','\\']
  a.cycle{|x| yield x}
end
# ... skip setup a big loop
print spinChar
# ... do next step of process
print "\b"

Naturalmente la chiamata spinChar vuole un blocco. Se gli do un blocco, si bloccherà indefinitamente.

Come posso ottenere solo il prossimo anno di questo blocco?

È stato utile?

Soluzione

Il yield di Ruby non funziona in come vorrebbe il tuo esempio. Ma questo potrebbe essere un buon posto per una chiusura :

def spinner()
  state = ['|','/','-','\\']
  return proc { state.push(state.shift)[0] }
end

spin = spinner

# start working
print spin.call
# more work
print spin.call
# etc...

In pratica penso che questa soluzione potrebbe essere troppo "intelligente" per il suo bene, ma comprendendo l'idea di Proc s potrebbe essere comunque utile.

Altri suggerimenti

Mi piacciono tutti questi suggerimenti, ma ho trovato Generator nella libreria standard e penso che sia più in linea con quello che volevo fare:

spinChar=Generator.new{ |g|
  ['|','/','-','\\'].cycle{ |x|
    g.yield x
  }
}
#then
spinChar.next
#will indefinitly output the next character.
Gli incrementi di

?? array array semplici con modulo su un array congelato sembrano essere i più veloci.

Il thread di Vlad è elegante ma non è esattamente quello che volevo. E nella classe spinner l'incremento di una riga sarebbe migliore se Ruby supportasse i ++ come GLYPHS [@i ++% GLYPHS.length]

La chiusura dello spinner di Max con push shift mi sembra un po 'intensa, ma la sintassi risultante è quasi esattamente come questo generatore. Almeno penso che sia una chiusura con proc lì dentro.

Il di_spinner di Chuck è in realtà abbastanza vicino a quello che volevo, ma perché rompere se non devi avere un generatore come sopra.

Vadim, grazie per aver sottolineato il generatore sarebbe lento.

"Here's a test of 50,000 spins:"
                   user       system     total       real
"array index"      0.050000   0.000000   0.050000 (  0.055520)
"spinner class"    0.100000   0.010000   0.110000 (  0.105594)
"spinner closure"  0.080000   0.030000   0.110000 (  0.116068)
"with_spinner"     0.070000   0.030000   0.100000 (  0.095915)
"generator"        6.710000   0.320000   7.030000 (  7.304569)

Penso che tu fossi sulla buona strada con ciclo . Che ne dici di qualcosa del genere:

1.8.7 :001 > spinner = ['|','/','-','\\'].cycle
 => #<Enumerable::Enumerator:0x7f111c165790> 
1.8.7 :002 > spinner.next
 => "|" 
1.8.7 :003 > spinner.next
 => "/" 
1.8.7 :004 > spinner.next
 => "-" 
1.8.7 :005 > spinner.next
 => "\\" 
1.8.7 :006 > spinner.next
 => "|" 

Non credo che tu capisca esattamente cosa yield fa in Ruby. Non restituisce un valore da un blocco & # 8212; passa un valore a il blocco che hai passato al metodo che racchiude.

Penso che tu voglia qualcosa di più simile a questo:

def with_spinner
  a=['|','/','-','\\']
  a.cycle do |x|
    print x
    $stdout.flush # needed because standard out is usually buffered
    yield # this will call the do-block you pass to with_spinner
  end
end

with_spinner do
  #process here
  #break when done
end

C'era una volta, ho scritto un array. Ma non è solo un array, è un array che ha un puntatore, quindi puoi chiamare nextrrr! http://gist.github.com/55955

Associa questa classe a un semplice iteratore o loop e sei d'oro.

 a = Collection.new(:a, :b, :c)
 1000.times do |i|
   puts a.current
   a.next
 end

Il tuo codice è un po 'rovesciato, se mi perdoni dirlo. :)

Perché no:

class Spinner
  GLYPHS=['|','/','-','\\']
  def budge
    print "#{GLYPHS[@idx = ((@idx || 0) + 1) % GLYPHS.length]}\b"
  end
end

spinner = Spinner.new
spinner.budge
# do something
spinner.budge
spinner.budge
# do something else
spinner.budge

Ora , se vuoi qualcosa del tipo:

with_spinner do
  # do my big task here
end

... quindi dovresti utilizzare il multi-threading :

def with_spinner
  t = Thread.new do
    ['|','/','-','\\'].cycle { |c| print "#{c}\b" ; sleep(1) }
  end
  yield
  Thread.kill(t) # nasty but effective
end

hehe, la risposta sopra la mia è tutta sporca.

a=['|','/','-','\\']
a << a
a.each {|item| puts item}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top