method_source gemを使用できます。
require 'method_source'
def flatten_source_code(klass)
excluded_parents = [Kernel, Object, BasicObject]
type = klass.instance_of?(Module) ? "module" : "class"
puts "#{type} #{klass}"
(klass.ancestors-excluded_parents).reverse.each do |ancestor|
ancestor.instance_methods(false).each do |method_name|
method = ancestor.instance_method(method_name)
script, line = method.source_location
if script then
puts
puts " # #{script} (line #{line})"
puts method.source
else
puts
puts " # def #{method_name}"
puts " # end"
end
end
end
puts "end"
end
module Nameable
def name
"John"
end
end
class User
include Nameable
def email
"[email protected]"
end
end
flatten_source_code(User)
puts
flatten_source_code(Nameable)
#=>
# class User
#
# # flatten_source_code.rb (line 27)
# def name
# "John"
# end
#
# # flatten_source_code.rb (line 34)
# def email
# "[email protected]"
# end
# end
# module Nameable
#
# # flatten_source_code.rb (line 27)
# def name
# "John"
# end
# end
複雑なケースでは完全には機能しませんが、あなたの例では機能します。楽しみのためだけに
、:
John
prepended [email protected]
ので、表示されたRubyのコードが有効であると継承の順序を尊重:
module Nameable
def name
"John"
end
def email
"included [email protected]"
end
end
module AnotherModule
def email
"prepended [email protected]"
end
end
class User
include Nameable
prepend AnotherModule
def email
"[email protected]"
end
end
flatten_source_code(User)
puts "u = User.new"
puts "puts u.name"
puts "puts u.email"
ruby flatten_source_code.rb | ruby
リターンを起動します。しかし、同じメソッドを複数回定義します。
ハッシュを|method_name,method_source|
にすることができます。メソッドが古いものを上書きしてsuper
を呼び出す場合は、古いメソッドをプライベートold_method_name_from_Module_blabla
として定義し、それに応じてsuper
を置き換えます。
これを平坦化することはできません。 'User'は' name'をオーバーライドし、もう存在しない 'super'を呼び出すことができます。 – Stefan
最も簡単な方法 'user.instance_methods'は、メソッド名のリストを表示します。 –
@Stefan。それは問題をより困難にしますが、不可能ではありません。 'super'をエイリアスに置き換え、古い' name'をエイリアスのプライベートメソッドとして保持することができます。 –