Is there a hook similar to Class#inherited that

2020-01-31 23:35发布

#inherited is called right after the class Foo statement. I want something that'll run only after the end statement that closes the class declaration.

Here's some code to exemplify what I need:

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.

Does anything like that exist? Can it be created? Am I totally out of luck?

8条回答
Deceive 欺骗
2楼-- · 2020-02-01 00:20

I am late, but I think I have an answer (to anyone who visit here).

You can trace until you find the end of the class definition. I did it in a method which I called 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

Output:

YYY
XXX
查看更多
甜甜的少女心
3楼-- · 2020-02-01 00:24

Use TracePoint to track when your class sends up an :end event.

This module will let you create a self.finalize callback in any class.

module Finalize
  def self.extended(obj)
    TracePoint.trace(:end) do |t|
      if obj == t.self
        obj.finalize
        t.disable
      end
    end
  end
end

Now you can extend your class and define self.finalize, which will run as soon as the class definition ends:

class Foo
  puts "Top of class"

  extend Finalize

  def self.finalize
    puts "Finalizing #{self}"
  end

  puts "Bottom of class"
end

puts "Outside class"

# output:
#   Top of class
#   Bottom of class
#   Finalizing Foo
#   Outside class
查看更多
登录 后发表回答