diff options
Diffstat (limited to 'lib/rdoc/markup/to_html_crossref.rb')
-rw-r--r-- | lib/rdoc/markup/to_html_crossref.rb | 208 |
1 files changed, 62 insertions, 146 deletions
diff --git a/lib/rdoc/markup/to_html_crossref.rb b/lib/rdoc/markup/to_html_crossref.rb index aeecc3f4d0..5175b79192 100644 --- a/lib/rdoc/markup/to_html_crossref.rb +++ b/lib/rdoc/markup/to_html_crossref.rb @@ -1,92 +1,19 @@ require 'rdoc/markup/to_html' +require 'rdoc/cross_reference' ## -# Subclass of the RDoc::Markup::ToHtml class that supports looking up words -# from a context. Those that are found will be hyperlinked. +# Subclass of the RDoc::Markup::ToHtml class that supports looking up method +# names, classes, etc to create links. RDoc::CrossReference is used to +# generate those links based on the current context. class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml - ## - # Regular expression to match class references - # - # 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 (not recommended) - - CLASS_REGEXP_STR = '\\\\?((?:\:{2})?[A-Z]\w*(?:\:\:\w+)*)' - - ## - # Regular expression to match method references. - # - # See CLASS_REGEXP_STR - - METHOD_REGEXP_STR = '([a-z]\w*[!?=]?)(?:\([\w.+*/=<>-]*\))?' - - ## - # Regular expressions matching text that should potentially have - # cross-reference links generated are passed to add_special. Note that - # these expressions are meant to pick up text for which cross-references - # have been suppressed, since the suppression characters are removed by the - # code that is triggered. - - CROSSREF_REGEXP = /( - # A::B::C.meth - #{CLASS_REGEXP_STR}(?:[.#]|::)#{METHOD_REGEXP_STR} - - # Stand-alone method (preceded by a #) - | \\?\##{METHOD_REGEXP_STR} - - # Stand-alone method (preceded by ::) - | ::#{METHOD_REGEXP_STR} - - # A::B::C - # The stuff after CLASS_REGEXP_STR is a - # nasty hack. CLASS_REGEXP_STR unfortunately matches - # words like dog and cat (these are legal "class" - # names in Fortran 95). When a word is flagged as a - # potential cross-reference, limitations in the markup - # engine suppress other processing, such as typesetting. - # This is particularly noticeable for contractions. - # 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-reference 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 - # one special character (period, slash, or - # underscore). - | (?:\.\.\/)*[-\/\w]+[_\/\.][-\w\/\.]+ - - # Things that have markup suppressed - # 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 + # :stopdoc: + ALL_CROSSREF_REGEXP = RDoc::CrossReference::ALL_CROSSREF_REGEXP + CLASS_REGEXP_STR = RDoc::CrossReference::CLASS_REGEXP_STR + CROSSREF_REGEXP = RDoc::CrossReference::CROSSREF_REGEXP + METHOD_REGEXP_STR = RDoc::CrossReference::METHOD_REGEXP_STR + # :startdoc: ## # RDoc::CodeObject for generating references @@ -102,7 +29,7 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml # 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. Only method names - # preceded by '#' or '::' are hyperlinked, unless +hyperlink_all+ is true. + # preceded by '#' or '::' are linked, unless +hyperlink_all+ is true. def initialize(from_path, context, show_hash, hyperlink_all = false, markup = nil) @@ -111,22 +38,36 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml crossref_re = hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP + @cross_reference = RDoc::CrossReference.new context + @markup.add_special crossref_re, :CROSSREF + @markup.add_special(/rdoc-ref:\S+\w/, :HYPERLINK) - @from_path = from_path - @context = context - @show_hash = show_hash + @from_path = from_path @hyperlink_all = hyperlink_all + @show_hash = show_hash + end + + ## + # Creates a link to the reference +name+ if the name exists. If +text+ is + # given it is used as the link text, otherwise +name+ is used. + + def cross_reference name, text = nil + lookup = name - @seen = {} + name = name[1..-1] unless @show_hash if name[0, 1] == '#' + + text = name unless text + + link lookup, text end ## # 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, ToHtml is found, even without the <tt>RDoc::Markup::</tt> - # prefix, because we look for it in module Markup first. + # corresponding reference, generate a link. If the name we're looking for + # contains no punctuation, we look for it up the module/class chain. 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 @@ -138,66 +79,41 @@ class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml return name if name =~ /\A[a-z]*\z/ end - return @seen[name] if @seen.include? name + cross_reference name + end - lookup = name + ## + # Handles <tt>rdoc-ref:</tt> scheme links and allows RDoc::Markup::ToHtml to + # handle other schemes. - name = name[1..-1] unless @show_hash if name[0, 1] == '#' + def handle_special_HYPERLINK special + return cross_reference $' if special.text =~ /\Ardoc-ref:/ - # Find class, module, or method in class or module. - # - # Do not, however, use an if/elsif/else chain to do so. Instead, test - # each possible pattern until one matches. The reason for this is that a - # string like "YAML.txt" could be the txt() class method of class YAML (in - # which case it would match the first pattern, which splits the string - # into container and method components and looks up both) or a filename - # (in which case it would match the last pattern, which just checks - # whether the string as a whole is a known symbol). - - if /#{CLASS_REGEXP_STR}([.#]|::)#{METHOD_REGEXP_STR}/ =~ lookup then - type = $2 - type = '' if type == '.' # will find either #method or ::method - method = "#{type}#{$3}" - 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 + super + end - if container then - ref = container.find_local_symbol method + ## + # Generates links for <tt>rdoc-ref:</tt> scheme URLs and allows + # RDoc::Markup::ToHtml to handle other schemes. - unless ref || RDoc::TopLevel === container then - ref = container.find_ancestor_local_symbol method - end - end + def gen_url url, text + super unless url =~ /\Ardoc-ref:/ - 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 - # 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 - lookup - end - - @seen[lookup] = out - - out + cross_reference $', text + end + + ## + # Creates an HTML link to +name+ with the given +text+. + + def link name, text + ref = @cross_reference.resolve name, text + + case ref + when String then + ref + else + "<a href=\"#{ref.as_href @from_path}\">#{text}</a>" + end end end |