dry-types 0.14.1 → 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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +631 -134
  3. data/LICENSE +17 -17
  4. data/README.md +15 -13
  5. data/dry-types.gemspec +27 -30
  6. data/lib/dry/types/any.rb +32 -12
  7. data/lib/dry/types/array/constructor.rb +32 -0
  8. data/lib/dry/types/array/member.rb +75 -16
  9. data/lib/dry/types/array.rb +19 -6
  10. data/lib/dry/types/builder.rb +131 -15
  11. data/lib/dry/types/builder_methods.rb +49 -20
  12. data/lib/dry/types/coercions/json.rb +43 -7
  13. data/lib/dry/types/coercions/params.rb +118 -31
  14. data/lib/dry/types/coercions.rb +76 -22
  15. data/lib/dry/types/compat.rb +0 -2
  16. data/lib/dry/types/compiler.rb +56 -41
  17. data/lib/dry/types/constrained/coercible.rb +36 -6
  18. data/lib/dry/types/constrained.rb +81 -32
  19. data/lib/dry/types/constraints.rb +18 -4
  20. data/lib/dry/types/constructor/function.rb +216 -0
  21. data/lib/dry/types/constructor/wrapper.rb +94 -0
  22. data/lib/dry/types/constructor.rb +126 -56
  23. data/lib/dry/types/container.rb +7 -0
  24. data/lib/dry/types/core.rb +54 -21
  25. data/lib/dry/types/decorator.rb +38 -17
  26. data/lib/dry/types/default.rb +61 -16
  27. data/lib/dry/types/enum.rb +43 -20
  28. data/lib/dry/types/errors.rb +75 -9
  29. data/lib/dry/types/extensions/maybe.rb +74 -16
  30. data/lib/dry/types/extensions/monads.rb +29 -0
  31. data/lib/dry/types/extensions.rb +7 -1
  32. data/lib/dry/types/fn_container.rb +6 -1
  33. data/lib/dry/types/hash/constructor.rb +33 -0
  34. data/lib/dry/types/hash.rb +86 -67
  35. data/lib/dry/types/inflector.rb +3 -1
  36. data/lib/dry/types/json.rb +18 -16
  37. data/lib/dry/types/lax.rb +75 -0
  38. data/lib/dry/types/map.rb +76 -33
  39. data/lib/dry/types/meta.rb +51 -0
  40. data/lib/dry/types/module.rb +120 -0
  41. data/lib/dry/types/nominal.rb +210 -0
  42. data/lib/dry/types/options.rb +13 -26
  43. data/lib/dry/types/params.rb +39 -25
  44. data/lib/dry/types/predicate_inferrer.rb +238 -0
  45. data/lib/dry/types/predicate_registry.rb +34 -0
  46. data/lib/dry/types/primitive_inferrer.rb +97 -0
  47. data/lib/dry/types/printable.rb +16 -0
  48. data/lib/dry/types/printer.rb +315 -0
  49. data/lib/dry/types/result.rb +29 -3
  50. data/lib/dry/types/schema/key.rb +156 -0
  51. data/lib/dry/types/schema.rb +408 -0
  52. data/lib/dry/types/spec/types.rb +103 -33
  53. data/lib/dry/types/sum.rb +84 -35
  54. data/lib/dry/types/type.rb +49 -0
  55. data/lib/dry/types/version.rb +3 -1
  56. data/lib/dry/types.rb +156 -76
  57. data/lib/dry-types.rb +3 -1
  58. metadata +65 -78
  59. data/.gitignore +0 -10
  60. data/.rspec +0 -2
  61. data/.travis.yml +0 -27
  62. data/.yardopts +0 -5
  63. data/CONTRIBUTING.md +0 -29
  64. data/Gemfile +0 -24
  65. data/Rakefile +0 -20
  66. data/benchmarks/hash_schemas.rb +0 -51
  67. data/lib/dry/types/compat/form_types.rb +0 -27
  68. data/lib/dry/types/compat/int.rb +0 -14
  69. data/lib/dry/types/definition.rb +0 -113
  70. data/lib/dry/types/hash/schema.rb +0 -199
  71. data/lib/dry/types/hash/schema_builder.rb +0 -75
  72. data/lib/dry/types/safe.rb +0 -59
  73. data/log/.gitkeep +0 -0
@@ -1,199 +0,0 @@
1
- require 'dry/types/fn_container'
2
-
3
- module Dry
4
- module Types
5
- class Hash < Definition
6
- # The built-in Hash type has constructors that you can use to define
7
- # hashes with explicit schemas and coercible values using the built-in types.
8
- #
9
- # Basic {Schema} evaluates default values for keys missing in input hash
10
- # (see {Schema#resolve_missing_value})
11
- #
12
- # @see Dry::Types::Default#evaluate
13
- # @see Dry::Types::Default::Callable#evaluate
14
- class Schema < Hash
15
- NO_TRANSFORM = Dry::Types::FnContainer.register { |x| x }
16
- SYMBOLIZE_KEY = Dry::Types::FnContainer.register(:to_sym.to_proc)
17
-
18
- # @return [Hash{Symbol => Definition}]
19
- attr_reader :member_types
20
-
21
- # @return [#call]
22
- attr_reader :transform_key
23
-
24
- # @param [Class] _primitive
25
- # @param [Hash] options
26
- # @option options [Hash{Symbol => Definition}] :member_types
27
- # @option options [String] :key_transform_fn
28
- def initialize(_primitive, **options)
29
- @member_types = options.fetch(:member_types)
30
-
31
- meta = options[:meta] || EMPTY_HASH
32
- key_fn = meta.fetch(:key_transform_fn, NO_TRANSFORM)
33
-
34
- @transform_key = Dry::Types::FnContainer[key_fn]
35
-
36
- super
37
- end
38
-
39
- # @param [Hash] hash
40
- # @return [Hash{Symbol => Object}]
41
- def call(hash)
42
- coerce(hash)
43
- end
44
- alias_method :[], :call
45
-
46
- # @param [Hash] hash
47
- # @yieldparam [Failure] failure
48
- # @yieldreturn [Result]
49
- # @return [Logic::Result]
50
- # @return [Object] if coercion fails and a block is given
51
- def try(hash)
52
- if hash.is_a?(::Hash)
53
- success = true
54
- output = {}
55
-
56
- begin
57
- result = try_coerce(hash) do |key, member_result|
58
- success &&= member_result.success?
59
- output[key] = member_result.input
60
-
61
- member_result
62
- end
63
- rescue ConstraintError, UnknownKeysError, SchemaError, MissingKeyError => e
64
- success = false
65
- result = e
66
- end
67
- else
68
- success = false
69
- output = hash
70
- result = "#{hash} must be a hash"
71
- end
72
-
73
- if success
74
- success(output)
75
- else
76
- failure = failure(output, result)
77
- block_given? ? yield(failure) : failure
78
- end
79
- end
80
-
81
- # @param meta [Boolean] Whether to dump the meta to the AST
82
- # @return [Array] An AST representation
83
- def to_ast(meta: true)
84
- [
85
- :hash_schema,
86
- [
87
- member_types.map { |name, member| [:member, [name, member.to_ast(meta: meta)]] },
88
- meta ? self.meta : EMPTY_HASH
89
- ]
90
- ]
91
- end
92
-
93
- # @param [Hash] hash
94
- # @return [Boolean]
95
- def valid?(hash)
96
- result = try(hash)
97
- result.success?
98
- end
99
- alias_method :===, :valid?
100
-
101
- # Whether the schema rejects unknown keys
102
- # @return [Boolean]
103
- def strict?
104
- meta.fetch(:strict, false)
105
- end
106
-
107
- # Make the schema intolerant to unknown keys
108
- # @return [Schema]
109
- def strict
110
- meta(strict: true)
111
- end
112
-
113
- # Injects a key transformation function
114
- # @param [#call,nil] proc
115
- # @param [#call,nil] block
116
- # @return [Schema]
117
- def with_key_transform(proc = nil, &block)
118
- fn = proc || block
119
-
120
- if fn.nil?
121
- raise ArgumentError, "a block or callable argument is required"
122
- end
123
-
124
- handle = Dry::Types::FnContainer.register(fn)
125
- meta(key_transform_fn: handle)
126
- end
127
-
128
- # @param [{Symbol => Definition}] type_map
129
- # @return [Schema]
130
- def schema(type_map)
131
- member_types = self.member_types.merge(transform_types(type_map))
132
- Schema.new(primitive, **options, member_types: member_types, meta: meta)
133
- end
134
-
135
- private
136
-
137
- def resolve(hash)
138
- result = {}
139
-
140
- hash.each do |key, value|
141
- k = transform_key.(key)
142
-
143
- if member_types.key?(k)
144
- result[k] = yield(member_types[k], k, value)
145
- elsif strict?
146
- raise UnknownKeysError.new(*unexpected_keys(hash.keys))
147
- end
148
- end
149
-
150
- if result.size < member_types.size
151
- resolve_missing_keys(result, &Proc.new)
152
- end
153
-
154
- result
155
- end
156
-
157
- def resolve_missing_keys(result)
158
- member_types.each do |k, type|
159
- next if result.key?(k)
160
-
161
- if type.default?
162
- result[k] = yield(type, k, Undefined)
163
- elsif !type.meta[:omittable]
164
- raise MissingKeyError, k
165
- end
166
- end
167
- end
168
-
169
- # @param keys [Array<Symbol>]
170
- # @return [Array<Symbol>]
171
- def unexpected_keys(keys)
172
- keys.map(&transform_key) - member_types.keys
173
- end
174
-
175
- # @param [Hash] hash
176
- # @return [Hash{Symbol => Object}]
177
- def try_coerce(hash)
178
- resolve(hash) do |type, key, value|
179
- yield(key, type.try(value))
180
- end
181
- end
182
-
183
- # @param [Hash] hash
184
- # @return [Hash{Symbol => Object}]
185
- def coerce(hash)
186
- resolve(hash) do |type, key, value|
187
- begin
188
- type.call(value)
189
- rescue ConstraintError => e
190
- raise SchemaError.new(key, value, e.result)
191
- rescue TypeError, ArgumentError => e
192
- raise SchemaError.new(key, value, e.message)
193
- end
194
- end
195
- end
196
- end
197
- end
198
- end
199
- end
@@ -1,75 +0,0 @@
1
- require 'dry/types/hash/schema'
2
- require 'dry/types/fn_container'
3
-
4
- module Dry
5
- module Types
6
- class Hash < Definition
7
- # A bulder for legacy schemas
8
- # @api private
9
- class SchemaBuilder
10
- NIL_TO_UNDEFINED = -> v { v.nil? ? Undefined : v }
11
- OMITTABLE_KEYS = %i(schema weak symbolized).freeze
12
- STRICT = %i(strict strict_with_defaults).freeze
13
-
14
- # @param primitive [Type]
15
- # @option options [Hash{Symbol => Definition}] :member_types
16
- # @option options [Symbol] :hash_type
17
- def call(primitive, **options)
18
- hash_type = options.fetch(:hash_type)
19
- member_types = {}
20
-
21
- options.fetch(:member_types).each do |k, t|
22
- member_types[k] = build_type(hash_type, t)
23
- end
24
-
25
- instantiate(primitive, **options, member_types: member_types)
26
- end
27
-
28
- def instantiate(primitive, hash_type: :base, meta: EMPTY_HASH, **options)
29
- meta = meta.dup
30
-
31
- meta[:strict] = true if strict?(hash_type)
32
- meta[:key_transform_fn] = Schema::SYMBOLIZE_KEY if hash_type == :symbolized
33
-
34
- Schema.new(primitive, **options, meta: meta)
35
- end
36
-
37
- private
38
-
39
- def omittable?(constructor)
40
- OMITTABLE_KEYS.include?(constructor)
41
- end
42
-
43
- def strict?(constructor)
44
- STRICT.include?(constructor)
45
- end
46
-
47
- def build_type(constructor, type)
48
- type = safe(constructor, type)
49
- type = default(constructor, type) if type.default?
50
- type = type.meta(omittable: true) if omittable?(constructor)
51
- type
52
- end
53
-
54
- def safe(constructor, type)
55
- if constructor == :weak || constructor == :symbolized
56
- type.safe
57
- else
58
- type
59
- end
60
- end
61
-
62
- def default(constructor, type)
63
- case constructor
64
- when :strict_with_defaults
65
- type
66
- when :strict
67
- type.type
68
- else
69
- type.constructor(NIL_TO_UNDEFINED)
70
- end
71
- end
72
- end
73
- end
74
- end
75
- end
@@ -1,59 +0,0 @@
1
- require 'dry/types/decorator'
2
-
3
- module Dry
4
- module Types
5
- class Safe
6
- include Type
7
- include Dry::Equalizer(:type)
8
- include Decorator
9
- include Builder
10
- private :options, :meta
11
-
12
- # @param [Object] input
13
- # @return [Object]
14
- def call(input)
15
- result = try(input)
16
-
17
- if result.respond_to?(:input)
18
- result.input
19
- else
20
- input
21
- end
22
- end
23
- alias_method :[], :call
24
-
25
- # @param [Object] input
26
- # @param [#call,nil] block
27
- # @yieldparam [Failure] failure
28
- # @yieldreturn [Result]
29
- # @return [Result,Logic::Result]
30
- def try(input, &block)
31
- type.try(input, &block)
32
- rescue TypeError, ArgumentError => e
33
- result = failure(input, e.message)
34
- block ? yield(result) : result
35
- end
36
-
37
- # @api public
38
- #
39
- # @see Definition#to_ast
40
- def to_ast(meta: true)
41
- [:safe, [type.to_ast(meta: meta), EMPTY_HASH]]
42
- end
43
-
44
- # @api public
45
- # @return [Safe]
46
- def safe
47
- self
48
- end
49
-
50
- private
51
-
52
- # @param [Object, Dry::Types::Constructor] response
53
- # @return [Boolean]
54
- def decorate?(response)
55
- super || response.kind_of?(Constructor)
56
- end
57
- end
58
- end
59
- end
data/log/.gitkeep DELETED
File without changes