重构respond_to?在if-elsif-else条件下调用

时间:2010-07-19 20:21:16

标签: ruby

我有以下方法,并希望使其更具可读性:

def value_format(value)
  if value.respond_to? :to_actor
    value.to_actor
  elsif value.respond_to? :to_subject
    value.to_subject
  elsif value.respond_to? :to_json
    value.to_json
  elsif value.respond_to? :to_hash
    value.to_hash
  else
    value.inspect
  end
end

这是我的解决方案。你觉得怎么样?

def value_format(value)
  methods = [:to_actor, :to_subject, :to_json, :to_hash, :inspect]
  value.send(methods.find_all { |m| m if value.respond_to? m }.first)
end

3 个答案:

答案 0 :(得分:4)

您的解决方案看起来不错,但您也可以使用find代替find_all

METHODS = [:to_actor, :to_subject, :to_json, :to_hash, :inspect]
def value_format(value)
  value.send(METHODS.find { |m| value.respond_to? m })
end

使用常量的优点是每次运行value_format时都不会创建新数组。

答案 1 :(得分:0)

似乎对您的解决方案进行了非常简单的优化:

def value_format(value)
  methods = [:to_actor, :to_subject, :to_json, :to_hash]
  value.send(methods.find(:inspect) { |m| value.respond_to? m })
end

答案 2 :(得分:0)

facet gem为这个问题提供了一个优雅的解决方案(我认为)。它结合了检查对象是否响应方法并实际调用该方法的两个步骤。

所以你的例子可以改写为:

require 'facets/kernel/respond'

def value_format(v)
  v.respond.to_actor || v.respond.to_subject || v.respond.to_json || v.respond.to_hash || v.respond.inspect
end

请注意,此方法仅适用于可以安全地假设这些方法都不会返回nilfalse(因为respond会返回nil对象没有响应,这就是允许我们将它与一堆or s链接在一起的原因。

由于您列出的所有方法都应该返回字符串,我相信这种方法在您的示例中可以正常工作。

Documentation

  # Like #respond_to? but returns the result of the call
  # if it does indeed respond.
  #
  #   class RespondExample
  #     def f; "f"; end
  #   end
  #
  #   x = RespondExample.new
  #   x.respond(:f)  #=> "f"
  #   x.respond(:g)  #=> nil
  #
  # or
  #
  #   x.respond.f   #=> "f"
  #   x.respond.g   #=> nil