5

Ruby (および特に Rails) では、何かが存在するかどうかを確認し、それに対してアクションを実行する必要があることがよくあります。たとえば、次のようになります。

if @objects.any?
  puts "We have these objects:"
  @objects.each { |o| puts "hello: #{o}"
end

これは可能な限り短く、すべて問題ありませんが、@objects.some_association.something.hit_database.process代わりに? がある場合はどうなります@objectsか? 式の中でもう一度繰り返す必要がifあり、実装の詳細がわからず、メソッド呼び出しが高価な場合はどうすればよいでしょうか?

明らかな選択は、変数を作成し、それをテストしてから処理することですが、変数名を考え出す必要があり (うーん)、スコープの最後までメモリに残ります。

なぜこのようなものではありません:

@objects.some_association.something.hit_database.process.with :any? do |objects|
    puts "We have these objects:"
    objects.each { ... }
end

これをどのように行いますか?

4

4 に答える 4

3

空の配列への送信はノーオペレーションであるため、送信any?するだけの場合は、配列に少なくとも1つの要素があることを確認する理由がないことに注意してください。eacheach

あなたの質問に答えるために、おそらくあなたはhttps://github.com/raganwald/andandを探していますか?

于 2012-12-11T21:27:15.727 に答える
3

if (var = value).predicate確かに、変数を使用すると名前空間が汚染されますが、それでも、これはかなり一般的なイディオムであり、通常は完全に問題ないと思います。

if (objects = @objects.some_association.hit_database).present?
  puts "We have these objects: #{objects}"
end

オプション2:宣言型の方法で独自の抽象化を作成したい場合は、ブロックを使用してそれを行うこともできます。

@objects.some_association.hit_database.as(:if => :present?) do |objects|
  puts "We have these objects: #{objects}"
end

書くObject#as(options = {})ことはかなり簡単です。

于 2012-12-11T22:25:16.523 に答える
2

編集:Ruby 1.9を使用している場合、このObject#tapメソッドは以下にリストされているコードと同じ機能を提供します。

スコープを汚染せずにオブジェクトへの参照を保存できるようにしたいだけのようですね。クラスを開いてObjectメソッドを追加するdoと、ブロックにそれ自体が生成されます。

class Object
  def do
    yield self if block_given?
    return self # allow chaining
  end
end

次に、たとえば次のように呼び出すことができます。

[1,2,3].do { |a| puts a.length if a.any? }
=> 3
[].do { |a| puts a.length if a.any? }
=> nil
于 2012-12-11T21:30:28.313 に答える
2

タップはどうですか?

@objects.some_association.something.hit_database.process.tap do |objects|
  if objects.any?
    puts "We have these objects:"
    objects.each { ... }
  end
end
于 2012-12-11T21:38:27.053 に答える