dry-types 1.2.2 → 1.5.1

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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +405 -225
  3. data/LICENSE +1 -1
  4. data/README.md +14 -12
  5. data/dry-types.gemspec +26 -31
  6. data/lib/dry-types.rb +1 -1
  7. data/lib/dry/types.rb +55 -40
  8. data/lib/dry/types/any.rb +2 -2
  9. data/lib/dry/types/array.rb +2 -2
  10. data/lib/dry/types/array/constructor.rb +1 -1
  11. data/lib/dry/types/array/member.rb +1 -1
  12. data/lib/dry/types/builder.rb +70 -18
  13. data/lib/dry/types/builder_methods.rb +1 -2
  14. data/lib/dry/types/coercions.rb +0 -17
  15. data/lib/dry/types/coercions/json.rb +22 -5
  16. data/lib/dry/types/coercions/params.rb +20 -3
  17. data/lib/dry/types/compiler.rb +10 -10
  18. data/lib/dry/types/constrained.rb +6 -9
  19. data/lib/dry/types/constraints.rb +3 -3
  20. data/lib/dry/types/constructor.rb +40 -6
  21. data/lib/dry/types/constructor/function.rb +48 -32
  22. data/lib/dry/types/constructor/wrapper.rb +94 -0
  23. data/lib/dry/types/container.rb +1 -1
  24. data/lib/dry/types/core.rb +15 -13
  25. data/lib/dry/types/decorator.rb +2 -9
  26. data/lib/dry/types/default.rb +14 -1
  27. data/lib/dry/types/enum.rb +4 -3
  28. data/lib/dry/types/errors.rb +1 -1
  29. data/lib/dry/types/extensions.rb +2 -2
  30. data/lib/dry/types/extensions/maybe.rb +18 -17
  31. data/lib/dry/types/extensions/monads.rb +1 -1
  32. data/lib/dry/types/fn_container.rb +1 -1
  33. data/lib/dry/types/hash.rb +9 -15
  34. data/lib/dry/types/hash/constructor.rb +1 -1
  35. data/lib/dry/types/inflector.rb +1 -1
  36. data/lib/dry/types/json.rb +15 -15
  37. data/lib/dry/types/lax.rb +3 -6
  38. data/lib/dry/types/map.rb +2 -2
  39. data/lib/dry/types/meta.rb +3 -3
  40. data/lib/dry/types/module.rb +6 -6
  41. data/lib/dry/types/nominal.rb +11 -11
  42. data/lib/dry/types/params.rb +31 -28
  43. data/lib/dry/types/predicate_inferrer.rb +52 -11
  44. data/lib/dry/types/predicate_registry.rb +1 -1
  45. data/lib/dry/types/primitive_inferrer.rb +1 -1
  46. data/lib/dry/types/printer.rb +25 -25
  47. data/lib/dry/types/result.rb +3 -3
  48. data/lib/dry/types/schema.rb +26 -13
  49. data/lib/dry/types/schema/key.rb +15 -6
  50. data/lib/dry/types/spec/types.rb +65 -42
  51. data/lib/dry/types/sum.rb +6 -5
  52. data/lib/dry/types/type.rb +1 -1
  53. data/lib/dry/types/version.rb +1 -1
  54. metadata +27 -78
  55. data/.codeclimate.yml +0 -12
  56. data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +0 -10
  57. data/.github/ISSUE_TEMPLATE/---bug-report.md +0 -30
  58. data/.github/ISSUE_TEMPLATE/---feature-request.md +0 -18
  59. data/.github/workflows/custom_ci.yml +0 -76
  60. data/.github/workflows/docsite.yml +0 -34
  61. data/.github/workflows/sync_configs.yml +0 -34
  62. data/.gitignore +0 -11
  63. data/.rspec +0 -4
  64. data/.rubocop.yml +0 -92
  65. data/.yardopts +0 -9
  66. data/CODE_OF_CONDUCT.md +0 -13
  67. data/CONTRIBUTING.md +0 -29
  68. data/Gemfile +0 -34
  69. data/Rakefile +0 -22
  70. data/benchmarks/hash_schemas.rb +0 -55
  71. data/benchmarks/lax_schema.rb +0 -15
  72. data/benchmarks/profile_invalid_input.rb +0 -15
  73. data/benchmarks/profile_lax_schema_valid.rb +0 -16
  74. data/benchmarks/profile_valid_input.rb +0 -15
  75. data/benchmarks/schema_valid_vs_invalid.rb +0 -21
  76. data/benchmarks/setup.rb +0 -17
  77. data/docsite/source/array-with-member.html.md +0 -13
  78. data/docsite/source/built-in-types.html.md +0 -116
  79. data/docsite/source/constraints.html.md +0 -31
  80. data/docsite/source/custom-types.html.md +0 -93
  81. data/docsite/source/default-values.html.md +0 -91
  82. data/docsite/source/enum.html.md +0 -69
  83. data/docsite/source/extensions.html.md +0 -15
  84. data/docsite/source/extensions/maybe.html.md +0 -57
  85. data/docsite/source/extensions/monads.html.md +0 -61
  86. data/docsite/source/getting-started.html.md +0 -57
  87. data/docsite/source/hash-schemas.html.md +0 -169
  88. data/docsite/source/index.html.md +0 -156
  89. data/docsite/source/map.html.md +0 -17
  90. data/docsite/source/optional-values.html.md +0 -35
  91. data/docsite/source/sum.html.md +0 -21
@@ -0,0 +1,94 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Types
5
+ # @api public
6
+ class Constructor < Nominal
7
+ module Wrapper
8
+ # @return [Object]
9
+ #
10
+ # @api private
11
+ def call_safe(input, &block)
12
+ fn.(input, type, &block)
13
+ end
14
+
15
+ # @return [Object]
16
+ #
17
+ # @api private
18
+ def call_unsafe(input)
19
+ fn.(input, type)
20
+ end
21
+
22
+ # @param [Object] input
23
+ # @param [#call,nil] block
24
+ #
25
+ # @return [Logic::Result, Types::Result]
26
+ # @return [Object] if block given and try fails
27
+ #
28
+ # @api public
29
+ def try(input, &block)
30
+ value = fn.(input, type)
31
+ rescue CoercionError => e
32
+ failure = failure(input, e)
33
+ block_given? ? yield(failure) : failure
34
+ else
35
+ type.try(value, &block)
36
+ end
37
+
38
+ # Define a constructor for the type
39
+ #
40
+ # @param [#call,nil] constructor
41
+ # @param [Hash] options
42
+ # @param [#call,nil] block
43
+ #
44
+ # @return [Constructor]
45
+ #
46
+ # @api public
47
+ define_method(:constructor, Builder.instance_method(:constructor))
48
+ alias_method :append, :constructor
49
+ alias_method :>>, :constructor
50
+
51
+ # Build a new constructor by prepending a block to the coercion function
52
+ #
53
+ # @param [#call, nil] new_fn
54
+ # @param [Hash] options
55
+ # @param [#call, nil] block
56
+ #
57
+ # @return [Constructor]
58
+ #
59
+ # @api public
60
+ def prepend(new_fn = nil, **options, &block)
61
+ prep_fn = Function[new_fn || block]
62
+
63
+ decorated =
64
+ if prep_fn.wrapper?
65
+ type.constructor(prep_fn, **options)
66
+ else
67
+ type.prepend(prep_fn, **options)
68
+ end
69
+
70
+ __new__(decorated)
71
+ end
72
+ alias_method :<<, :prepend
73
+
74
+ # @return [Constructor]
75
+ #
76
+ # @api public
77
+ def lax
78
+ # return self back because wrapping function
79
+ # can handle failed type check
80
+ self
81
+ end
82
+
83
+ private
84
+
85
+ # Replace underlying type
86
+ #
87
+ # @api private
88
+ def __new__(type)
89
+ self.class.new(type, *@__args__.drop(1), **@options)
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/container'
3
+ require "dry/container"
4
4
 
5
5
  module Dry
6
6
  module Types
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/types/any'
3
+ require "dry/types/any"
4
4
 
5
5
  module Dry
6
6
  module Types
@@ -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
@@ -81,17 +83,17 @@ module Dry
81
83
  end
82
84
 
83
85
  # Register `:bool` since it's common and not a built-in Ruby type :(
84
- register('nominal.bool', self['nominal.true'] | self['nominal.false'])
85
- bool = self['strict.true'] | self['strict.false']
86
- register('strict.bool', bool)
87
- register('bool', bool)
88
-
89
- register('any', Any)
90
- register('nominal.any', Any)
91
- register('strict.any', Any)
86
+ register("nominal.bool", self["nominal.true"] | self["nominal.false"])
87
+ bool = self["strict.true"] | self["strict.false"]
88
+ register("strict.bool", bool)
89
+ register("bool", bool)
90
+
91
+ register("any", Any)
92
+ register("nominal.any", Any)
93
+ register("strict.any", Any)
92
94
  end
93
95
  end
94
96
 
95
- require 'dry/types/coercions'
96
- require 'dry/types/params'
97
- require 'dry/types/json'
97
+ require "dry/types/coercions"
98
+ require "dry/types/params"
99
+ require "dry/types/json"
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/types/options'
3
+ require "dry/types/options"
4
4
 
5
5
  module Dry
6
6
  module 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
  #
@@ -107,7 +100,7 @@ module Dry
107
100
  #
108
101
  # @api private
109
102
  def __new__(type)
110
- self.class.new(type, *@__args__[1..-1], **@options)
103
+ self.class.new(type, *@__args__.drop(1), **@options)
111
104
  end
112
105
  end
113
106
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/types/decorator'
3
+ require "dry/core/equalizer"
4
+ require "dry/types/decorator"
4
5
 
5
6
  module Dry
6
7
  module Types
@@ -17,6 +18,11 @@ module Dry
17
18
  def evaluate
18
19
  value.call(type)
19
20
  end
21
+
22
+ # @return [true]
23
+ def callable?
24
+ true
25
+ end
20
26
  end
21
27
 
22
28
  include Type
@@ -111,6 +117,13 @@ module Dry
111
117
  Undefined.default(type.call_safe(input, &block)) { evaluate }
112
118
  end
113
119
  end
120
+
121
+ # @return [false]
122
+ #
123
+ # @api private
124
+ def callable?
125
+ false
126
+ end
114
127
  end
115
128
  end
116
129
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/types/decorator'
3
+ require "dry/core/equalizer"
4
+ require "dry/types/decorator"
4
5
 
5
6
  module Dry
6
7
  module Types
@@ -58,8 +59,8 @@ module Dry
58
59
 
59
60
  # @api private
60
61
  def default(*)
61
- raise '.enum(*values).default(value) is not supported. Call '\
62
- '.default(value).enum(*values) instead'
62
+ raise ".enum(*values).default(value) is not supported. Call "\
63
+ ".default(value).enum(*values) instead"
63
64
  end
64
65
 
65
66
  # Check whether a value is in the enum
@@ -56,7 +56,7 @@ module Dry
56
56
 
57
57
  # @return string
58
58
  def message
59
- errors.map(&:message).join(', ')
59
+ errors.map(&:message).join(", ")
60
60
  end
61
61
 
62
62
  # @return [Array]
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  Dry::Types.register_extension(:maybe) do
4
- require 'dry/types/extensions/maybe'
4
+ require "dry/types/extensions/maybe"
5
5
  end
6
6
 
7
7
  Dry::Types.register_extension(:monads) do
8
- require 'dry/types/extensions/monads'
8
+ require "dry/types/extensions/monads"
9
9
  end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/monads/maybe'
4
- require 'dry/types/decorator'
3
+ require "dry/core/equalizer"
4
+ require "dry/monads/maybe"
5
+ require "dry/types/decorator"
5
6
 
6
7
  module Dry
7
8
  module Types
@@ -10,11 +11,11 @@ module Dry
10
11
  # @api public
11
12
  class Maybe
12
13
  include Type
13
- include Dry::Equalizer(:type, :options, inspect: false, immutable: true)
14
+ include ::Dry::Equalizer(:type, :options, inspect: false, immutable: true)
14
15
  include Decorator
15
16
  include Builder
16
17
  include Printable
17
- include Dry::Monads::Maybe::Mixin
18
+ include ::Dry::Monads::Maybe::Mixin
18
19
 
19
20
  # @param [Dry::Monads::Maybe, Object] input
20
21
  #
@@ -23,7 +24,7 @@ module Dry
23
24
  # @api private
24
25
  def call_unsafe(input = Undefined)
25
26
  case input
26
- when Dry::Monads::Maybe
27
+ when ::Dry::Monads::Maybe
27
28
  input
28
29
  when Undefined
29
30
  None()
@@ -37,14 +38,14 @@ module Dry
37
38
  # @return [Dry::Monads::Maybe]
38
39
  #
39
40
  # @api private
40
- def call_safe(input = Undefined, &block)
41
+ def call_safe(input = Undefined)
41
42
  case input
42
- when Dry::Monads::Maybe
43
+ when ::Dry::Monads::Maybe
43
44
  input
44
45
  when Undefined
45
46
  None()
46
47
  else
47
- Maybe(type.call_safe(input, &block))
48
+ Maybe(type.call_safe(input) { |output = input| return yield(output) })
48
49
  end
49
50
  end
50
51
 
@@ -54,13 +55,13 @@ module Dry
54
55
  #
55
56
  # @api public
56
57
  def try(input = Undefined)
57
- res = if input.equal?(Undefined)
58
- None()
59
- else
60
- Maybe(type[input])
61
- end
58
+ result = type.try(input)
62
59
 
63
- Result::Success.new(res)
60
+ if result.success?
61
+ Result::Success.new(Maybe(result.input))
62
+ else
63
+ result
64
+ end
64
65
  end
65
66
 
66
67
  # @return [true]
@@ -79,7 +80,7 @@ module Dry
79
80
  # @api public
80
81
  def default(value)
81
82
  if value.nil?
82
- raise ArgumentError, 'nil cannot be used as a default of a maybe type'
83
+ raise ArgumentError, "nil cannot be used as a default of a maybe type"
83
84
  else
84
85
  super
85
86
  end
@@ -93,7 +94,7 @@ module Dry
93
94
  #
94
95
  # @api public
95
96
  def maybe
96
- Maybe.new(Types['strict.nil'] | self)
97
+ Maybe.new(Types["nil"] | self)
97
98
  end
98
99
  end
99
100
 
@@ -119,7 +120,7 @@ module Dry
119
120
 
120
121
  # Register non-coercible maybe types
121
122
  NON_NIL.each_key do |name|
122
- register("maybe.strict.#{name}", self["strict.#{name}"].maybe)
123
+ register("maybe.strict.#{name}", self[name.to_s].maybe)
123
124
  end
124
125
 
125
126
  # Register coercible maybe types
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/monads/result'
3
+ require "dry/monads/result"
4
4
 
5
5
  module Dry
6
6
  module Types
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/types/container'
3
+ require "dry/types/container"
4
4
 
5
5
  module Dry
6
6
  module Types
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/types/hash/constructor'
3
+ require "dry/types/hash/constructor"
4
4
 
5
5
  module Dry
6
6
  module Types
@@ -8,7 +8,7 @@ module Dry
8
8
  #
9
9
  # @api public
10
10
  class Hash < Nominal
11
- NOT_REQUIRED = { required: false }.freeze
11
+ NOT_REQUIRED = {required: false}.freeze
12
12
 
13
13
  # @overload schema(type_map, meta = EMPTY_HASH)
14
14
  # @param [{Symbol => Dry::Types::Nominal}] type_map
@@ -50,8 +50,8 @@ module Dry
50
50
 
51
51
  # @api private
52
52
  def weak(*)
53
- raise 'Support for old hash schemas was removed, please refer to the CHANGELOG '\
54
- 'on how to proceed with the new API https://github.com/dry-rb/dry-types/blob/master/CHANGELOG.md'
53
+ raise "Support for old hash schemas was removed, please refer to the CHANGELOG "\
54
+ "on how to proceed with the new API https://github.com/dry-rb/dry-types/blob/master/CHANGELOG.md"
55
55
  end
56
56
  alias_method :permissive, :weak
57
57
  alias_method :strict, :weak
@@ -69,7 +69,7 @@ module Dry
69
69
  def with_type_transform(proc = nil, &block)
70
70
  fn = proc || block
71
71
 
72
- raise ArgumentError, 'a block or callable argument is required' if fn.nil?
72
+ raise ArgumentError, "a block or callable argument is required" if fn.nil?
73
73
 
74
74
  handle = Dry::Types::FnContainer.register(fn)
75
75
  with(type_transform_fn: handle)
@@ -95,13 +95,7 @@ module Dry
95
95
  #
96
96
  # @api public
97
97
  def to_ast(meta: true)
98
- opts = if RUBY_VERSION >= '2.5'
99
- options.slice(:type_transform_fn)
100
- else
101
- options.select { |k, _| k == :type_transform_fn }
102
- end
103
-
104
- [:hash, [opts, meta ? self.meta : EMPTY_HASH]]
98
+ [:hash, [options.slice(:type_transform_fn), meta ? self.meta : EMPTY_HASH]]
105
99
  end
106
100
 
107
101
  private
@@ -129,7 +123,7 @@ module Dry
129
123
 
130
124
  # @api private
131
125
  def key_name(key)
132
- if key.to_s.end_with?('?')
126
+ if key.to_s.end_with?("?")
133
127
  [key.to_s.chop.to_sym, NOT_REQUIRED]
134
128
  else
135
129
  [key, EMPTY_HASH]
@@ -139,5 +133,5 @@ module Dry
139
133
  end
140
134
  end
141
135
 
142
- require 'dry/types/schema/key'
143
- require 'dry/types/schema'
136
+ require "dry/types/schema/key"
137
+ require "dry/types/schema"
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'dry/types/constructor'
3
+ require "dry/types/constructor"
4
4
 
5
5
  module Dry
6
6
  module Types