Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Ruby中将条件表达式作为参数传递?_Ruby - Fatal编程技术网

如何在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的用户无论如何都需要知道这两种情况之间的不同行为,并且