dry-types 0.10.3 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -6
- data/CHANGELOG.md +10 -0
- data/CONTRIBUTING.md +29 -0
- data/README.md +1 -1
- data/dry-types.gemspec +1 -1
- data/lib/dry/types.rb +6 -0
- data/lib/dry/types/array.rb +2 -0
- data/lib/dry/types/array/member.rb +7 -0
- data/lib/dry/types/compiler.rb +38 -35
- data/lib/dry/types/constrained.rb +9 -0
- data/lib/dry/types/constructor.rb +13 -0
- data/lib/dry/types/definition.rb +9 -0
- data/lib/dry/types/enum.rb +7 -0
- data/lib/dry/types/errors.rb +3 -2
- data/lib/dry/types/fn_container.rb +33 -0
- data/lib/dry/types/hash/schema.rb +39 -2
- data/lib/dry/types/options.rb +7 -1
- data/lib/dry/types/safe.rb +13 -0
- data/lib/dry/types/sum.rb +7 -0
- data/lib/dry/types/version.rb +1 -1
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12cffdbb9c18b6f1ab0bb726c5a13fbd13c1178e
|
4
|
+
data.tar.gz: 150931c98379624c229416370bd63cd8830bbab5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b6bd371faf9ae94c6559c01309216205c3df88614c86cb2862929b2836d8cc4c32b76d916f6deeb6e4390bb296c8e1733e85e8997b3f00092584960961e02ee
|
7
|
+
data.tar.gz: 584c9552a9185595008a63c2ca6f3a8cc88ec56b7c063f720d36ff10d9c1b26b403443456416a484429cae4b7e10bd6a06995acd3adf99eb89b1026825a9fd83
|
data/.travis.yml
CHANGED
@@ -9,17 +9,13 @@ script:
|
|
9
9
|
- bundle exec rake
|
10
10
|
rvm:
|
11
11
|
- 2.2.7
|
12
|
-
- 2.3.
|
12
|
+
- 2.3.4
|
13
13
|
- 2.4.1
|
14
|
-
- jruby-9.1.
|
15
|
-
- rbx-3
|
14
|
+
- jruby-9.1.10.0
|
16
15
|
env:
|
17
16
|
global:
|
18
17
|
- COVERAGE=true
|
19
18
|
- JRUBY_OPTS='--dev -J-Xmx1024M'
|
20
|
-
matrix:
|
21
|
-
allow_failures:
|
22
|
-
- rvm: rbx-3
|
23
19
|
notifications:
|
24
20
|
email: false
|
25
21
|
webhooks:
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
# v0.11.0 2017-06-30
|
2
|
+
|
3
|
+
## Added
|
4
|
+
|
5
|
+
* `#to_ast` available for all type objects (GustavoCaso)
|
6
|
+
* `Types::Array#of` as an alias for `#member` (maliqq)
|
7
|
+
* Detailed failure objects are passed to results which improves constraint violation messages (GustavoCaso)
|
8
|
+
|
9
|
+
[Compare v0.10.3...v0.11.0](https://github.com/dry-rb/dry-types/compare/v0.10.3...v0.11.0)
|
10
|
+
|
1
11
|
# v0.10.3 2017-05-06
|
2
12
|
|
3
13
|
## Added
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# Issue Guidelines
|
2
|
+
|
3
|
+
## Reporting bugs
|
4
|
+
|
5
|
+
If you found a bug, report an issue and describe what's the expected behavior versus what actually happens. If the bug causes a crash, attach a full backtrace. If possible, a reproduction script showing the problem is highly appreciated.
|
6
|
+
|
7
|
+
## Reporting feature requests
|
8
|
+
|
9
|
+
Report a feature request **only after discussing it first on [discuss.dry-rb.org](https://discuss.dry-rb.org)** where it was accepted. Please provide a concise description of the feature, don't link to a discussion thread, and instead summarize what was discussed.
|
10
|
+
|
11
|
+
## Reporting questions, support requests, ideas, concerns etc.
|
12
|
+
|
13
|
+
**PLEASE DON'T** - use [discuss.dry-rb.org](http://discuss.dry-rb.org) instead.
|
14
|
+
|
15
|
+
# Pull Request Guidelines
|
16
|
+
|
17
|
+
A Pull Request will only be accepted if it addresses a specific issue that was reported previously, or fixes typos, mistakes in documentation etc.
|
18
|
+
|
19
|
+
Other requirements:
|
20
|
+
|
21
|
+
1) Do not open a pull request if you can't provide tests along with it. If you have problems writing tests, ask for help in the related issue.
|
22
|
+
2) Follow the style conventions of the surrounding code. In most cases, this is standard ruby style.
|
23
|
+
3) Add API documentation if it's a new feature
|
24
|
+
4) Update API documentation if it changes an existing feature
|
25
|
+
5) Bonus points for sending a PR to [github.com/dry-rb/dry-rb.org](github.com/dry-rb/dry-rb.org) which updates user documentation and guides
|
26
|
+
|
27
|
+
# Asking for help
|
28
|
+
|
29
|
+
If these guidelines aren't helpful, and you're stuck, please post a message on [discuss.dry-rb.org](https://discuss.dry-rb.org).
|
data/README.md
CHANGED
@@ -20,7 +20,7 @@
|
|
20
20
|
|
21
21
|
## Development
|
22
22
|
|
23
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake
|
23
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake run_specs` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
24
24
|
|
25
25
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
26
26
|
|
data/dry-types.gemspec
CHANGED
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.bindir = "exe"
|
27
27
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
28
|
spec.require_paths = ["lib"]
|
29
|
-
spec.required_ruby_version = ">= 2.
|
29
|
+
spec.required_ruby_version = ">= 2.2.0"
|
30
30
|
|
31
31
|
spec.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
|
32
32
|
spec.add_runtime_dependency 'dry-core', '~> 0.2', '>= 0.2.1'
|
data/lib/dry/types.rb
CHANGED
@@ -15,6 +15,7 @@ require 'dry/types/container'
|
|
15
15
|
require 'dry/types/type'
|
16
16
|
require 'dry/types/definition'
|
17
17
|
require 'dry/types/constructor'
|
18
|
+
require 'dry/types/fn_container'
|
18
19
|
|
19
20
|
require 'dry/types/errors'
|
20
21
|
|
@@ -51,6 +52,11 @@ module Dry
|
|
51
52
|
@container ||= Container.new
|
52
53
|
end
|
53
54
|
|
55
|
+
# @api private
|
56
|
+
def self.registered?(class_or_identifier)
|
57
|
+
container.key?(identifier(class_or_identifier))
|
58
|
+
end
|
59
|
+
|
54
60
|
# @param [String] name
|
55
61
|
# @param [Type] type
|
56
62
|
# @param [#call,nil] block
|
data/lib/dry/types/array.rb
CHANGED
data/lib/dry/types/compiler.rb
CHANGED
@@ -11,73 +11,76 @@ module Dry
|
|
11
11
|
visit(ast)
|
12
12
|
end
|
13
13
|
|
14
|
-
def visit(node
|
15
|
-
|
14
|
+
def visit(node)
|
15
|
+
type, body = node
|
16
|
+
send(:"visit_#{ type }", body)
|
16
17
|
end
|
17
18
|
|
18
19
|
def visit_constructor(node)
|
19
|
-
|
20
|
+
definition, fn_register_name, meta = node
|
21
|
+
fn = Dry::Types::FnContainer[fn_register_name]
|
22
|
+
primitive = visit(definition)
|
20
23
|
Types::Constructor.new(primitive, &fn)
|
21
24
|
end
|
22
25
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
26
|
+
def visit_safe(node)
|
27
|
+
ast, meta = node
|
28
|
+
Types::Safe.new(visit(ast), meta: meta)
|
29
|
+
end
|
30
|
+
|
31
|
+
def visit_definition(node)
|
32
|
+
type, meta = node
|
26
33
|
|
27
|
-
if
|
28
|
-
|
34
|
+
if registry.registered?(type)
|
35
|
+
registry[type].meta(meta)
|
29
36
|
else
|
30
|
-
|
37
|
+
Definition.new(type, meta: meta)
|
31
38
|
end
|
32
39
|
end
|
33
40
|
|
34
41
|
def visit_sum(node)
|
35
|
-
|
42
|
+
*types, meta = node
|
43
|
+
types.map { |type| visit(type) }.reduce(:|).meta(meta)
|
36
44
|
end
|
37
45
|
|
38
46
|
def visit_array(node)
|
39
|
-
|
47
|
+
member, meta = node
|
48
|
+
registry['array'].member(visit(member)).meta(meta)
|
40
49
|
end
|
41
50
|
|
42
|
-
def
|
43
|
-
|
51
|
+
def visit_hash(node)
|
52
|
+
constructor, schema, meta = node
|
53
|
+
merge_with('hash', constructor, schema).meta(meta)
|
44
54
|
end
|
45
55
|
|
46
|
-
def
|
47
|
-
|
56
|
+
def visit_json_hash(node)
|
57
|
+
schema, meta = node
|
58
|
+
merge_with('json.hash', :symbolized, schema).meta(meta)
|
48
59
|
end
|
49
60
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
61
|
+
def visit_json_array(node)
|
62
|
+
member, meta = node
|
63
|
+
registry['json.array'].member(visit(member)).meta(meta)
|
53
64
|
end
|
54
65
|
|
55
66
|
def visit_form_hash(node)
|
56
|
-
|
57
|
-
|
58
|
-
merge_with('form.hash', constructor, schema)
|
59
|
-
else
|
60
|
-
registry['form.hash']
|
61
|
-
end
|
67
|
+
schema, meta = node
|
68
|
+
merge_with('form.hash', :symbolized, schema).meta(meta)
|
62
69
|
end
|
63
70
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
merge_with('json.hash', constructor, schema)
|
68
|
-
else
|
69
|
-
registry['json.hash']
|
70
|
-
end
|
71
|
+
def visit_form_array(node)
|
72
|
+
member, meta = node
|
73
|
+
registry['form.array'].member(visit(member)).meta(meta)
|
71
74
|
end
|
72
75
|
|
73
|
-
def
|
74
|
-
name,
|
75
|
-
{ name => visit(
|
76
|
+
def visit_member(node)
|
77
|
+
name, type = node
|
78
|
+
{ name => visit(type) }
|
76
79
|
end
|
77
80
|
|
78
81
|
def merge_with(hash_id, constructor, schema)
|
79
82
|
registry[hash_id].__send__(
|
80
|
-
constructor, schema.map { |key| visit(key) }.reduce({}, :
|
83
|
+
constructor, schema.map { |key| visit(key) }.reduce({}, :update)
|
81
84
|
)
|
82
85
|
end
|
83
86
|
end
|
@@ -73,6 +73,15 @@ module Dry
|
|
73
73
|
valid?(value)
|
74
74
|
end
|
75
75
|
|
76
|
+
# @api public
|
77
|
+
#
|
78
|
+
# @see Definition#to_ast
|
79
|
+
def to_ast(meta: true)
|
80
|
+
[:constrained, [type.to_ast(meta: meta),
|
81
|
+
rule.to_ast,
|
82
|
+
meta ? self.meta : EMPTY_HASH]]
|
83
|
+
end
|
84
|
+
|
76
85
|
private
|
77
86
|
|
78
87
|
# @param [Object] response
|
@@ -72,8 +72,21 @@ module Dry
|
|
72
72
|
Constrained::Coercible
|
73
73
|
end
|
74
74
|
|
75
|
+
# @api public
|
76
|
+
#
|
77
|
+
# @see Definition#to_ast
|
78
|
+
def to_ast(meta: true)
|
79
|
+
[:constructor, [type.to_ast(meta: meta),
|
80
|
+
register_fn(fn),
|
81
|
+
meta ? self.meta : EMPTY_HASH]]
|
82
|
+
end
|
83
|
+
|
75
84
|
private
|
76
85
|
|
86
|
+
def register_fn(fn)
|
87
|
+
Dry::Types::FnContainer.register(fn)
|
88
|
+
end
|
89
|
+
|
77
90
|
# @param [Symbol] meth
|
78
91
|
# @param [Boolean] include_private
|
79
92
|
# @return [Boolean]
|
data/lib/dry/types/definition.rb
CHANGED
@@ -106,6 +106,15 @@ module Dry
|
|
106
106
|
end
|
107
107
|
alias_method :valid?, :primitive?
|
108
108
|
alias_method :===, :primitive?
|
109
|
+
|
110
|
+
# Return AST representation of a type definition
|
111
|
+
#
|
112
|
+
# @api public
|
113
|
+
#
|
114
|
+
# @return [Array]
|
115
|
+
def to_ast(meta: true)
|
116
|
+
[:definition, [primitive, meta ? self.meta : EMPTY_HASH]]
|
117
|
+
end
|
109
118
|
end
|
110
119
|
end
|
111
120
|
end
|
data/lib/dry/types/enum.rb
CHANGED
@@ -41,6 +41,13 @@ module Dry
|
|
41
41
|
raise '.enum(*values).default(value) is not supported. Call '\
|
42
42
|
'.default(value).enum(*values) instead'
|
43
43
|
end
|
44
|
+
|
45
|
+
# @api public
|
46
|
+
#
|
47
|
+
# @see Definition#to_ast
|
48
|
+
def to_ast(meta: true)
|
49
|
+
[:enum, [type.to_ast(meta: meta), meta ? self.meta : EMPTY_HASH]]
|
50
|
+
end
|
44
51
|
end
|
45
52
|
end
|
46
53
|
end
|
data/lib/dry/types/errors.rb
CHANGED
@@ -9,8 +9,9 @@ module Dry
|
|
9
9
|
class SchemaError < TypeError
|
10
10
|
# @param [String,Symbol] key
|
11
11
|
# @param [Object] value
|
12
|
-
|
13
|
-
|
12
|
+
# @param [String, #to_s] result
|
13
|
+
def initialize(key, value, result)
|
14
|
+
super("#{value.inspect} (#{value.class}) has invalid type for :#{key} violates constraints (#{result} failed)")
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'dry/types/container'
|
2
|
+
|
3
|
+
module Dry
|
4
|
+
module Types
|
5
|
+
class FnContainer
|
6
|
+
# @api private
|
7
|
+
def self.container
|
8
|
+
@container ||= Container.new
|
9
|
+
end
|
10
|
+
|
11
|
+
# @api private
|
12
|
+
def self.register(function)
|
13
|
+
register_function_name = register_name(function)
|
14
|
+
container.register(register_function_name, function) unless container.key?(register_function_name)
|
15
|
+
register_function_name
|
16
|
+
end
|
17
|
+
|
18
|
+
# @api private
|
19
|
+
def self.[](function_name)
|
20
|
+
if container.key?(function_name)
|
21
|
+
container[function_name]
|
22
|
+
else
|
23
|
+
function_name
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# @api private
|
28
|
+
def self.register_name(function)
|
29
|
+
"fn_#{function.object_id}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -58,8 +58,23 @@ module Dry
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
+
def to_ast(meta: true)
|
62
|
+
[
|
63
|
+
:hash,
|
64
|
+
[
|
65
|
+
hash_type,
|
66
|
+
member_types.map { |name, member| [:member, [name, member.to_ast(meta: meta)]] },
|
67
|
+
meta ? self.meta : EMPTY_HASH
|
68
|
+
]
|
69
|
+
]
|
70
|
+
end
|
71
|
+
|
61
72
|
private
|
62
73
|
|
74
|
+
def hash_type
|
75
|
+
:schema
|
76
|
+
end
|
77
|
+
|
63
78
|
# @param [Hash] hash
|
64
79
|
# @return [Hash{Symbol => Object}]
|
65
80
|
def try_coerce(hash)
|
@@ -74,8 +89,8 @@ module Dry
|
|
74
89
|
resolve(hash) do |type, key, value|
|
75
90
|
begin
|
76
91
|
type.call(value)
|
77
|
-
rescue ConstraintError
|
78
|
-
raise SchemaError.new(key, value)
|
92
|
+
rescue ConstraintError => e
|
93
|
+
raise SchemaError.new(key, value, e.result)
|
79
94
|
end
|
80
95
|
end
|
81
96
|
end
|
@@ -114,6 +129,10 @@ module Dry
|
|
114
129
|
class Permissive < Schema
|
115
130
|
private
|
116
131
|
|
132
|
+
def hash_type
|
133
|
+
:permissive
|
134
|
+
end
|
135
|
+
|
117
136
|
# @param [Symbol] key
|
118
137
|
# @raise [MissingKeyError] when key is missing in given input
|
119
138
|
def resolve_missing_value(_, key, _)
|
@@ -132,6 +151,10 @@ module Dry
|
|
132
151
|
class Strict < Permissive
|
133
152
|
private
|
134
153
|
|
154
|
+
def hash_type
|
155
|
+
:strict
|
156
|
+
end
|
157
|
+
|
135
158
|
# @param [Hash] hash
|
136
159
|
# @return [Hash{Symbol => Object}]
|
137
160
|
# @raise [UnknownKeysError]
|
@@ -160,6 +183,10 @@ module Dry
|
|
160
183
|
class StrictWithDefaults < Strict
|
161
184
|
private
|
162
185
|
|
186
|
+
def hash_type
|
187
|
+
:strict_with_defaults
|
188
|
+
end
|
189
|
+
|
163
190
|
# @param [Hash] result
|
164
191
|
# @param [Symbol] key
|
165
192
|
# @param [Type] type
|
@@ -203,12 +230,22 @@ module Dry
|
|
203
230
|
block ? yield(result) : result
|
204
231
|
end
|
205
232
|
end
|
233
|
+
|
234
|
+
private
|
235
|
+
|
236
|
+
def hash_type
|
237
|
+
:weak
|
238
|
+
end
|
206
239
|
end
|
207
240
|
|
208
241
|
# {Symbolized} hash will turn string key names into symbols.
|
209
242
|
class Symbolized < Weak
|
210
243
|
private
|
211
244
|
|
245
|
+
def hash_type
|
246
|
+
:symbolized
|
247
|
+
end
|
248
|
+
|
212
249
|
def resolve(hash)
|
213
250
|
result = {}
|
214
251
|
member_types.each do |key, type|
|
data/lib/dry/types/options.rb
CHANGED
@@ -24,7 +24,13 @@ module Dry
|
|
24
24
|
# @param [Hash] new metadata to merge into existing metadata
|
25
25
|
# @return [Type] new type with added metadata
|
26
26
|
def meta(data = nil)
|
27
|
-
|
27
|
+
if !data
|
28
|
+
@meta
|
29
|
+
elsif data.empty?
|
30
|
+
self
|
31
|
+
else
|
32
|
+
with(meta: @meta.merge(data))
|
33
|
+
end
|
28
34
|
end
|
29
35
|
|
30
36
|
# Resets meta
|
data/lib/dry/types/safe.rb
CHANGED
@@ -33,6 +33,19 @@ module Dry
|
|
33
33
|
block ? yield(result) : result
|
34
34
|
end
|
35
35
|
|
36
|
+
# @api public
|
37
|
+
#
|
38
|
+
# @see Definition#to_ast
|
39
|
+
def to_ast(meta: true)
|
40
|
+
[:safe, [type.to_ast, meta ? self.meta : EMPTY_HASH]]
|
41
|
+
end
|
42
|
+
|
43
|
+
# @api public
|
44
|
+
# @return [Safe]
|
45
|
+
def safe
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
36
49
|
private
|
37
50
|
|
38
51
|
# @param [Object, Dry::Types::Constructor] response
|
data/lib/dry/types/sum.rb
CHANGED
@@ -102,6 +102,13 @@ module Dry
|
|
102
102
|
def valid?(value)
|
103
103
|
left.valid?(value) || right.valid?(value)
|
104
104
|
end
|
105
|
+
|
106
|
+
# @api public
|
107
|
+
#
|
108
|
+
# @see Definition#to_ast
|
109
|
+
def to_ast(meta: true)
|
110
|
+
[:sum, [left.to_ast(meta: meta), right.to_ast(meta: meta), meta ? self.meta : EMPTY_HASH]]
|
111
|
+
end
|
105
112
|
end
|
106
113
|
end
|
107
114
|
end
|
data/lib/dry/types/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-types
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Solnica
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-06-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -209,6 +209,7 @@ files:
|
|
209
209
|
- ".travis.yml"
|
210
210
|
- ".yardopts"
|
211
211
|
- CHANGELOG.md
|
212
|
+
- CONTRIBUTING.md
|
212
213
|
- Gemfile
|
213
214
|
- LICENSE
|
214
215
|
- README.md
|
@@ -238,6 +239,7 @@ files:
|
|
238
239
|
- lib/dry/types/errors.rb
|
239
240
|
- lib/dry/types/extensions.rb
|
240
241
|
- lib/dry/types/extensions/maybe.rb
|
242
|
+
- lib/dry/types/fn_container.rb
|
241
243
|
- lib/dry/types/form.rb
|
242
244
|
- lib/dry/types/hash.rb
|
243
245
|
- lib/dry/types/hash/schema.rb
|
@@ -262,7 +264,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
262
264
|
requirements:
|
263
265
|
- - ">="
|
264
266
|
- !ruby/object:Gem::Version
|
265
|
-
version: 2.
|
267
|
+
version: 2.2.0
|
266
268
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
267
269
|
requirements:
|
268
270
|
- - ">="
|
@@ -270,7 +272,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
270
272
|
version: '0'
|
271
273
|
requirements: []
|
272
274
|
rubyforge_project:
|
273
|
-
rubygems_version: 2.6.
|
275
|
+
rubygems_version: 2.6.9
|
274
276
|
signing_key:
|
275
277
|
specification_version: 4
|
276
278
|
summary: Type system for Ruby supporting coercions, constraints and complex types
|