1## 2# A TopLevel context is a representation of the contents of a single file 3 4class RDoc::TopLevel < RDoc::Context 5 6 MARSHAL_VERSION = 0 # :nodoc: 7 8 ## 9 # This TopLevel's File::Stat struct 10 11 attr_accessor :file_stat 12 13 ## 14 # Relative name of this file 15 16 attr_accessor :relative_name 17 18 ## 19 # Absolute name of this file 20 21 attr_accessor :absolute_name 22 23 ## 24 # All the classes or modules that were declared in 25 # this file. These are assigned to either +#classes_hash+ 26 # or +#modules_hash+ once we know what they really are. 27 28 attr_reader :classes_or_modules 29 30 attr_accessor :diagram # :nodoc: 31 32 ## 33 # The parser that processed this file 34 35 attr_accessor :parser 36 37 ## 38 # Creates a new TopLevel for the file at +absolute_name+. If documentation 39 # is being generated outside the source dir +relative_name+ is relative to 40 # the source directory. 41 42 def initialize absolute_name, relative_name = absolute_name 43 super() 44 @name = nil 45 @absolute_name = absolute_name 46 @relative_name = relative_name 47 @file_stat = File.stat(absolute_name) rescue nil # HACK for testing 48 @diagram = nil 49 @parser = nil 50 51 @classes_or_modules = [] 52 end 53 54 ## 55 # An RDoc::TopLevel is equal to another with the same relative_name 56 57 def == other 58 self.class === other and @relative_name == other.relative_name 59 end 60 61 alias eql? == 62 63 ## 64 # Adds +an_alias+ to +Object+ instead of +self+. 65 66 def add_alias(an_alias) 67 object_class.record_location self 68 return an_alias unless @document_self 69 object_class.add_alias an_alias 70 end 71 72 ## 73 # Adds +constant+ to +Object+ instead of +self+. 74 75 def add_constant constant 76 object_class.record_location self 77 return constant unless @document_self 78 object_class.add_constant constant 79 end 80 81 ## 82 # Adds +include+ to +Object+ instead of +self+. 83 84 def add_include(include) 85 object_class.record_location self 86 return include unless @document_self 87 object_class.add_include include 88 end 89 90 ## 91 # Adds +method+ to +Object+ instead of +self+. 92 93 def add_method(method) 94 object_class.record_location self 95 return method unless @document_self 96 object_class.add_method method 97 end 98 99 ## 100 # Adds class or module +mod+. Used in the building phase 101 # by the ruby parser. 102 103 def add_to_classes_or_modules mod 104 @classes_or_modules << mod 105 end 106 107 ## 108 # Base name of this file 109 110 def base_name 111 File.basename @relative_name 112 end 113 114 alias name base_name 115 116 ## 117 # Only a TopLevel that contains text file) will be displayed. See also 118 # RDoc::CodeObject#display? 119 120 def display? 121 text? and super 122 end 123 124 ## 125 # See RDoc::TopLevel::find_class_or_module 126 #-- 127 # TODO Why do we search through all classes/modules found, not just the 128 # ones of this instance? 129 130 def find_class_or_module name 131 @store.find_class_or_module name 132 end 133 134 ## 135 # Finds a class or module named +symbol+ 136 137 def find_local_symbol(symbol) 138 find_class_or_module(symbol) || super 139 end 140 141 ## 142 # Finds a module or class with +name+ 143 144 def find_module_named(name) 145 find_class_or_module(name) 146 end 147 148 ## 149 # Returns the relative name of this file 150 151 def full_name 152 @relative_name 153 end 154 155 ## 156 # An RDoc::TopLevel has the same hash as another with the same 157 # relative_name 158 159 def hash 160 @relative_name.hash 161 end 162 163 ## 164 # URL for this with a +prefix+ 165 166 def http_url(prefix) 167 path = [prefix, @relative_name.tr('.', '_')] 168 169 File.join(*path.compact) + '.html' 170 end 171 172 def inspect # :nodoc: 173 "#<%s:0x%x %p modules: %p classes: %p>" % [ 174 self.class, object_id, 175 base_name, 176 @modules.map { |n,m| m }, 177 @classes.map { |n,c| c } 178 ] 179 end 180 181 ## 182 # Time this file was last modified, if known 183 184 def last_modified 185 @file_stat ? file_stat.mtime : nil 186 end 187 188 ## 189 # Dumps this TopLevel for use by ri. See also #marshal_load 190 191 def marshal_dump 192 [ 193 MARSHAL_VERSION, 194 @relative_name, 195 @parser, 196 parse(@comment), 197 ] 198 end 199 200 ## 201 # Loads this TopLevel from +array+. 202 203 def marshal_load array # :nodoc: 204 initialize array[1] 205 206 @parser = array[2] 207 @comment = array[3] 208 209 @file_stat = nil 210 end 211 212 ## 213 # Returns the NormalClass "Object", creating it if not found. 214 # 215 # Records +self+ as a location in "Object". 216 217 def object_class 218 @object_class ||= begin 219 oc = @store.find_class_named('Object') || add_class(RDoc::NormalClass, 'Object') 220 oc.record_location self 221 oc 222 end 223 end 224 225 ## 226 # Base name of this file without the extension 227 228 def page_name 229 basename = File.basename @relative_name 230 basename =~ /\.(rb|rdoc|txt|md)$/i 231 232 $` || basename 233 end 234 235 ## 236 # Path to this file for use with HTML generator output. 237 238 def path 239 http_url @store.rdoc.generator.file_dir 240 end 241 242 def pretty_print q # :nodoc: 243 q.group 2, "[#{self.class}: ", "]" do 244 q.text "base name: #{base_name.inspect}" 245 q.breakable 246 247 items = @modules.map { |n,m| m } 248 items.concat @modules.map { |n,c| c } 249 q.seplist items do |mod| q.pp mod end 250 end 251 end 252 253 ## 254 # Search record used by RDoc::Generator::JsonIndex 255 256 def search_record 257 return unless @parser < RDoc::Parser::Text 258 259 [ 260 page_name, 261 '', 262 page_name, 263 '', 264 path, 265 '', 266 snippet(@comment), 267 ] 268 end 269 270 ## 271 # Is this TopLevel from a text file instead of a source code file? 272 273 def text? 274 @parser and @parser.ancestors.include? RDoc::Parser::Text 275 end 276 277 def to_s # :nodoc: 278 "file #{full_name}" 279 end 280 281end 282 283