如何在Ruby中将条件表达式作为参数传递?
比如这就是我想做的如何在Ruby中将条件表达式作为参数传递?,ruby,Ruby,比如这就是我想做的 def method_a(condition, params={}, &block) if condition method_b(params, &block) else yield end end 我试着这样调用这个方法 method_a(#{@date > Date.today}, {:param1 => 'value1', :param2 => 'value2'}) do end 结果是,
def method_a(condition, params={}, &block)
if condition
method_b(params, &block)
else
yield
end
end
我试着这样调用这个方法
method_a(#{@date > Date.today}, {:param1 => 'value1', :param2 => 'value2'}) do
end
结果是,条件的计算结果始终为true。如何使其工作?我认为合理的方法是使用Proc或lambda:
def method_a(condition, params={}, &block)
if condition.call
method_b(params, &block)
else
yield
end
end
method_a(lambda { @date > Date.today }, { :param1 => 'value1', :param2 => 'value2' }) do
# ...
end
在对lambda调用
call
之前,不会对其进行求值。我认为明智的方法是使用Proc或lambda:
def method_a(condition, params={}, &block)
if condition.call
method_b(params, &block)
else
yield
end
end
method_a(lambda { @date > Date.today }, { :param1 => 'value1', :param2 => 'value2' }) do
# ...
end
在对lambda调用
call
之前,不会对其求值。作为条件求值的结果,您不能通过条件吗
method_a(@date > Date.today, {:param1 => 'value1', :param2 => 'value2'}) do
puts "Do stuff"
end
作为条件求值的结果,您不能传递条件吗
method_a(@date > Date.today, {:param1 => 'value1', :param2 => 'value2'}) do
puts "Do stuff"
end
实际上,如果你在中间没有这个评论,那就只是工作:
method_a(@date > Date.today, {:param1 => 'value1', :param2 => 'value2'}) do; end
顺便说一句:如果方法的最后一个参数是散列,那么可以省去大括号,这使其读起来几乎像Python风格的关键字参数:
method_a(@date > Date.today, :param1 => 'value1', :param2 => 'value2') do; end
method_a(@date > Date.today, param1: 'value1', param2: 'value2') do; end
如果您使用Ruby 1.9,并且有一个散列,其中键是符号,则可以使用新的可选散列语法:
method_a(@date > Date.today, {param1: 'value1', param2: 'value2'}) do; end
将这两个参数结合起来看起来很像关键字参数:
method_a(@date > Date.today, :param1 => 'value1', :param2 => 'value2') do; end
method_a(@date > Date.today, param1: 'value1', param2: 'value2') do; end
在方法a
中,如果表达式:
def method_a(condition, params={}, &block)
return method_b(params, &block) if condition
yield
end
或者反过来,无论你认为哪个读起来更好:
def method_a(condition, params={}, &block)
return yield unless condition
method_b(params, &block)
end
然而,这是一个巨大的代码气味。一个方法应该总是做一件事,而且只能做一件事。每个采用布尔参数的方法都违反了这一规则,因为根据定义,它几乎可以做两件事:如果条件为真,则做一件事;如果条件为假,则做另一件事
在您的原始代码中,这是显而易见的,因为整个方法周围有一个巨大的if
表达式,两个分支中的代码完全不同。更明显的是,因为else
分支不仅具有与then
分支完全不同的代码,它还完全忽略传递到方法中的参数!因此,该方法不仅根据条件的不同而表现不同,甚至具有不同的签名
您真正想要做的是将该方法拆分为两个方法。method_a
的用户无论如何都需要知道这两种情况之间的不同行为,并且他必须自己提供条件。相反,他可以首先调用正确的方法。因此,我将方法a
分为两部分:
def method_one(params={}, &block)
method_b(params, &block)
end
def method_two
yield
end
客户可以决定呼叫哪一个:
if @date > Date.today then
method_two(param1: 'value1', param2: 'value2')
else
method_one do
# something
end
end
但是,如果仔细观察method\u one
,您会发现它所做的只是将其参数未经修改地转发到method\u b
。因此,我们可以完全摆脱method\u one
,让客户端直接调用method\u b
方法二也是如此:它所做的就是调用块。客户机也可以首先运行代码
现在我们的库代码如下所示:
# there is no spoon
if @date > Date.today then
method_b(param1: 'value1', param2: 'value2')
else
# something
end
没错!没有库代码了!(除了不属于您问题的方法b
)
客户端代码如下所示:
# there is no spoon
if @date > Date.today then
method_b(param1: 'value1', param2: 'value2')
else
# something
end
Ruby核心库中的Module#instance_methods
就是违反此规则的方法的一个很好的例子。它告诉您在特定模块和类中定义的所有实例方法,并使用一个布尔参数来决定此列表是否包含从超类继承的方法。没有人能记住是通过false
还是通过true
。没有。Jim Weirich在谈到好的设计时使用了这个例子,他通常会问观众哪些是继承的,哪些是直接的。通常,很高比例的人会弄错。有时候,这个百分比比掷硬币还糟糕
如果你看,这是完全混乱。我永远都记不起条件的方向,我总是要在文档中查找它。这并不是很有帮助,因为官方文档是YARV和MRI的实际源代码的一部分,它也有错误的方向事实上,如果你在中间没有这个评论,那就只是工作:
method_a(@date > Date.today, {:param1 => 'value1', :param2 => 'value2'}) do; end
顺便说一句:如果方法的最后一个参数是散列,那么可以省去大括号,这使其读起来几乎像Python风格的关键字参数:
method_a(@date > Date.today, :param1 => 'value1', :param2 => 'value2') do; end
method_a(@date > Date.today, param1: 'value1', param2: 'value2') do; end
如果您使用Ruby 1.9,并且有一个散列,其中键是符号,则可以使用新的可选散列语法:
method_a(@date > Date.today, {param1: 'value1', param2: 'value2'}) do; end
将这两个参数结合起来看起来很像关键字参数:
method_a(@date > Date.today, :param1 => 'value1', :param2 => 'value2') do; end
method_a(@date > Date.today, param1: 'value1', param2: 'value2') do; end
在方法a
中,如果表达式:
def method_a(condition, params={}, &block)
return method_b(params, &block) if condition
yield
end
或者反过来,无论你认为哪个读起来更好:
def method_a(condition, params={}, &block)
return yield unless condition
method_b(params, &block)
end
然而,这是一个巨大的代码气味。一个方法应该总是做一件事,而且只能做一件事。每个采用布尔参数的方法都违反了这一规则,因为根据定义,它几乎可以做两件事:如果条件为真,则做一件事;如果条件为假,则做另一件事
在您的原始代码中,这是显而易见的,因为整个方法周围有一个巨大的if
表达式,两个分支中的代码完全不同。更明显的是,因为else
分支不仅具有与then
分支完全不同的代码,它还完全忽略传递到方法中的参数!因此,该方法不仅根据条件的不同而表现不同,甚至具有不同的签名
您真正想要做的是将该方法拆分为两个方法。方法a的用户无论如何都需要知道这两种情况之间的不同行为,并且