rdl 2.0.0.rc4 → 2.0.0.rc5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +56 -84
- data/lib/rdl/boot.rb +4 -0
- data/lib/rdl/boot_rails.rb +3 -1
- data/lib/rdl/contracts/flat.rb +1 -2
- data/lib/rdl/typecheck.rb +138 -27
- data/lib/rdl/types/annotated_arg.rb +8 -0
- data/lib/rdl/types/finite_hash.rb +32 -17
- data/lib/rdl/types/lexer.rex +1 -0
- data/lib/rdl/types/lexer.rex.rb +3 -0
- data/lib/rdl/types/method.rb +24 -4
- data/lib/rdl/types/optional.rb +8 -1
- data/lib/rdl/types/parser.racc +12 -9
- data/lib/rdl/types/parser.tab.rb +293 -255
- data/lib/rdl/types/type.rb +20 -11
- data/lib/rdl/types/union.rb +3 -0
- data/lib/rdl/types/vararg.rb +7 -2
- data/lib/rdl/wrap.rb +15 -2
- data/lib/types/core-ruby-2.x/proc.rb +16 -0
- data/lib/types/rails-5.x/_helpers.rb +20 -0
- data/lib/types/rails-5.x/active_model/errors.rb +15 -0
- data/lib/types/rails-5.x/active_model/validations.rb +5 -0
- data/lib/types/rails-5.x/active_record/associations.rb +190 -0
- data/lib/types/rails-5.x/active_record/core.rb +3 -0
- data/lib/types/rails-5.x/active_record/model_schema.rb +7 -10
- data/rdl.gemspec +2 -2
- data/test/test_le.rb +24 -0
- data/test/test_member.rb +24 -2
- data/test/test_parser.rb +21 -10
- data/test/test_query.rb +5 -2
- data/test/test_type_contract.rb +34 -2
- data/test/test_typecheck.rb +296 -36
- data/test/test_types.rb +8 -4
- metadata +7 -2
data/lib/rdl/types/type.rb
CHANGED
@@ -25,9 +25,9 @@ module RDL::Type
|
|
25
25
|
end
|
26
26
|
|
27
27
|
# default behavior, override in appropriate subclasses
|
28
|
-
def canonical
|
29
|
-
|
30
|
-
end
|
28
|
+
def canonical; return self; end
|
29
|
+
def optional?; return false; end
|
30
|
+
def vararg?; return false; end
|
31
31
|
|
32
32
|
# [+ other +] is a Type
|
33
33
|
# [+ inst +] is a Hash<Symbol, Type> representing an instantiation
|
@@ -143,6 +143,7 @@ module RDL::Type
|
|
143
143
|
return false # one has a block and the other doesn't
|
144
144
|
end
|
145
145
|
end
|
146
|
+
return true if left.is_a?(MethodType) && right.is_a?(NominalType) && right.name == 'Proc'
|
146
147
|
|
147
148
|
# structural
|
148
149
|
if left.is_a?(StructuralType) && right.is_a?(StructuralType)
|
@@ -175,18 +176,26 @@ module RDL::Type
|
|
175
176
|
if left.is_a?(FiniteHashType) && right.is_a?(FiniteHashType)
|
176
177
|
# Like Tuples, FiniteHashes are immutable, so covariant subtyping allowed
|
177
178
|
# But note, no width subtyping allowed, to match #member?
|
178
|
-
|
179
|
+
right_elts = right.elts.clone # shallow copy
|
179
180
|
left.elts.each_pair { |k, tl|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
181
|
+
if right_elts.has_key? k
|
182
|
+
tr = right_elts[k]
|
183
|
+
return false if tl.is_a?(OptionalType) && !tr.is_a?(OptionalType) # optional left, required right not allowed, since left may not have key
|
184
|
+
tl = tl.type if tl.is_a? OptionalType
|
185
|
+
tr = tr.type if tr.is_a? OptionalType
|
186
|
+
return false unless leq(tl, tr, inst, ileft)
|
187
|
+
right_elts.delete k
|
188
|
+
else
|
189
|
+
return false unless right.rest && leq(tl, right.rest, inst, ileft)
|
190
|
+
end
|
186
191
|
}
|
187
|
-
|
192
|
+
right_elts.each_pair { |k, t|
|
188
193
|
return false unless t.is_a? OptionalType
|
189
194
|
}
|
195
|
+
unless left.rest.nil?
|
196
|
+
# If left has optional stuff, right needs to accept it
|
197
|
+
return false unless !(right.rest.nil?) && leq(left.rest, right.rest, inst, ileft)
|
198
|
+
end
|
190
199
|
left.ubounds << right
|
191
200
|
right.lbounds << left
|
192
201
|
return true
|
data/lib/rdl/types/union.rb
CHANGED
@@ -15,6 +15,9 @@ module RDL::Type
|
|
15
15
|
ts.concat t.types
|
16
16
|
else
|
17
17
|
raise RuntimeError, "Attempt to create union type with non-type" unless t.is_a? Type
|
18
|
+
raise RuntimeError, "Attempt to create union with optional type" if t.is_a? OptionalType
|
19
|
+
raise RuntimeError, "Attempt to create union with vararg type" if t.is_a? VarargType
|
20
|
+
raise RuntimeError, "Attempt to create union with annotated type" if t.is_a? AnnotatedArgType
|
18
21
|
ts << t
|
19
22
|
end
|
20
23
|
}
|
data/lib/rdl/types/vararg.rb
CHANGED
@@ -17,8 +17,9 @@ module RDL::Type
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def initialize(type)
|
20
|
-
raise "Can't have vararg optional type" if type.
|
21
|
-
raise "Can't have vararg vararg type" if type.
|
20
|
+
raise "Can't have vararg optional type" if type.is_a? OptionalType
|
21
|
+
raise "Can't have vararg vararg type" if type.is_a? VarargType
|
22
|
+
raise "Can't have optional annotated type" if type.is_a? AnnotatedArgType
|
22
23
|
@type = type
|
23
24
|
super()
|
24
25
|
end
|
@@ -55,5 +56,9 @@ module RDL::Type
|
|
55
56
|
def hash # :nodoc:
|
56
57
|
return 59 + @type.hash
|
57
58
|
end
|
59
|
+
|
60
|
+
def vararg?
|
61
|
+
return true
|
62
|
+
end
|
58
63
|
end
|
59
64
|
end
|
data/lib/rdl/wrap.rb
CHANGED
@@ -535,13 +535,26 @@ class Object
|
|
535
535
|
nil
|
536
536
|
end
|
537
537
|
|
538
|
-
#
|
538
|
+
# Register [+ blk +] to be executed when `rdl_do_typecheck [+ sym +]` is called.
|
539
|
+
# The blk will be called with sym as its argument. The order
|
540
|
+
# in which multiple blks for the same sym will be executed is unspecified
|
541
|
+
def rdl_at(sym, &blk)
|
542
|
+
$__rdl_at[sym] = [] unless $__rdl_at[sym]
|
543
|
+
$__rdl_at[sym] << blk
|
544
|
+
end
|
545
|
+
|
546
|
+
# Invokes all callbacks from rdl_at(sym), in unspecified order.
|
547
|
+
# Afterwards, type checks all methods that had annotation `typecheck: sym' at type call, in unspecified order.
|
539
548
|
def rdl_do_typecheck(sym)
|
549
|
+
if $__rdl_at[sym]
|
550
|
+
$__rdl_at[sym].each { |blk| blk.call(sym) }
|
551
|
+
end
|
552
|
+
$__rdl_at[sym] = Array.new
|
540
553
|
return unless $__rdl_to_typecheck[sym]
|
541
554
|
$__rdl_to_typecheck[sym].each { |klass, meth|
|
542
555
|
RDL::Typecheck.typecheck(klass, meth)
|
543
556
|
}
|
544
|
-
$__rdl_to_typecheck[sym] =
|
557
|
+
$__rdl_to_typecheck[sym] = Set.new
|
545
558
|
nil
|
546
559
|
end
|
547
560
|
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Proc
|
2
|
+
rdl_nowrap
|
3
|
+
|
4
|
+
type :arity, '() -> %integer'
|
5
|
+
type :binding, '() -> Binding'
|
6
|
+
type :curry, '(?%integer arity) -> Proc'
|
7
|
+
type :hash, '() -> %integer'
|
8
|
+
rdl_alias :inspect, :to_s
|
9
|
+
type :lambda, '() -> %bool'
|
10
|
+
type :parameters, '() -> Array<[Symbol, Symbol]>'
|
11
|
+
type :source_location, '() -> [String, %integer]'
|
12
|
+
type :to_proc, '() -> self'
|
13
|
+
type :to_s, '() -> String'
|
14
|
+
|
15
|
+
|
16
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# :integer, :bigint, :float, :decimal, :numeric, :datetime, :time, :date, :binary, :boolean.
|
2
2
|
# null allowed
|
3
3
|
|
4
|
+
type_alias '%symstr', 'Symbol or String'
|
5
|
+
|
4
6
|
module RDL
|
5
7
|
class Rails
|
6
8
|
|
@@ -28,5 +30,23 @@ module RDL
|
|
28
30
|
raise RuntimeError, "Unrecoganized column type #{rails_type}"
|
29
31
|
end
|
30
32
|
end
|
33
|
+
|
34
|
+
# [+ model +] is an ActiveRecord::Base subclass that has been loaded.
|
35
|
+
# Gets the columns_hash of the model and returns a String that can
|
36
|
+
# serve as the paramter list to a method that accepts any number
|
37
|
+
# of the model's attributes keyed by the attribute names.
|
38
|
+
def self.attribute_types(model)
|
39
|
+
args = []
|
40
|
+
|
41
|
+
model.columns_hash.each { |name, col|
|
42
|
+
t = column_to_rdl(col.type)
|
43
|
+
if col.null
|
44
|
+
args << "#{name}: ?#{t}"
|
45
|
+
else
|
46
|
+
args << "#{name}: ?!#{t}"
|
47
|
+
end
|
48
|
+
}
|
49
|
+
return args.join ','
|
50
|
+
end
|
31
51
|
end
|
32
52
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class ActiveModel::Errors
|
2
|
+
type :clear, '() -> %any'
|
3
|
+
type :delete, '(%symstr) -> %any'
|
4
|
+
type :[], '(%symstr) -> Array<String>'
|
5
|
+
type :each, '() { (%symstr, String) -> %any } -> %any'
|
6
|
+
type :size, '() -> %integer'
|
7
|
+
rdl_alias :count, :size
|
8
|
+
type :values, '() -> Array<String>'
|
9
|
+
type :keys, '() -> Array<Symbol>'
|
10
|
+
type :empty?, '() -> %bool'
|
11
|
+
rdl_alias :blank?, :empty?
|
12
|
+
type :hash, '(?%bool full_messages) -> Hash<Symbol, String>'
|
13
|
+
type :add, '(%symstr, %symstr, Hash<Symbol, %any>) -> %any'
|
14
|
+
type :add, '(%symstr, { () -> String }, Hash<Symbol, %any>) -> %any' # TODO: combine with prev with union once supported
|
15
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
class ActiveRecord::Associations::CollectionProxy
|
2
|
+
type_params [:t], :all?
|
3
|
+
|
4
|
+
type :<<, '(*(t or Array<t>)) -> self'
|
5
|
+
type :==, '(%any) -> %bool'
|
6
|
+
type :any?, '() ?{ (t) -> %bool } -> %bool'
|
7
|
+
rdl_alias :append, :<<
|
8
|
+
type :build, '(Hash<Symbol, %any> or Array<Hash<Symbol, %any>>) -> self'
|
9
|
+
type :clear, '() -> self'
|
10
|
+
type :concat, '(*t) -> self'
|
11
|
+
type :count, '() -> %integer'
|
12
|
+
type :create, '(Hash<Symbol, %any> or Array<Hash<Symbol, %any>>) -> self'
|
13
|
+
type :create!, '(Hash<Symbol, %any> or Array<Hash<Symbol, %any>>) -> self'
|
14
|
+
type :delete, '(*t) -> Array<t>'
|
15
|
+
type :delete_all, '(?Symbol dependent) -> Array<t>'
|
16
|
+
type :destroy, '(*t) -> Array<t>'
|
17
|
+
type :destroy_all, '() -> %any'
|
18
|
+
type :distinct, '() -> self'
|
19
|
+
type :empty?, '() -> %bool'
|
20
|
+
type :find, '(%integer) -> t'
|
21
|
+
type :find, '(%integer, %integer, *%integer) -> ActiveRecord::Associations::CollectionProxy<t>'
|
22
|
+
type :include?, '(t) -> %bool'
|
23
|
+
type :length, '() -> %integer'
|
24
|
+
type :load_target, '() -> %any'
|
25
|
+
type :loaded?, '() -> %bool'
|
26
|
+
type :many?, '() ?{ (t) -> %bool } -> %bool'
|
27
|
+
rdl_alias :new, :build
|
28
|
+
rdl_alias :push, :<<
|
29
|
+
type :reload, '() -> self'
|
30
|
+
type :replace, '(Array<t>) -> %any'
|
31
|
+
type :reset, '() -> self'
|
32
|
+
type :scope, '() -> ActiveRecord::Relation' # TODO fix
|
33
|
+
type :select, '(*Symbol) -> t'
|
34
|
+
type :select, '() { (t) -> %bool } -> ActiveRecord::Associations::CollectionProxy<t>'
|
35
|
+
type :size, '() -> %integer'
|
36
|
+
rdl_alias :spawn, :scope
|
37
|
+
type :take, '() -> t or nil'
|
38
|
+
type :take, '(%integer) -> ActiveRecord::Associations::CollectionProxy<t>'
|
39
|
+
type :to_ary, '() -> Array<t>'
|
40
|
+
rdl_alias :to_a, :to_ary
|
41
|
+
rdl_alias :unique, :distinct
|
42
|
+
|
43
|
+
type :first, '() -> t or nil'
|
44
|
+
type :first, '(%integer) -> ActiveRecord::Associations::CollectionProxy<t>'
|
45
|
+
type :second, '() -> t or nil'
|
46
|
+
type :second, '(%integer) -> ActiveRecord::Associations::CollectionProxy<t>'
|
47
|
+
type :third, '() -> t or nil'
|
48
|
+
type :third, '(%integer) -> ActiveRecord::Associations::CollectionProxy<t>'
|
49
|
+
type :fourth, '() -> t or nil'
|
50
|
+
type :fourth, '(%integer) -> ActiveRecord::Associations::CollectionProxy<t>'
|
51
|
+
type :fifth, '() -> t or nil'
|
52
|
+
type :fifth, '(%integer) -> ActiveRecord::Associations::CollectionProxy<t>'
|
53
|
+
type :forty_two, '() -> t or nil'
|
54
|
+
type :forty_two, '(%integer) -> ActiveRecord::Associations::CollectionProxy<t>'
|
55
|
+
type :third_to_last, '() -> t or nil'
|
56
|
+
type :third_to_last, '(%integer) -> ActiveRecord::Associations::CollectionProxy<t>'
|
57
|
+
type :second_to_last, '() -> t or nil'
|
58
|
+
type :second_to_last, '(%integer) -> ActiveRecord::Associations::CollectionProxy<t>'
|
59
|
+
type :last, '() -> t or nil'
|
60
|
+
type :last, '(%integer) -> ActiveRecord::Associations::CollectionProxy<t>'
|
61
|
+
end
|
62
|
+
|
63
|
+
module ActiveRecord::Associations::ClassMethods
|
64
|
+
|
65
|
+
# TODO: Check presence of methods required by, e.g., foreign_key, primary_key, etc.
|
66
|
+
# TODO: Check counter_cache, add to model attr_readonly_type
|
67
|
+
|
68
|
+
|
69
|
+
type :belongs_to, '(%symstr name, ?{ (?ActiveRecord::Base) -> %any } scope, class_name: ?%symstr, foreign_key: ?%symstr,' +
|
70
|
+
'primary_key: ?%symstr, dependent: ?(:delete or :destroy), counter_cache: ?(%bool or %symstr),' +
|
71
|
+
'polymorphic: ?%bool, validate: ?%bool, autosave: ?%bool, touch: ?(%bool or %symstr),' +
|
72
|
+
'inverse_of: ?%symstr, optional: ?%bool, required: ?%bool, anonymous_class: ?Class) -> %any'
|
73
|
+
|
74
|
+
pre :belongs_to do |name, scope=nil, class_name: nil, foreign_key: nil, primary_key: nil,
|
75
|
+
dependent: nil, counter_cache: nil, polymorphic: nil,
|
76
|
+
validate: nil, autosave: nil, touch: nil, inverse_of: nil,
|
77
|
+
optional: nil, required: nil, anonymous_class: nil|
|
78
|
+
if polymorphic
|
79
|
+
assoc_type = '%any' # type is data-driven, can't determine statically
|
80
|
+
elsif class_name
|
81
|
+
assoc_type = class_name.to_s.classify
|
82
|
+
elsif anonymous_class
|
83
|
+
assoc_type = anonymous_class.to_s
|
84
|
+
else
|
85
|
+
assoc_type = name.to_s.classify # camelize?
|
86
|
+
end
|
87
|
+
type name, "(?%bool force_reload) -> #{assoc_type}"
|
88
|
+
type "#{name}=", "(#{assoc_type}) -> #{assoc_type}"
|
89
|
+
unless polymorphic
|
90
|
+
rdl_at(:model) { |sym|
|
91
|
+
assoc_attribute_types = RDL::Rails.attribute_types(assoc_type.constantize)
|
92
|
+
type "build_#{name}", "(#{assoc_attribute_types}) -> #{assoc_type}"
|
93
|
+
type "create_#{name}", "(#{assoc_attribute_types}) -> #{assoc_type}"
|
94
|
+
type "create_#{name}!", "(#{assoc_attribute_types}) -> #{assoc_type}"
|
95
|
+
}
|
96
|
+
end
|
97
|
+
true
|
98
|
+
end
|
99
|
+
|
100
|
+
type :has_one, '(%symstr name, ?{ (?ActiveRecord::Base) -> %any } scope, class_name: ?%symstr,'+
|
101
|
+
'dependent: ?(:destroy or :delete or :nullify or :restrict_with_exception or :restrict_with_error),' +
|
102
|
+
'foreign_key: ?%symstr, foreign_type: ?%symstr, primary_key: ?%symstr, as: ?%symstr,' +
|
103
|
+
'through: ?%symstr, source: ?%symstr, source_type: ?%symstr, validate: ?%bool, autosave: ?%bool,' +
|
104
|
+
'inverse_of: ?%symstr, required: ?%bool, anonymous_class: ?Class) -> %any'
|
105
|
+
|
106
|
+
pre :has_one do |name, scope=nil, class_name: nil, dependent: nil, foreign_key: nil,
|
107
|
+
foreign_type: nil, primary_key: nil, as: nil, through: nil, source: nil,
|
108
|
+
source_type: nil, vadliate: nil, autosave: nil, inverse_of: nil,
|
109
|
+
required: nil|
|
110
|
+
if as
|
111
|
+
assoc_type = '%any' # type is data-driven, can't determine statically
|
112
|
+
elsif class_name
|
113
|
+
assoc_type = class_name.to_s.classify
|
114
|
+
elsif anonymous_class # not sure this has anonymou_class
|
115
|
+
assoc_type = anonymous_class.to_s.classify
|
116
|
+
else
|
117
|
+
assoc_type = name.to_s.classify # camelize?
|
118
|
+
end
|
119
|
+
type name, "(?%bool force_reload) -> #{assoc_type}"
|
120
|
+
type "#{name}=", "(#{assoc_type}) -> #{assoc_type}"
|
121
|
+
unless as
|
122
|
+
rdl_at(:model) { |sym|
|
123
|
+
assoc_attribute_types = RDL::Rails.attribute_types(assoc_type.constantize)
|
124
|
+
type "build_#{name}", "(#{assoc_attribute_types}) -> #{assoc_type}"
|
125
|
+
type "create_#{name}", "(#{assoc_attribute_types}) -> #{assoc_type}"
|
126
|
+
type "create_#{name}!", "(#{assoc_attribute_types}) -> #{assoc_type}"
|
127
|
+
}
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
type :has_many, '(%symstr name, ?{ (?ActiveRecord::Base) -> %any } scope, class_name: ?%symstr,' +
|
132
|
+
'foreign_key: ?%symstr, foreign_type: ?%symstr, primary_key: ?%symstr,' +
|
133
|
+
'dependent: ?(:destroy or :delete_all or :nullify or :restrict_with_exception or :restrict_with_error),' +
|
134
|
+
'counter_cache: ?(%bool or %symstr), as: ?%symstr, through: ?%symstr, source: ?%symstr,' +
|
135
|
+
'source_type: ?%symstr, validate: ?%bool, inverse_of: ?%symstr, extend: ?(Module or Array<Module>))' +
|
136
|
+
'?{ () -> %any } -> %any'
|
137
|
+
|
138
|
+
pre :has_many do |name, scope=nil, class_name: nil, foreign_key: nil, foreign_type: nil, primary_key: nil,
|
139
|
+
dependent: nil, counter_cache: nil, as: nil, through: nil, source: nil, source_type: nil,
|
140
|
+
validate: nil, inverse_of: nil, extend: nil|
|
141
|
+
if class_name
|
142
|
+
collect_type = class_name.to_s.classify
|
143
|
+
else
|
144
|
+
collect_type = name.to_s.singularize.classify
|
145
|
+
end
|
146
|
+
type name, "() -> ActiveRecord::Associations::CollectionProxy<#{collect_type}>"
|
147
|
+
type "#{name}=", "(Array<t>) -> ActiveRecord::Associations::CollectionProxy<#{collect_type}>" # TODO not sure of type
|
148
|
+
id_type = RDL::Rails.column_to_rdl(collect_type.constantize.columns_hash['id'].type) # TODO assumes id field is "id"
|
149
|
+
type "#{name.to_s.singularize}_ids", "() -> Array<#{id_type}>"
|
150
|
+
type "#{name.to_s.singularize}_ids=", "() -> Array<#{id_type}>"
|
151
|
+
|
152
|
+
true
|
153
|
+
end
|
154
|
+
|
155
|
+
type :has_and_belongs_to_many, '(%symstr name, ?{ (?ActiveRecord::Base) -> %any } scope, class_name: ?%symstr,' +
|
156
|
+
'join_table: ?%symstr, foreign_key: ?%symstr, association_foreign_key: ?%symstr,' +
|
157
|
+
'validate: ?%bool, autosave: ?%bool) ?{ () -> %any } -> %any'
|
158
|
+
|
159
|
+
pre :has_and_belongs_to_many do |name, scope=nil, class_name: nil, join_table: nil,
|
160
|
+
foreign_key: nil, association_foreign_key: nil,
|
161
|
+
validate: nil, autosave: nil|
|
162
|
+
if class_name
|
163
|
+
collect_type = class_name.to_s.classify
|
164
|
+
else
|
165
|
+
collect_type = name.to_s.singularize.classify
|
166
|
+
end
|
167
|
+
type name, "() -> ActiveRecord::Associations::CollectionProxy<#{collect_type}>"
|
168
|
+
type "#{name}=", "(Array<t>) -> ActiveRecord::Associations::CollectionProxy<#{collect_type}>" # TODO not sure of type
|
169
|
+
id_type = RDL::Rails.column_to_rdl(collect_type.constantize.columns_hash['id'].type) # TODO assumes id field is "id"
|
170
|
+
type "#{name.to_s.singularize}_ids", "() -> Array<#{id_type}>"
|
171
|
+
type "#{name.to_s.singularize}_ids=", "() -> Array<#{id_type}>"
|
172
|
+
|
173
|
+
# Remaining methods are from CollectionProxy
|
174
|
+
# TODO give these precise types for this particular model
|
175
|
+
# collection<<(object, ...)
|
176
|
+
# collection.delete(object, ...)
|
177
|
+
# collection.destroy(object, ...)
|
178
|
+
# collection.clear
|
179
|
+
# collection.empty?
|
180
|
+
# collection.size
|
181
|
+
# collection.find(...)
|
182
|
+
# collection.where(...)
|
183
|
+
# collection.exists?(...)
|
184
|
+
# collection.build(attributes = {})
|
185
|
+
# collection.create(attributes = {})
|
186
|
+
# collection.create!(attributes = {})
|
187
|
+
true
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
@@ -2,8 +2,6 @@ module ActiveRecord
|
|
2
2
|
module ModelSchema
|
3
3
|
module ClassMethods
|
4
4
|
post(:load_schema!) { |ret| # load_schema! doesn't return anything interesting
|
5
|
-
find_by_args = []
|
6
|
-
|
7
5
|
columns_hash.each { |name, col|
|
8
6
|
t = RDL::Rails.column_to_rdl(col.type)
|
9
7
|
if col.null
|
@@ -13,7 +11,6 @@ module ActiveRecord
|
|
13
11
|
type "write_attribute", "(:#{name}, #{t}) -> %bool"
|
14
12
|
type "update_attribute", "(:#{name}, #{t}) -> %bool"
|
15
13
|
type "update_column", "(:#{name}, #{t}) -> %bool"
|
16
|
-
find_by_args << "#{name}: ?#{t}"
|
17
14
|
else
|
18
15
|
# not null; can't truly check in type system but hint via the name
|
19
16
|
type name, "() -> !#{t}" # getter
|
@@ -21,15 +18,15 @@ module ActiveRecord
|
|
21
18
|
type "write_attribute", "(:#{name}, !#{t}) -> %bool"
|
22
19
|
type "update_attribute", "(:#{name}, #{t}) -> %bool"
|
23
20
|
type "update_column", "(:#{name}, #{t}) -> %bool"
|
24
|
-
find_by_args << "#{name}: ?!#{t}"
|
25
21
|
end
|
26
22
|
}
|
27
|
-
|
28
|
-
|
29
|
-
type 'self.find_by
|
30
|
-
type '
|
31
|
-
type '
|
32
|
-
type '
|
23
|
+
|
24
|
+
attribute_types = RDL::Rails.attribute_types(self)
|
25
|
+
type 'self.find_by', '(' + attribute_types + ") -> #{self} or nil"
|
26
|
+
type 'self.find_by!', '(' + attribute_types + ") -> #{self}"
|
27
|
+
type 'update', '(' + attribute_types + ') -> %bool'
|
28
|
+
type 'update_columns', '(' + attribute_types + ') -> %bool'
|
29
|
+
type 'attributes=', '(' + attribute_types + ') -> %bool'
|
33
30
|
|
34
31
|
# If called with String arguments, can't check types as precisely
|
35
32
|
type 'write_attribute', '(String, %any) -> %bool'
|
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 = '2.0.0.
|
8
|
-
s.date = '2016-08-
|
7
|
+
s.version = '2.0.0.rc5'
|
8
|
+
s.date = '2016-08-24'
|
9
9
|
s.summary = 'Ruby type and contract system'
|
10
10
|
s.description = <<-EOF
|
11
11
|
RDL is a gem that adds types and contracts to Ruby. RDL includes extensive
|
data/test/test_le.rb
CHANGED
@@ -168,6 +168,29 @@ class TestLe < Minitest::Test
|
|
168
168
|
assert (tfs2_4 <= thfs_4) # allowed, both tfs2_4 and tfs_4 promoted to hash
|
169
169
|
tfs3_4 = tt "{x: Fixnum, y: String}"
|
170
170
|
assert (not(tfs_4 <= tfs3_4)) # not allowed, tfs_4 has been promoted
|
171
|
+
|
172
|
+
tfss_5 = tt "{x: Fixnum, y: String, **Symbol}"
|
173
|
+
tfns_5 = tt "{x: Fixnum, **Symbol}"
|
174
|
+
tfsn_5 = tt "{x: Fixnum, y: String}"
|
175
|
+
tftn_5 = tt "{x: Fixnum, z: Symbol}"
|
176
|
+
tooo_5 = tt "{x: Object, y: Object, **Object}"
|
177
|
+
tono_5 = tt "{x: Object, **Object}"
|
178
|
+
assert (tfss_5 <= tooo_5)
|
179
|
+
assert (tfns_5 <= tono_5)
|
180
|
+
assert (not (tfss_5 <= tfns_5))
|
181
|
+
assert (not (tfss_5 <= tfsn_5))
|
182
|
+
assert (not (tfss_5 <= tftn_5))
|
183
|
+
assert (not (tfns_5 <= tfss_5))
|
184
|
+
assert (not (tfns_5 <= tfsn_5))
|
185
|
+
assert (not (tfns_5 <= tftn_5))
|
186
|
+
assert (tfsn_5 <= tfss_5)
|
187
|
+
assert (not (tfsn_5 <= tfns_5))
|
188
|
+
assert (not (tfsn_5 <= tftn_5))
|
189
|
+
assert (not (tftn_5 <= tfss_5))
|
190
|
+
assert (tftn_5 <= tfns_5)
|
191
|
+
assert (not (tftn_5 <= tfsn_5))
|
192
|
+
|
193
|
+
assert (not (tt("{x: ?Fixnum}") <= tt("{x: Fixnum}")))
|
171
194
|
end
|
172
195
|
|
173
196
|
def test_method
|
@@ -197,6 +220,7 @@ class TestLe < Minitest::Test
|
|
197
220
|
assert (not (tbos <= tbso))
|
198
221
|
assert (tbso <= tbso)
|
199
222
|
assert (tbso <= tbos)
|
223
|
+
assert (tss <= $__rdl_proc_type)
|
200
224
|
end
|
201
225
|
|
202
226
|
def test_structural
|