dry-types 1.0.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +2 -5
- data/.github/ISSUE_TEMPLATE/----please-don-t-ask-for-support-via-issues.md +10 -0
- data/.github/ISSUE_TEMPLATE/---bug-report.md +34 -0
- data/.github/ISSUE_TEMPLATE/---feature-request.md +18 -0
- data/.github/workflows/custom_ci.yml +76 -0
- data/.github/workflows/docsite.yml +34 -0
- data/.github/workflows/sync_configs.yml +34 -0
- data/.gitignore +1 -1
- data/.rspec +3 -1
- data/.rubocop.yml +89 -0
- data/CHANGELOG.md +127 -3
- data/CODE_OF_CONDUCT.md +13 -0
- data/CONTRIBUTING.md +2 -2
- data/Gemfile +12 -6
- data/LICENSE +17 -17
- data/README.md +2 -2
- data/Rakefile +2 -2
- data/benchmarks/hash_schemas.rb +8 -6
- data/benchmarks/lax_schema.rb +0 -1
- data/benchmarks/profile_invalid_input.rb +1 -1
- data/benchmarks/profile_lax_schema_valid.rb +1 -1
- data/benchmarks/profile_valid_input.rb +1 -1
- data/docsite/source/array-with-member.html.md +13 -0
- data/docsite/source/built-in-types.html.md +116 -0
- data/docsite/source/constraints.html.md +31 -0
- data/docsite/source/custom-types.html.md +93 -0
- data/docsite/source/default-values.html.md +91 -0
- data/docsite/source/enum.html.md +69 -0
- data/docsite/source/extensions.html.md +15 -0
- data/docsite/source/extensions/maybe.html.md +57 -0
- data/docsite/source/extensions/monads.html.md +61 -0
- data/docsite/source/getting-started.html.md +57 -0
- data/docsite/source/hash-schemas.html.md +169 -0
- data/docsite/source/index.html.md +156 -0
- data/docsite/source/map.html.md +17 -0
- data/docsite/source/optional-values.html.md +35 -0
- data/docsite/source/sum.html.md +21 -0
- data/dry-types.gemspec +19 -19
- data/lib/dry/types.rb +9 -4
- data/lib/dry/types/any.rb +2 -2
- data/lib/dry/types/array.rb +6 -0
- data/lib/dry/types/array/constructor.rb +32 -0
- data/lib/dry/types/array/member.rb +10 -3
- data/lib/dry/types/builder.rb +2 -2
- data/lib/dry/types/builder_methods.rb +34 -8
- data/lib/dry/types/coercions.rb +19 -6
- data/lib/dry/types/coercions/params.rb +4 -4
- data/lib/dry/types/compiler.rb +2 -2
- data/lib/dry/types/constrained.rb +6 -1
- data/lib/dry/types/constructor.rb +10 -42
- data/lib/dry/types/constructor/function.rb +4 -5
- data/lib/dry/types/core.rb +27 -8
- data/lib/dry/types/decorator.rb +3 -2
- data/lib/dry/types/enum.rb +2 -1
- data/lib/dry/types/extensions.rb +4 -0
- data/lib/dry/types/extensions/maybe.rb +9 -1
- data/lib/dry/types/extensions/monads.rb +29 -0
- data/lib/dry/types/hash.rb +11 -12
- data/lib/dry/types/hash/constructor.rb +5 -5
- data/lib/dry/types/json.rb +4 -0
- data/lib/dry/types/lax.rb +4 -4
- data/lib/dry/types/map.rb +8 -4
- data/lib/dry/types/meta.rb +1 -1
- data/lib/dry/types/module.rb +6 -6
- data/lib/dry/types/nominal.rb +3 -4
- data/lib/dry/types/params.rb +9 -0
- data/lib/dry/types/predicate_inferrer.rb +197 -0
- data/lib/dry/types/predicate_registry.rb +34 -0
- data/lib/dry/types/primitive_inferrer.rb +97 -0
- data/lib/dry/types/printer.rb +17 -12
- data/lib/dry/types/schema.rb +16 -22
- data/lib/dry/types/schema/key.rb +19 -1
- data/lib/dry/types/spec/types.rb +6 -7
- data/lib/dry/types/sum.rb +2 -2
- data/lib/dry/types/version.rb +1 -1
- metadata +67 -35
- data/.travis.yml +0 -27
@@ -0,0 +1,156 @@
|
|
1
|
+
---
|
2
|
+
title: Introduction
|
3
|
+
layout: gem-single
|
4
|
+
type: gem
|
5
|
+
name: dry-types
|
6
|
+
sections:
|
7
|
+
- getting-started
|
8
|
+
- built-in-types
|
9
|
+
- optional-values
|
10
|
+
- default-values
|
11
|
+
- sum
|
12
|
+
- constraints
|
13
|
+
- hash-schemas
|
14
|
+
- array-with-member
|
15
|
+
- enum
|
16
|
+
- map
|
17
|
+
- custom-types
|
18
|
+
- extensions
|
19
|
+
---
|
20
|
+
|
21
|
+
`dry-types` is a simple and extendable type system for Ruby; useful for value coercions, applying constraints, defining complex structs or value objects and more. It was created as a successor to [Virtus](https://github.com/solnic/virtus).
|
22
|
+
|
23
|
+
### Example usage
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
require 'dry-types'
|
27
|
+
require 'dry-struct'
|
28
|
+
|
29
|
+
module Types
|
30
|
+
include Dry.Types()
|
31
|
+
end
|
32
|
+
|
33
|
+
User = Dry.Struct(name: Types::String, age: Types::Integer)
|
34
|
+
|
35
|
+
User.new(name: 'Bob', age: 35)
|
36
|
+
# => #<User name="Bob" age=35>
|
37
|
+
```
|
38
|
+
|
39
|
+
See [Built-in Types](docs::built-in-types/) for a full list of available types.
|
40
|
+
|
41
|
+
By themselves, the basic type definitions like `Types::String` and `Types::Integer` don't do anything except provide documentation about which type an attribute is expected to have. However, there are many more advanced possibilities:
|
42
|
+
|
43
|
+
- `Strict` types will raise an error if passed an attribute of the wrong type:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
class User < Dry::Struct
|
47
|
+
attribute :name, Types::Strict::String
|
48
|
+
attribute :age, Types::Strict::Integer
|
49
|
+
end
|
50
|
+
|
51
|
+
User.new(name: 'Bob', age: '18')
|
52
|
+
# => Dry::Struct::Error: [User.new] "18" (String) has invalid type for :age
|
53
|
+
```
|
54
|
+
|
55
|
+
- `Coercible` types will attempt to convert an attribute to the correct class
|
56
|
+
using Ruby's built-in coercion methods:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
class User < Dry::Struct
|
60
|
+
attribute :name, Types::Coercible::String
|
61
|
+
attribute :age, Types::Coercible::Integer
|
62
|
+
end
|
63
|
+
|
64
|
+
User.new(name: 'Bob', age: '18')
|
65
|
+
# => #<User name="Bob" age=18>
|
66
|
+
User.new(name: 'Bob', age: 'not coercible')
|
67
|
+
# => ArgumentError: invalid value for Integer(): "not coercible"
|
68
|
+
```
|
69
|
+
|
70
|
+
- Use `.optional` to denote that an attribute can be `nil` (see [Optional Values](docs::optional-values)):
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
class User < Dry::Struct
|
74
|
+
attribute :name, Types::String
|
75
|
+
attribute :age, Types::Integer.optional
|
76
|
+
end
|
77
|
+
|
78
|
+
User.new(name: 'Bob', age: nil)
|
79
|
+
# => #<User name="Bob" age=nil>
|
80
|
+
# name is not optional:
|
81
|
+
User.new(name: nil, age: 18)
|
82
|
+
# => Dry::Struct::Error: [User.new] nil (NilClass) has invalid type for :name
|
83
|
+
# keys must still be present:
|
84
|
+
User.new(name: 'Bob')
|
85
|
+
# => Dry::Struct::Error: [User.new] :age is missing in Hash input
|
86
|
+
```
|
87
|
+
|
88
|
+
- Add custom constraints (see [Constraints](docs::constraints.html)):
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
class User < Dry::Struct
|
92
|
+
attribute :name, Types::Strict::String
|
93
|
+
attribute :age, Types::Strict::Integer.constrained(gteq: 18)
|
94
|
+
end
|
95
|
+
|
96
|
+
User.new(name: 'Bob', age: 17)
|
97
|
+
# => Dry::Struct::Error: [User.new] 17 (Fixnum) has invalid type for :age
|
98
|
+
```
|
99
|
+
|
100
|
+
- Add custom metadata to a type:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
class User < Dry::Struct
|
104
|
+
attribute :name, Types::String
|
105
|
+
attribute :age, Types::Integer.meta(info: 'extra info about age')
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
- Pass values directly to `Dry::Types` without creating an object using `[]`:
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
Types::Strict::String["foo"]
|
113
|
+
# => "foo"
|
114
|
+
Types::Strict::String["10000"]
|
115
|
+
# => "10000"
|
116
|
+
Types::Coercible::String[10000]
|
117
|
+
# => "10000"
|
118
|
+
Types::Strict::String[10000]
|
119
|
+
# Dry::Types::ConstraintError: 1000 violates constraints
|
120
|
+
```
|
121
|
+
|
122
|
+
### Features
|
123
|
+
|
124
|
+
* Support for [constrained types](docs::constraints)
|
125
|
+
* Support for [optional values](docs::optional-values)
|
126
|
+
* Support for [default values](docs::default-values)
|
127
|
+
* Support for [sum types](docs::sum)
|
128
|
+
* Support for [enums](docs::enum)
|
129
|
+
* Support for [hash type with type schemas](docs::hash-schemas)
|
130
|
+
* Support for [array type with members](docs::array-with-member)
|
131
|
+
* Support for arbitrary meta information
|
132
|
+
* Support for typed struct objects via [dry-struct](/gems/dry-struct)
|
133
|
+
* Types are [categorized](docs::built-in-types), which is especially important for optimized and dedicated coercion logic
|
134
|
+
* Types are composable and reusable objects
|
135
|
+
* No const-missing magic and complicated const lookups
|
136
|
+
* Roughly 6-10 x faster than Virtus
|
137
|
+
|
138
|
+
### Use cases
|
139
|
+
|
140
|
+
`dry-types` is suitable for many use-cases, for example:
|
141
|
+
|
142
|
+
* Value coercions
|
143
|
+
* Processing arrays
|
144
|
+
* Processing hashes with explicit schemas
|
145
|
+
* Defining various domain-specific information shared between multiple parts of your application
|
146
|
+
* Annotating objects
|
147
|
+
|
148
|
+
### Other gems using dry-types
|
149
|
+
|
150
|
+
`dry-types` is often used as a low-level abstraction. The following gems use it already:
|
151
|
+
|
152
|
+
* [dry-struct](/gems/dry-struct)
|
153
|
+
* [dry-initializer](/gems/dry-initializer)
|
154
|
+
* [Hanami](http://hanamirb.org)
|
155
|
+
* [rom-rb](http://rom-rb.org)
|
156
|
+
* [Trailblazer](http://trailblazer.to)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
---
|
2
|
+
title: Map
|
3
|
+
layout: gem-single
|
4
|
+
name: dry-types
|
5
|
+
---
|
6
|
+
|
7
|
+
`Map` describes a homogeneous hashmap. This means only types of keys and values are known. You can simply imagine a map input as a list of key-value pairs.
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
int_float_hash = Types::Hash.map(Types::Integer, Types::Float)
|
11
|
+
int_float_hash[100 => 300.0, 42 => 70.0]
|
12
|
+
# => {100=>300.0, 42=>70.0}
|
13
|
+
|
14
|
+
# Only accepts mappings of integers to floats
|
15
|
+
int_float_hash[name: 'Jane']
|
16
|
+
# => Dry::Types::MapError: input key :name is invalid: type?(Integer, :name)
|
17
|
+
```
|
@@ -0,0 +1,35 @@
|
|
1
|
+
---
|
2
|
+
title: Type Attributes
|
3
|
+
layout: gem-single
|
4
|
+
name: dry-types
|
5
|
+
---
|
6
|
+
|
7
|
+
Types themselves have optional attributes you can apply to get further functionality.
|
8
|
+
|
9
|
+
### Append `.optional` to a _Type_ to allow `nil`
|
10
|
+
|
11
|
+
By default, nil values raise an error:
|
12
|
+
|
13
|
+
``` ruby
|
14
|
+
Types::Strict::String[nil]
|
15
|
+
# => raises Dry::Types::ConstraintError
|
16
|
+
```
|
17
|
+
|
18
|
+
Add `.optional` and `nil` values become valid:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
optional_string = Types::Strict::String.optional
|
22
|
+
|
23
|
+
optional_string[nil]
|
24
|
+
# => nil
|
25
|
+
optional_string['something']
|
26
|
+
# => "something"
|
27
|
+
optional_string[123]
|
28
|
+
# raises Dry::Types::ConstraintError
|
29
|
+
```
|
30
|
+
|
31
|
+
`Types::String.optional` is just syntactic sugar for `Types::Strict::Nil | Types::Strict::String`.
|
32
|
+
|
33
|
+
### Handle optional values using Monads
|
34
|
+
|
35
|
+
See [Maybe](docs::extensions/maybe) extension for another approach to handling optional values by returning a [_Monad_](/gems/dry-monads/) object.
|
@@ -0,0 +1,21 @@
|
|
1
|
+
---
|
2
|
+
title: Sum
|
3
|
+
layout: gem-single
|
4
|
+
name: dry-types
|
5
|
+
order: 7
|
6
|
+
---
|
7
|
+
|
8
|
+
You can specify sum types using `|` operator, it is an explicit way of defining what the valid types of a value are.
|
9
|
+
|
10
|
+
For example `dry-types` defines the `Bool` type which is a sum consisting of the `True` and `False` types, expressed as `Types::True | Types::False`.
|
11
|
+
|
12
|
+
Another common case is defining that something can be either `nil` or something else:
|
13
|
+
|
14
|
+
``` ruby
|
15
|
+
nil_or_string = Types::Nil | Types::String
|
16
|
+
|
17
|
+
nil_or_string[nil] # => nil
|
18
|
+
nil_or_string["hello"] # => "hello"
|
19
|
+
|
20
|
+
nil_or_string[123] # raises Dry::Types::ConstraintError
|
21
|
+
```
|
data/dry-types.gemspec
CHANGED
@@ -1,47 +1,47 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
lib = File.expand_path('
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
5
|
require 'dry/types/version'
|
6
6
|
|
7
7
|
Gem::Specification.new do |spec|
|
8
|
-
spec.name =
|
8
|
+
spec.name = 'dry-types'
|
9
9
|
spec.version = Dry::Types::VERSION.dup
|
10
|
-
spec.authors = [
|
11
|
-
spec.email = [
|
10
|
+
spec.authors = ['Piotr Solnica']
|
11
|
+
spec.email = ['piotr.solnica@gmail.com']
|
12
12
|
spec.license = 'MIT'
|
13
13
|
|
14
14
|
spec.summary = 'Type system for Ruby supporting coercions, constraints and complex types like structs, value objects, enums etc.'
|
15
15
|
spec.description = spec.summary
|
16
|
-
spec.homepage =
|
16
|
+
spec.homepage = 'https://github.com/dry-rb/dry-types'
|
17
17
|
|
18
18
|
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
19
19
|
# delete this section to allow pushing this gem to any host.
|
20
20
|
if spec.respond_to?(:metadata)
|
21
|
-
spec.metadata['allowed_push_host'] =
|
22
|
-
spec.metadata['changelog_uri'] =
|
23
|
-
spec.metadata['source_code_uri'] =
|
24
|
-
spec.metadata['bug_tracker_uri'] =
|
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
25
|
else
|
26
|
-
raise
|
26
|
+
raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
|
27
27
|
end
|
28
28
|
|
29
29
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } - ['bin/console', 'bin/setup']
|
30
|
-
spec.bindir =
|
30
|
+
spec.bindir = 'exe'
|
31
31
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
32
|
-
spec.require_paths = [
|
33
|
-
spec.required_ruby_version =
|
32
|
+
spec.require_paths = ['lib']
|
33
|
+
spec.required_ruby_version = '>= 2.4.0'
|
34
34
|
|
35
35
|
spec.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
|
36
|
-
spec.add_runtime_dependency 'dry-core', '~> 0.4', '>= 0.4.4'
|
37
|
-
spec.add_runtime_dependency 'dry-inflector', '~> 0.1', '>= 0.1.2'
|
38
36
|
spec.add_runtime_dependency 'dry-container', '~> 0.3'
|
37
|
+
spec.add_runtime_dependency 'dry-core', '~> 0.4', '>= 0.4.4'
|
39
38
|
spec.add_runtime_dependency 'dry-equalizer', '~> 0.2', '>= 0.2.2'
|
40
|
-
spec.add_runtime_dependency 'dry-
|
39
|
+
spec.add_runtime_dependency 'dry-inflector', '~> 0.1', '>= 0.1.2'
|
40
|
+
spec.add_runtime_dependency 'dry-logic', '~> 1.0', '>= 1.0.2'
|
41
41
|
|
42
|
-
spec.add_development_dependency
|
43
|
-
spec.add_development_dependency "rake", "~> 11.0"
|
44
|
-
spec.add_development_dependency "rspec", "~> 3.3"
|
42
|
+
spec.add_development_dependency 'bundler'
|
45
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
46
|
spec.add_development_dependency 'yard', '~> 0.9.5'
|
47
47
|
end
|
data/lib/dry/types.rb
CHANGED
@@ -33,7 +33,7 @@ module Dry
|
|
33
33
|
extend Dry::Core::Deprecations[:'dry-types']
|
34
34
|
include Dry::Core::Constants
|
35
35
|
|
36
|
-
TYPE_SPEC_REGEX =
|
36
|
+
TYPE_SPEC_REGEX = /(.+)<(.+)>/.freeze
|
37
37
|
|
38
38
|
# @see Dry.Types
|
39
39
|
def self.module(*namespaces, default: :nominal, **aliases)
|
@@ -45,7 +45,7 @@ module Dry
|
|
45
45
|
|
46
46
|
# @api private
|
47
47
|
def self.included(*)
|
48
|
-
raise
|
48
|
+
raise 'Import Dry.Types, not Dry::Types'
|
49
49
|
end
|
50
50
|
|
51
51
|
# Return container with registered built-in type objects
|
@@ -89,7 +89,7 @@ module Dry
|
|
89
89
|
def self.[](name)
|
90
90
|
type_map.fetch_or_store(name) do
|
91
91
|
case name
|
92
|
-
when String
|
92
|
+
when ::String
|
93
93
|
result = name.match(TYPE_SPEC_REGEX)
|
94
94
|
|
95
95
|
if result
|
@@ -98,7 +98,12 @@ module Dry
|
|
98
98
|
else
|
99
99
|
container[name]
|
100
100
|
end
|
101
|
-
when Class
|
101
|
+
when ::Class
|
102
|
+
warn(<<~DEPRECATION)
|
103
|
+
Using Dry::Types.[] with a class is deprecated, please use string identifiers: Dry::Types[Integer] -> Dry::Types['integer'].
|
104
|
+
If you're using dry-struct this means changing `attribute :counter, Integer` to `attribute :counter, Dry::Types['integer']` or to `attribute :counter, 'integer'`.
|
105
|
+
DEPRECATION
|
106
|
+
|
102
107
|
type_name = identifier(name)
|
103
108
|
|
104
109
|
if container.key?(type_name)
|
data/lib/dry/types/any.rb
CHANGED
@@ -15,7 +15,7 @@ module Dry
|
|
15
15
|
|
16
16
|
# @api private
|
17
17
|
def initialize(**options)
|
18
|
-
super(::Object, options)
|
18
|
+
super(::Object, **options)
|
19
19
|
end
|
20
20
|
|
21
21
|
# @return [String]
|
@@ -30,7 +30,7 @@ module Dry
|
|
30
30
|
# @return [Type]
|
31
31
|
#
|
32
32
|
# @api public
|
33
|
-
def with(new_options)
|
33
|
+
def with(**new_options)
|
34
34
|
self.class.new(**options, meta: @meta, **new_options)
|
35
35
|
end
|
36
36
|
|
data/lib/dry/types/array.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'dry/types/array/member'
|
4
|
+
require 'dry/types/array/constructor'
|
4
5
|
|
5
6
|
module Dry
|
6
7
|
module Types
|
@@ -24,6 +25,11 @@ module Dry
|
|
24
25
|
|
25
26
|
Array::Member.new(primitive, **options, member: member)
|
26
27
|
end
|
28
|
+
|
29
|
+
# @api private
|
30
|
+
def constructor_type
|
31
|
+
::Dry::Types::Array::Constructor
|
32
|
+
end
|
27
33
|
end
|
28
34
|
end
|
29
35
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'dry/types/constructor'
|
4
|
+
|
5
|
+
module Dry
|
6
|
+
module Types
|
7
|
+
# @api public
|
8
|
+
class Array < Nominal
|
9
|
+
# @api private
|
10
|
+
class Constructor < ::Dry::Types::Constructor
|
11
|
+
# @api private
|
12
|
+
def constructor_type
|
13
|
+
::Dry::Types::Array::Constructor
|
14
|
+
end
|
15
|
+
|
16
|
+
# @return [Lax]
|
17
|
+
#
|
18
|
+
# @api public
|
19
|
+
def lax
|
20
|
+
Lax.new(type.lax.constructor(fn, meta: meta))
|
21
|
+
end
|
22
|
+
|
23
|
+
# @see Dry::Types::Array#of
|
24
|
+
#
|
25
|
+
# @api public
|
26
|
+
def of(member)
|
27
|
+
type.of(member).constructor(fn, meta: meta)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'dry/types/array/constructor'
|
4
|
+
|
3
5
|
module Dry
|
4
6
|
module Types
|
5
7
|
class Array < Nominal
|
@@ -16,7 +18,7 @@ module Dry
|
|
16
18
|
# @option options [Type] :member
|
17
19
|
#
|
18
20
|
# @api private
|
19
|
-
def initialize(primitive, options
|
21
|
+
def initialize(primitive, **options)
|
20
22
|
@member = options.fetch(:member)
|
21
23
|
super
|
22
24
|
end
|
@@ -87,7 +89,7 @@ module Dry
|
|
87
89
|
block ? yield(failure) : failure
|
88
90
|
end
|
89
91
|
else
|
90
|
-
failure = failure(input, "#{input} is not an array")
|
92
|
+
failure = failure(input, CoercionError.new("#{input} is not an array"))
|
91
93
|
block ? yield(failure) : failure
|
92
94
|
end
|
93
95
|
end
|
@@ -98,7 +100,7 @@ module Dry
|
|
98
100
|
#
|
99
101
|
# @api public
|
100
102
|
def lax
|
101
|
-
Lax.new(Member.new(primitive,
|
103
|
+
Lax.new(Member.new(primitive, **options, member: member.lax, meta: meta))
|
102
104
|
end
|
103
105
|
|
104
106
|
# @see Nominal#to_ast
|
@@ -111,6 +113,11 @@ module Dry
|
|
111
113
|
[:array, [member, meta ? self.meta : EMPTY_HASH]]
|
112
114
|
end
|
113
115
|
end
|
116
|
+
|
117
|
+
# @api private
|
118
|
+
def constructor_type
|
119
|
+
::Dry::Types::Array::Constructor
|
120
|
+
end
|
114
121
|
end
|
115
122
|
end
|
116
123
|
end
|