21

Rubyでメソッドを条件付きでチェーンする良い方法はありますか?

機能的にやりたいことは

if a && b && c
 my_object.some_method_because_of_a.some_method_because_of_b.some_method_because_of_c
elsif a && b && !c
 my_object.some_method_because_of_a.some_method_because_of_b
elsif a && !b && c
 my_object.some_method_because_of_a.some_method_because_of_c

etc...

したがって、いくつかの条件に応じて、メソッド チェーンでどのメソッドを呼び出すかを考えたいと思います。

これまでのところ、これを「良い方法」で行うための最善の試みは、条件付きで一連のメソッドを構築し、 を使用するevalことですが、より良い、よりルビーな方法があることは確かですか?

4

10 に答える 10

33

メソッドを配列に入れてから、この配列内のすべてを実行できます

l= []
l << :method_a if a
l << :method_b if b
l << :method_c if c

l.inject(object) { |obj, method| obj.send(method) }

Object#send指定された名前のメソッドを実行します。Enumerable#injectブロックに最後に返された値と現在の配列項目を与えながら、配列を反復処理します。

メソッドに引数を取りたい場合は、この方法でも実行できます

l= []
l << [:method_a, arg_a1, arg_a2] if a
l << [:method_b, arg_b1] if b
l << [:method_c, arg_c1, arg_c2, arg_c3] if c

l.inject(object) { |obj, method_and_args| obj.send(*method_and_args) }
于 2009-11-25T14:26:41.547 に答える
12

あなたが使用することができますtap

my_object.tap{|o|o.method_a if a}.tap{|o|o.method_b if b}.tap{|o|o.method_c if c}
于 2009-11-27T09:41:06.023 に答える
4

inject メソッドは完全に有効ですが、そのような Enumerable の使用は人々を混乱させ、任意のパラメーターを渡すことができないという制限に悩まされます。

このアプリケーションには、次のようなパターンが適している場合があります。

object = my_object

if (a)
  object = object.method_a(:arg_a)
end

if (b)
  object = object.method_b
end

if (c)
  object = object.method_c('arg_c1', 'arg_c2')
end

これは、名前付きスコープを使用するときに役立つことがわかりました。例えば:

scope = Person

if (params[:filter_by_age])
  scope = scope.in_age_group(params[:filter_by_age])
end

if (params[:country])
  scope = scope.in_country(params[:country])
end

# Usually a will_paginate-type call is made here, too
@people = scope.all
于 2009-11-25T15:31:55.287 に答える
1

私はこのパターンを使用します:

class A
  def some_method_because_of_a
     ...
     return self
  end

  def some_method_because_of_b
     ...
     return self
  end
end

a = A.new
a.some_method_because_of_a().some_method_because_of_b()
于 2009-11-25T14:31:13.723 に答える
1

あなたの状況はこれよりも複雑かもしれませんが、そうではありません:

my_object.method_a if a
my_object.method_b if b
my_object.method_c if c
于 2009-11-25T14:33:29.473 に答える
1

Rails を使用している場合は、#try. それ以外の

foo ? (foo.bar ? foo.bar.baz : nil) : nil

書きます:

foo.try(:bar).try(:baz)

または、引数付き:

foo.try(:bar, arg: 3).try(:baz)

バニラ ルビーでは定義されていませんが、多くのコードではありません。

私がCoffeeScriptの?.オペレーターに与えたくないもの。

于 2013-08-05T22:31:25.353 に答える