1## 2# Subclass of the RDoc::Markup::ToHtml class that supports looking up method 3# names, classes, etc to create links. RDoc::CrossReference is used to 4# generate those links based on the current context. 5 6class RDoc::Markup::ToHtmlCrossref < RDoc::Markup::ToHtml 7 8 # :stopdoc: 9 ALL_CROSSREF_REGEXP = RDoc::CrossReference::ALL_CROSSREF_REGEXP 10 CLASS_REGEXP_STR = RDoc::CrossReference::CLASS_REGEXP_STR 11 CROSSREF_REGEXP = RDoc::CrossReference::CROSSREF_REGEXP 12 METHOD_REGEXP_STR = RDoc::CrossReference::METHOD_REGEXP_STR 13 # :startdoc: 14 15 ## 16 # RDoc::CodeObject for generating references 17 18 attr_accessor :context 19 20 ## 21 # Should we show '#' characters on method references? 22 23 attr_accessor :show_hash 24 25 ## 26 # Creates a new crossref resolver that generates links relative to +context+ 27 # which lives at +from_path+ in the generated files. '#' characters on 28 # references are removed unless +show_hash+ is true. Only method names 29 # preceded by '#' or '::' are linked, unless +hyperlink_all+ is true. 30 31 def initialize(options, from_path, context, markup = nil) 32 raise ArgumentError, 'from_path cannot be nil' if from_path.nil? 33 34 super options, markup 35 36 @context = context 37 @from_path = from_path 38 @hyperlink_all = @options.hyperlink_all 39 @show_hash = @options.show_hash 40 41 crossref_re = @hyperlink_all ? ALL_CROSSREF_REGEXP : CROSSREF_REGEXP 42 @markup.add_special crossref_re, :CROSSREF 43 44 @cross_reference = RDoc::CrossReference.new @context 45 end 46 47 ## 48 # Creates a link to the reference +name+ if the name exists. If +text+ is 49 # given it is used as the link text, otherwise +name+ is used. 50 51 def cross_reference name, text = nil 52 lookup = name 53 54 name = name[1..-1] unless @show_hash if name[0, 1] == '#' 55 56 name = "#{CGI.unescape $'} at #{$1}" if name =~ /(.*[^#:])@/ 57 58 text = name unless text 59 60 link lookup, text 61 end 62 63 ## 64 # We're invoked when any text matches the CROSSREF pattern. If we find the 65 # corresponding reference, generate a link. If the name we're looking for 66 # contains no punctuation, we look for it up the module/class chain. For 67 # example, ToHtml is found, even without the <tt>RDoc::Markup::</tt> prefix, 68 # because we look for it in module Markup first. 69 70 def handle_special_CROSSREF(special) 71 name = special.text 72 73 return name if name =~ /@[\w-]+\.[\w-]/ # labels that look like emails 74 75 unless @hyperlink_all then 76 # This ensures that words entirely consisting of lowercase letters will 77 # not have cross-references generated (to suppress lots of erroneous 78 # cross-references to "new" in text, for instance) 79 return name if name =~ /\A[a-z]*\z/ 80 end 81 82 cross_reference name 83 end 84 85 ## 86 # Handles <tt>rdoc-ref:</tt> scheme links and allows RDoc::Markup::ToHtml to 87 # handle other schemes. 88 89 def handle_special_HYPERLINK special 90 return cross_reference $' if special.text =~ /\Ardoc-ref:/ 91 92 super 93 end 94 95 ## 96 # +special+ is an rdoc-schemed link that will be converted into a hyperlink. 97 # For the rdoc-ref scheme the cross-reference will be looked up and the 98 # given name will be used. 99 # 100 # All other contents are handled by 101 # {the superclass}[rdoc-ref:RDoc::Markup::ToHtml#handle_special_RDOCLINK] 102 103 def handle_special_RDOCLINK special 104 url = special.text 105 106 case url 107 when /\Ardoc-ref:/ then 108 cross_reference $' 109 else 110 super 111 end 112 end 113 114 ## 115 # Generates links for <tt>rdoc-ref:</tt> scheme URLs and allows 116 # RDoc::Markup::ToHtml to handle other schemes. 117 118 def gen_url url, text 119 return super unless url =~ /\Ardoc-ref:/ 120 121 cross_reference $', text 122 end 123 124 ## 125 # Creates an HTML link to +name+ with the given +text+. 126 127 def link name, text 128 original_name = name 129 130 if name =~ /(.*[^#:])@/ then 131 name = $1 132 label = $' 133 end 134 135 ref = @cross_reference.resolve name, text 136 137 text = ref.output_name @context if 138 RDoc::MethodAttr === ref and text == original_name 139 140 case ref 141 when String then 142 ref 143 else 144 path = ref.as_href @from_path 145 146 if path =~ /#/ then 147 path << "-label-#{label}" 148 else 149 path << "#label-#{label}" 150 end if label 151 152 "<a href=\"#{path}\">#{text}</a>" 153 end 154 end 155 156end 157 158