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.
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 |
# File 'lib/multimethod/signature.rb', line 247 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.
241 242 243 |
# File 'lib/multimethod/signature.rb', line 241 def add_self add_parameter(Parameter.new('self', mod)) if @parameter.empty? end |
#inspect ⇒ Object
Calls #to_s.
372 373 374 |
# File 'lib/multimethod/signature.rb', line 372 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.
322 323 324 325 326 327 328 |
# File 'lib/multimethod/signature.rb', line 322 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.
341 342 343 344 |
# File 'lib/multimethod/signature.rb', line 341 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' ]
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
# File 'lib/multimethod/signature.rb', line 207 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"
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 193 194 195 196 197 198 199 200 |
# File 'lib/multimethod/signature.rb', line 166 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 153 154 155 156 157 158 159 160 |
# File 'lib/multimethod/signature.rb', line 108 def scan_string(str, need_names = true) str.sub!(/\A\s+/, '') if @mod && md = /\Adef\s+(self\.)?([^\s\(]+)/.match(str) str = md.post_match @class_method = ! ! md[1] @name = md[2] elsif @mod && md = /\A(self\.)?([^\s\(]+)/.match(str) str = md.post_match @class_method = ! ! md[1] @name = md[2] elsif md = /\A(\w+(::\w+)*)#([^\s\(]+)/.match(str) str = md.post_match @mod = md[1] unless @mod @name = md[3] elsif md = /\A(\w+(::\w+)*)\.([^\s\(]+)/.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\.)?([^\s\(]+)/.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.
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
# File 'lib/multimethod/signature.rb', line 276 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.
310 311 312 313 314 315 316 |
# File 'lib/multimethod/signature.rb', line 310 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.
365 366 367 368 369 |
# File 'lib/multimethod/signature.rb', line 365 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.
348 349 350 351 |
# File 'lib/multimethod/signature.rb', line 348 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.
355 356 357 358 359 360 361 |
# File 'lib/multimethod/signature.rb', line 355 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.
332 333 334 335 336 337 |
# File 'lib/multimethod/signature.rb', line 332 def to_s(name = nil) name ||= @name || '_' p = @parameter.clone rcvr = p.shift "#{rcvr.type.name}##{name}(#{parameter_to_s(p)})" end |