Refactoring respond_to? call in if-elsif-else condition
I have the following method and want to make it more readable:
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
This is my solution. What do you think?
def value_format(value)
me开发者_开发技巧thods = [:to_actor, :to_subject, :to_json, :to_hash, :inspect]
value.send(methods.find_all { |m| m if value.respond_to? m }.first)
end
Your solution looks fine, but you might as well use find
instead of 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
Using a constant has the advantage of not creating a new array every time value_format
is ran.
Seems there's a pretty simple optimization to your solution:
def value_format(value)
methods = [:to_actor, :to_subject, :to_json, :to_hash]
value.send(methods.find(:inspect) { |m| value.respond_to? m })
end
The facets gem provides an elegant solution (I think) to this problem. It combines the two steps of checking if an object responds to a method and actually calling that method into a single step.
So your example could be rewritten as this:
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
Note that this method only works if it is safe to assume that none of these methods are going to return nil
or false
(because respond
returns nil
if the object doesn't respond, that is what allows us to chain it together with a bunch of or
s).
Since all of the methods you listed should return strings, I believe this approach would work fine in your example.
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
精彩评论