Pergunta

Eu estou tentando aprender alguma rubi. Imagine que eu estou looping e fazendo um processo de longa duração, e nesse processo eu quero começar um girador por tanto tempo quanto necessário.

Assim que eu poderia fazer:

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"

Mas eu pensei que seria mais limpo para fazer:

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

É claro que a chamada spinChar quer um bloco. Se eu dar-lhe um bloco que vai pendurar indefinidamente.

Como posso obter apenas o lado de rendimento que deste bloco?

Foi útil?

Solução

yield não funciona da maneira seu exemplo gostaria. Mas isso pode ser um bom lugar para um fechamento :

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

spin = spinner

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

Na prática, eu acho que esta solução pode ser muito "inteligente" para seu próprio bem, mas compreender a idéia de Proc s poderia ser útil de qualquer maneira.

Outras dicas

Eu gosto de todas essas sugestões, mas eu achei o Generator na biblioteca padrão, e eu acho que é mais ao longo das linhas do que eu queria fazer:

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

incrementos Plain array index com módulo em uma matriz congelado parece ser mais rápido.

fio de Vlad é bacana, mas não exatamente o que eu queria. E em spinner class o incremento de uma linha seria melhor se Rubi suportado i++ como GLYPHS[@i++%GLYPHS.length]

spinner closure de Max com mudança impulso parece um pouco intenso para mim, mas a sintaxe resultante é quase exatamente como este Generator. Pelo menos eu acho que é um fechamento com proc lá.

with_spinner de Chuck é realmente muito parecido com o que eu queria, mas porque pausa, se você não tem para com um gerador como acima.

Vadim, Obrigado por apontar o generator seria lenta.

"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)

Eu acho que você estava no caminho certo com cycle. Que tal algo como isto:

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
 => "|" 

Eu não acho que você entendo muito bem o que yield faz em Ruby. Ela não retorna um valor de um bloco -. Ele passa um valor para o bloco que você passou para o método anexando

Eu acho que você quer algo mais parecido com isto:

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

Era uma vez, eu escrevi um array. Mas não é apenas uma matriz, é uma matriz que tem um ponteiro, para que possa chamar próxima foreverrr! http://gist.github.com/55955

Par esta classe com um iterador simples ou loop e você é ouro.

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

Seu código é um pouco de dentro para fora, se você pardon me dizendo isso. :)

Por que não:

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

Agora , se você quiser algo como:

with_spinner do
  # do my big task here
end

... então você teria que Usar 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, a resposta acima minha é toda suja.

a=['|','/','-','\\']
a << a
a.each {|item| puts item}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top