Class: Multimethod::Signature
- Inherits:
-
Object
- Object
- Multimethod::Signature
- Includes:
- Comparable
- Defined in:
- lib/multimethod/signature.rb
Overview
Represents a method signature.
A Signature has a bound Module, a name and a Parameter list.
Each Parameter contributes to the scoring of the Method based on the message argument types, including the message receiver.
Instance Attribute Summary collapse
-
#class_method ⇒ Object
True if the signature is bound to the class.
-
#default ⇒ Object
An Array of all Parameters with a default value.
-
#file ⇒ Object
The file where this Signature is specified.
-
#line ⇒ Object
The line in the file where this Signature is specified.
-
#max_args ⇒ Object
The maximum # of arguments for this signature.
-
#min_args ⇒ Object
The minimum # of arguments for this signature.
-
#mod ⇒ Object
Returns the bound Module.
-
#name ⇒ Object
The name of the method.
-
#parameter ⇒ Object
The list of Parameters, self is included at position 0.
-
#restarg ⇒ Object
The “*args” parameter or nil.
-
#verbose ⇒ Object
Defines level of verbosity during processing.
Instance Method Summary collapse
-
#<=>(s) ⇒ Object
Compares two Signature objects.
-
#add_parameter(p) ⇒ Object
Adds a new Parameter.
-
#add_self ⇒ Object
Add the implicit “self” parameter at the front of the Parameter list.
-
#initialize(*opts) ⇒ Signature
constructor
Initialize a new Signature.
-
#inspect ⇒ Object
Calls #to_s.
-
#parameter_at(i) ⇒ Object
Returns the Parameter at argument position i.
-
#parameter_to_s(p = nil) ⇒ Object
Returns a String representing this Signature’s Parameters.
-
#scan_parameters(params) ⇒ Object
Scan a programmatic Parameter list:.
-
#scan_parameters_string(str, need_names = true) ⇒ Object
Scan the parameter string of a Signature:.
-
#scan_string(str, need_names = true) ⇒ Object
Scan a string as a Signature, e.g.: “def foo(A a, x = true, *restargs)”.
-
#score(args) ⇒ Object
Score of this Signature based on the argument types.
-
#score_cached(args) ⇒ Object
Score of this Signature using a cache.
-
#to_ruby_arg ⇒ Object
Returns a String representing this Signature’s definition parameters in Ruby syntax.
-
#to_ruby_def(name = nil) ⇒ Object
Returns a String representing this Signature’s definition in Ruby syntax.
-
#to_ruby_signature(name = nil) ⇒ Object
Returns a String representing this Signature’s definition in Ruby Doc syntax.
-
#to_s(name = nil) ⇒ Object
Returns a String representing this Signature.
Constructor Details
#initialize(*opts) ⇒ Signature
Initialize a new Signature.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/multimethod/signature.rb', line 49 def initialize(*opts) opts = Hash[*opts] @mod = opts[:mod] @name = opts[:name] @class_method = false @parameter = [ ] @min_args = 0 @max_args = 0 @restarg = nil @default = nil @multimethod = nil @verbose = nil @score = { } # Handle a string representation of a signature. case params = opts[:string] when String scan_string(params) end # Handle other parameters. case params = opts[:parameter] when Array scan_parameters(params) when String scan_parameters_string(params) end end |
Instance Attribute Details
#class_method ⇒ Object
True if the signature is bound to the class.
17 18 19 |
# File 'lib/multimethod/signature.rb', line 17 def class_method @class_method end |
#default ⇒ Object
An Array of all Parameters with a default value. Will be nil if there is not a Parameter with a default values.
37 38 39 |
# File 'lib/multimethod/signature.rb', line 37 def default @default end |
#file ⇒ Object
The file where this Signature is specified.
40 41 42 |
# File 'lib/multimethod/signature.rb', line 40 def file @file end |
#line ⇒ Object
The line in the file where this Signature is specified.
43 44 45 |
# File 'lib/multimethod/signature.rb', line 43 def line @line end |
#max_args ⇒ Object
The maximum # of arguments for this signature. May be nil, if this Signature accepts restargs.
30 31 32 |
# File 'lib/multimethod/signature.rb', line 30 def max_args @max_args end |
#min_args ⇒ Object
The minimum # of arguments for this signature.
26 27 28 |
# File 'lib/multimethod/signature.rb', line 26 def min_args @min_args end |
#mod ⇒ Object
Returns the bound Module.
14 15 16 |
# File 'lib/multimethod/signature.rb', line 14 def mod @mod end |
#name ⇒ Object
The name of the method.
20 21 22 |
# File 'lib/multimethod/signature.rb', line 20 def name @name end |
#parameter ⇒ Object
The list of Parameters, self is included at position 0.
23 24 25 |
# File 'lib/multimethod/signature.rb', line 23 def parameter @parameter end |
#restarg ⇒ Object
The “*args” parameter or nil.
33 34 35 |
# File 'lib/multimethod/signature.rb', line 33 def restarg @restarg end |
#verbose ⇒ Object
Defines level of verbosity during processing.
46 47 48 |
# File 'lib/multimethod/signature.rb', line 46 def verbose @verbose end |
Instance Method Details
#<=>(s) ⇒ Object
Compares two Signature objects.
84 85 86 87 88 89 90 |
# File 'lib/multimethod/signature.rb', line 84 def <=>(s) x = @name.to_s <=> s.name.to_s x = (! @class_method == ! s.class_method ? 0 : 1) if x == 0 x = @parameter <=> s.parameter if x == 0 # $stderr.puts "#{to_s} <=> #{s.to_s} => #{x.inspect}" x end |
#add_parameter(p) ⇒ Object
Adds a new Parameter.
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/multimethod/signature.rb', line 239 def add_parameter(p) if p.restarg raise("Too many restargs") if @restarg @restarg = p @max_args = nil end if p.default (@default ||= [ ]).push(p) end p.i = @parameter.size @parameter.push(p) p.signature = self unless p.default || p.restarg @min_args = @parameter.size end unless @restarg @max_args = @parameter.size end end |
#add_self ⇒ Object
Add the implicit “self” parameter at the front of the Parameter list.
233 234 235 |
# File 'lib/multimethod/signature.rb', line 233 def add_self add_parameter(Parameter.new('self', mod)) if @parameter.empty? end |
#inspect ⇒ Object
Calls #to_s.
364 365 366 |
# File 'lib/multimethod/signature.rb', line 364 def inspect to_s end |
#parameter_at(i) ⇒ Object
Returns the Parameter at argument position i. If the Signature has a restarg, it will be used for argument postitions past the end of the Parameter list.
314 315 316 317 318 319 320 |
# File 'lib/multimethod/signature.rb', line 314 def parameter_at(i) if i >= @parameter.size && @restarg @restarg else @parameter[i] end end |
#parameter_to_s(p = nil) ⇒ Object
Returns a String representing this Signature’s Parameters.
333 334 335 336 |
# File 'lib/multimethod/signature.rb', line 333 def parameter_to_s(p = nil) p ||= @parameter p.collect{|x| x.to_s}.join(', ') end |
#scan_parameters(params) ⇒ Object
Scan a programmatic Parameter list:
[ A, :a, B, :b, :c, '*d' ]
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/multimethod/signature.rb', line 199 def scan_parameters(params) # Add self parameter at front. add_self until params.empty? name = nil type = nil restarg = false default = nil if x = params.shift case x when Class type = x else name = x end end if ! name && (x = params.shift) name = x end raise("Parameter name expected, found #{name.inspect}") unless name.kind_of?(String) || name.kind_of?(Symbol) raise("Parameter type expected, found #{type.inspect}") unless type.kind_of?(Module) || type.nil? p = Parameter.new(name, type, default) add_parameter(p) end end |
#scan_parameters_string(str, need_names = true) ⇒ Object
Scan the parameter string of a Signature:
"A a, x = true, *restargs"
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/multimethod/signature.rb', line 158 def scan_parameters_string(str, need_names = true) # @verbose = true # Add self parameter at front. add_self $stderr.puts "scan_parameters_string(#{str.inspect})" if @verbose until str.empty? # Scan parameter p = Parameter.new p.verbose = @verbose str = p.scan_string(str) add_parameter(p) $stderr.puts " params=#{parameter_to_s}" if @verbose # Parse , or ) str.sub!(/\A\s+/, '') if ! str.empty? if md = /\A,/s.match(str) str = md.post_match elsif md = /\A\)/s.match(str) $stderr.puts " DONE: #{to_s}\n Remaining: #{str.inspect}" if @verbose break else raise NameError, "Syntax error in multimethod parameters: expected ',' or ')' at #{str.inspect}" end end end $stderr.puts "scan_parameters_string(...): DONE: #{to_s}\n Remaining: #{str}" if @verbose str end |
#scan_string(str, need_names = true) ⇒ Object
Scan a string as a Signature, e.g.: “def foo(A a, x = true, *restargs)”
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/multimethod/signature.rb', line 108 def scan_string(str, need_names = true) str.sub!(/\A\s+/, '') if md = /\A(\w+(::\w+)*)#(\w+)/.match(str) str = md.post_match @mod = md[1] unless @mod @name = md[3] elsif md = /\A(\w+(::\w+)*)\.(\w+)/.match(str) str = md.post_match @mod = md[1] unless @mod @class_method = true @name = md[3] elsif md = /\A((\w+(::\w+)*)\s+)?def\s+(self\.)?(\w+)/.match(str) str = md.post_match @mod = md[2] unless @mod @class_method = ! ! md[4] @name = md[5] else raise NameError, "Syntax error in multimethod signature at #{str.inspect}" end # Resolve mod name. # FIXME! # Add self parameter. add_self # Parse parameter list. if md = /\A\(/.match(str) str = md.post_match str = scan_parameters_string(str, need_names) $stderr.puts " str=#{str.inspect}" if @verbose if md = /\A\)/.match(str) str = md.post_match else raise NameError, "Syntax error in multimethod parameters expected ')' at #{str.inspect}" end end str end |
#score(args) ⇒ Object
Score of this Signature based on the argument types.
The score is an Array of values that when sorted against other Signature scores will place the best matching Signature at the top of the list.
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
# File 'lib/multimethod/signature.rb', line 268 def score(args) if @min_args > args.size # Not enough args score = nil elsif @max_args && @max_args < args.size # Too many args? # $stderr.puts "max_args = #{@max_args}, args.size = #{args.size}" score = nil else # Interpret how close the argument type is to the parameter's type. i = -1 score = args.collect{|a| parameter_at(i = i + 1).score(a)} # Handle score for trailing restargs. if @restarg || @default while (i = i + 1) < @parameter.size # $stderr.puts " Adding score i=#{i}" # nil means there is no argument for this parameter. score << parameter_at(i).score(nil) end end # If any argument cannot match, avoid this method entirely. score.flatten! score = nil if score.index(nil) end # $stderr.puts " score(#{to_s}, #{args.inspect} => #{score.inspect})" score end |
#score_cached(args) ⇒ Object
Score of this Signature using a cache.
302 303 304 305 306 307 308 |
# File 'lib/multimethod/signature.rb', line 302 def score_cached(args) unless x = @score[args] x = @score[args] = score(args) end x end |
#to_ruby_arg ⇒ Object
Returns a String representing this Signature’s definition parameters in Ruby syntax.
357 358 359 360 361 |
# File 'lib/multimethod/signature.rb', line 357 def to_ruby_arg x = @parameter.clone x.shift x.collect{|x| x.to_ruby_arg}.join(', ') end |
#to_ruby_def(name = nil) ⇒ Object
Returns a String representing this Signature’s definition in Ruby syntax.
340 341 342 343 |
# File 'lib/multimethod/signature.rb', line 340 def to_ruby_def(name = nil) name ||= @name || '_' "def #{name}(#{to_ruby_arg})" end |
#to_ruby_signature(name = nil) ⇒ Object
Returns a String representing this Signature’s definition in Ruby Doc syntax.
347 348 349 350 351 352 353 |
# File 'lib/multimethod/signature.rb', line 347 def to_ruby_signature(name = nil) name ||= @name || '_' p = @parameter.clone rcvr = p.shift m = mod "#{m && m.name}##{name}(#{to_ruby_arg})" end |
#to_s(name = nil) ⇒ Object
Returns a String representing this Signature.
324 325 326 327 328 329 |
# File 'lib/multimethod/signature.rb', line 324 def to_s(name = nil) name ||= @name || '_' p = @parameter.clone rcvr = p.shift "#{rcvr.type.name}##{name}(#{parameter_to_s(p)})" end |