Как и просили, вот пример того, что я имел в виду, связывая выбор между доходами. Чистая реализация может выглядеть примерно так:
def choose_one_of_each(choices,results,&block)
if choices.empty?
yield results
else
c = choices.dup
var,val = c.shift
choose(val) { |v|
choose_one_of_each(c,results.update(var => v),&block)
}
end
end
def choose(options,&block)
case options
when Hash then choose_one_of_each options,{},&block
when Range then options.each { |item| yield item rescue nil }
else options.each { |item| yield item rescue nil }
end
end
И вы бы использовали его следующим образом (несколько расширенный из вашего примера, чтобы показать, как части взаимодействуют):
a = 7
b = 'frog'
choose(
:one => [a,b],
:two => ['stay','go','punt'],
:three => {:how => ['in the car','in a boat','by magic'],:how_fast => 0..2 }
) do |choices|
raise "illegal" if choices[:one] == a
raise "You can't stay fast!" if choices[:two] == 'stay' and choices[:three][:how_fast] > 0
raise "You go that slow!" if choices[:two] == 'go' and choices[:three][:how_fast] < 1
print choices.inspect,"\n"
end
Что произвело бы что-то вроде этого (из-за печати):
{:three=>{:how=>"in the car", :how_fast=>0}, :one=>"frog", :two=>"stay"}
{:three=>{:how=>"in the car", :how_fast=>0}, :one=>"frog", :two=>"punt"}
{:three=>{:how=>"in the car", :how_fast=>1}, :one=>"frog", :two=>"go"}
{:three=>{:how=>"in the car", :how_fast=>1}, :one=>"frog", :two=>"punt"}
{:three=>{:how=>"in the car", :how_fast=>2}, :one=>"frog", :two=>"go"}
{:three=>{:how=>"in the car", :how_fast=>2}, :one=>"frog", :two=>"punt"}
{:three=>{:how=>"in a boat", :how_fast=>0}, :one=>"frog", :two=>"stay"}
{:three=>{:how=>"in a boat", :how_fast=>0}, :one=>"frog", :two=>"punt"}
{:three=>{:how=>"in a boat", :how_fast=>1}, :one=>"frog", :two=>"go"}
{:three=>{:how=>"in a boat", :how_fast=>1}, :one=>"frog", :two=>"punt"}
{:three=>{:how=>"in a boat", :how_fast=>2}, :one=>"frog", :two=>"go"}
{:three=>{:how=>"in a boat", :how_fast=>2}, :one=>"frog", :two=>"punt"}
{:three=>{:how=>"by magic", :how_fast=>0}, :one=>"frog", :two=>"stay"}
{:three=>{:how=>"by magic", :how_fast=>0}, :one=>"frog", :two=>"punt"}
{:three=>{:how=>"by magic", :how_fast=>1}, :one=>"frog", :two=>"go"}
{:three=>{:how=>"by magic", :how_fast=>1}, :one=>"frog", :two=>"punt"}
{:three=>{:how=>"by magic", :how_fast=>2}, :one=>"frog", :two=>"go"}
{:three=>{:how=>"by magic", :how_fast=>2}, :one=>"frog", :two=>"punt"}