1## 2# A Module include in a class with \#include 3 4class RDoc::Include < RDoc::CodeObject 5 6 ## 7 # Name of included module 8 9 attr_accessor :name 10 11 ## 12 # Creates a new Include for +name+ with +comment+ 13 14 def initialize(name, comment) 15 super() 16 @name = name 17 self.comment = comment 18 @module = nil # cache for module if found 19 end 20 21 ## 22 # Includes are sorted by name 23 24 def <=> other 25 return unless self.class === other 26 27 name <=> other.name 28 end 29 30 def == other # :nodoc: 31 self.class === other and @name == other.name 32 end 33 34 alias eql? == 35 36 ## 37 # Full name based on #module 38 39 def full_name 40 m = self.module 41 RDoc::ClassModule === m ? m.full_name : @name 42 end 43 44 def hash # :nodoc: 45 [@name, self.module].hash 46 end 47 48 def inspect # :nodoc: 49 "#<%s:0x%x %s.include %s>" % [ 50 self.class, 51 object_id, 52 parent_name, @name, 53 ] 54 end 55 56 ## 57 # Attempts to locate the included module object. Returns the name if not 58 # known. 59 # 60 # The scoping rules of Ruby to resolve the name of an included module are: 61 # - first look into the children of the current context; 62 # - if not found, look into the children of included modules, 63 # in reverse inclusion order; 64 # - if still not found, go up the hierarchy of names. 65 # 66 # This method has <code>O(n!)</code> behavior when the module calling 67 # include is referencing nonexistent modules. Avoid calling #module until 68 # after all the files are parsed. This behavior is due to ruby's constant 69 # lookup behavior. 70 # 71 # As of the beginning of October, 2011, no gem includes nonexistent modules. 72 73 def module 74 return @module if @module 75 76 # search the current context 77 return @name unless parent 78 full_name = parent.child_name(@name) 79 @module = @store.modules_hash[full_name] 80 return @module if @module 81 return @name if @name =~ /^::/ 82 83 # search the includes before this one, in reverse order 84 searched = parent.includes.take_while { |i| i != self }.reverse 85 searched.each do |i| 86 inc = i.module 87 next if String === inc 88 full_name = inc.child_name(@name) 89 @module = @store.modules_hash[full_name] 90 return @module if @module 91 end 92 93 # go up the hierarchy of names 94 up = parent.parent 95 while up 96 full_name = up.child_name(@name) 97 @module = @store.modules_hash[full_name] 98 return @module if @module 99 up = up.parent 100 end 101 102 @name 103 end 104 105 ## 106 # Sets the store for this class or module and its contained code objects. 107 108 def store= store 109 super 110 111 @file = @store.add_file @file.full_name if @file 112 end 113 114 def to_s # :nodoc: 115 "include #@name in: #{parent}" 116 end 117 118end 119 120