是否可以在Ruby中创建一个方法,该方法接受一个块并运行块中的每个语句,直到其中一个返回false?
done = prepare_it do |x|
method_1
method_2
method_3
end
puts "Something did not work" unless done
我希望函数prepare_it运行每个语句,但如果其中一个语句失败,则该函数退出。如果函数返回true,则表示所有步骤都成功。
这似乎要求一个Exception,但我不确定如何触发和处理它。我希望我没有必要修改method_x函数以在失败时抛出异常,而是让prepare_it抛出异常,如果其中一个method_x失败(返回false)
修改 感谢您的建议,我想我需要在我的问题中添加更多细节。这是我第一次尝试元编程和创建DSL。 :)
我有一个类向路由器发送命令。总是需要按顺序执行许多步骤(连接,登录,传递等)。我认为如果用户愿意,可以让用户更改命令的顺序。例如,某些路由器不会要求用户直接进入密码提示。其他人完全跳过登录。在某些情况下,您需要提升权限或设置终端选项。
但是,如果任何命令失败,应该有一种机制使整个块失败。因此,如果由于某种原因密码失败(该方法返回false / nil),继续使用其余命令是没有意义的。 而且我应该告诉它失败了。
&&方法有效,但我认为它不是一个很好的界面。
也许我应该强迫用户给我一个较小的块,一次一个,这些块放在一个堆栈中,然后运行命令逐个产生?
my_router.setup do {send_pass}
my_router.setup do {set_terminal}
my_router.setup do {enable_mode}
my_router.run_setup
我认为如果我能做到的话会更加清洁
my_router.setup do |cmd|
cmd.send_pass
cmd.set_terminal
end
puts "Done" if my_router.ready?
所以在幕后发生的任何神奇诡计都是受欢迎的! :)
答案 0 :(得分:9)
done = prepare_it do |x|
method_1 && method_2 && method_3
end
puts "Something did not work" unless done
&&
运算符“短路”因此,如果method_1
返回false
,则不会调用2和3,done
将是false
。
答案 1 :(得分:1)
没有一种好方法可以像这样破解工作。我会做类似以下的事情之一:
done = prepare_it do |x|
method_1 && method_2 && method_3
end
现在,在某些特定情况下,你可以通过魔术来实现这项工作。例如,如果应该在块参数x
上调用这些方法:你可以这样做:
class SuccessProxy
def initialize(obj)
@object = obj
end
def method_missing(meth, *args, &block)
@object.send(meth, *args, &block) || raise SuccessProxy::Exception
end
class Exception < ::Exception
end
end
def prepare_it
# however you usually generate x
yield SuccessProxy.new(x)
rescue SuccessProxy::Exception
false
end
prepare_it do |x|
x.method_1
x.method_2
x.method_3
end
或者,如果要在上下文中的默认对象上调用方法method_1
,则可以使用instance_eval
而不是yield
将代理放在范围内。< / p>
最后,如果你真的想要花哨,你实际上可以使用Ruby解析器解析单独的语句。
但老实说,我不相信你真的想要将元编程作为一种工具。也许如果你提供更好的细节,我可以更好地了解最佳解决方案是什么,但它可能与上面的第一个代码示例类似。
答案 2 :(得分:1)
自然紧凑将是您的首要任务,所以我相信这是最好的答案:
done = (1..3).all? { |n| send "method_#{n}" }
puts "Something did not work" unless done
答案 3 :(得分:0)
如果您使用例外,它不是很漂亮,但您不必依赖返回值:
done = prepare_it do |x|
begin
method_1
method_2
method_3
true
rescue
false
end
end
puts "Something did not work" unless done
def method_1
# No issues, doesn't matter what we return
return true
end
def method_2
# Uh-oh, problem
raise
end
答案 4 :(得分:0)
起初我想,“如果这是Lisp会不会很好......”但这让我意识到了确切的问题。做你想做的事(执行一个块中的每一步,直到一个是假的)会很好,但需要访问AST。
你的想法
my_router.setup do {send_pass}
my_router.setup do {set_terminal}
my_router.setup do {enable_mode}
my_router.run_setup
正试图完成你在Lisp中所做的事情 - 构建一个列表并将列表移交给其他东西来执行每一件事,直到你得到一个错误的返回值。
如果你只是在没有任何参数的情况下调用类中的方法,那么如何定义带符号的东西呢?
class Router
def run_setup *cmds
# needs error handling
while c = cmds.shift
return false unless send(c)
end
end
end
my_router.run_setup :send_pass, :set_terminal, :enable_mode