Class: Object
- Inherits:
- BasicObject
- Defined in:
- lib/rdl/wrap.rb,
lib/rdl/query.rb,
lib/rdl_disable.rb,
lib/types/core-ruby-2.x/object.rb
Class Method Summary collapse
Instance Method Summary collapse
-
#attr_accessor_type(*args) ⇒ Object
In the following three methods [+ args +] is a sequence of symbol, typ.
- #attr_reader_type(*args) ⇒ Object (also: #attr_type)
- #attr_writer_type(*args) ⇒ Object
- #deinstantaite!(*args) ⇒ Object
- #deinstantiate! ⇒ Object
- #instantaite!(*args) ⇒ Object
-
#instantiate!(*typs) ⇒ Object
typs-
is an array of types, classes, symbols, or strings to instantiate the type parameters.
-
#post(*args) ⇒ Object
Add a postcondition to a method.
-
#pre(*args) ⇒ Object
klass-
may be Class, Symbol, or String [
method] may be Symbol or String [contract] must be a Contract [wrap] indicates whether the contract should be enforced (true) or just recorded (false).
-
#rdl_alias(*args) ⇒ Object
Aliases contracts for meth_old and meth_new.
-
#rdl_at(sym, &blk) ⇒ Object
Register [+ blk ] to be executed when ‘rdl_do_typecheck [ sym +]` is called.
-
#rdl_do_typecheck(*args) ⇒ Object
Invokes all callbacks from rdl_at(sym), in unspecified order.
-
#rdl_note_type(*args) ⇒ Object
Does nothing at run time.
- #rdl_nowrap(*args) ⇒ Object
- #rdl_query(q) ⇒ Object
- #rdl_remove_type(*args) ⇒ Object
-
#type(*args) ⇒ Object
- + klass +
-
may be Class, Symbol, or String [+ method ] may be Symbol or String [ type ] may be Type or String [ wrap ] indicates whether the type should be enforced (true) or just recorded (false) [ typecheck +] indicates a method that should be statically type checked, as follows if :call, indicates method should be typechecked when called if :now, indicates method should be typechecked immediately if other-symbol, indicates method should be typechecked when rdl_do_typecheck(other-symbol) is called.
-
#type_alias(*args) ⇒ Object
Add a new type alias.
-
#type_cast(*args) ⇒ Object
Returns a new object that wraps self in a type cast.
-
#type_params(*args) ⇒ Object
params-
is an array of symbols or strings that are the parameters of this (generic) type [
variance] is an array of the corresponding variances, :+ for covariant, :- for contravariant, and :~ for invariant.
-
#var_type(*args) ⇒ Object
- + klass +
-
is the class containing the variable; self if omitted; ignored for local and global variables [+ var ] is a symbol or string containing the name of the variable [ typ +] is a string containing the type.
Class Method Details
.method_added(meth) ⇒ Object
397 398 399 400 401 402 |
# File 'lib/rdl/wrap.rb', line 397 def self.method_added(meth) klass = self.to_s klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main") RDL::Wrap.do_method_added(self, false, klass, meth) nil end |
.singleton_method_added(meth) ⇒ Object
404 405 406 407 408 409 410 |
# File 'lib/rdl/wrap.rb', line 404 def self.singleton_method_added(meth) klass = self.to_s klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main") sklass = RDL::Util.add_singleton_marker(klass) RDL::Wrap.do_method_added(self, true, sklass, meth) nil end |
Instance Method Details
#attr_accessor_type(*args) ⇒ Object
In the following three methods
- + args +
-
is a sequence of symbol, typ. attr_reader is called for each symbol,
and var_type is called to assign the immediately following type to the attribute named after that symbol.
367 368 369 370 371 372 373 374 375 |
# File 'lib/rdl/wrap.rb', line 367 def attr_accessor_type(*args) args.each_slice(2) { |name, typ| attr_accessor name var_type ("@" + name.to_s), typ type name, "() -> #{typ}" type name.to_s + "=", "(#{typ}) -> #{typ}" } nil end |
#attr_reader_type(*args) ⇒ Object Also known as: attr_type
377 378 379 380 381 382 383 384 |
# File 'lib/rdl/wrap.rb', line 377 def attr_reader_type(*args) args.each_slice(2) { |name, typ| attr_reader name var_type ("@" + name.to_s), typ type name, "() -> #{typ}" } nil end |
#attr_writer_type(*args) ⇒ Object
388 389 390 391 392 393 394 395 |
# File 'lib/rdl/wrap.rb', line 388 def attr_writer_type(*args) args.each_slice(2) { |name, typ| attr_writer name var_type ("@" + name.to_s), typ type name.to_s + "=", "(#{typ}) -> #{typ}" } nil end |
#deinstantaite!(*args) ⇒ Object
16 |
# File 'lib/rdl_disable.rb', line 16 def deinstantaite!(*args); self; end |
#deinstantiate! ⇒ Object
504 505 506 507 508 509 |
# File 'lib/rdl/wrap.rb', line 504 def deinstantiate! raise RuntimeError, "Class #{self.to_s} is not parameterized" unless $__rdl_type_params[klass] raise RuntimeError, "Instance is not instantiated" unless @__rdl_type && @@__rdl_type.instance_of?(RDL::Type::GenericType) @__rdl_type = nil self end |
#instantaite!(*args) ⇒ Object
15 |
# File 'lib/rdl_disable.rb', line 15 def instantaite!(*args); self; end |
#instantiate!(*typs) ⇒ Object
typs-
is an array of types, classes, symbols, or strings to instantiate
the type parameters. If a class, symbol, or string is given, it is converted to a NominalType.
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 |
# File 'lib/rdl/wrap.rb', line 476 def instantiate!(*typs) klass = self.class.to_s klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main") formals, _, all = $__rdl_type_params[klass] raise RuntimeError, "Receiver is of class #{klass}, which is not parameterized" unless formals raise RuntimeError, "Expecting #{params.size} type parameters, got #{typs.size}" unless formals.size == typs.size raise RuntimeError, "Instance already has type instantiation" if (defined? @__rdl_type) && @rdl_type new_typs = typs.map { |t| if t.is_a? RDL::Type::Type then t else $__rdl_parser.scan_str "#T #{t}" end } t = RDL::Type::GenericType.new(RDL::Type::NominalType.new(klass), *new_typs) if all.instance_of? Symbol self.send(all) { |*objs| new_typs.zip(objs).each { |nt, obj| if nt.instance_of? RDL::Type::GenericType # require obj to be instantiated t_obj = RDL::Util.rdl_type(obj) raise RDL::Type::TypeError, "Expecting element of type #{nt.to_s}, but got uninstantiated object #{obj.inspect}" unless t_obj raise RDL::Type::TypeError, "Expecting type #{nt.to_s}, got type #{t_obj.to_s}" unless t_obj <= nt else raise RDL::Type::TypeError, "Expecting type #{nt.to_s}, got #{obj.inspect}" unless nt.member? obj end } } else raise RDL::Type::TypeError, "Not an instance of #{t}" unless instance_exec(*new_typs, &all) end @__rdl_type = t self end |
#post(*args) ⇒ Object
Add a postcondition to a method. Same possible invocations as pre.
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 |
# File 'lib/rdl/wrap.rb', line 275 def post(*args, wrap: RDL::Config.instance.post_defaults[:wrap], &blk) klass, meth, contract = RDL::Wrap.process_pre_post_args(self, "Postcondition", *args, &blk) if meth $__rdl_info.add(klass, meth, :post, contract) if wrap if RDL::Util.method_defined?(klass, meth) || meth == :initialize RDL::Wrap.wrap(klass, meth) else $__rdl_to_wrap << [klass, meth] end end else $__rdl_deferred << [klass, :post, contract, {wrap: wrap}] end nil end |
#pre(*args) ⇒ Object
klass-
may be Class, Symbol, or String
method-
may be Symbol or String
contract-
must be a Contract
wrap-
indicates whether the contract should be enforced (true) or just recorded (false)
Add a precondition to a method. Possible invocations: pre(klass, meth, contract) pre(klass, meth) { block } = pre(klass, meth, FlatContract.new { block }) pre(meth, contract) = pre(self, meth, contract) pre(meth) { block } = pre(self, meth, FlatContract.new { block }) pre(contract) = pre(self, next method, contract) pre { block } = pre(self, next method, FlatContract.new { block })
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 |
# File 'lib/rdl/wrap.rb', line 257 def pre(*args, wrap: RDL::Config.instance.pre_defaults[:wrap], &blk) klass, meth, contract = RDL::Wrap.process_pre_post_args(self, "Precondition", *args, &blk) if meth $__rdl_info.add(klass, meth, :pre, contract) if wrap if RDL::Util.method_defined?(klass, meth) || meth == :initialize # there is always an initialize RDL::Wrap.wrap(klass, meth) else $__rdl_to_wrap << [klass, meth] end end else $__rdl_deferred << [klass, :pre, contract, {wrap: wrap}] end nil end |
#rdl_alias(*args) ⇒ Object
Aliases contracts for meth_old and meth_new. Currently, this must be called for any aliases or they will not be wrapped with contracts. Only creates aliases in the current class.
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 |
# File 'lib/rdl/wrap.rb', line 415 def rdl_alias(new_name, old_name) klass = self.to_s klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main") $__rdl_aliases[klass] = {} unless $__rdl_aliases[klass] if $__rdl_aliases[klass][new_name] raise RuntimeError, "Tried to alias #{new_name}, already aliased to #{$__rdl_aliases[klass][new_name]}" end $__rdl_aliases[klass][new_name] = old_name if self.method_defined? new_name RDL::Wrap.wrap(klass, new_name) else $__rdl_to_wrap << [klass, old_name] end nil end |
#rdl_at(sym, &blk) ⇒ Object
Register [+ blk ] to be executed when ‘rdl_do_typecheck [ sym +]` is called. The blk will be called with sym as its argument. The order in which multiple blks for the same sym will be executed is unspecified
541 542 543 544 |
# File 'lib/rdl/wrap.rb', line 541 def rdl_at(sym, &blk) $__rdl_at[sym] = [] unless $__rdl_at[sym] $__rdl_at[sym] << blk end |
#rdl_do_typecheck(*args) ⇒ Object
Invokes all callbacks from rdl_at(sym), in unspecified order. Afterwards, type checks all methods that had annotation ‘typecheck: sym’ at type call, in unspecified order.
548 549 550 551 552 553 554 555 556 557 558 559 |
# File 'lib/rdl/wrap.rb', line 548 def rdl_do_typecheck(sym) if $__rdl_at[sym] $__rdl_at[sym].each { |blk| blk.call(sym) } end $__rdl_at[sym] = Array.new return unless $__rdl_to_typecheck[sym] $__rdl_to_typecheck[sym].each { |klass, meth| RDL::Typecheck.typecheck(klass, meth) } $__rdl_to_typecheck[sym] = Set.new nil end |
#rdl_note_type(*args) ⇒ Object
Does nothing at run time
562 563 564 |
# File 'lib/rdl/wrap.rb', line 562 def rdl_note_type(x) return x end |
#rdl_nowrap(*args) ⇒ Object
468 469 470 471 |
# File 'lib/rdl/wrap.rb', line 468 def rdl_nowrap RDL.config { |config| config.add_nowrap(self, self.singleton_class) } nil end |
#rdl_query(q) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/rdl/query.rb', line 72 def rdl_query(q) $__rdl_contract_switch.off { if q =~ /^[A-Z]\w*(#|\.)([a-z_]\w*(!|\?|=)?|!|~|\+|\*\*|-|\*|\/|%|<<|>>|&|\||\^|<|<=|=>|>|==|===|!=|=~|!~|<=>|\[\]|\[\]=)$/ typs = RDL::Query.method_query(q) if typs.nil? then puts "No types for #{q}" else typs.each { |t| puts "#{q}: #{t}" } end elsif q =~ /^[A-Z]\w*$/ typs = RDL::Query.class_query(q) if typs.nil? then puts "No method types for #{q}" else typs.each { |m, t| puts "#{m}: #{t}"} end elsif q =~ /\(.*\)/ typs = RDL::Query.method_type_query(q) if typs.empty? then puts "No matching methods" else typs.each { |m, t| puts "#{m}: #{t}" } end else raise "Don't know how to handle query" end nil } end |
#rdl_remove_type(*args) ⇒ Object
566 567 568 569 570 |
# File 'lib/rdl/wrap.rb', line 566 def rdl_remove_type(klass, meth) raise RuntimeError, "No existing type for #{RDL::Util.pp_klass_method(klass, meth)}" unless $__rdl_info.has? klass, meth, :type $__rdl_info.remove klass, meth, :type nil end |
#type(*args) ⇒ Object
- + klass +
-
may be Class, Symbol, or String
- + method +
-
may be Symbol or String
- + type +
-
may be Type or String
- + wrap +
-
indicates whether the type should be enforced (true) or just recorded (false)
- + typecheck +
-
indicates a method that should be statically type checked, as follows
if :call, indicates method should be typechecked when called
if :now, indicates method should be typechecked immediately
if other-symbol, indicates method should be typechecked when rdl_do_typecheck(other-symbol) is called
Set a method’s type. Possible invocations: type(klass, meth, type) type(meth, type) type(type)
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 |
# File 'lib/rdl/wrap.rb', line 305 def type(*args, wrap: RDL::Config.instance.type_defaults[:wrap], typecheck: RDL::Config.instance.type_defaults[:typecheck]) klass, meth, type = begin RDL::Wrap.process_type_args(self, *args) rescue Racc::ParseError => err # Remove enough backtrace to only include actual source line # Warning: Adjust the -5 below if the code (or this comment) changes bt = err.backtrace bt.shift until bt[0] =~ /^#{__FILE__}:#{__LINE__-5}/ bt.shift # remove $__rdl_contract_switch.off call bt.shift # remove type call itself err.set_backtrace bt raise err end if meth # It turns out Ruby core/stdlib don't always follow this convention... # if (meth.to_s[-1] == "?") && (type.ret != $__rdl_type_bool) # warn "#{RDL::Util.pp_klass_method(klass, meth)}: methods that end in ? should have return type %bool" # end $__rdl_info.add(klass, meth, :type, type) unless $__rdl_info.set(klass, meth, :typecheck, typecheck) raise RuntimeError, "Inconsistent typecheck flag on #{RDL::Util.pp_klass_method(klass, meth)}" end if wrap || typecheck == :now if RDL::Util.method_defined?(klass, meth) || meth == :initialize $__rdl_info.set(klass, meth, :source_location, RDL::Util.to_class(klass).instance_method(meth).source_location) RDL::Typecheck.typecheck(klass, meth) if typecheck == :now RDL::Wrap.wrap(klass, meth) if wrap else if wrap $__rdl_to_wrap << [klass, meth] if (typecheck && typecheck != :call) $__rdl_to_typecheck[typecheck] = Set.new unless $__rdl_to_typecheck[typecheck] $__rdl_to_typecheck[typecheck].add([klass, meth]) end end end end else $__rdl_deferred << [klass, :type, type, {wrap: wrap, typecheck: typecheck}] end nil end |
#type_alias(*args) ⇒ Object
Add a new type alias.
name-
must be a string beginning with %.
typ-
can be either a string, in which case it will be parsed
into a type, or a Type.
524 525 526 527 528 529 530 531 532 533 534 535 536 |
# File 'lib/rdl/wrap.rb', line 524 def type_alias(name, typ) raise RuntimeError, "Attempt to redefine type #{name}" if $__rdl_special_types[name] case typ when String t = $__rdl_parser.scan_str "#T #{typ}" $__rdl_special_types[name] = t when RDL::Type::Type $__rdl_special_types[name] = typ else raise RuntimeError, "Unexpected typ argument #{typ.inspect}" end nil end |
#type_cast(*args) ⇒ Object
Returns a new object that wraps self in a type cast. If force is true this cast is unchecked, so use with caution
512 513 514 515 516 517 518 |
# File 'lib/rdl/wrap.rb', line 512 def type_cast(typ, force: false) new_typ = if typ.is_a? RDL::Type::Type then typ else $__rdl_parser.scan_str "#T #{typ}" end raise RuntimeError, "type cast error: self not a member of #{new_typ}" unless force || typ.member?(self) obj = SimpleDelegator.new(self) obj.instance_variable_set('@__rdl_type', new_typ) obj end |
#type_params(*args) ⇒ Object
params-
is an array of symbols or strings that are the
parameters of this (generic) type
variance-
is an array of the corresponding variances, :+ for
covariant, :- for contravariant, and :~ for invariant. If omitted, all parameters are assumed to be invariant
all-
should be a symbol naming an all? method that behaves like Array#all?, and that accepts
a block that takes arguments in the same order as the type parameters
blk-
is for advanced use only. If present, [
all] must be
nil. Whenever an instance of this class is instantiated!, the block will be passed an array typs corresponding to the type parameters of the class, and the block should return true if and only if self is a member of self.class<typs>.
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 |
# File 'lib/rdl/wrap.rb', line 445 def type_params(params, all, variance: nil, &blk) raise RuntimeError, "Empty type parameters not allowed" if params.empty? klass = self.to_s klass = "Object" if (klass.is_a? Object) && (klass.to_s == "main") if $__rdl_type_params[klass] raise RuntimeError, "#{klass} already has type parameters #{$__rdl_type_params[klass]}" end params = params.map { |v| raise RuntimeError, "Type parameter #{v.inspect} is not symbol or string" unless v.class == String || v.class == Symbol v.to_sym } raise RuntimeError, "Duplicate type parameters not allowed" unless params.uniq.size == params.size raise RuntimeError, "Expecting #{params.size} variance annotations, got #{variance.size}" if variance && params.size != variance.size raise RuntimeError, "Only :+, +-, and :~ are allowed variance annotations" unless (not variance) || variance.all? { |v| [:+, :-, :~].member? v } raise RuntimeError, "Can't pass both all and a block" if all && blk raise RuntimeError, "all must be a symbol" unless (not all) || (all.instance_of? Symbol) chk = all || blk raise RuntimeError, "At least one of {all, blk} required" unless chk variance = params.map { |p| :~ } unless variance # default to invariant $__rdl_type_params[klass] = [params, variance, chk] nil end |
#var_type(*args) ⇒ Object
- + klass +
-
is the class containing the variable; self if omitted; ignored for local and global variables
- + var +
-
is a symbol or string containing the name of the variable
- + typ +
-
is a string containing the type
352 353 354 355 356 357 358 359 360 361 |
# File 'lib/rdl/wrap.rb', line 352 def var_type(klass=self, var, typ) raise RuntimeError, "Variable cannot begin with capital" if var.to_s =~ /^[A-Z]/ return if var.to_s =~ /^[a-z]/ # local variables handled specially, inside type checker raise RuntimeError, "Global variables can't be typed in a class" unless klass = self klass = RDL::Util::GLOBAL_NAME if var.to_s =~ /^\$/ unless $__rdl_info.set(klass, var, :type, $__rdl_parser.scan_str("#T #{typ}")) raise RuntimeError, "Type already declared for #{var}" end nil end |