dry-types 0.10.3 → 0.11.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 39a0be1972bae04a7b9f3f45e5b4430948c825a1
4
- data.tar.gz: b74e55614628bc6a556ebef86a8bfa6abfc12e85
3
+ metadata.gz: 12cffdbb9c18b6f1ab0bb726c5a13fbd13c1178e
4
+ data.tar.gz: 150931c98379624c229416370bd63cd8830bbab5
5
5
  SHA512:
6
- metadata.gz: f2a0a595e1feb9a642269b6fdaaaf42be81f09a6cb31be3f30ed63a4ac85a1cf816fa1ba9e147b487cceff6436f52161fa032321c7828ed2c657d12a8fa13a72
7
- data.tar.gz: 1e5d6ad66e3fef84f7d31a0d430b2bb7b20c0225d5ad527e5cdf90a6f4dbcb12b8837705173372732034416aa76f6f915df044ef64305ad0d557675d8b1beca9
6
+ metadata.gz: 7b6bd371faf9ae94c6559c01309216205c3df88614c86cb2862929b2836d8cc4c32b76d916f6deeb6e4390bb296c8e1733e85e8997b3f00092584960961e02ee
7
+ data.tar.gz: 584c9552a9185595008a63c2ca6f3a8cc88ec56b7c063f720d36ff10d9c1b26b403443456416a484429cae4b7e10bd6a06995acd3adf99eb89b1026825a9fd83
@@ -9,17 +9,13 @@ script:
9
9
  - bundle exec rake
10
10
  rvm:
11
11
  - 2.2.7
12
- - 2.3.3
12
+ - 2.3.4
13
13
  - 2.4.1
14
- - jruby-9.1.8.0
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:
@@ -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
@@ -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 spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
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
 
@@ -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.1.0"
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'
@@ -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
@@ -14,6 +14,8 @@ module Dry
14
14
 
15
15
  Array::Member.new(primitive, options.merge(member: member))
16
16
  end
17
+
18
+ alias_method :of, :member
17
19
  end
18
20
  end
19
21
  end
@@ -48,6 +48,13 @@ module Dry
48
48
  block ? yield(failure) : failure
49
49
  end
50
50
  end
51
+
52
+ # @api public
53
+ #
54
+ # @see Definition#to_ast
55
+ def to_ast(meta: true)
56
+ [:array, [member.to_ast(meta: meta), meta ? self.meta : EMPTY_HASH]]
57
+ end
51
58
  end
52
59
  end
53
60
  end
@@ -11,73 +11,76 @@ module Dry
11
11
  visit(ast)
12
12
  end
13
13
 
14
- def visit(node, *args)
15
- send(:"visit_#{node[0]}", node[1], *args)
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
- primitive, fn = node
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 visit_type(node)
24
- type, args = node
25
- meth = :"visit_#{type.tr('.', '_')}"
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 respond_to?(meth) && args
28
- send(meth, args)
34
+ if registry.registered?(type)
35
+ registry[type].meta(meta)
29
36
  else
30
- registry[type]
37
+ Definition.new(type, meta: meta)
31
38
  end
32
39
  end
33
40
 
34
41
  def visit_sum(node)
35
- node.map { |type| visit(type) }.reduce(:|)
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
- registry['array'].member(call(node))
47
+ member, meta = node
48
+ registry['array'].member(visit(member)).meta(meta)
40
49
  end
41
50
 
42
- def visit_form_array(node)
43
- registry['form.array'].member(call(node))
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 visit_json_array(node)
47
- registry['json.array'].member(call(node))
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 visit_hash(node)
51
- constructor, schema = node
52
- merge_with('hash', constructor, schema)
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
- if node
57
- constructor, schema = node
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 visit_json_hash(node)
65
- if node
66
- constructor, schema = node
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 visit_key(node)
74
- name, types = node
75
- { name => visit(types) }
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({}, :merge)
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]
@@ -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
@@ -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
@@ -9,8 +9,9 @@ module Dry
9
9
  class SchemaError < TypeError
10
10
  # @param [String,Symbol] key
11
11
  # @param [Object] value
12
- def initialize(key, value)
13
- super("#{value.inspect} (#{value.class}) has invalid type for :#{key}")
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|
@@ -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
- data ? with(meta: @meta.merge(data)) : @meta
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
@@ -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
@@ -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
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module Types
3
- VERSION = '0.10.3'.freeze
3
+ VERSION = '0.11.0'.freeze
4
4
  end
5
5
  end
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.10.3
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-05-06 00:00:00.000000000 Z
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.1.0
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.11
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