0

私はこの厄介な繰り返しのテーマを持っています。たとえば、インスタンスメソッドと保護されたクラスメソッドを定義するクラスがあります。インスタンスメソッドはクラスメソッドを呼び出す必要があります。そのためには、可視性のルールを破り、危険な「送信」機能を使用する必要があります。このようなもの:

class Bang
    def instance_bang
      self.class.send(:class_band)
    end

    protected
    def self.class_bang
      puts "bang"
    end
end

クラスメソッドはクラススコープ内で使用する必要があるため、これはひどいことに気づきます。したがって、クラスメソッド内で表示および呼び出し可能のままにする必要があります。「send」関数に依存する必要があり、したがって可視性を壊さないインスタンスメソッドでクラスメソッドを使用する別の方法はありますか?

アップデート:

Sergio Tulentsevの応答(修正のためのthx)に続いて、メソッドの可視性が定義されている範囲内で考慮されているという懸念をまとめたコードスニペットで懸念を更新します。

class Bang
  def instance_bang
    private_bang = 1
    self.private_bang(private_bang)
  end
  private
  def private_bang(p)
    puts "bang"
    p
  end
end

Bang.new.instance_bangを呼び出すと、そのprivate_bang呼び出しでsendを使用しない限り、例外が発生します(今回はチェックしました:))。

4

3 に答える 3

4

編集:更新された質問への回答

明示的な受信側でプライベート メソッドを呼び出すことは禁止されています。暗黙の受信者 ( private_bang、なしself)を使用するか、 を使用する必要がありますsend詳細については、別の回答を参照してください。

ところで、元の質問は、インスタンス メソッドからクラス インスタンス メソッドを呼び出すことについてです。あなたの説明にはそれが含まれていません。しかし、それでもそうである場合はself.class.send、メソッドを使用するか公開する必要があります (明示的な受信者を使用できるようにするため)。

于 2012-06-21T17:48:49.737 に答える
2

プライベート クラス メソッドを考えてみましょう (保護されたクラス メソッドは意味がないため)。

明示的なレシーバー ( ) を使用していない限り、インスタンスがそれ自体でプライベート メソッドを呼び出すことができることはわかっていますself.call_something_privateインスタンスが独自のクラスでプライベート クラス メソッドを呼び出すことも期待しているようですが、そうではありません。

を使用せずにこれを行う方法を見てみましょうsend

privateおよびマクロはprotected、クラス メソッドではなく、現在のスコープのインスタンス メソッドにのみ影響します。元のコードを書き換える 3 つの方法を次に示します。

class Bang
  def instance_bang
    self.class.class_bang
  end

  # declare method visibility after
  def self.class_bang
    puts "bang"
  end
  private_class_method :class_bang

  # inline
  private_class_method def self.class_bang
    puts "bang"
  end

  # class scope
  class << self
    # the private macro works here because we're inside the class scope
    private

    def class_bang
      puts "bang"
    end
  end
end

そのため、 を呼び出すクラスのインターフェースを公開したいと考えていますが、class_bangそれは のインスタンスによって呼び出された場合に限られますBang

class Bang
  def instance_bang
    self.class.invoke_class_bang(self)
  end

  class << self
    private

    def class_bang
      puts "bang"
    end

    public

    # we ask the receiver to pass itself as an argument ...
    def invoke_class_bang(receiver)
      # ... so that we can check whether it's
      class_bang if receiver.is_a?(Bang)
    end
  end
end

ただし、これは見栄えの良いソリューションではありません。これはより卑劣な方法です:

class Bang
  def initialize
    def self.instance_bang() self.class.method(:class_bang).call end
  end

  class << self
    private
    def class_bang
      puts "bang"
    end
  end
end
于 2016-04-07T18:57:52.463 に答える
0

「クラスメソッドはクラススコープ内で使用する必要があるため、クラス内で表示および呼び出し可能である必要がありますよね?」はい、それは正しいです、そしてそれはRubyが示す振る舞いです。(明確にするために、インスタンススコープはクラススコープの「範囲内」ではありません。適切に分離されています。)

send解決策は、クラスをサブクラス化するか再度開いて、保護されたクラスメソッドにアクセスするためのパブリッククラスメソッドを追加することです。

于 2012-06-21T15:40:55.030 に答える