diff options
Diffstat (limited to 'lib/rdoc/markup/to_html_crossref.rb')
-rw-r--r-- | lib/rdoc/markup/to_html_crossref.rb | 109 |
1 files changed, 82 insertions, 27 deletions
diff --git a/lib/rdoc/markup/to_html_crossref.rb b/lib/rdoc/markup/to_html_crossref.rb index 44e71486fb..a3feb848a2 100644 --- a/lib/rdoc/markup/to_html_crossref.rb +++ b/lib/rdoc/markup/to_html_crossref.rb @@ -9,10 +9,10 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml ## # Regular expression to match class references # - # 1) There can be a '\' in front of text to suppress any cross-references - # 2) There can be a '::' in front of class names to reference from the + # 1. There can be a '\\' in front of text to suppress the cross-reference + # 2. There can be a '::' in front of class names to reference from the # top-level namespace. - # 3) The method can be followed by parenthesis + # 3. The method can be followed by parenthesis (not recommended) CLASS_REGEXP_STR = '\\\\?((?:\:{2})?[A-Z]\w*(?:\:\:\w+)*)' @@ -34,10 +34,10 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml # A::B::C.meth #{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR} - # Stand-alone method (proceeded by a #) + # Stand-alone method (preceeded by a #) | \\?\##{METHOD_REGEXP_STR} - # Stand-alone method (proceeded by ::) + # Stand-alone method (preceeded by ::) | ::#{METHOD_REGEXP_STR} # A::B::C @@ -51,9 +51,10 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml # In order that words like "can't" not # be flagged as potential cross-references, only # flag potential class cross-references if the character - # after the cross-referece is a space or sentence - # punctuation. - | #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;]|\z) + # after the cross-referece is a space, sentence + # punctuation, tag start character, or attribute + # marker. + | #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;<\000]|\z) # Things that look like filenames # The key thing is that there must be at least @@ -62,7 +63,29 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml | (?:\.\.\/)*[-\/\w]+[_\/\.][-\w\/\.]+ # Things that have markup suppressed - | \\[^\s] + # Don't process things like '\<' in \<tt>, though. + # TODO: including < is a hack, not very satisfying. + | \\[^\s<] + )/x + + ## + # Version of CROSSREF_REGEXP used when <tt>--hyperlink-all</tt> is specified. + + ALL_CROSSREF_REGEXP = /( + # A::B::C.meth + #{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR} + + # Stand-alone method + | \\?#{METHOD_REGEXP_STR} + + # A::B::C + | #{CLASS_REGEXP_STR}(?=[\s\)\.\?\!\,\;<\000]|\z) + + # Things that look like filenames + | (?:\.\.\/)*[-\/\w]+[_\/\.][-\w\/\.]+ + + # Things that have markup suppressed + | \\[^\s<] )/x ## @@ -71,19 +94,28 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml attr_accessor :context ## + # Should we show '#' characters on method references? + + attr_accessor :show_hash + + ## # Creates a new crossref resolver that generates links relative to +context+ # which lives at +from_path+ in the generated files. '#' characters on - # references are removed unless +show_hash+ is true. + # references are removed unless +show_hash+ is true. Only method names + # preceded by '#' or '::' are hyperlinked, unless +hyperlink_all+ is true. - def initialize(from_path, context, show_hash) + def initialize(from_path, context, show_hash, hyperlink_all = false) raise ArgumentError, 'from_path cannot be nil' if from_path.nil? super() - @markup.add_special(CROSSREF_REGEXP, :CROSSREF) + crossref_re = hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP + + @markup.add_special crossref_re, :CROSSREF @from_path = from_path @context = context @show_hash = show_hash + @hyperlink_all = hyperlink_all @seen = {} end @@ -92,22 +124,24 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml # We're invoked when any text matches the CROSSREF pattern. If we find the # corresponding reference, generate a hyperlink. If the name we're looking # for contains no punctuation, we look for it up the module/class chain. - # For example, HyperlinkHtml is found, even without the Generator:: prefix, - # because we look for it in module Generator first. + # For example, ToHtml is found, even without the <tt>RDoc::Markup::</tt> + # prefix, because we look for it in module Markup first. def handle_special_CROSSREF(special) name = special.text - # This ensures that words entirely consisting of lowercase letters will - # not have cross-references generated (to suppress lots of erroneous - # cross-references to "new" in text, for instance) - return name if name =~ /\A[a-z]*\z/ + unless @hyperlink_all then + # This ensures that words entirely consisting of lowercase letters will + # not have cross-references generated (to suppress lots of erroneous + # cross-references to "new" in text, for instance) + return name if name =~ /\A[a-z]*\z/ + end return @seen[name] if @seen.include? name lookup = name - name = name[0, 1] unless @show_hash if name[0, 1] == '#' + name = name[1..-1] unless @show_hash if name[0, 1] == '#' # Find class, module, or method in class or module. # @@ -120,26 +154,47 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml # whether the string as a whole is a known symbol). if /#{CLASS_REGEXP_STR}([.#]|::)#{METHOD_REGEXP_STR}/ =~ lookup then - container = $1 type = $2 - type = '#' if type == '.' + type = '' if type == '.' # will find either #method or ::method method = "#{type}#{$3}" - ref = @context.find_symbol container, method + container = @context.find_symbol_module($1) + elsif /^([.#]|::)#{METHOD_REGEXP_STR}/ =~ lookup then + type = $1 + type = '' if type == '.' + method = "#{type}#{$2}" + container = @context + else + container = nil + end + + if container then + ref = container.find_local_symbol method + + unless ref || RDoc::TopLevel === container then + ref = container.find_ancestor_local_symbol method + end end ref = @context.find_symbol lookup unless ref + ref = nil if RDoc::Alias === ref # external alias: can't link to it out = if lookup == '\\' then lookup elsif lookup =~ /^\\/ then - $' - elsif ref and ref.document_self then - "<a href=\"#{ref.as_href @from_path}\">#{name}</a>" + # we remove the \ only in front of what we know: + # other backslashes are treated later, only outside of <tt> + ref ? $' : lookup + elsif ref then + if ref.document_self then + "<a href=\"#{ref.as_href @from_path}\">#{name}</a>" + else + name + end else - name + lookup end - @seen[name] = out + @seen[lookup] = out out end |