summaryrefslogtreecommitdiff
path: root/lib/rdoc/top_level.rb
blob: 306790fc159de0c029eac2b96c5dcfb73c1cebdd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
require 'rdoc/context'

##
# A TopLevel context is a representation of the contents of a single file

class RDoc::TopLevel < RDoc::Context

  ##
  # This TopLevel's File::Stat struct

  attr_accessor :file_stat

  ##
  # Relative name of this file

  attr_accessor :relative_name

  ##
  # Absolute name of this file

  attr_accessor :absolute_name

  attr_accessor :diagram

  ##
  # The parser that processed this file

  attr_accessor :parser

  ##
  # Returns all classes and modules discovered by RDoc

  def self.all_classes_and_modules
    classes_hash.values + modules_hash.values
  end

  ##
  # Returns all classes discovered by RDoc

  def self.classes
    classes_hash.values
  end

  ##
  # Hash of all classes known to RDoc

  def self.classes_hash
    @all_classes
  end

  ##
  # All TopLevels known to RDoc

  def self.files
    @all_files.values
  end

  ##
  # Hash of all files known to RDoc

  def self.files_hash
    @all_files
  end

  ##
  # Finds the class with +name+ in all discovered classes

  def self.find_class_named(name)
    classes_hash[name]
  end

  ##
  # Finds the class with +name+ starting in namespace +from+

  def self.find_class_named_from name, from
    from = find_class_named from unless RDoc::Context === from

    until RDoc::TopLevel === from do
      return nil unless from

      klass = from.find_class_named name
      return klass if klass

      from = from.parent
    end

    find_class_named name
  end

  ##
  # Finds the class or module with +name+

  def self.find_class_or_module(name)
    name =~ /^::/
    name = $' || name

    RDoc::TopLevel.classes_hash[name] || RDoc::TopLevel.modules_hash[name]
  end

  ##
  # Finds the file with +name+ in all discovered files

  def self.find_file_named(name)
    @all_files[name]
  end

  ##
  # Finds the module with +name+ in all discovered modules

  def self.find_module_named(name)
    modules_hash[name]
  end

  ##
  # Returns all modules discovered by RDoc

  def self.modules
    modules_hash.values
  end

  ##
  # Hash of all modules known to RDoc

  def self.modules_hash
    @all_modules
  end

  ##
  # Empties RDoc of stored class, module and file information

  def self.reset
    @all_classes = {}
    @all_modules = {}
    @all_files   = {}
  end

  reset

  ##
  # Creates a new TopLevel for +file_name+

  def initialize(file_name)
    super()
    @name = nil
    @relative_name = file_name
    @absolute_name = file_name
    @file_stat     = File.stat(file_name) rescue nil # HACK for testing
    @diagram       = nil
    @parser        = nil

    RDoc::TopLevel.files_hash[file_name] = self
  end

  ##
  # Adds +method+ to Object instead of RDoc::TopLevel

  def add_method(method)
    object = self.class.find_class_named 'Object'
    object = add_class RDoc::NormalClass, 'Object' unless object

    object.add_method method
  end

  ##
  # Base name of this file

  def base_name
    File.basename @absolute_name
  end

  ##
  # See RDoc::TopLevel.find_class_or_module

  def find_class_or_module name
    RDoc::TopLevel.find_class_or_module name
  end

  ##
  # Finds a class or module named +symbol+

  def find_local_symbol(symbol)
    find_class_or_module(symbol) || super
  end

  ##
  # Finds a module or class with +name+

  def find_module_named(name)
    find_class_or_module(name) || find_enclosing_module_named(name)
  end

  ##
  # The name of this file

  def full_name
    @relative_name
  end

  ##
  # URL for this with a +prefix+

  def http_url(prefix)
    path = [prefix, @relative_name.tr('.', '_')]

    File.join(*path.compact) + '.html'
  end

  def inspect # :nodoc:
    "#<%s:0x%x %p modules: %p classes: %p>" % [
      self.class, object_id,
      base_name,
      @modules.map { |n,m| m },
      @classes.map { |n,c| c }
    ]
  end

  ##
  # Date this file was last modified, if known

  def last_modified
    @file_stat ? file_stat.mtime.to_s : 'Unknown'
  end

  ##
  # Base name of this file

  alias name base_name

  ##
  # Path to this file

  def path
    http_url RDoc::RDoc.current.generator.file_dir
  end

  def pretty_print q # :nodoc:
    q.group 2, "[#{self.class}: ", "]" do
      q.text "base name: #{base_name.inspect}"
      q.breakable

      items = @modules.map { |n,m| m }
      items.push(*@modules.map { |n,c| c })
      q.seplist items do |mod| q.pp mod end
    end
  end

end