1 | # We represent the various high-level code constructs that appear
|
---|
2 | # in Ruby programs: classes, modules, methods, and so on.
|
---|
3 |
|
---|
4 | require 'rdoc/tokenstream'
|
---|
5 |
|
---|
6 | module RDoc
|
---|
7 |
|
---|
8 |
|
---|
9 | # We contain the common stuff for contexts (which are containers)
|
---|
10 | # and other elements (methods, attributes and so on)
|
---|
11 | #
|
---|
12 | class CodeObject
|
---|
13 |
|
---|
14 | attr_accessor :parent
|
---|
15 |
|
---|
16 | # We are the model of the code, but we know that at some point
|
---|
17 | # we will be worked on by viewers. By implementing the Viewable
|
---|
18 | # protocol, viewers can associated themselves with these objects.
|
---|
19 |
|
---|
20 | attr_accessor :viewer
|
---|
21 |
|
---|
22 | # are we done documenting (ie, did we come across a :enddoc:)?
|
---|
23 |
|
---|
24 | attr_accessor :done_documenting
|
---|
25 |
|
---|
26 | # Which section are we in
|
---|
27 |
|
---|
28 | attr_accessor :section
|
---|
29 |
|
---|
30 | # do we document ourselves?
|
---|
31 |
|
---|
32 | attr_reader :document_self
|
---|
33 |
|
---|
34 | def document_self=(val)
|
---|
35 | @document_self = val
|
---|
36 | if !val
|
---|
37 | remove_methods_etc
|
---|
38 | end
|
---|
39 | end
|
---|
40 |
|
---|
41 | # set and cleared by :startdoc: and :enddoc:, this is used to toggle
|
---|
42 | # the capturing of documentation
|
---|
43 | def start_doc
|
---|
44 | @document_self = true
|
---|
45 | @document_children = true
|
---|
46 | end
|
---|
47 |
|
---|
48 | def stop_doc
|
---|
49 | @document_self = false
|
---|
50 | @document_children = false
|
---|
51 | end
|
---|
52 |
|
---|
53 | # do we document ourselves and our children
|
---|
54 |
|
---|
55 | attr_reader :document_children
|
---|
56 |
|
---|
57 | def document_children=(val)
|
---|
58 | @document_children = val
|
---|
59 | if !val
|
---|
60 | remove_classes_and_modules
|
---|
61 | end
|
---|
62 | end
|
---|
63 |
|
---|
64 | # Do we _force_ documentation, even is we wouldn't normally show the entity
|
---|
65 | attr_accessor :force_documentation
|
---|
66 |
|
---|
67 | # Default callbacks to nothing, but this is overridden for classes
|
---|
68 | # and modules
|
---|
69 | def remove_classes_and_modules
|
---|
70 | end
|
---|
71 |
|
---|
72 | def remove_methods_etc
|
---|
73 | end
|
---|
74 |
|
---|
75 | def initialize
|
---|
76 | @document_self = true
|
---|
77 | @document_children = true
|
---|
78 | @force_documentation = false
|
---|
79 | @done_documenting = false
|
---|
80 | end
|
---|
81 |
|
---|
82 | # Access the code object's comment
|
---|
83 | attr_reader :comment
|
---|
84 |
|
---|
85 | # Update the comment, but don't overwrite a real comment
|
---|
86 | # with an empty one
|
---|
87 | def comment=(comment)
|
---|
88 | @comment = comment unless comment.empty?
|
---|
89 | end
|
---|
90 |
|
---|
91 | # There's a wee trick we pull. Comment blocks can have directives that
|
---|
92 | # override the stuff we extract during the parse. So, we have a special
|
---|
93 | # class method, attr_overridable, that lets code objects list
|
---|
94 | # those directives. Wehn a comment is assigned, we then extract
|
---|
95 | # out any matching directives and update our object
|
---|
96 |
|
---|
97 | def CodeObject.attr_overridable(name, *aliases)
|
---|
98 | @overridables ||= {}
|
---|
99 |
|
---|
100 | attr_accessor name
|
---|
101 |
|
---|
102 | aliases.unshift name
|
---|
103 | aliases.each do |directive_name|
|
---|
104 | @overridables[directive_name.to_s] = name
|
---|
105 | end
|
---|
106 | end
|
---|
107 |
|
---|
108 | end
|
---|
109 |
|
---|
110 | # A Context is something that can hold modules, classes, methods,
|
---|
111 | # attributes, aliases, requires, and includes. Classes, modules, and
|
---|
112 | # files are all Contexts.
|
---|
113 |
|
---|
114 | class Context < CodeObject
|
---|
115 | attr_reader :name, :method_list, :attributes, :aliases, :constants
|
---|
116 | attr_reader :requires, :includes, :in_files, :visibility
|
---|
117 |
|
---|
118 | attr_reader :sections
|
---|
119 |
|
---|
120 | class Section
|
---|
121 | attr_reader :title, :comment, :sequence
|
---|
122 |
|
---|
123 | @@sequence = "SEC00000"
|
---|
124 |
|
---|
125 | def initialize(title, comment)
|
---|
126 | @title = title
|
---|
127 | @@sequence.succ!
|
---|
128 | @sequence = @@sequence.dup
|
---|
129 | set_comment(comment)
|
---|
130 | end
|
---|
131 |
|
---|
132 | private
|
---|
133 |
|
---|
134 | # Set the comment for this section from the original comment block
|
---|
135 | # If the first line contains :section:, strip it and use the rest. Otherwise
|
---|
136 | # remove lines up to the line containing :section:, and look for
|
---|
137 | # those lines again at the end and remove them. This lets us write
|
---|
138 | #
|
---|
139 | # # ---------------------
|
---|
140 | # # :SECTION: The title
|
---|
141 | # # The body
|
---|
142 | # # ---------------------
|
---|
143 |
|
---|
144 | def set_comment(comment)
|
---|
145 | return unless comment
|
---|
146 |
|
---|
147 | if comment =~ /^.*?:section:.*$/
|
---|
148 | start = $`
|
---|
149 | rest = $'
|
---|
150 | if start.empty?
|
---|
151 | @comment = rest
|
---|
152 | else
|
---|
153 | @comment = rest.sub(/#{start.chomp}\Z/, '')
|
---|
154 | end
|
---|
155 | else
|
---|
156 | @comment = comment
|
---|
157 | end
|
---|
158 | @comment = nil if @comment.empty?
|
---|
159 | end
|
---|
160 | end
|
---|
161 |
|
---|
162 |
|
---|
163 | def initialize
|
---|
164 | super()
|
---|
165 |
|
---|
166 | @in_files = []
|
---|
167 |
|
---|
168 | @name ||= "unknown"
|
---|
169 | @comment ||= ""
|
---|
170 | @parent = nil
|
---|
171 | @visibility = :public
|
---|
172 |
|
---|
173 | @current_section = Section.new(nil, nil)
|
---|
174 | @sections = [ @current_section ]
|
---|
175 |
|
---|
176 | initialize_methods_etc
|
---|
177 | initialize_classes_and_modules
|
---|
178 | end
|
---|
179 |
|
---|
180 | # map the class hash to an array externally
|
---|
181 | def classes
|
---|
182 | @classes.values
|
---|
183 | end
|
---|
184 |
|
---|
185 | # map the module hash to an array externally
|
---|
186 | def modules
|
---|
187 | @modules.values
|
---|
188 | end
|
---|
189 |
|
---|
190 | # Change the default visibility for new methods
|
---|
191 | def ongoing_visibility=(vis)
|
---|
192 | @visibility = vis
|
---|
193 | end
|
---|
194 |
|
---|
195 | # Given an array +methods+ of method names, set the
|
---|
196 | # visibility of the corresponding AnyMethod object
|
---|
197 |
|
---|
198 | def set_visibility_for(methods, vis, singleton=false)
|
---|
199 | count = 0
|
---|
200 | @method_list.each do |m|
|
---|
201 | if methods.include?(m.name) && m.singleton == singleton
|
---|
202 | m.visibility = vis
|
---|
203 | count += 1
|
---|
204 | end
|
---|
205 | end
|
---|
206 |
|
---|
207 | return if count == methods.size || singleton
|
---|
208 |
|
---|
209 | # perhaps we need to look at attributes
|
---|
210 |
|
---|
211 | @attributes.each do |a|
|
---|
212 | if methods.include?(a.name)
|
---|
213 | a.visibility = vis
|
---|
214 | count += 1
|
---|
215 | end
|
---|
216 | end
|
---|
217 | end
|
---|
218 |
|
---|
219 | # Record the file that we happen to find it in
|
---|
220 | def record_location(toplevel)
|
---|
221 | @in_files << toplevel unless @in_files.include?(toplevel)
|
---|
222 | end
|
---|
223 |
|
---|
224 | # Return true if at least part of this thing was defined in +file+
|
---|
225 | def defined_in?(file)
|
---|
226 | @in_files.include?(file)
|
---|
227 | end
|
---|
228 |
|
---|
229 | def add_class(class_type, name, superclass)
|
---|
230 | add_class_or_module(@classes, class_type, name, superclass)
|
---|
231 | end
|
---|
232 |
|
---|
233 | def add_module(class_type, name)
|
---|
234 | add_class_or_module(@modules, class_type, name, nil)
|
---|
235 | end
|
---|
236 |
|
---|
237 | def add_method(a_method)
|
---|
238 | puts "Adding #@visibility method #{a_method.name} to #@name" if $DEBUG
|
---|
239 | a_method.visibility = @visibility
|
---|
240 | add_to(@method_list, a_method)
|
---|
241 | end
|
---|
242 |
|
---|
243 | def add_attribute(an_attribute)
|
---|
244 | add_to(@attributes, an_attribute)
|
---|
245 | end
|
---|
246 |
|
---|
247 | def add_alias(an_alias)
|
---|
248 | meth = find_instance_method_named(an_alias.old_name)
|
---|
249 | if meth
|
---|
250 | new_meth = AnyMethod.new(an_alias.text, an_alias.new_name)
|
---|
251 | new_meth.is_alias_for = meth
|
---|
252 | new_meth.singleton = meth.singleton
|
---|
253 | new_meth.params = meth.params
|
---|
254 | new_meth.comment = "Alias for \##{meth.name}"
|
---|
255 | meth.add_alias(new_meth)
|
---|
256 | add_method(new_meth)
|
---|
257 | else
|
---|
258 | add_to(@aliases, an_alias)
|
---|
259 | end
|
---|
260 | end
|
---|
261 |
|
---|
262 | def add_include(an_include)
|
---|
263 | add_to(@includes, an_include)
|
---|
264 | end
|
---|
265 |
|
---|
266 | def add_constant(const)
|
---|
267 | add_to(@constants, const)
|
---|
268 | end
|
---|
269 |
|
---|
270 | # Requires always get added to the top-level (file) context
|
---|
271 | def add_require(a_require)
|
---|
272 | if self.kind_of? TopLevel
|
---|
273 | add_to(@requires, a_require)
|
---|
274 | else
|
---|
275 | parent.add_require(a_require)
|
---|
276 | end
|
---|
277 | end
|
---|
278 |
|
---|
279 | def add_class_or_module(collection, class_type, name, superclass=nil)
|
---|
280 | cls = collection[name]
|
---|
281 | if cls
|
---|
282 | puts "Reusing class/module #{name}" if $DEBUG
|
---|
283 | else
|
---|
284 | cls = class_type.new(name, superclass)
|
---|
285 | puts "Adding class/module #{name} to #@name" if $DEBUG
|
---|
286 | # collection[name] = cls if @document_self && !@done_documenting
|
---|
287 | collection[name] = cls if !@done_documenting
|
---|
288 | cls.parent = self
|
---|
289 | cls.section = @current_section
|
---|
290 | end
|
---|
291 | cls
|
---|
292 | end
|
---|
293 |
|
---|
294 | def add_to(array, thing)
|
---|
295 | array << thing if @document_self && !@done_documenting
|
---|
296 | thing.parent = self
|
---|
297 | thing.section = @current_section
|
---|
298 | end
|
---|
299 |
|
---|
300 | # If a class's documentation is turned off after we've started
|
---|
301 | # collecting methods etc., we need to remove the ones
|
---|
302 | # we have
|
---|
303 |
|
---|
304 | def remove_methods_etc
|
---|
305 | initialize_methods_etc
|
---|
306 | end
|
---|
307 |
|
---|
308 | def initialize_methods_etc
|
---|
309 | @method_list = []
|
---|
310 | @attributes = []
|
---|
311 | @aliases = []
|
---|
312 | @requires = []
|
---|
313 | @includes = []
|
---|
314 | @constants = []
|
---|
315 | end
|
---|
316 |
|
---|
317 | # and remove classes and modules when we see a :nodoc: all
|
---|
318 | def remove_classes_and_modules
|
---|
319 | initialize_classes_and_modules
|
---|
320 | end
|
---|
321 |
|
---|
322 | def initialize_classes_and_modules
|
---|
323 | @classes = {}
|
---|
324 | @modules = {}
|
---|
325 | end
|
---|
326 |
|
---|
327 | # Find a named module
|
---|
328 | def find_module_named(name)
|
---|
329 | return self if self.name == name
|
---|
330 | res = @modules[name] || @classes[name]
|
---|
331 | return res if res
|
---|
332 | find_enclosing_module_named(name)
|
---|
333 | end
|
---|
334 |
|
---|
335 | # find a module at a higher scope
|
---|
336 | def find_enclosing_module_named(name)
|
---|
337 | parent && parent.find_module_named(name)
|
---|
338 | end
|
---|
339 |
|
---|
340 | # Iterate over all the classes and modules in
|
---|
341 | # this object
|
---|
342 |
|
---|
343 | def each_classmodule
|
---|
344 | @modules.each_value {|m| yield m}
|
---|
345 | @classes.each_value {|c| yield c}
|
---|
346 | end
|
---|
347 |
|
---|
348 | def each_method
|
---|
349 | @method_list.each {|m| yield m}
|
---|
350 | end
|
---|
351 |
|
---|
352 | def each_attribute
|
---|
353 | @attributes.each {|a| yield a}
|
---|
354 | end
|
---|
355 |
|
---|
356 | def each_constant
|
---|
357 | @constants.each {|c| yield c}
|
---|
358 | end
|
---|
359 |
|
---|
360 | # Return the toplevel that owns us
|
---|
361 |
|
---|
362 | def toplevel
|
---|
363 | return @toplevel if defined? @toplevel
|
---|
364 | @toplevel = self
|
---|
365 | @toplevel = @toplevel.parent until TopLevel === @toplevel
|
---|
366 | @toplevel
|
---|
367 | end
|
---|
368 |
|
---|
369 | # allow us to sort modules by name
|
---|
370 | def <=>(other)
|
---|
371 | name <=> other.name
|
---|
372 | end
|
---|
373 |
|
---|
374 | # Look up the given symbol. If method is non-nil, then
|
---|
375 | # we assume the symbol references a module that
|
---|
376 | # contains that method
|
---|
377 | def find_symbol(symbol, method=nil)
|
---|
378 | result = nil
|
---|
379 | case symbol
|
---|
380 | when /^::(.*)/
|
---|
381 | result = toplevel.find_symbol($1)
|
---|
382 | when /::/
|
---|
383 | modules = symbol.split(/::/)
|
---|
384 | unless modules.empty?
|
---|
385 | module_name = modules.shift
|
---|
386 | result = find_module_named(module_name)
|
---|
387 | if result
|
---|
388 | modules.each do |module_name|
|
---|
389 | result = result.find_module_named(module_name)
|
---|
390 | break unless result
|
---|
391 | end
|
---|
392 | end
|
---|
393 | end
|
---|
394 | else
|
---|
395 | # if a method is specified, then we're definitely looking for
|
---|
396 | # a module, otherwise it could be any symbol
|
---|
397 | if method
|
---|
398 | result = find_module_named(symbol)
|
---|
399 | else
|
---|
400 | result = find_local_symbol(symbol)
|
---|
401 | if result.nil?
|
---|
402 | if symbol =~ /^[A-Z]/
|
---|
403 | result = parent
|
---|
404 | while result && result.name != symbol
|
---|
405 | result = result.parent
|
---|
406 | end
|
---|
407 | end
|
---|
408 | end
|
---|
409 | end
|
---|
410 | end
|
---|
411 | if result && method
|
---|
412 | if !result.respond_to?(:find_local_symbol)
|
---|
413 | p result.name
|
---|
414 | p method
|
---|
415 | fail
|
---|
416 | end
|
---|
417 | result = result.find_local_symbol(method)
|
---|
418 | end
|
---|
419 | result
|
---|
420 | end
|
---|
421 |
|
---|
422 | def find_local_symbol(symbol)
|
---|
423 | res = find_method_named(symbol) ||
|
---|
424 | find_constant_named(symbol) ||
|
---|
425 | find_attribute_named(symbol) ||
|
---|
426 | find_module_named(symbol)
|
---|
427 | end
|
---|
428 |
|
---|
429 | # Handle sections
|
---|
430 |
|
---|
431 | def set_current_section(title, comment)
|
---|
432 | @current_section = Section.new(title, comment)
|
---|
433 | @sections << @current_section
|
---|
434 | end
|
---|
435 |
|
---|
436 | private
|
---|
437 |
|
---|
438 | # Find a named method, or return nil
|
---|
439 | def find_method_named(name)
|
---|
440 | @method_list.find {|meth| meth.name == name}
|
---|
441 | end
|
---|
442 |
|
---|
443 | # Find a named instance method, or return nil
|
---|
444 | def find_instance_method_named(name)
|
---|
445 | @method_list.find {|meth| meth.name == name && !meth.singleton}
|
---|
446 | end
|
---|
447 |
|
---|
448 | # Find a named constant, or return nil
|
---|
449 | def find_constant_named(name)
|
---|
450 | @constants.find {|m| m.name == name}
|
---|
451 | end
|
---|
452 |
|
---|
453 | # Find a named attribute, or return nil
|
---|
454 | def find_attribute_named(name)
|
---|
455 | @attributes.find {|m| m.name == name}
|
---|
456 | end
|
---|
457 |
|
---|
458 | end
|
---|
459 |
|
---|
460 |
|
---|
461 | # A TopLevel context is a source file
|
---|
462 |
|
---|
463 | class TopLevel < Context
|
---|
464 | attr_accessor :file_stat
|
---|
465 | attr_accessor :file_relative_name
|
---|
466 | attr_accessor :file_absolute_name
|
---|
467 | attr_accessor :diagram
|
---|
468 |
|
---|
469 | @@all_classes = {}
|
---|
470 | @@all_modules = {}
|
---|
471 |
|
---|
472 | def TopLevel::reset
|
---|
473 | @@all_classes = {}
|
---|
474 | @@all_modules = {}
|
---|
475 | end
|
---|
476 |
|
---|
477 | def initialize(file_name)
|
---|
478 | super()
|
---|
479 | @name = "TopLevel"
|
---|
480 | @file_relative_name = file_name
|
---|
481 | @file_absolute_name = file_name
|
---|
482 | @file_stat = File.stat(file_name)
|
---|
483 | @diagram = nil
|
---|
484 | end
|
---|
485 |
|
---|
486 | def full_name
|
---|
487 | nil
|
---|
488 | end
|
---|
489 |
|
---|
490 | # Adding a class or module to a TopLevel is special, as we only
|
---|
491 | # want one copy of a particular top-level class. For example,
|
---|
492 | # if both file A and file B implement class C, we only want one
|
---|
493 | # ClassModule object for C. This code arranges to share
|
---|
494 | # classes and modules between files.
|
---|
495 |
|
---|
496 | def add_class_or_module(collection, class_type, name, superclass)
|
---|
497 | cls = collection[name]
|
---|
498 | if cls
|
---|
499 | puts "Reusing class/module #{name}" if $DEBUG
|
---|
500 | else
|
---|
501 | if class_type == NormalModule
|
---|
502 | all = @@all_modules
|
---|
503 | else
|
---|
504 | all = @@all_classes
|
---|
505 | end
|
---|
506 | cls = all[name]
|
---|
507 | if !cls
|
---|
508 | cls = class_type.new(name, superclass)
|
---|
509 | all[name] = cls unless @done_documenting
|
---|
510 | end
|
---|
511 | puts "Adding class/module #{name} to #@name" if $DEBUG
|
---|
512 | collection[name] = cls unless @done_documenting
|
---|
513 | cls.parent = self
|
---|
514 | end
|
---|
515 | cls
|
---|
516 | end
|
---|
517 |
|
---|
518 | def TopLevel.all_classes_and_modules
|
---|
519 | @@all_classes.values + @@all_modules.values
|
---|
520 | end
|
---|
521 |
|
---|
522 | def TopLevel.find_class_named(name)
|
---|
523 | @@all_classes.each_value do |c|
|
---|
524 | res = c.find_class_named(name)
|
---|
525 | return res if res
|
---|
526 | end
|
---|
527 | nil
|
---|
528 | end
|
---|
529 |
|
---|
530 | def find_local_symbol(symbol)
|
---|
531 | find_class_or_module_named(symbol) || super
|
---|
532 | end
|
---|
533 |
|
---|
534 | def find_class_or_module_named(symbol)
|
---|
535 | @@all_classes.each_value {|c| return c if c.name == symbol}
|
---|
536 | @@all_modules.each_value {|m| return m if m.name == symbol}
|
---|
537 | nil
|
---|
538 | end
|
---|
539 |
|
---|
540 | # Find a named module
|
---|
541 | def find_module_named(name)
|
---|
542 | find_class_or_module_named(name) || find_enclosing_module_named(name)
|
---|
543 | end
|
---|
544 |
|
---|
545 |
|
---|
546 | end
|
---|
547 |
|
---|
548 | # ClassModule is the base class for objects representing either a
|
---|
549 | # class or a module.
|
---|
550 |
|
---|
551 | class ClassModule < Context
|
---|
552 |
|
---|
553 | attr_reader :superclass
|
---|
554 | attr_accessor :diagram
|
---|
555 |
|
---|
556 | def initialize(name, superclass = nil)
|
---|
557 | @name = name
|
---|
558 | @diagram = nil
|
---|
559 | @superclass = superclass
|
---|
560 | @comment = ""
|
---|
561 | super()
|
---|
562 | end
|
---|
563 |
|
---|
564 | # Return the fully qualified name of this class or module
|
---|
565 | def full_name
|
---|
566 | if @parent && @parent.full_name
|
---|
567 | @parent.full_name + "::" + @name
|
---|
568 | else
|
---|
569 | @name
|
---|
570 | end
|
---|
571 | end
|
---|
572 |
|
---|
573 | def http_url(prefix)
|
---|
574 | path = full_name.split("::")
|
---|
575 | File.join(prefix, *path) + ".html"
|
---|
576 | end
|
---|
577 |
|
---|
578 | # Return +true+ if this object represents a module
|
---|
579 | def is_module?
|
---|
580 | false
|
---|
581 | end
|
---|
582 |
|
---|
583 | # to_s is simply for debugging
|
---|
584 | def to_s
|
---|
585 | res = self.class.name + ": " + @name
|
---|
586 | res << @comment.to_s
|
---|
587 | res << super
|
---|
588 | res
|
---|
589 | end
|
---|
590 |
|
---|
591 | def find_class_named(name)
|
---|
592 | return self if full_name == name
|
---|
593 | @classes.each_value {|c| return c if c.find_class_named(name) }
|
---|
594 | nil
|
---|
595 | end
|
---|
596 | end
|
---|
597 |
|
---|
598 | # Anonymous classes
|
---|
599 | class AnonClass < ClassModule
|
---|
600 | end
|
---|
601 |
|
---|
602 | # Normal classes
|
---|
603 | class NormalClass < ClassModule
|
---|
604 | end
|
---|
605 |
|
---|
606 | # Singleton classes
|
---|
607 | class SingleClass < ClassModule
|
---|
608 | end
|
---|
609 |
|
---|
610 | # Module
|
---|
611 | class NormalModule < ClassModule
|
---|
612 | def is_module?
|
---|
613 | true
|
---|
614 | end
|
---|
615 | end
|
---|
616 |
|
---|
617 |
|
---|
618 | # AnyMethod is the base class for objects representing methods
|
---|
619 |
|
---|
620 | class AnyMethod < CodeObject
|
---|
621 | attr_accessor :name
|
---|
622 | attr_accessor :visibility
|
---|
623 | attr_accessor :block_params
|
---|
624 | attr_accessor :dont_rename_initialize
|
---|
625 | attr_accessor :singleton
|
---|
626 | attr_reader :aliases # list of other names for this method
|
---|
627 | attr_accessor :is_alias_for # or a method we're aliasing
|
---|
628 |
|
---|
629 | attr_overridable :params, :param, :parameters, :parameter
|
---|
630 |
|
---|
631 | attr_accessor :call_seq
|
---|
632 |
|
---|
633 |
|
---|
634 | include TokenStream
|
---|
635 |
|
---|
636 | def initialize(text, name)
|
---|
637 | super()
|
---|
638 | @text = text
|
---|
639 | @name = name
|
---|
640 | @token_stream = nil
|
---|
641 | @visibility = :public
|
---|
642 | @dont_rename_initialize = false
|
---|
643 | @block_params = nil
|
---|
644 | @aliases = []
|
---|
645 | @is_alias_for = nil
|
---|
646 | @comment = ""
|
---|
647 | @call_seq = nil
|
---|
648 | end
|
---|
649 |
|
---|
650 | def <=>(other)
|
---|
651 | @name <=> other.name
|
---|
652 | end
|
---|
653 |
|
---|
654 | def to_s
|
---|
655 | res = self.class.name + ": " + @name + " (" + @text + ")\n"
|
---|
656 | res << @comment.to_s
|
---|
657 | res
|
---|
658 | end
|
---|
659 |
|
---|
660 | def param_seq
|
---|
661 | p = params.gsub(/\s*\#.*/, '')
|
---|
662 | p = p.tr("\n", " ").squeeze(" ")
|
---|
663 | p = "(" + p + ")" unless p[0] == ?(
|
---|
664 |
|
---|
665 | if (block = block_params)
|
---|
666 | # If this method has explicit block parameters, remove any
|
---|
667 | # explicit &block
|
---|
668 | $stderr.puts p
|
---|
669 | p.sub!(/,?\s*&\w+/)
|
---|
670 | $stderr.puts p
|
---|
671 |
|
---|
672 | block.gsub!(/\s*\#.*/, '')
|
---|
673 | block = block.tr("\n", " ").squeeze(" ")
|
---|
674 | if block[0] == ?(
|
---|
675 | block.sub!(/^\(/, '').sub!(/\)/, '')
|
---|
676 | end
|
---|
677 | p << " {|#{block}| ...}"
|
---|
678 | end
|
---|
679 | p
|
---|
680 | end
|
---|
681 |
|
---|
682 | def add_alias(method)
|
---|
683 | @aliases << method
|
---|
684 | end
|
---|
685 | end
|
---|
686 |
|
---|
687 |
|
---|
688 | # Represent an alias, which is an old_name/ new_name pair associated
|
---|
689 | # with a particular context
|
---|
690 | class Alias < CodeObject
|
---|
691 | attr_accessor :text, :old_name, :new_name, :comment
|
---|
692 |
|
---|
693 | def initialize(text, old_name, new_name, comment)
|
---|
694 | super()
|
---|
695 | @text = text
|
---|
696 | @old_name = old_name
|
---|
697 | @new_name = new_name
|
---|
698 | self.comment = comment
|
---|
699 | end
|
---|
700 |
|
---|
701 | def to_s
|
---|
702 | "alias: #{self.old_name} -> #{self.new_name}\n#{self.comment}"
|
---|
703 | end
|
---|
704 | end
|
---|
705 |
|
---|
706 | # Represent a constant
|
---|
707 | class Constant < CodeObject
|
---|
708 | attr_accessor :name, :value
|
---|
709 |
|
---|
710 | def initialize(name, value, comment)
|
---|
711 | super()
|
---|
712 | @name = name
|
---|
713 | @value = value
|
---|
714 | self.comment = comment
|
---|
715 | end
|
---|
716 | end
|
---|
717 |
|
---|
718 | # Represent attributes
|
---|
719 | class Attr < CodeObject
|
---|
720 | attr_accessor :text, :name, :rw, :visibility
|
---|
721 |
|
---|
722 | def initialize(text, name, rw, comment)
|
---|
723 | super()
|
---|
724 | @text = text
|
---|
725 | @name = name
|
---|
726 | @rw = rw
|
---|
727 | @visibility = :public
|
---|
728 | self.comment = comment
|
---|
729 | end
|
---|
730 |
|
---|
731 | def to_s
|
---|
732 | "attr: #{self.name} #{self.rw}\n#{self.comment}"
|
---|
733 | end
|
---|
734 |
|
---|
735 | def <=>(other)
|
---|
736 | self.name <=> other.name
|
---|
737 | end
|
---|
738 | end
|
---|
739 |
|
---|
740 | # a required file
|
---|
741 |
|
---|
742 | class Require < CodeObject
|
---|
743 | attr_accessor :name
|
---|
744 |
|
---|
745 | def initialize(name, comment)
|
---|
746 | super()
|
---|
747 | @name = name.gsub(/'|"/, "") #'
|
---|
748 | self.comment = comment
|
---|
749 | end
|
---|
750 |
|
---|
751 | end
|
---|
752 |
|
---|
753 | # an included module
|
---|
754 | class Include < CodeObject
|
---|
755 | attr_accessor :name
|
---|
756 |
|
---|
757 | def initialize(name, comment)
|
---|
758 | super()
|
---|
759 | @name = name
|
---|
760 | self.comment = comment
|
---|
761 | end
|
---|
762 |
|
---|
763 | end
|
---|
764 |
|
---|
765 | end
|
---|