dry-types 1.2.2 → 1.3.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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +306 -225
  3. data/LICENSE +1 -1
  4. data/README.md +14 -12
  5. data/dry-types.gemspec +27 -31
  6. data/lib/dry/types.rb +0 -9
  7. data/lib/dry/types/builder.rb +4 -0
  8. data/lib/dry/types/constructor/function.rb +17 -31
  9. data/lib/dry/types/core.rb +3 -1
  10. data/lib/dry/types/decorator.rb +0 -7
  11. data/lib/dry/types/extensions/maybe.rb +14 -14
  12. data/lib/dry/types/lax.rb +1 -4
  13. data/lib/dry/types/meta.rb +2 -2
  14. data/lib/dry/types/params.rb +1 -0
  15. data/lib/dry/types/result.rb +2 -2
  16. data/lib/dry/types/schema.rb +23 -2
  17. data/lib/dry/types/schema/key.rb +11 -2
  18. data/lib/dry/types/spec/types.rb +11 -0
  19. data/lib/dry/types/sum.rb +2 -2
  20. data/lib/dry/types/version.rb +1 -1
  21. metadata +21 -59
  22. data/.codeclimate.yml +0 -12
  23. data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +0 -10
  24. data/.github/ISSUE_TEMPLATE/---bug-report.md +0 -30
  25. data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
  26. data/.github/workflows/custom_ci.yml +0 -76
  27. data/.github/workflows/docsite.yml +0 -34
  28. data/.github/workflows/sync_configs.yml +0 -34
  29. data/.gitignore +0 -11
  30. data/.rspec +0 -4
  31. data/.rubocop.yml +0 -92
  32. data/.yardopts +0 -9
  33. data/CODE_OF_CONDUCT.md +0 -13
  34. data/CONTRIBUTING.md +0 -29
  35. data/Gemfile +0 -34
  36. data/Rakefile +0 -22
  37. data/benchmarks/hash_schemas.rb +0 -55
  38. data/benchmarks/lax_schema.rb +0 -15
  39. data/benchmarks/profile_invalid_input.rb +0 -15
  40. data/benchmarks/profile_lax_schema_valid.rb +0 -16
  41. data/benchmarks/profile_valid_input.rb +0 -15
  42. data/benchmarks/schema_valid_vs_invalid.rb +0 -21
  43. data/benchmarks/setup.rb +0 -17
  44. data/docsite/source/array-with-member.html.md +0 -13
  45. data/docsite/source/built-in-types.html.md +0 -116
  46. data/docsite/source/constraints.html.md +0 -31
  47. data/docsite/source/custom-types.html.md +0 -93
  48. data/docsite/source/default-values.html.md +0 -91
  49. data/docsite/source/enum.html.md +0 -69
  50. data/docsite/source/extensions.html.md +0 -15
  51. data/docsite/source/extensions/maybe.html.md +0 -57
  52. data/docsite/source/extensions/monads.html.md +0 -61
  53. data/docsite/source/getting-started.html.md +0 -57
  54. data/docsite/source/hash-schemas.html.md +0 -169
  55. data/docsite/source/index.html.md +0 -156
  56. data/docsite/source/map.html.md +0 -17
  57. data/docsite/source/optional-values.html.md +0 -35
  58. data/docsite/source/sum.html.md +0 -21
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2019 dry-rb team
3
+ Copyright (c) 2015-2020 dry-rb team
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
data/README.md CHANGED
@@ -1,27 +1,29 @@
1
1
  [gem]: https://rubygems.org/gems/dry-types
2
- [ci]: https://github.com/dry-rb/dry-types/actions?query=workflow%3Aci
3
- [codeclimate]: https://codeclimate.com/github/dry-rb/dry-types
4
- [inchpages]: http://inch-ci.org/github/dry-rb/dry-types
2
+ [actions]: https://github.com/dry-rb/dry-types/actions
3
+ [codacy]: https://www.codacy.com/gh/dry-rb/dry-types
5
4
  [chat]: https://dry-rb.zulipchat.com
5
+ [inchpages]: http://inch-ci.org/github/dry-rb/dry-types
6
6
 
7
7
  # dry-types [![Join the chat at https://dry-rb.zulipchat.com](https://img.shields.io/badge/dry--rb-join%20chat-%23346b7a.svg)][chat]
8
8
 
9
9
  [![Gem Version](https://badge.fury.io/rb/dry-types.svg)][gem]
10
- [![Build Status](https://github.com/dry-rb/dry-types/workflows/ci/badge.svg)][ci]
11
- [![Code Climate](https://codeclimate.com/github/dry-rb/dry-types/badges/gpa.svg)][codeclimate]
12
- [![Test Coverage](https://codeclimate.com/github/dry-rb/dry-types/badges/coverage.svg)][codeclimate]
10
+ [![CI Status](https://github.com/dry-rb/dry-types/workflows/ci/badge.svg)][actions]
11
+ [![Codacy Badge](https://api.codacy.com/project/badge/Grade/f2d71613195f4da993acb9ac9d6ea336)][codacy]
12
+ [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/f2d71613195f4da993acb9ac9d6ea336)][codacy]
13
13
  [![Inline docs](http://inch-ci.org/github/dry-rb/dry-types.svg?branch=master)][inchpages]
14
14
 
15
15
  ## Links
16
16
 
17
- - [Documentation](http://dry-rb.org/gems/dry-types)
17
+ * [User documentation](http://dry-rb.org/gems/dry-types)
18
+ * [API documentation](http://rubydoc.info/gems/dry-types)
18
19
 
19
- ## Development
20
+ ## Supported Ruby versions
20
21
 
21
- 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.
22
+ This library officially supports the following Ruby versions:
22
23
 
23
- 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).
24
+ * MRI >= `2.4`
25
+ * jruby >= `9.2`
24
26
 
25
- ## Contributing
27
+ ## License
26
28
 
27
- Bug reports and pull requests are welcome on GitHub at https://github.com/dry-rb/dry-types.
29
+ See `LICENSE` file.
data/dry-types.gemspec CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+ # this file is managed by dry-rb/devtools project
2
3
 
3
4
  lib = File.expand_path('lib', __dir__)
4
5
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
@@ -6,42 +7,37 @@ require 'dry/types/version'
6
7
 
7
8
  Gem::Specification.new do |spec|
8
9
  spec.name = 'dry-types'
9
- spec.version = Dry::Types::VERSION.dup
10
- spec.authors = ['Piotr Solnica']
11
- spec.email = ['piotr.solnica@gmail.com']
10
+ spec.authors = ["Piotr Solnica"]
11
+ spec.email = ["piotr.solnica@gmail.com"]
12
12
  spec.license = 'MIT'
13
+ spec.version = Dry::Types::VERSION.dup
13
14
 
14
- spec.summary = 'Type system for Ruby supporting coercions, constraints and complex types like structs, value objects, enums etc.'
15
+ spec.summary = "Type system for Ruby supporting coercions, constraints and complex types like structs, value objects, enums etc"
15
16
  spec.description = spec.summary
16
- spec.homepage = 'https://github.com/dry-rb/dry-types'
17
+ spec.homepage = 'https://dry-rb.org/gems/dry-types'
18
+ spec.files = Dir["CHANGELOG.md", "LICENSE", "README.md", "dry-types.gemspec", "lib/**/*"]
19
+ spec.bindir = 'bin'
20
+ spec.executables = []
21
+ spec.require_paths = ['lib']
17
22
 
18
- # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
19
- # delete this section to allow pushing this gem to any host.
20
- if spec.respond_to?(:metadata)
21
- spec.metadata['allowed_push_host'] = 'https://rubygems.org'
22
- spec.metadata['changelog_uri'] = 'https://github.com/dry-rb/dry-types/blob/master/CHANGELOG.md'
23
- spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-types'
24
- spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-types/issues'
25
- else
26
- raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
27
- end
23
+ spec.metadata['allowed_push_host'] = 'https://rubygems.org'
24
+ spec.metadata['changelog_uri'] = 'https://github.com/dry-rb/dry-types/blob/master/CHANGELOG.md'
25
+ spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-types'
26
+ spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-types/issues'
28
27
 
29
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } - ['bin/console', 'bin/setup']
30
- spec.bindir = 'exe'
31
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
- spec.require_paths = ['lib']
33
- spec.required_ruby_version = '>= 2.4.0'
28
+ spec.required_ruby_version = ">= 2.4.0"
34
29
 
35
- spec.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
36
- spec.add_runtime_dependency 'dry-container', '~> 0.3'
37
- spec.add_runtime_dependency 'dry-core', '~> 0.4', '>= 0.4.4'
38
- spec.add_runtime_dependency 'dry-equalizer', '~> 0.3'
39
- spec.add_runtime_dependency 'dry-inflector', '~> 0.1', '>= 0.1.2'
40
- spec.add_runtime_dependency 'dry-logic', '~> 1.0', '>= 1.0.2'
30
+ # to update dependencies edit project.yml
31
+ spec.add_runtime_dependency "concurrent-ruby", "~> 1.0"
32
+ spec.add_runtime_dependency "dry-container", "~> 0.3"
33
+ spec.add_runtime_dependency "dry-core", "~> 0.4", ">= 0.4.4"
34
+ spec.add_runtime_dependency "dry-equalizer", "~> 0.3"
35
+ spec.add_runtime_dependency "dry-inflector", "~> 0.1", ">= 0.1.2"
36
+ spec.add_runtime_dependency "dry-logic", "~> 1.0", ">= 1.0.2"
41
37
 
42
- spec.add_development_dependency 'bundler'
43
- spec.add_development_dependency 'dry-monads', '~> 0.2'
44
- spec.add_development_dependency 'rake', '~> 11.0'
45
- spec.add_development_dependency 'rspec', '~> 3.3'
46
- spec.add_development_dependency 'yard', '~> 0.9.5'
38
+ spec.add_development_dependency "bundler"
39
+ spec.add_development_dependency "dry-monads", "~> 1.0"
40
+ spec.add_development_dependency "rake"
41
+ spec.add_development_dependency "rspec"
42
+ spec.add_development_dependency "yard"
47
43
  end
data/lib/dry/types.rb CHANGED
@@ -133,15 +133,6 @@ module Dry
133
133
  @type_map ||= Concurrent::Map.new
134
134
  end
135
135
 
136
- # List of type keys defined in {Dry::Types.container}
137
- #
138
- # @return [String]
139
- #
140
- # @api private
141
- def self.type_keys
142
- container.keys
143
- end
144
-
145
136
  # @api private
146
137
  def self.const_missing(const)
147
138
  underscored = Inflector.underscore(const)
@@ -129,6 +129,10 @@ module Dry
129
129
  def constructor(constructor = nil, **options, &block)
130
130
  constructor_type.new(with(**options), fn: constructor || block)
131
131
  end
132
+ alias_method :append, :constructor
133
+ alias_method :prepend, :constructor
134
+ alias_method :>>, :constructor
135
+ alias_method :<<, :constructor
132
136
  end
133
137
  end
134
138
  end
@@ -15,7 +15,7 @@ module Dry
15
15
  class Safe < Function
16
16
  def call(input, &block)
17
17
  @fn.(input, &block)
18
- rescue NoMethodError, TypeError, ArgumentError => e
18
+ rescue ::NoMethodError, ::TypeError, ::ArgumentError => e
19
19
  CoercionError.handle(e, &block)
20
20
  end
21
21
  end
@@ -30,7 +30,7 @@ module Dry
30
30
  #
31
31
  # @return [Function]
32
32
  def self.call_class(method, public, safe)
33
- @cache.fetch_or_store([method, public, safe].hash) do
33
+ @cache.fetch_or_store([method, public, safe]) do
34
34
  if public
35
35
  ::Class.new(PublicCall) do
36
36
  include PublicCall.call_interface(method, safe)
@@ -53,7 +53,7 @@ module Dry
53
53
  #
54
54
  # @return [::Module]
55
55
  def self.call_interface(method, safe)
56
- @interfaces.fetch_or_store([method, safe].hash) do
56
+ @interfaces.fetch_or_store([method, safe]) do
57
57
  ::Module.new do
58
58
  if safe
59
59
  module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
@@ -65,7 +65,7 @@ module Dry
65
65
  module_eval(<<~RUBY, __FILE__, __LINE__ + 1)
66
66
  def call(input, &block)
67
67
  @target.#{method}(input)
68
- rescue NoMethodError, TypeError, ArgumentError => error
68
+ rescue ::NoMethodError, ::TypeError, ::ArgumentError => error
69
69
  CoercionError.handle(error, &block)
70
70
  end
71
71
  RUBY
@@ -90,7 +90,7 @@ module Dry
90
90
  class PrivateSafeCall < PrivateCall
91
91
  def call(input, &block)
92
92
  @target.send(@name, input)
93
- rescue NoMethodError, TypeError, ArgumentError => e
93
+ rescue ::NoMethodError, ::TypeError, ::ArgumentError => e
94
94
  CoercionError.handle(e, &block)
95
95
  end
96
96
  end
@@ -121,7 +121,7 @@ module Dry
121
121
  # @param [#call] fn
122
122
  # @return [Function]
123
123
  def self.[](fn)
124
- raise ArgumentError, 'Missing constructor block' if fn.nil?
124
+ raise ::ArgumentError, 'Missing constructor block' if fn.nil?
125
125
 
126
126
  if fn.is_a?(Function)
127
127
  fn
@@ -146,7 +146,7 @@ module Dry
146
146
  last_arg.equal?(:block)
147
147
  end
148
148
 
149
- include Dry::Equalizer(:fn, immutable: true)
149
+ include ::Dry::Equalizer(:fn, immutable: true)
150
150
 
151
151
  attr_reader :fn
152
152
 
@@ -163,36 +163,22 @@ module Dry
163
163
  # @return [Array]
164
164
  def to_ast
165
165
  if fn.is_a?(::Proc)
166
- [:id, Dry::Types::FnContainer.register(fn)]
166
+ [:id, FnContainer.register(fn)]
167
167
  else
168
168
  [:callable, fn]
169
169
  end
170
170
  end
171
171
 
172
- if RUBY_VERSION >= '2.6'
173
- # @return [Function]
174
- def >>(other)
175
- proc = other.is_a?(::Proc) ? other : other.fn
176
- Function[@fn >> proc]
177
- end
178
-
179
- # @return [Function]
180
- def <<(other)
181
- proc = other.is_a?(::Proc) ? other : other.fn
182
- Function[@fn << proc]
183
- end
184
- else
185
- # @return [Function]
186
- def >>(other)
187
- proc = other.is_a?(::Proc) ? other : other.fn
188
- Function[-> x { proc[@fn[x]] }]
189
- end
172
+ # @return [Function]
173
+ def >>(other)
174
+ f = Function[other]
175
+ Function[-> x, &b { f.(self.(x, &b), &b) }]
176
+ end
190
177
 
191
- # @return [Function]
192
- def <<(other)
193
- proc = other.is_a?(::Proc) ? other : other.fn
194
- Function[-> x { @fn[proc[x]] }]
195
- end
178
+ # @return [Function]
179
+ def <<(other)
180
+ f = Function[other]
181
+ Function[-> x, &b { self.(f.(x, &b), &b) }]
196
182
  end
197
183
  end
198
184
  end
@@ -72,7 +72,9 @@ module Dry
72
72
 
73
73
  # Register optional strict {NON_NIL} types
74
74
  NON_NIL.each_key do |name|
75
- register("optional.strict.#{name}", self["strict.#{name}"].optional)
75
+ type = self[name.to_s].optional
76
+ register("optional.strict.#{name}", type)
77
+ register("optional.#{name}", type)
76
78
  end
77
79
 
78
80
  # Register optional {COERCIBLE} types
@@ -44,13 +44,6 @@ module Dry
44
44
  type.constrained?
45
45
  end
46
46
 
47
- # @return [Sum]
48
- #
49
- # @api public
50
- def optional
51
- Types['strict.nil'] | self
52
- end
53
-
54
47
  # @param [Symbol] meth
55
48
  # @param [Boolean] include_private
56
49
  #
@@ -10,11 +10,11 @@ module Dry
10
10
  # @api public
11
11
  class Maybe
12
12
  include Type
13
- include Dry::Equalizer(:type, :options, inspect: false, immutable: true)
13
+ include ::Dry::Equalizer(:type, :options, inspect: false, immutable: true)
14
14
  include Decorator
15
15
  include Builder
16
16
  include Printable
17
- include Dry::Monads::Maybe::Mixin
17
+ include ::Dry::Monads::Maybe::Mixin
18
18
 
19
19
  # @param [Dry::Monads::Maybe, Object] input
20
20
  #
@@ -23,7 +23,7 @@ module Dry
23
23
  # @api private
24
24
  def call_unsafe(input = Undefined)
25
25
  case input
26
- when Dry::Monads::Maybe
26
+ when ::Dry::Monads::Maybe
27
27
  input
28
28
  when Undefined
29
29
  None()
@@ -37,14 +37,14 @@ module Dry
37
37
  # @return [Dry::Monads::Maybe]
38
38
  #
39
39
  # @api private
40
- def call_safe(input = Undefined, &block)
40
+ def call_safe(input = Undefined)
41
41
  case input
42
- when Dry::Monads::Maybe
42
+ when ::Dry::Monads::Maybe
43
43
  input
44
44
  when Undefined
45
45
  None()
46
46
  else
47
- Maybe(type.call_safe(input, &block))
47
+ Maybe(type.call_safe(input) { |output = input| return yield(output) })
48
48
  end
49
49
  end
50
50
 
@@ -54,13 +54,13 @@ module Dry
54
54
  #
55
55
  # @api public
56
56
  def try(input = Undefined)
57
- res = if input.equal?(Undefined)
58
- None()
59
- else
60
- Maybe(type[input])
61
- end
57
+ result = type.try(input)
62
58
 
63
- Result::Success.new(res)
59
+ if result.success?
60
+ Result::Success.new(Maybe(result.input))
61
+ else
62
+ result
63
+ end
64
64
  end
65
65
 
66
66
  # @return [true]
@@ -93,7 +93,7 @@ module Dry
93
93
  #
94
94
  # @api public
95
95
  def maybe
96
- Maybe.new(Types['strict.nil'] | self)
96
+ Maybe.new(Types['nil'] | self)
97
97
  end
98
98
  end
99
99
 
@@ -119,7 +119,7 @@ module Dry
119
119
 
120
120
  # Register non-coercible maybe types
121
121
  NON_NIL.each_key do |name|
122
- register("maybe.strict.#{name}", self["strict.#{name}"].maybe)
122
+ register("maybe.strict.#{name}", self[name.to_s].maybe)
123
123
  end
124
124
 
125
125
  # Register coercible maybe types
data/lib/dry/types/lax.rb CHANGED
@@ -15,7 +15,7 @@ module Dry
15
15
  include Printable
16
16
  include Dry::Equalizer(:type, inspect: false, immutable: true)
17
17
 
18
- undef :options, :constructor
18
+ undef :options, :constructor, :<<, :>>, :prepend, :append
19
19
 
20
20
  # @param [Object] input
21
21
  #
@@ -40,9 +40,6 @@ module Dry
40
40
  # @api public
41
41
  def try(input, &block)
42
42
  type.try(input, &block)
43
- rescue CoercionError => e
44
- result = failure(input, e.message)
45
- block ? yield(result) : result
46
43
  end
47
44
 
48
45
  # @see Nominal#to_ast
@@ -28,8 +28,8 @@ module Dry
28
28
  # @return [Type] new type with added metadata
29
29
  #
30
30
  # @api public
31
- def meta(data = nil)
32
- if !data
31
+ def meta(data = Undefined)
32
+ if Undefined.equal?(data)
33
33
  @meta
34
34
  elsif data.empty?
35
35
  self
@@ -58,6 +58,7 @@ module Dry
58
58
 
59
59
  COERCIBLE.each_key do |name|
60
60
  next if name.equal?(:string)
61
+
61
62
  register("optional.params.#{name}", self['params.nil'] | self["params.#{name}"])
62
63
  end
63
64
  end
@@ -8,7 +8,7 @@ module Dry
8
8
  #
9
9
  # @api public
10
10
  class Result
11
- include Dry::Equalizer(:input, inspect: false, immutable: true)
11
+ include ::Dry::Equalizer(:input, immutable: true)
12
12
 
13
13
  # @return [Object]
14
14
  attr_reader :input
@@ -43,7 +43,7 @@ module Dry
43
43
  #
44
44
  # @api public
45
45
  class Failure < Result
46
- include Dry::Equalizer(:input, :error, inspect: false, immutable: true)
46
+ include ::Dry::Equalizer(:input, :error, immutable: true)
47
47
 
48
48
  # @return [#to_s]
49
49
  attr_reader :error
@@ -145,7 +145,7 @@ module Dry
145
145
  #
146
146
  # @api public
147
147
  def to_ast(meta: true)
148
- if RUBY_VERSION >= "2.5"
148
+ if RUBY_VERSION >= '2.5'
149
149
  opts = options.slice(:key_transform_fn, :type_transform_fn, :strict)
150
150
  else
151
151
  opts = options.select { |k, _|
@@ -179,7 +179,7 @@ module Dry
179
179
  with(strict: strict)
180
180
  end
181
181
 
182
- # Injects a key transformation function
182
+ # Inject a key transformation function
183
183
  #
184
184
  # @param [#call,nil] proc
185
185
  # @param [#call,nil] block
@@ -284,6 +284,27 @@ module Dry
284
284
  Lax.new(schema(keys.map(&:lax)))
285
285
  end
286
286
 
287
+ # Merge given schema keys into current schema
288
+ #
289
+ # A new instance is returned.
290
+ #
291
+ # @param schema [Schema]
292
+ # @return [Schema]
293
+ #
294
+ # @api public
295
+ def merge(other)
296
+ schema(other.keys)
297
+ end
298
+
299
+ # Empty schema with the same options
300
+ #
301
+ # @return [Schema]
302
+ #
303
+ # @api public
304
+ def clear
305
+ with(keys: EMPTY_ARRAY)
306
+ end
307
+
287
308
  private
288
309
 
289
310
  # @param [Array<Dry::Types::Schema::Keys>] keys