rdl 2.0.0.rc4 → 2.0.0.rc5
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/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
|