2010-07-19 2 views
2

У меня есть следующий метод и хотите сделать его более удобным для чтения:Рефакторинг reply_to? заехать, если-ELSIF-то еще условие

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 

ответ

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 побежал.

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 
+0

Он он, та же идея, то же самое время. Обратите внимание, что аргумент 'find' должен быть' Proc' или 'lambda'. –

+0

@ Marc-André Lafortune: Ваш ответ был немного раньше. Кроме того, я не понимал, что о аргументе «найти» ... Я бы лучше подумал о вашей версии. –

0

Грань камень обеспечивает элегантное решение (я думаю) к этой проблеме. Он объединяет два этапа проверки, отвечает ли объект методу и фактически вызывает этот метод на один шаг.

Так что ваш пример может быть переписан, как это:

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 

Обратите внимание, что этот метод работает только если это безопасно предположить, что ни один из этих методов не собираются возвращать nil или false (потому что 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 
Смежные вопросы