rdoc 3.8 → 3.9

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rdoc might be problematic. Click here for more details.

@@ -71,9 +71,7 @@ class RDoc::Markup::Document
71
71
  # Does this document have no parts?
72
72
 
73
73
  def empty?
74
- @parts.empty? or
75
- (@parts.length == 1 and RDoc::Markup::Document === @parts.first and
76
- @parts.first.empty?)
74
+ @parts.empty? or (@parts.length == 1 and merged? and @parts.first.empty?)
77
75
  end
78
76
 
79
77
  ##
@@ -85,6 +83,11 @@ class RDoc::Markup::Document
85
83
  # The information in +other+ is preferred over the receiver
86
84
 
87
85
  def merge other
86
+ if empty? then
87
+ @parts = other.parts
88
+ return self
89
+ end
90
+
88
91
  other.parts.each do |other_part|
89
92
  self.parts.delete_if do |self_part|
90
93
  self_part.file and self_part.file == other_part.file
@@ -96,6 +99,13 @@ class RDoc::Markup::Document
96
99
  self
97
100
  end
98
101
 
102
+ ##
103
+ # Does this Document contain other Documents?
104
+
105
+ def merged?
106
+ RDoc::Markup::Document === @parts.first
107
+ end
108
+
99
109
  def pretty_print q # :nodoc:
100
110
  start = @file ? "[doc (#{@file}): " : '[doc: '
101
111
 
@@ -4,6 +4,10 @@ require 'rdoc/markup'
4
4
  # Base class for RDoc markup formatters
5
5
  #
6
6
  # Formatters use a visitor pattern to convert content into output.
7
+ #
8
+ # If you'd like to write your own Formatter use
9
+ # RDoc::Markup::FormatterTestCase. If you're writing a text-output formatter
10
+ # use RDoc::Markup::TextFormatterTestCase which provides extra test cases.
7
11
 
8
12
  class RDoc::Markup::Formatter
9
13
 
@@ -405,13 +405,19 @@ class RDoc::Markup::Parser
405
405
  @line += 1
406
406
  token
407
407
  # === text => :HEADER then :TEXT
408
- when s.scan(/(=+)\s*/) then
408
+ when s.scan(/(=+)(\s*)/) then
409
409
  level = s[1].length
410
- level = 6 if level > 6
411
- @tokens << [:HEADER, level, *token_pos(pos)]
412
- pos = s.pos
413
- s.scan(/.*/)
414
- [:TEXT, s.matched.sub(/\r$/, ''), *token_pos(pos)]
410
+ header = [:HEADER, level, *token_pos(pos)]
411
+
412
+ if s[2] =~ /^\r?\n/ then
413
+ s.pos -= s[2].length
414
+ header
415
+ else
416
+ pos = s.pos
417
+ s.scan(/.*/)
418
+ @tokens << header
419
+ [:TEXT, s.matched.sub(/\r$/, ''), *token_pos(pos)]
420
+ end
415
421
  # --- (at least 3) and nothing else on the line => :RULE
416
422
  when s.scan(/(-{3,}) *$/) then
417
423
  [:RULE, s[1].length - 2, *token_pos(pos)]
@@ -13,6 +13,8 @@ require 'rdoc/encoding'
13
13
 
14
14
  class RDoc::Markup::PreProcess
15
15
 
16
+ attr_accessor :options
17
+
16
18
  @registered = {}
17
19
 
18
20
  ##
@@ -38,6 +40,7 @@ class RDoc::Markup::PreProcess
38
40
  def initialize(input_file_name, include_path)
39
41
  @input_file_name = input_file_name
40
42
  @include_path = include_path
43
+ @options = nil
41
44
  end
42
45
 
43
46
  ##
@@ -54,54 +57,120 @@ class RDoc::Markup::PreProcess
54
57
  # If +code_object+ is given and the param is set as metadata on the
55
58
  # +code_object+. See RDoc::CodeObject#metadata
56
59
 
57
- def handle text, code_object = nil
60
+ def handle text, code_object = nil, &block
61
+ encoding = if defined?(Encoding) then text.encoding else nil end
58
62
  # regexp helper (square brackets for optional)
59
63
  # $1 $2 $3 $4 $5
60
64
  # [prefix][\]:directive:[spaces][param]newline
61
- text.gsub!(/^([ \t]*#?[ \t]*)(\\?):(\w+):([ \t]*)(.+)?\n/) do
65
+ text.gsub!(/^([ \t]*(?:#|\/?\*)?[ \t]*)(\\?):(\w+):([ \t]*)(.+)?\n/) do
62
66
  # skip something like ':toto::'
63
67
  next $& if $4.empty? and $5 and $5[0, 1] == ':'
64
68
 
65
69
  # skip if escaped
66
70
  next "#$1:#$3:#$4#$5\n" unless $2.empty?
67
71
 
68
- prefix = $1
69
- directive = $3.downcase
70
- param = $5
71
-
72
- case directive
73
- when 'include' then
74
- filename = param.split[0]
75
- encoding = if defined?(Encoding) then text.encoding else nil end
76
- include_file filename, prefix, encoding
77
- when 'category' then
78
- if RDoc::Context === code_object then
79
- section = code_object.add_section param, ''
80
- code_object.temporary_section = section
81
- end
72
+ handle_directive $1, $3, $5, code_object, encoding, &block
73
+ end
74
+
75
+ text
76
+ end
77
+
78
+ #--
79
+ # When 1.8.7 support is ditched prefix can be defaulted to ''
80
+
81
+ def handle_directive prefix, directive, param, code_object = nil,
82
+ encoding = nil
83
+ blankline = "#{prefix.strip}\n"
84
+ directive = directive.downcase
85
+
86
+ case directive
87
+ when 'arg', 'args' then
88
+ return blankline unless code_object
89
+
90
+ code_object.params = param
91
+
92
+ blankline
93
+ when 'category' then
94
+ if RDoc::Context === code_object then
95
+ section = code_object.add_section param, ''
96
+ code_object.temporary_section = section
97
+ end
98
+
99
+ blankline # ignore category if we're not on an RDoc::Context
100
+ when 'doc' then
101
+ return blankline unless code_object
102
+ code_object.document_self = true
103
+ code_object.force_documentation = true
104
+
105
+ blankline
106
+ when 'enddoc' then
107
+ return blankline unless code_object
108
+ code_object.done_documenting = true
109
+
110
+ blankline
111
+ when 'include' then
112
+ filename = param.split.first
113
+ include_file filename, prefix, encoding
114
+ when 'main' then
115
+ @options.main_page = param if @options.respond_to? :main_page
116
+
117
+ blankline
118
+ when 'nodoc' then
119
+ return blankline unless code_object
120
+ code_object.document_self = nil # notify nodoc
121
+ code_object.document_children = param !~ /all/i
82
122
 
83
- '' # ignore category if we're not on an RDoc::Context
84
- else
85
- result = yield directive, param if block_given?
86
-
87
- case result
88
- when nil then
89
- code_object.metadata[directive] = param if code_object
90
- if RDoc::Markup::PreProcess.registered.include? directive then
91
- handler = RDoc::Markup::PreProcess.registered[directive]
92
- result = handler.call directive, param if handler
93
- else
94
- result = "#{prefix}:#{directive}: #{param}\n"
95
- end
96
- when false then
123
+ blankline
124
+ when 'notnew', 'not_new', 'not-new' then
125
+ return blankline unless RDoc::AnyMethod === code_object
126
+
127
+ code_object.dont_rename_initialize = true
128
+
129
+ blankline
130
+ when 'startdoc' then
131
+ return blankline unless code_object
132
+
133
+ code_object.start_doc
134
+ code_object.force_documentation = true
135
+
136
+ blankline
137
+ when 'stopdoc' then
138
+ return blankline unless code_object
139
+
140
+ code_object.stop_doc
141
+
142
+ blankline
143
+ when 'title' then
144
+ @options.default_title = param if @options.respond_to? :default_title=
145
+
146
+ blankline
147
+ when 'yield', 'yields' then
148
+ return blankline unless code_object
149
+ # remove parameter &block
150
+ code_object.params.sub!(/,?\s*&\w+/, '') if code_object.params
151
+
152
+ code_object.block_params = param
153
+
154
+ blankline
155
+ else
156
+ result = yield directive, param if block_given?
157
+
158
+ case result
159
+ when nil then
160
+ code_object.metadata[directive] = param if code_object
161
+
162
+ if RDoc::Markup::PreProcess.registered.include? directive then
163
+ handler = RDoc::Markup::PreProcess.registered[directive]
164
+ result = handler.call directive, param if handler
165
+ else
97
166
  result = "#{prefix}:#{directive}: #{param}\n"
98
167
  end
99
-
100
- result
168
+ when false then
169
+ result = "#{prefix}:#{directive}: #{param}\n"
101
170
  end
102
- end
103
171
 
104
- text
172
+ result
173
+ end
105
174
  end
106
175
 
107
176
  ##
@@ -70,7 +70,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
70
70
  @list = nil
71
71
  @from_path = ''
72
72
 
73
- # external hyperlinks
73
+ # external links
74
74
  @markup.add_special(/((link:|https?:|mailto:|ftp:|www\.)\S+\w)/, :HYPERLINK)
75
75
 
76
76
  # and links of the form <text>[<url>]
@@ -84,7 +84,7 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
84
84
  # These methods handle special markup added by RDoc::Markup#add_special.
85
85
 
86
86
  ##
87
- # +special+ is a potential hyperlink. The following schemes are handled:
87
+ # +special+ is a potential link. The following schemes are handled:
88
88
  #
89
89
  # <tt>mailto:</tt>::
90
90
  # Inserted as-is.
@@ -97,12 +97,13 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
97
97
 
98
98
  def handle_special_HYPERLINK(special)
99
99
  url = special.text
100
+
100
101
  gen_url url, url
101
102
  end
102
103
 
103
104
  ##
104
- # This +special+ is a hyperlink where the label is different from the URL
105
- # label[url] or {long label}[url]
105
+ # This +special+ is a link where the label is different from the URL
106
+ # <tt>label[url]</tt> or <tt>{long label}[url]</tt>
106
107
 
107
108
  def handle_special_TIDYLINK(special)
108
109
  text = special.text
@@ -232,8 +233,8 @@ class RDoc::Markup::ToHtml < RDoc::Markup::Formatter
232
233
  end
233
234
 
234
235
  ##
235
- # Generate a hyperlink for +url+, labeled with +text+. Handles the special
236
- # cases for img: and link: described under handle_special_HYPERLINK
236
+ # Generate a link for +url+, labeled with +text+. Handles the special cases
237
+ # for img: and link: described under handle_special_HYPERLINK
237
238
 
238
239
  def gen_url(url, text)
239
240
  if url =~ /([A-Za-z]+):(.*)/ then
@@ -1,92 +1,19 @@
1
1
  require 'rdoc/markup/to_html'
2
+ require 'rdoc/cross_reference'
2
3
 
3
4
  ##
4
- # Subclass of the RDoc::Markup::ToHtml class that supports looking up words
5
- # from a context. Those that are found will be hyperlinked.
5
+ # Subclass of the RDoc::Markup::ToHtml class that supports looking up method
6
+ # names, classes, etc to create links. RDoc::CrossReference is used to
7
+ # generate those links based on the current context.
6
8
 
7
9
  class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
8
10
 
9
- ##
10
- # Regular expression to match class references
11
- #
12
- # 1. There can be a '\\' in front of text to suppress the cross-reference
13
- # 2. There can be a '::' in front of class names to reference from the
14
- # top-level namespace.
15
- # 3. The method can be followed by parenthesis (not recommended)
16
-
17
- CLASS_REGEXP_STR = '\\\\?((?:\:{2})?[A-Z]\w*(?:\:\:\w+)*)'
18
-
19
- ##
20
- # Regular expression to match method references.
21
- #
22
- # See CLASS_REGEXP_STR
23
-
24
- METHOD_REGEXP_STR = '([a-z]\w*[!?=]?)(?:\([\w.+*/=<>-]*\))?'
25
-
26
- ##
27
- # Regular expressions matching text that should potentially have
28
- # cross-reference links generated are passed to add_special. Note that
29
- # these expressions are meant to pick up text for which cross-references
30
- # have been suppressed, since the suppression characters are removed by the
31
- # code that is triggered.
32
-
33
- CROSSREF_REGEXP = /(
34
- # A::B::C.meth
35
- #{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR}
36
-
37
- # Stand-alone method (preceded by a #)
38
- | \\?\##{METHOD_REGEXP_STR}
39
-
40
- # Stand-alone method (preceded by ::)
41
- | ::#{METHOD_REGEXP_STR}
42
-
43
- # A::B::C
44
- # The stuff after CLASS_REGEXP_STR is a
45
- # nasty hack. CLASS_REGEXP_STR unfortunately matches
46
- # words like dog and cat (these are legal "class"
47
- # names in Fortran 95). When a word is flagged as a
48
- # potential cross-reference, limitations in the markup
49
- # engine suppress other processing, such as typesetting.
50
- # This is particularly noticeable for contractions.
51
- # In order that words like "can't" not
52
- # be flagged as potential cross-references, only
53
- # flag potential class cross-references if the character
54
- # after the cross-reference is a space, sentence
55
- # punctuation, tag start character, or attribute
56
- # marker.
57
- | #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;<\000]|\z)
58
-
59
- # Things that look like filenames
60
- # The key thing is that there must be at least
61
- # one special character (period, slash, or
62
- # underscore).
63
- | (?:\.\.\/)*[-\/\w]+[_\/\.][-\w\/\.]+
64
-
65
- # Things that have markup suppressed
66
- # Don't process things like '\<' in \<tt>, though.
67
- # TODO: including < is a hack, not very satisfying.
68
- | \\[^\s<]
69
- )/x
70
-
71
- ##
72
- # Version of CROSSREF_REGEXP used when <tt>--hyperlink-all</tt> is specified.
73
-
74
- ALL_CROSSREF_REGEXP = /(
75
- # A::B::C.meth
76
- #{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR}
77
-
78
- # Stand-alone method
79
- | \\?#{METHOD_REGEXP_STR}
80
-
81
- # A::B::C
82
- | #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;<\000]|\z)
83
-
84
- # Things that look like filenames
85
- | (?:\.\.\/)*[-\/\w]+[_\/\.][-\w\/\.]+
86
-
87
- # Things that have markup suppressed
88
- | \\[^\s<]
89
- )/x
11
+ # :stopdoc:
12
+ ALL_CROSSREF_REGEXP = RDoc::CrossReference::ALL_CROSSREF_REGEXP
13
+ CLASS_REGEXP_STR = RDoc::CrossReference::CLASS_REGEXP_STR
14
+ CROSSREF_REGEXP = RDoc::CrossReference::CROSSREF_REGEXP
15
+ METHOD_REGEXP_STR = RDoc::CrossReference::METHOD_REGEXP_STR
16
+ # :startdoc:
90
17
 
91
18
  ##
92
19
  # RDoc::CodeObject for generating references
@@ -102,7 +29,7 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
102
29
  # Creates a new crossref resolver that generates links relative to +context+
103
30
  # which lives at +from_path+ in the generated files. '#' characters on
104
31
  # references are removed unless +show_hash+ is true. Only method names
105
- # preceded by '#' or '::' are hyperlinked, unless +hyperlink_all+ is true.
32
+ # preceded by '#' or '::' are linked, unless +hyperlink_all+ is true.
106
33
 
107
34
  def initialize(from_path, context, show_hash, hyperlink_all = false,
108
35
  markup = nil)
@@ -111,22 +38,36 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
111
38
 
112
39
  crossref_re = hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP
113
40
 
41
+ @cross_reference = RDoc::CrossReference.new context
42
+
114
43
  @markup.add_special crossref_re, :CROSSREF
44
+ @markup.add_special(/rdoc-ref:\S+\w/, :HYPERLINK)
115
45
 
116
- @from_path = from_path
117
- @context = context
118
- @show_hash = show_hash
46
+ @from_path = from_path
119
47
  @hyperlink_all = hyperlink_all
48
+ @show_hash = show_hash
49
+ end
50
+
51
+ ##
52
+ # Creates a link to the reference +name+ if the name exists. If +text+ is
53
+ # given it is used as the link text, otherwise +name+ is used.
54
+
55
+ def cross_reference name, text = nil
56
+ lookup = name
120
57
 
121
- @seen = {}
58
+ name = name[1..-1] unless @show_hash if name[0, 1] == '#'
59
+
60
+ text = name unless text
61
+
62
+ link lookup, text
122
63
  end
123
64
 
124
65
  ##
125
66
  # We're invoked when any text matches the CROSSREF pattern. If we find the
126
- # corresponding reference, generate a hyperlink. If the name we're looking
127
- # for contains no punctuation, we look for it up the module/class chain.
128
- # For example, ToHtml is found, even without the <tt>RDoc::Markup::</tt>
129
- # prefix, because we look for it in module Markup first.
67
+ # corresponding reference, generate a link. If the name we're looking for
68
+ # contains no punctuation, we look for it up the module/class chain. For
69
+ # example, ToHtml is found, even without the <tt>RDoc::Markup::</tt> prefix,
70
+ # because we look for it in module Markup first.
130
71
 
131
72
  def handle_special_CROSSREF(special)
132
73
  name = special.text
@@ -138,66 +79,41 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml
138
79
  return name if name =~ /\A[a-z]*\z/
139
80
  end
140
81
 
141
- return @seen[name] if @seen.include? name
82
+ cross_reference name
83
+ end
142
84
 
143
- lookup = name
85
+ ##
86
+ # Handles <tt>rdoc-ref:</tt> scheme links and allows RDoc::Markup::ToHtml to
87
+ # handle other schemes.
144
88
 
145
- name = name[1..-1] unless @show_hash if name[0, 1] == '#'
89
+ def handle_special_HYPERLINK special
90
+ return cross_reference $' if special.text =~ /\Ardoc-ref:/
146
91
 
147
- # Find class, module, or method in class or module.
148
- #
149
- # Do not, however, use an if/elsif/else chain to do so. Instead, test
150
- # each possible pattern until one matches. The reason for this is that a
151
- # string like "YAML.txt" could be the txt() class method of class YAML (in
152
- # which case it would match the first pattern, which splits the string
153
- # into container and method components and looks up both) or a filename
154
- # (in which case it would match the last pattern, which just checks
155
- # whether the string as a whole is a known symbol).
156
-
157
- if /#{CLASS_REGEXP_STR}([.#]|::)#{METHOD_REGEXP_STR}/ =~ lookup then
158
- type = $2
159
- type = '' if type == '.' # will find either #method or ::method
160
- method = "#{type}#{$3}"
161
- container = @context.find_symbol_module($1)
162
- elsif /^([.#]|::)#{METHOD_REGEXP_STR}/ =~ lookup then
163
- type = $1
164
- type = '' if type == '.'
165
- method = "#{type}#{$2}"
166
- container = @context
167
- else
168
- container = nil
169
- end
92
+ super
93
+ end
170
94
 
171
- if container then
172
- ref = container.find_local_symbol method
95
+ ##
96
+ # Generates links for <tt>rdoc-ref:</tt> scheme URLs and allows
97
+ # RDoc::Markup::ToHtml to handle other schemes.
173
98
 
174
- unless ref || RDoc::TopLevel === container then
175
- ref = container.find_ancestor_local_symbol method
176
- end
177
- end
99
+ def gen_url url, text
100
+ super unless url =~ /\Ardoc-ref:/
178
101
 
179
- ref = @context.find_symbol lookup unless ref
180
- ref = nil if RDoc::Alias === ref # external alias: can't link to it
181
-
182
- out = if lookup == '\\' then
183
- lookup
184
- elsif lookup =~ /^\\/ then
185
- # we remove the \ only in front of what we know:
186
- # other backslashes are treated later, only outside of <tt>
187
- ref ? $' : lookup
188
- elsif ref then
189
- if ref.document_self then
190
- "<a href=\"#{ref.as_href @from_path}\">#{name}</a>"
191
- else
192
- name
193
- end
194
- else
195
- lookup
196
- end
197
-
198
- @seen[lookup] = out
199
-
200
- out
102
+ cross_reference $', text
103
+ end
104
+
105
+ ##
106
+ # Creates an HTML link to +name+ with the given +text+.
107
+
108
+ def link name, text
109
+ ref = @cross_reference.resolve name, text
110
+
111
+ case ref
112
+ when String then
113
+ ref
114
+ else
115
+ "<a href=\"#{ref.as_href @from_path}\">#{text}</a>"
116
+ end
201
117
  end
202
118
 
203
119
  end