2016-11-30 1 views
1

Скажет, у меня есть следующий Ruby:Можно ли отобразить «исходный код» для класса Ruby, который включает в себя любые включенные модели?

module Nameable 
    def name 
    "John" 
    end 
end 

class User 
    include Nameable 
    def email 
    "[email protected]" 
    end 
end 

Есть ли способ отображения, печати или просмотреть «расширенный исходный код» всего «Пользователь»? Я не уверен, что этот термин будет, но с «расширенным исходным кодом» Я имею в виду код, в Ruby (так не AST), который имеет комлекты включены:

class User 
    def name 
    "John" 
    end 

    def email 
    "[email protected]" 
    end 
end 

когда бонус-очки решения также может отображать код для унаследованного поведения.

+1

Вы не можете сгладить его. «Пользователь» может переопределить «имя» и назвать «супер», которого больше не будет. – Stefan

+0

Простейший способ 'user.instance_methods', покажет вам список имен методов. –

+1

@Stefan. Это затрудняет задачу, но не невозможно. Вы можете заменить 'super' псевдонимом и сохранить старое' name' как частный метод под псевдонимом. –

ответ

2

Вы можете использовать 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 

Это не сработает отлично для более сложных случаев, но это делает работу для вашего примера.

Просто для удовольствия, с:

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 возвращается:

John 
prepended [email protected] 

Так отображаемая рубин код действителен и уважает порядок наследования. Он будет определять один и тот же метод несколько раз.

Вы можете оставить хэш |method_name,method_source|. Если метод переопределяет старый и вызывает super, вы можете определить старый метод как частный old_method_name_from_Module_blabla и заменить super соответственно.

Смежные вопросы