pockestrap

Programmer's memo

refineをしてるモジュールをFiddleを使わずに取り出してみた

元ネタ:

qiita.com

require 'objspace'

class C
  using Module.new {
    refine(C) {
      def hi
        puts "hi"
      end
    }
  }
end

def reachable?(from:, to:)
  ObjectSpace.reachable_objects_from(from).include?(to)
end


def rob(klass)
  modules = ObjectSpace.each_object(Module).to_a
  reachable_modules_to_klass = modules.select do |mod|
    next false unless mod.instance_of?(Module)
    reachable?(from: mod, to: klass)
  end

  res = []
  modules.each do |mod|
    next unless mod.instance_of?(Module)

    reachable_modules_to_klass.each do |r|
      ObjectSpace.reachable_objects_from(mod).each do |x|
        next unless x.is_a?(ObjectSpace::InternalObjectWrapper)
        next unless x.type == :T_HASH
        next unless reachable?(from: x, to: r)
        res << mod 
      end
    end
  end
  res
end

p rob(C) # => [#<Module:0x00005651666789b0>]

class D < C
  using(*rob(C))

  def hi2
    hi
  end
end

D.new.hi2 # => hi

ちゃんと検証してないから要らないModuleも引っ張ってきてしまいそうだけど、とりあえずrefineしているモジュールを取り出すことには成功している。