rdl 1.0.0 → 1.0.1.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/README.md +75 -12
- data/bin/rdl_query +24 -0
- data/lib/rdl.rb +2 -1
- data/lib/rdl/query.rb +96 -0
- data/lib/rdl/types/annotated_arg.rb +4 -1
- data/lib/rdl/types/dots_query.rb +26 -0
- data/lib/rdl/types/finitehash.rb +11 -3
- data/lib/rdl/types/generic.rb +8 -2
- data/lib/rdl/types/intersection.rb +10 -3
- data/lib/rdl/types/lexer.rex +4 -1
- data/lib/rdl/types/lexer.rex.rb +11 -2
- data/lib/rdl/types/method.rb +41 -4
- data/lib/rdl/types/nil.rb +8 -2
- data/lib/rdl/types/nominal.rb +8 -2
- data/lib/rdl/types/optional.rb +9 -3
- data/lib/rdl/types/parser.racc +10 -6
- data/lib/rdl/types/parser.tab.rb +305 -257
- data/lib/rdl/types/singleton.rb +10 -3
- data/lib/rdl/types/structural.rb +9 -2
- data/lib/rdl/types/top.rb +9 -3
- data/lib/rdl/types/tuple.rb +9 -3
- data/lib/rdl/types/type_query.rb +5 -0
- data/lib/rdl/types/union.rb +11 -4
- data/lib/rdl/types/var.rb +6 -0
- data/lib/rdl/types/vararg.rb +8 -2
- data/lib/rdl/types/wild_query.rb +28 -0
- data/lib/rdl/util.rb +18 -5
- data/lib/rdl/wrap.rb +3 -37
- data/rdl.gemspec +3 -2
- data/test/test_parser.rb +24 -24
- data/test/test_query.rb +108 -0
- data/test/test_rdl.rb +4 -4
- data/types/ruby-2.x/file.rb +3 -1
- data/types/ruby-2.x/fileutils.rb +2 -2
- metadata +13 -6
data/lib/rdl/types/singleton.rb
CHANGED
@@ -6,7 +6,7 @@ module RDL::Type
|
|
6
6
|
|
7
7
|
@@cache = {}
|
8
8
|
@@cache.compare_by_identity
|
9
|
-
|
9
|
+
|
10
10
|
class << self
|
11
11
|
alias :__new__ :new
|
12
12
|
end
|
@@ -30,6 +30,12 @@ module RDL::Type
|
|
30
30
|
return (other.instance_of? self.class) && (other.val.equal? @val)
|
31
31
|
end
|
32
32
|
|
33
|
+
def match(other)
|
34
|
+
other = other.type if other.instance_of? AnnotatedArgType
|
35
|
+
return true if other.instance_of? WildQuery
|
36
|
+
return self == other
|
37
|
+
end
|
38
|
+
|
33
39
|
def hash # :nodoc:
|
34
40
|
return @val.hash
|
35
41
|
end
|
@@ -38,7 +44,8 @@ module RDL::Type
|
|
38
44
|
if @val.instance_of? Symbol
|
39
45
|
":{@val}"
|
40
46
|
else
|
41
|
-
|
47
|
+
@val.to_s
|
48
|
+
# "Singleton(#{@val.to_s})"
|
42
49
|
end
|
43
50
|
end
|
44
51
|
|
@@ -54,7 +61,7 @@ module RDL::Type
|
|
54
61
|
return t <= self if t
|
55
62
|
obj.nil? || obj.equal?(@val)
|
56
63
|
end
|
57
|
-
|
64
|
+
|
58
65
|
def instantiate(inst)
|
59
66
|
return self
|
60
67
|
end
|
data/lib/rdl/types/structural.rb
CHANGED
@@ -52,11 +52,11 @@ module RDL::Type
|
|
52
52
|
return t <= self if t
|
53
53
|
return NominalType.new(obj.class) <= self
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
def instantiate(inst)
|
57
57
|
StructuralType.new(Hash[*@methods.each_pair.map { |m, t| [m, t.instantiate(inst)] }.flatten])
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
def eql?(other)
|
61
61
|
self == other
|
62
62
|
end
|
@@ -65,6 +65,13 @@ module RDL::Type
|
|
65
65
|
return (other.instance_of? StructuralType) && (other.methods == @methods)
|
66
66
|
end
|
67
67
|
|
68
|
+
def match(other)
|
69
|
+
other = other.type if other.instance_of? AnnotatedArgType
|
70
|
+
return true if other.instance_of? WildQuery
|
71
|
+
return (@methods.length == other.methods.length &&
|
72
|
+
@methods.all? { |k, v| (other.methods.has_key? k) && (v.match(other.methods[k]))})
|
73
|
+
end
|
74
|
+
|
68
75
|
def hash # :nodoc:
|
69
76
|
@methods.hash
|
70
77
|
end
|
data/lib/rdl/types/top.rb
CHANGED
@@ -24,11 +24,17 @@ module RDL::Type
|
|
24
24
|
def eql?(other)
|
25
25
|
self == other
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def ==(other)
|
29
29
|
other.instance_of? TopType
|
30
30
|
end
|
31
31
|
|
32
|
+
def match(other)
|
33
|
+
other = other.type if other.instance_of? AnnotatedArgType
|
34
|
+
return true if other.instance_of? WildQuery
|
35
|
+
return self == other
|
36
|
+
end
|
37
|
+
|
32
38
|
def <=(other)
|
33
39
|
other.instance_of? TopType
|
34
40
|
end
|
@@ -38,11 +44,11 @@ module RDL::Type
|
|
38
44
|
return t <= self if t
|
39
45
|
true
|
40
46
|
end
|
41
|
-
|
47
|
+
|
42
48
|
def instantiate(inst)
|
43
49
|
return self
|
44
50
|
end
|
45
|
-
|
51
|
+
|
46
52
|
def hash
|
47
53
|
17
|
48
54
|
end
|
data/lib/rdl/types/tuple.rb
CHANGED
@@ -14,7 +14,7 @@ module RDL::Type
|
|
14
14
|
def self.new(*params)
|
15
15
|
t = @@cache[params]
|
16
16
|
return t if t
|
17
|
-
raise RuntimeError, "Attempt to create
|
17
|
+
raise RuntimeError, "Attempt to create tuple type with non-type param" unless params.all? { |p| p.is_a? Type }
|
18
18
|
t = TupleType.__new__(params)
|
19
19
|
return (@@cache[params] = t) # assignment evaluates to t
|
20
20
|
end
|
@@ -36,13 +36,19 @@ module RDL::Type
|
|
36
36
|
return (other.instance_of? TupleType) && (other.params == @params)
|
37
37
|
end
|
38
38
|
|
39
|
+
def match(other)
|
40
|
+
other = other.type if other.instance_of? AnnotatedArgType
|
41
|
+
return true if other.instance_of? WildQuery
|
42
|
+
return @params.length == other.params.length && @params.zip(other.params).all? { |t,o| t.match(o) }
|
43
|
+
end
|
44
|
+
|
39
45
|
def <=(other)
|
40
46
|
return true if other.instance_of? TopType
|
41
47
|
return self == other
|
42
48
|
# Subtyping with Array not allowed
|
43
49
|
# All positions of Tuple are invariant since tuples are mutable
|
44
50
|
end
|
45
|
-
|
51
|
+
|
46
52
|
def member?(obj, *args)
|
47
53
|
t = RDL::Util.rdl_type obj
|
48
54
|
return t <= self if t
|
@@ -53,7 +59,7 @@ module RDL::Type
|
|
53
59
|
def instantiate(inst)
|
54
60
|
TupleType.new(*@params.map { |t| t.instantiate(inst) })
|
55
61
|
end
|
56
|
-
|
62
|
+
|
57
63
|
def hash
|
58
64
|
h = 73 * @params.hash
|
59
65
|
end
|
data/lib/rdl/types/union.rb
CHANGED
@@ -3,7 +3,7 @@ require_relative 'type'
|
|
3
3
|
module RDL::Type
|
4
4
|
class UnionType < Type
|
5
5
|
attr_reader :types
|
6
|
-
|
6
|
+
|
7
7
|
@@cache = {}
|
8
8
|
|
9
9
|
class << self
|
@@ -26,7 +26,7 @@ module RDL::Type
|
|
26
26
|
end
|
27
27
|
}
|
28
28
|
|
29
|
-
ts.sort! { |a,b| a.object_id <=> b.object_id }
|
29
|
+
ts.sort! { |a,b| a.object_id <=> b.object_id }
|
30
30
|
ts.uniq!
|
31
31
|
|
32
32
|
return NilType.new if ts.size == 0
|
@@ -55,6 +55,13 @@ module RDL::Type
|
|
55
55
|
return (other.instance_of? UnionType) && (other.types == @types)
|
56
56
|
end
|
57
57
|
|
58
|
+
def match(other)
|
59
|
+
other = other.type if other.instance_of? AnnotatedArgType
|
60
|
+
return true if other.instance_of? WildQuery
|
61
|
+
return false if @types.length != other.types.length
|
62
|
+
@types.all? { |t| other.types.any? { |ot| t.match(ot) } }
|
63
|
+
end
|
64
|
+
|
58
65
|
def <=(other)
|
59
66
|
@types.all? { |t| t <= other }
|
60
67
|
end
|
@@ -62,11 +69,11 @@ module RDL::Type
|
|
62
69
|
def member?(obj, *args)
|
63
70
|
@types.any? { |t| t.member?(obj, *args) }
|
64
71
|
end
|
65
|
-
|
72
|
+
|
66
73
|
def instantiate(inst)
|
67
74
|
return UnionType.new(*(@types.map { |t| t.instantiate(inst) }))
|
68
75
|
end
|
69
|
-
|
76
|
+
|
70
77
|
def hash # :nodoc:
|
71
78
|
41 + @types.hash
|
72
79
|
end
|
data/lib/rdl/types/var.rb
CHANGED
@@ -34,6 +34,12 @@ module RDL::Type
|
|
34
34
|
return (other.instance_of? self.class) && (other.name.to_s == @name.to_s)
|
35
35
|
end
|
36
36
|
|
37
|
+
def match(other)
|
38
|
+
other = other.type if other.instance_of? AnnotatedArgType
|
39
|
+
return true if other.instance_of? WildQuery
|
40
|
+
return self == other
|
41
|
+
end
|
42
|
+
|
37
43
|
def hash # :nodoc:
|
38
44
|
return @name.to_s.hash
|
39
45
|
end
|
data/lib/rdl/types/vararg.rb
CHANGED
@@ -41,12 +41,18 @@ module RDL::Type
|
|
41
41
|
return (other.instance_of? VarargType) && (other.type == @type)
|
42
42
|
end
|
43
43
|
|
44
|
+
def match(other)
|
45
|
+
other = other.type if other.instance_of? AnnotatedArgType
|
46
|
+
return true if other.instance_of? WildQuery
|
47
|
+
return (other.instance_of? VarargType) && (@type.match(other.type))
|
48
|
+
end
|
49
|
+
|
44
50
|
# Note: no member?, because these can only appear in MethodType, where they're handled specially
|
45
|
-
|
51
|
+
|
46
52
|
def instantiate(inst)
|
47
53
|
return VarargType.new(@type.instantiate(inst))
|
48
54
|
end
|
49
|
-
|
55
|
+
|
50
56
|
def hash # :nodoc:
|
51
57
|
return 59 + @type.hash
|
52
58
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative 'type_query'
|
2
|
+
|
3
|
+
module RDL::Type
|
4
|
+
class WildQuery < TypeQuery
|
5
|
+
@@cache = nil
|
6
|
+
|
7
|
+
class << self
|
8
|
+
alias :__new__ :new
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.new
|
12
|
+
@@cache = WildQuery.__new__ unless @@cache
|
13
|
+
return @@cache
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_s
|
17
|
+
"*"
|
18
|
+
end
|
19
|
+
|
20
|
+
def ==(other)
|
21
|
+
return (other.instance_of? WildQuery)
|
22
|
+
end
|
23
|
+
|
24
|
+
def match(other)
|
25
|
+
return true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/rdl/util.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
1
|
class RDL::Util
|
2
|
+
|
3
|
+
SINGLETON_MARKER = "[s]"
|
4
|
+
SINGLETON_MARKER_REGEXP = Regexp.escape(SINGLETON_MARKER)
|
5
|
+
|
2
6
|
def self.to_class(klass)
|
3
7
|
return klass if klass.class == Class
|
4
8
|
if has_singleton_marker(klass)
|
@@ -11,11 +15,11 @@ class RDL::Util
|
|
11
15
|
end
|
12
16
|
|
13
17
|
def self.has_singleton_marker(klass)
|
14
|
-
return (klass =~
|
18
|
+
return (klass =~ /^#{SINGLETON_MARKER_REGEXP}/)
|
15
19
|
end
|
16
|
-
|
20
|
+
|
17
21
|
def self.remove_singleton_marker(klass)
|
18
|
-
if klass =~
|
22
|
+
if klass =~ /^#{SINGLETON_MARKER_REGEXP}(.*)/
|
19
23
|
return $1
|
20
24
|
else
|
21
25
|
return nil
|
@@ -23,9 +27,18 @@ class RDL::Util
|
|
23
27
|
end
|
24
28
|
|
25
29
|
def self.add_singleton_marker(klass)
|
26
|
-
return
|
30
|
+
return SINGLETON_MARKER + klass
|
31
|
+
end
|
32
|
+
|
33
|
+
# Klass should be a string and may have a singleton marker
|
34
|
+
def self.pretty_name(klass, meth)
|
35
|
+
if klass =~ /^#{SINGLETON_MARKER_REGEXP}(.*)/
|
36
|
+
return "#{$1}.#{meth}"
|
37
|
+
else
|
38
|
+
return "#{klass}##{meth}"
|
39
|
+
end
|
27
40
|
end
|
28
|
-
|
41
|
+
|
29
42
|
def self.method_defined?(klass, method)
|
30
43
|
begin
|
31
44
|
(self.to_class klass).method_defined?(method.to_sym) ||
|
data/lib/rdl/wrap.rb
CHANGED
@@ -418,7 +418,7 @@ class Object
|
|
418
418
|
raise RuntimeError, "Receiver is of class #{klass}, which is not parameterized" unless formals
|
419
419
|
raise RuntimeError, "Expecting #{params.size} type parameters, got #{typs.size}" unless formals.size == typs.size
|
420
420
|
raise RuntimeError, "Instance already has type instantiation" if @__rdl_type
|
421
|
-
new_typs = typs.map { |t| if t.is_a? RDL::Type::Type then t else $__rdl_parser.scan_str "
|
421
|
+
new_typs = typs.map { |t| if t.is_a? RDL::Type::Type then t else $__rdl_parser.scan_str "#T #{t}" end }
|
422
422
|
t = RDL::Type::GenericType.new(RDL::Type::NominalType.new(klass), *new_typs)
|
423
423
|
if all.instance_of? Symbol
|
424
424
|
self.send(all) { |*objs|
|
@@ -451,7 +451,7 @@ class Object
|
|
451
451
|
# Returns a new object that wraps self in a type cast. This cast is *unchecked*, so use with caution
|
452
452
|
def type_cast(typ)
|
453
453
|
$__rdl_contract_switch.off {
|
454
|
-
new_typ = if typ.is_a? RDL::Type::Type then typ else $__rdl_parser.scan_str "
|
454
|
+
new_typ = if typ.is_a? RDL::Type::Type then typ else $__rdl_parser.scan_str "#T #{typ}" end
|
455
455
|
obj = SimpleDelegator.new(self)
|
456
456
|
obj.instance_variable_set('@__rdl_type', new_typ)
|
457
457
|
return obj
|
@@ -467,7 +467,7 @@ class Object
|
|
467
467
|
raise RuntimeError, "Attempt to redefine type #{name}" if $__rdl_special_types[name]
|
468
468
|
case typ
|
469
469
|
when String
|
470
|
-
t = $__rdl_parser.scan_str "
|
470
|
+
t = $__rdl_parser.scan_str "#T #{typ}"
|
471
471
|
$__rdl_special_types[name] = t
|
472
472
|
when RDL::Type::Type
|
473
473
|
$__rdl_special_types[name] = typ
|
@@ -476,38 +476,4 @@ class Object
|
|
476
476
|
end
|
477
477
|
}
|
478
478
|
end
|
479
|
-
|
480
|
-
def rdl_query(q)
|
481
|
-
$__rdl_contract_switch.off {
|
482
|
-
if q =~ /^(\w+(#|\.))?(\w+(!|\?|=)?|!|~|\+|\*\*|-|\*|\/|%|<<|>>|&|\||\^|<|<=|=>|>|==|===|!=|=~|!~|<=>|\[\]|\[\]=)$/
|
483
|
-
klass = nil
|
484
|
-
klass_pref = nil
|
485
|
-
meth = nil
|
486
|
-
if q =~ /(.+)#(.+)/
|
487
|
-
klass = $1
|
488
|
-
klass_pref = "#{klass}#"
|
489
|
-
meth = $2.to_sym
|
490
|
-
elsif q =~ /(.+)\.(.+)/
|
491
|
-
klass_pref = "#{$1}."
|
492
|
-
klass = RDL::Util.add_singleton_marker($1)
|
493
|
-
meth = $2.to_sym
|
494
|
-
else
|
495
|
-
klass = self.class.to_s
|
496
|
-
klass_pref = "#{klass}#"
|
497
|
-
meth = q.to_sym
|
498
|
-
end
|
499
|
-
if RDL::Wrap.has_contracts?(klass, meth, :type)
|
500
|
-
typs = RDL::Wrap.get_contracts(klass, meth, :type)
|
501
|
-
typs.each { |t|
|
502
|
-
puts "#{klass_pref}#{meth}: #{t}"
|
503
|
-
}
|
504
|
-
nil
|
505
|
-
else
|
506
|
-
puts "No type for #{klass_pref}#{meth}"
|
507
|
-
end
|
508
|
-
else
|
509
|
-
puts "Not implemented"
|
510
|
-
end
|
511
|
-
}
|
512
|
-
end
|
513
479
|
end
|
data/rdl.gemspec
CHANGED
@@ -4,8 +4,8 @@
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = 'rdl'
|
7
|
-
s.version = '1.0.
|
8
|
-
s.date = '
|
7
|
+
s.version = '1.0.1.rc1'
|
8
|
+
s.date = '2016-01-01'
|
9
9
|
s.summary = 'Ruby type and contract system'
|
10
10
|
s.description = <<-EOF
|
11
11
|
RDL is a gem that allows contracts (pre- and postconditions) to be added to methods.
|
@@ -17,6 +17,7 @@ EOF
|
|
17
17
|
s.authors = ['Jeffrey S. Foster', 'Brianna M. Ren', 'T. Stephen Strickland', 'Alexander T. Yu']
|
18
18
|
s.email = ['rdl-users@googlegroups.com']
|
19
19
|
s.files = `git ls-files`.split($/)
|
20
|
+
s.executables << 'rdl_query'
|
20
21
|
s.homepage = 'https://github.com/plum-umd/rdl'
|
21
22
|
s.license = 'BSD-3-Clause'
|
22
23
|
s.add_runtime_dependency 'require_all', '~> 1.3', '>= 1.3.3'
|
data/test/test_parser.rb
CHANGED
@@ -72,16 +72,16 @@ class TestParser < Minitest::Test
|
|
72
72
|
end
|
73
73
|
|
74
74
|
def test_bare
|
75
|
-
t1 = @p.scan_str "
|
75
|
+
t1 = @p.scan_str "#T nil"
|
76
76
|
assert_equal @tnil, t1
|
77
|
-
t2 = @p.scan_str "
|
77
|
+
t2 = @p.scan_str "#T %any"
|
78
78
|
assert_equal @ttop, t2
|
79
|
-
t3 = @p.scan_str "
|
79
|
+
t3 = @p.scan_str "#T A"
|
80
80
|
assert_equal NominalType.new("A"), t3
|
81
81
|
end
|
82
82
|
|
83
83
|
def test_symbol
|
84
|
-
t1 = @p.scan_str "
|
84
|
+
t1 = @p.scan_str "#T :symbol"
|
85
85
|
assert_equal @tsymbol, t1
|
86
86
|
end
|
87
87
|
|
@@ -109,66 +109,66 @@ class TestParser < Minitest::Test
|
|
109
109
|
end
|
110
110
|
|
111
111
|
def test_generic
|
112
|
-
t1 = @p.scan_str "
|
112
|
+
t1 = @p.scan_str "#T t"
|
113
113
|
assert_equal (VarType.new "t"), t1
|
114
|
-
t2 = @p.scan_str "
|
114
|
+
t2 = @p.scan_str "#T Array"
|
115
115
|
assert_equal (NominalType.new "Array"), t2
|
116
|
-
t3 = @p.scan_str "
|
116
|
+
t3 = @p.scan_str "#T Array<t>"
|
117
117
|
assert_equal (GenericType.new(t2, t1)), t3
|
118
|
-
t4 = @p.scan_str "
|
118
|
+
t4 = @p.scan_str "#T Array<Array<t>>"
|
119
119
|
assert_equal (GenericType.new(t2, t3)), t4
|
120
|
-
t5 = @p.scan_str "
|
120
|
+
t5 = @p.scan_str "#T Hash"
|
121
121
|
assert_equal (NominalType.new "Hash"), t5
|
122
|
-
t6 = @p.scan_str "
|
122
|
+
t6 = @p.scan_str "#T Hash<u, v>"
|
123
123
|
assert_equal (GenericType.new(t5, VarType.new("u"), VarType.new("v"))), t6
|
124
|
-
t7 = @p.scan_str "
|
124
|
+
t7 = @p.scan_str "#T Foo<String, Array<t>, Array<Array<t>>>"
|
125
125
|
assert_equal (GenericType.new(NominalType.new("Foo"), @tstring, t3, t4)), t7
|
126
126
|
end
|
127
127
|
|
128
128
|
def test_tuple
|
129
|
-
t1 = @p.scan_str "
|
129
|
+
t1 = @p.scan_str "#T [Fixnum, String]"
|
130
130
|
assert_equal (TupleType.new(@tfixnum, @tstring)), t1
|
131
|
-
t2 = @p.scan_str "
|
131
|
+
t2 = @p.scan_str "#T [String]"
|
132
132
|
assert_equal (TupleType.new(@tstring)), t2
|
133
|
-
end
|
133
|
+
end
|
134
134
|
|
135
135
|
def test_fixnum
|
136
|
-
t1 = @p.scan_str "
|
136
|
+
t1 = @p.scan_str "#T 42"
|
137
137
|
assert_equal (SingletonType.new(42)), t1
|
138
|
-
t2 = @p.scan_str "
|
138
|
+
t2 = @p.scan_str "#T -42"
|
139
139
|
assert_equal (SingletonType.new(-42)), t2
|
140
140
|
end
|
141
141
|
|
142
142
|
def test_float
|
143
|
-
t1 = @p.scan_str "
|
143
|
+
t1 = @p.scan_str "#T 3.14"
|
144
144
|
assert_equal (SingletonType.new(3.14)), t1
|
145
145
|
end
|
146
146
|
|
147
147
|
def test_const
|
148
|
-
t1 = @p.scan_str "
|
148
|
+
t1 = @p.scan_str "#T ${Math::PI}"
|
149
149
|
assert_equal (SingletonType.new(Math::PI)), t1
|
150
150
|
end
|
151
151
|
|
152
152
|
def test_type_alias
|
153
153
|
type_alias '%foobarbaz', @tnil
|
154
|
-
assert_equal @tnil, (@p.scan_str "
|
154
|
+
assert_equal @tnil, (@p.scan_str "#T %foobarbaz")
|
155
155
|
type_alias '%quxquxqux', 'nil'
|
156
|
-
assert_equal @tnil, (@p.scan_str "
|
156
|
+
assert_equal @tnil, (@p.scan_str "#T %quxquxqux")
|
157
157
|
assert_raises(RuntimeError) { type_alias '%quxquxqux', 'nil' }
|
158
|
-
assert_raises(RuntimeError) { @p.scan_str "
|
158
|
+
assert_raises(RuntimeError) { @p.scan_str "#T %qux" }
|
159
159
|
end
|
160
160
|
|
161
161
|
def test_structural
|
162
|
-
t1 = @p.scan_str "
|
162
|
+
t1 = @p.scan_str "#T [to_str: () -> String]"
|
163
163
|
tm1 = MethodType.new [], nil, @tstring
|
164
164
|
ts1 = StructuralType.new(to_str: tm1)
|
165
165
|
assert_equal ts1, t1
|
166
166
|
end
|
167
167
|
|
168
168
|
def test_finite_hash
|
169
|
-
t1 = @p.scan_str "
|
169
|
+
t1 = @p.scan_str "#T {a: Fixnum, b: String}"
|
170
170
|
assert_equal (FiniteHashType.new({a: @tfixnum, b: @tstring})), t1
|
171
|
-
t2 = @p.scan_str "
|
171
|
+
t2 = @p.scan_str "#T {'a'=>Fixnum, 2=>String}"
|
172
172
|
assert_equal (FiniteHashType.new({"a"=>@tfixnum, 2=>@tstring})), t2
|
173
173
|
end
|
174
174
|
|