1## 2# AnyMethod is the base class for objects representing methods 3 4class RDoc::AnyMethod < RDoc::MethodAttr 5 6 ## 7 # 2:: 8 # RDoc 4 9 # Added calls_super 10 # Added parent name and class 11 # Added section title 12 13 MARSHAL_VERSION = 2 # :nodoc: 14 15 ## 16 # Don't rename \#initialize to \::new 17 18 attr_accessor :dont_rename_initialize 19 20 ## 21 # The C function that implements this method (if it was defined in a C file) 22 23 attr_accessor :c_function 24 25 ## 26 # Different ways to call this method 27 28 attr_accessor :call_seq 29 30 ## 31 # Parameters for this method 32 33 attr_accessor :params 34 35 ## 36 # If true this method uses +super+ to call a superclass version 37 38 attr_accessor :calls_super 39 40 include RDoc::TokenStream 41 42 ## 43 # Creates a new AnyMethod with a token stream +text+ and +name+ 44 45 def initialize text, name 46 super 47 48 @c_function = nil 49 @dont_rename_initialize = false 50 @token_stream = nil 51 @calls_super = false 52 @superclass_method = nil 53 end 54 55 ## 56 # Adds +an_alias+ as an alias for this method in +context+. 57 58 def add_alias an_alias, context = nil 59 method = self.class.new an_alias.text, an_alias.new_name 60 61 method.record_location an_alias.file 62 method.singleton = self.singleton 63 method.params = self.params 64 method.visibility = self.visibility 65 method.comment = an_alias.comment 66 method.is_alias_for = self 67 @aliases << method 68 context.add_method method if context 69 method 70 end 71 72 ## 73 # Prefix for +aref+ is 'method'. 74 75 def aref_prefix 76 'method' 77 end 78 79 ## 80 # The call_seq or the param_seq with method name, if there is no call_seq. 81 # 82 # Use this for displaying a method's argument lists. 83 84 def arglists 85 if @call_seq then 86 @call_seq 87 elsif @params then 88 "#{name}#{param_seq}" 89 end 90 end 91 92 ## 93 # Dumps this AnyMethod for use by ri. See also #marshal_load 94 95 def marshal_dump 96 aliases = @aliases.map do |a| 97 [a.name, parse(a.comment)] 98 end 99 100 [ MARSHAL_VERSION, 101 @name, 102 full_name, 103 @singleton, 104 @visibility, 105 parse(@comment), 106 @call_seq, 107 @block_params, 108 aliases, 109 @params, 110 @file.relative_name, 111 @calls_super, 112 @parent.name, 113 @parent.class, 114 @section.title, 115 ] 116 end 117 118 ## 119 # Loads this AnyMethod from +array+. For a loaded AnyMethod the following 120 # methods will return cached values: 121 # 122 # * #full_name 123 # * #parent_name 124 125 def marshal_load array 126 initialize_visibility 127 128 @dont_rename_initialize = nil 129 @is_alias_for = nil 130 @token_stream = nil 131 @aliases = [] 132 @parent = nil 133 @parent_name = nil 134 @parent_class = nil 135 @section = nil 136 @file = nil 137 138 version = array[0] 139 @name = array[1] 140 @full_name = array[2] 141 @singleton = array[3] 142 @visibility = array[4] 143 @comment = array[5] 144 @call_seq = array[6] 145 @block_params = array[7] 146 # 8 handled below 147 @params = array[9] 148 # 10 handled below 149 @calls_super = array[11] 150 @parent_name = array[12] 151 @parent_title = array[13] 152 @section_title = array[14] 153 154 array[8].each do |new_name, comment| 155 add_alias RDoc::Alias.new(nil, @name, new_name, comment, @singleton) 156 end 157 158 @parent_name ||= if @full_name =~ /#/ then 159 $` 160 else 161 name = @full_name.split('::') 162 name.pop 163 name.join '::' 164 end 165 166 @file = RDoc::TopLevel.new array[10] if version > 0 167 end 168 169 ## 170 # Method name 171 # 172 # If the method has no assigned name, it extracts it from #call_seq. 173 174 def name 175 return @name if @name 176 177 @name = @call_seq[/^.*?\.(\w+)/, 1] || @call_seq if @call_seq 178 end 179 180 ## 181 # A list of this method's method and yield parameters. +call-seq+ params 182 # are preferred over parsed method and block params. 183 184 def param_list 185 if @call_seq then 186 params = @call_seq.split("\n").last 187 params = params.sub(/.*?\((.*)\)/, '\1') 188 params = params.sub(/(\{|do)\s*\|([^|]*)\|.*/, ',\2') 189 elsif @params then 190 params = @params.sub(/\((.*)\)/, '\1') 191 192 params << ",#{@block_params}" if @block_params 193 elsif @block_params then 194 params = @block_params 195 else 196 return [] 197 end 198 199 params = params.gsub(/\s+/, '').split ',' 200 201 params.map { |param| param.sub(/=.*/, '') } 202 end 203 204 ## 205 # Pretty parameter list for this method. If the method's parameters were 206 # given by +call-seq+ it is preferred over the parsed values. 207 208 def param_seq 209 if @call_seq then 210 params = @call_seq.split("\n").last 211 params = params.sub(/[^( ]+/, '') 212 params = params.sub(/(\|[^|]+\|)\s*\.\.\.\s*(end|\})/, '\1 \2') 213 elsif @params then 214 params = @params.gsub(/\s*\#.*/, '') 215 params = params.tr("\n", " ").squeeze(" ") 216 params = "(#{params})" unless params[0] == ?( 217 else 218 params = '' 219 end 220 221 if @block_params then 222 # If this method has explicit block parameters, remove any explicit 223 # &block 224 params.sub!(/,?\s*&\w+/, '') 225 226 block = @block_params.gsub(/\s*\#.*/, '') 227 block = block.tr("\n", " ").squeeze(" ") 228 if block[0] == ?( 229 block.sub!(/^\(/, '').sub!(/\)/, '') 230 end 231 params << " { |#{block}| ... }" 232 end 233 234 params 235 end 236 237 ## 238 # Sets the store for this method and its referenced code objects. 239 240 def store= store 241 super 242 243 @file = @store.add_file @file.full_name if @file 244 end 245 246 ## 247 # For methods that +super+, find the superclass method that would be called. 248 249 def superclass_method 250 return unless @calls_super 251 return @superclass_method if @superclass_method 252 253 parent.each_ancestor do |ancestor| 254 if method = ancestor.method_list.find { |m| m.name == @name } then 255 @superclass_method = method 256 break 257 end 258 end 259 260 @superclass_method 261 end 262 263end 264 265