Pergunta

I know about Object#tap, which takes a value and returns that value. But is there a method that takes a block and returns the value evaluated by the block?

To improve my code in this answer (which is more complicated than the snippet below), I'd like to change

deck.index("A").tap {|index| 
  STDERR.puts "Result of indexing for #{"A".inspect} is #{index.inspect}"
}

, which has "A" repeated, into

def my_method(*args)
  yield *args
end

deck = ['A', 'B', 'C']
my_method("A") {|value| deck.index(value).tap {|index|
  STDERR.puts "Result of indexing for #{value.inspect} is #{index.inspect}"
} }
# Result of indexing for "A" is 0
# => 0
Foi útil?

Solução

What you're looking for is essentially the equivalent of let in Lisp or OCaml — something that allows you to temporarily bind a value to an identifier without introducing a new variable into the larger scope. There isn't anything that lets you do such a thing with that syntax in Ruby. The equivalent Ruby would be:

lambda {|value| deck.index(value).tap {|index|
  STDERR.puts "Result of indexing for #{value.inspect} is #{index.inspect}"
} }.call 'A'

You could of course just write a method like:

def let(*values) 
  yield *values 
end

Outras dicas

I think you could solve it with fibers. Something like:

def myfiber
    block = lambda{nil}
    loop{ block = Fiber.yield(block.call) } 
end
f = Fiber.new {myfiber }
f.resume

puts "result: #{f.resume(lambda{1})}"
puts "result: #{f.resume(lambda{5})}"
puts "result: #{f.resume(lambda{2})}"

will result in:

result: 1
result: 5
result: 2
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top