web-dev-qa-db-ja.com

メソッドに渡されたブロックをRuby

Ruby keep_ifおよびdelete_if配列メソッドのクローンを作成しようとしています。これが私のコードです。

module Strain
  def keep
    self.inject([]) do |extracts, element|
      yield(element) ? extracts << element : extracts 
    end
  end

  def discard
    self.inject([]) do |extracts, element|
      !yield(element) ? extracts << element : extracts
    end
  end
end

class Array
  include Strain
end

これは機能します。しかし、私は次のようなことをしたいと思います。

def discard
  self - self.keep &block
end

望ましい行動:

[1, 2, 3].discard { |number| number < 2 }
# => [2, 3]

したがって、discardメソッドに渡されるブロックを、keepメソッドに渡す必要があります。どうすればこれを達成できますか?

22
Kappie001

ブロックを明示的に参照できます

def discard(&block)
  self - self.keep(&block)
end

または暗黙的に

def discard
  self - self.keep(&Proc.new {})
end

あなたの場合、私は最初のアプローチを提案します。

30
Simone Carletti

2番目の例では、_&Proc.new {}_はブロックを渡さず、新しい空のブロックを作成します。 _{}_を省略して、self.keep(&Proc.new)または単にkeep(&proc)と書く必要があります。_self._は冗長であり、procは_Proc.new_:

_# passes on the block or the absence of a block
def discard(&block)
  self - keep(&block)
end

# passes on the block and fails if no block given
def discard
  self - keep(&proc)
end
_

ブロックのない_Proc.new_とprocはどちらも、現在のメソッドのブロックを使用します。

discardがブロックを取得しない場合、_&proc_は失敗します。したがって、最初の例は、ブロックを渡す場合、またはブロックがない場合に最適です(_&nil_はブロックをまったく渡しません)。 2番目の例(私が変更したもの)は、欠落しているブロックがエラーである場合に最適です。

どちらの場合も、「discard」が呼び出されるたびに、新しい「Proc」オブジェクトが作成され、それは無料ではありません。

1
Richard Nunan