Estou tentando usar Ruby 1.9.1 para uma linguagem de script incorporada, de modo que o código do "usuário final" seja escrito em um bloco Ruby. Um problema com isso é que eu gostaria que os usuários pudessem usar a palavra-chave 'return' nos blocos, para que não precisassem se preocupar com valores de retorno implícitos. Com isso em mente, este é o tipo de coisa que eu gostaria de ser capaz de fazer:
def thing(*args, &block)
value = block.call
puts "value=#{value}"
end
thing {
return 6 * 7
}
Se eu usar 'return' no exemplo acima, obtenho um LocalJumpError. Estou ciente de que isso ocorre porque o bloco em questão é um Proc e não um lambda. O código funcionará se eu remover 'return', mas eu realmente prefiro poder usar 'return' neste cenário. Isso é possível? Tentei converter o bloco em lambda, mas o resultado é o mesmo.
ruby
lambda
return
proc-object
MetaFu
fonte
fonte
Respostas:
Basta usar
next
neste contexto:return
sempre retorna do método, mas se você testar este trecho no irb você não tem o método, é por isso que você temLocalJumpError
break
retorna o valor do bloco e termina sua chamada. Se o seu bloco foi chamado poryield
ou.call
, entãobreak
interrompe este iterador tambémnext
retorna o valor do bloco e termina sua chamada. Se o seu bloco foi chamado poryield
ou.call
, entãonext
retorna o valor para a linha ondeyield
foi chamadofonte
Você não pode fazer isso em Ruby.
A
return
palavra-chave sempre retorna do método ou lambda no contexto atual. Em blocos, ele retornará do método em que o fechamento foi definido . Não pode ser feito para retornar do método de chamada ou lambda.O Rubyspec demonstra que este é realmente o comportamento correto para Ruby (reconhecidamente não é uma implementação real, mas visa compatibilidade total com C Ruby):
fonte
Você está olhando do ponto de vista errado. Este é um problema
thing
, não do lambda.fonte
Onde a coisa é invocada? Você está dentro de uma classe?
Você pode considerar o uso de algo assim:
fonte
Tive o mesmo problema ao escrever um DSL para um framework web em ruby ... (o framework web Anorexic vai arrasar!) ...
de qualquer maneira, eu pesquisei os detalhes internos do ruby e encontrei uma solução simples usando o LocalJumpError retornado quando uma chamada Proc retorna ... ele funciona bem nos testes até agora, mas não tenho certeza se é à prova completa:
a instrução if no segmento de resgate provavelmente seria algo assim:
mas é um território desconhecido para mim, então vou continuar com o que testei até agora.
fonte
Acredito que esta seja a resposta correta, apesar das desvantagens:
Este hack permite que os usuários usem return em seus procs sem consequências, self é preservado, etc.
A vantagem de usar Thread aqui é que em alguns casos você não obterá o LocalJumpError - e o retorno acontecerá no lugar mais inesperado (ao lado de um método de nível superior, ignorando inesperadamente o resto de seu corpo).
A principal desvantagem é a sobrecarga potencial (você pode substituir o Thread + join apenas com o
yield
se isso for suficiente em seu cenário).fonte
Eu encontrei uma maneira, mas envolve definir um método como uma etapa intermediária:
fonte