23

#inheritedclass Fooステートメントの直後に呼び出されます。endクラス宣言を閉じるステートメントの後にのみ実行されるものが必要です。

必要なものを例示するコードを次に示します。

class Class
  def inherited m
    puts "In #inherited for #{m}"
  end
end

class Foo
  puts "In Foo"
end
puts "I really wanted to have #inherited tiggered here."


### Output:
# In #inherited for Foo
# In Foo
# I really wanted to have #inherited tiggered here.

そのようなものは存在しますか?作成できますか?私は完全に運が悪いのでしょうか?

4

9 に答える 9

11

遅くなりましたが、(ここを訪れた方へ)答えがあると思います。

クラス定義の最後が見つかるまでトレースできます。私が呼び出したメソッドでそれを行いましたafter_inherited

class Class
  def after_inherited child = nil, &blk
    line_class = nil
    set_trace_func(lambda do |event, file, line, id, binding, classname|
      unless line_class
        # save the line of the inherited class entry
        line_class = line if event == 'class'
      else
        # check the end of inherited class
        if line == line_class && event == 'end'
          # if so, turn off the trace and call the block
          set_trace_func nil
          blk.call child
        end
      end
    end)
  end
end

# testing...

class A
  def self.inherited(child)
    after_inherited do
      puts "XXX"
    end
  end
end

class B < A
  puts "YYY"
  # .... code here can include class << self, etc.
end

出力:

YYY
XXX
于 2011-08-18T04:43:48.977 に答える
9

あなたは運が悪いかもしれません。しかし、これは単なる警告であり、決定的な答えではありません。

Ruby は、クラス定義の末尾ではなく先頭をフックします。これは、 Class#inheritedb/c ruby​​ クラス定義には実際の末尾がないためです。いつでも再開できます。

const_added トリガーを追加することについて数年前にいくつかの話がありましたが、まだ実現していません。 マッツ より:

考えられるすべてのフックを実装するつもりはありません。ですから、誰かがより具体的な使い方を教えてくれたら、私はこれをもう一度検討します。ではありconst_addedませんclass_added

したがって、これはあなたのケースを処理するかもしれません-しかし、私にはわかりません(最終的に実装されると、開始時にもトリガーされる可能性があります)。

このトリガーで何をしようとしていますか? それを行う別の方法があるかもしれません。

于 2009-04-26T13:59:38.623 に答える
5

defined宝石を見てください。次のようにできます。

require "defined"
Defined.enable!

class A
  def self.after_inherited(child)
    puts "A was inherited by #{child}"
  end

  def self.defined(*args)
    superclass.after_inherited(self) if superclass.respond_to?(:after_inherited)
  end
end

class B < A
  puts "B was defined"
end

出力:

B was defined
A was inherited by B

ただしself.defined、各クラス定義の後に発生します。したがって、次のコードを追加すると

class B < A
  puts "B was redefined"
end

あなたが見るでしょう

B was defined
A was inherited by B
B was redefined
A was inherited by B

必要に応じて説明できることを回避する方法があります。

ただし、前述のように、問題を解決するためのより良い方法がおそらくあります。

于 2011-08-17T16:28:02.200 に答える
1

Rails にはsubclassesメソッドがあります。実装を検討する価値があるかもしれません。

class Fruit; end

class Lemon < Fruit; end

Fruit.subclasses # => [Lemon]
于 2012-06-01T13:47:28.860 に答える
1

Ruby が ObjectSpaces を実装していると仮定する場合は、事後にすべてのモデル インスタンスを検索し、それらを適切に変更することができます。Google はhttp://phrogz.net/ProgrammingRuby/ospace.htmlを推奨しています

于 2009-04-26T15:05:59.900 に答える
0

すべてのモデルに一般的な検証を自動的に追加しようとしたときに、同じ質問がありました。問題は、モデルが #set_table_name を使用した場合、DB データ型に基づいて検証を追加したコードが失敗することでした。これは、モデルの名前に基づいてテーブル名を推測していたためです (#inherited が呼び出されていたため)。 BEFORE #set_table_name)。

あなたと同じように、モデル内のすべてが既にロードされた後に #inherited を起動する方法を本当に探していました。しかし、そこまでする必要はありませんでした。必要なのは #set_table_name の後に起動するものだけでした。したがって、メソッドをエイリアシングするだけの簡単なものであることがわかりました。ここで私が行ったことの例を見ることができます: https://gist.github.com/1019294

上記のコメントで、「アクティブレコード モデルに動作を追加しようとしていますが、モデルを台無しにする前に、すべてのモデルのカスタマイズを行う必要があります」と述べました。だから私の質問は、あなたが気にかけている特定のモデルのカスタマイズがあるかどうかということです。

于 2011-06-10T17:38:46.463 に答える