dry-types 0.9.2 → 0.9.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,6 +3,11 @@ require 'dry/types/hash/schema'
3
3
  module Dry
4
4
  module Types
5
5
  class Hash < Definition
6
+ # @param [{Symbol => Definition}] type_map
7
+ # @param [Class] klass
8
+ # {Schema} or one of its subclasses ({Weak}, {Permissive}, {Strict},
9
+ # {StrictWithDefaults}, {Symbolized})
10
+ # @return [Schema]
6
11
  def schema(type_map, klass = Schema)
7
12
  member_types = type_map.each_with_object({}) { |(name, type), result|
8
13
  result[name] =
@@ -15,28 +20,41 @@ module Dry
15
20
  klass.new(primitive, options.merge(member_types: member_types))
16
21
  end
17
22
 
23
+ # @param [{Symbol => Definition}] type_map
24
+ # @return [Weak]
18
25
  def weak(type_map)
19
26
  schema(type_map, Weak)
20
27
  end
21
28
 
29
+ # @param [{Symbol => Definition}] type_map
30
+ # @return [Permissive]
22
31
  def permissive(type_map)
23
32
  schema(type_map, Permissive)
24
33
  end
25
34
 
35
+ # @param [{Symbol => Definition}] type_map
36
+ # @return [Strict]
26
37
  def strict(type_map)
27
38
  schema(type_map, Strict)
28
39
  end
29
40
 
41
+ # @param [{Symbol => Definition}] type_map
42
+ # @return [StrictWithDefaults]
30
43
  def strict_with_defaults(type_map)
31
44
  schema(type_map, StrictWithDefaults)
32
45
  end
33
46
 
47
+ # @param [{Symbol => Definition}] type_map
48
+ # @return [Symbolized]
34
49
  def symbolized(type_map)
35
50
  schema(type_map, Symbolized)
36
51
  end
37
52
 
38
53
  private
39
54
 
55
+ # @param [Hash] _result
56
+ # @param [Symbol] _key
57
+ # @param [Definition] _type
40
58
  def resolve_missing_value(_result, _key, _type)
41
59
  # noop
42
60
  end
@@ -1,19 +1,38 @@
1
1
  module Dry
2
2
  module Types
3
3
  class Hash < Definition
4
+ # The built-in Hash type has constructors that you can use to define
5
+ # hashes with explicit schemas and coercible values using the built-in types.
6
+ #
7
+ # Basic {Schema} evaluates default values for keys missing in input hash
8
+ # (see {Schema#resolve_missing_value})
9
+ #
10
+ # @see Dry::Types::Default#evaluate
11
+ # @see Dry::Types::Default::Callable#evaluate
4
12
  class Schema < Hash
13
+ # @return [Hash{Symbol => Definition}]
5
14
  attr_reader :member_types
6
15
 
16
+ # @param [Class] _primitive
17
+ # @param [Hash] options
18
+ # @option options [Hash{Symbol => Definition}] :member_types
7
19
  def initialize(_primitive, options)
8
20
  @member_types = options.fetch(:member_types)
9
21
  super
10
22
  end
11
23
 
24
+ # @param [Hash] hash
25
+ # @return [Hash{Symbol => Object}]
12
26
  def call(hash)
13
27
  coerce(hash)
14
28
  end
15
29
  alias_method :[], :call
16
30
 
31
+ # @param [Hash] hash
32
+ # @param [#call] block
33
+ # @yieldparam [Failure] failure
34
+ # @yieldreturn [Result]
35
+ # @return [Result]
17
36
  def try(hash, &block)
18
37
  success = true
19
38
  output = {}
@@ -40,12 +59,16 @@ module Dry
40
59
 
41
60
  private
42
61
 
62
+ # @param [Hash] hash
63
+ # @return [Hash{Symbol => Object}]
43
64
  def try_coerce(hash)
44
65
  resolve(hash) do |type, key, value|
45
66
  yield(key, type.try(value))
46
67
  end
47
68
  end
48
69
 
70
+ # @param [Hash] hash
71
+ # @return [Hash{Symbol => Object}]
49
72
  def coerce(hash)
50
73
  resolve(hash) do |type, key, value|
51
74
  begin
@@ -56,6 +79,8 @@ module Dry
56
79
  end
57
80
  end
58
81
 
82
+ # @param [Hash] hash
83
+ # @return [Hash{Symbol => Object}]
59
84
  def resolve(hash)
60
85
  result = {}
61
86
  member_types.each do |key, type|
@@ -68,6 +93,12 @@ module Dry
68
93
  result
69
94
  end
70
95
 
96
+ # @param [Hash] result
97
+ # @param [Symbol] key
98
+ # @param [Definition] type
99
+ # @return [Object]
100
+ # @see Dry::Types::Default#evaluate
101
+ # @see Dry::Types::Default::Callable#evaluate
71
102
  def resolve_missing_value(result, key, type)
72
103
  if type.default?
73
104
  result[key] = type.evaluate
@@ -77,17 +108,33 @@ module Dry
77
108
  end
78
109
  end
79
110
 
111
+ # Permissive schema raises a {MissingKeyError} if the given key is missing
112
+ # in provided hash.
80
113
  class Permissive < Schema
81
114
  private
82
115
 
116
+ # @param [Symbol] key
117
+ # @raise [MissingKeyError] when key is missing in given input
83
118
  def resolve_missing_value(_, key, _)
84
119
  raise MissingKeyError, key
85
120
  end
86
121
  end
87
122
 
123
+ # Strict hash will raise errors when keys are missing or value types are incorrect.
124
+ # Strict schema raises a {UnknownKeysError} if there are any unexpected
125
+ # keys in given hash, and raises a {MissingKeyError} if any key is missing
126
+ # in it.
127
+ # @example
128
+ # hash = Types::Hash.strict(name: Types::String, age: Types::Coercible::Int)
129
+ # hash[email: 'jane@doe.org', name: 'Jane', age: 21]
130
+ # # => Dry::Types::SchemaKeyError: :email is missing in Hash input
88
131
  class Strict < Permissive
89
132
  private
90
133
 
134
+ # @param [Hash] hash
135
+ # @return [Hash{Symbol => Object}]
136
+ # @raise [UnknownKeysError]
137
+ # if there any unexpected key in given hash
91
138
  def resolve(hash)
92
139
  unexpected = hash.keys - member_types.keys
93
140
  raise UnknownKeysError.new(*unexpected) unless unexpected.empty?
@@ -100,9 +147,20 @@ module Dry
100
147
  end
101
148
  end
102
149
 
150
+ # {StrictWithDefaults} checks that there are no extra keys
151
+ # (raises {UnknownKeysError} otherwise) and there a no missing keys
152
+ # without default values given (raises {MissingKeyError} otherwise).
153
+ # @see Default#evaluate
154
+ # @see Default::Callable#evaluate
103
155
  class StrictWithDefaults < Strict
104
156
  private
105
157
 
158
+ # @param [Hash] result
159
+ # @param [Symbol] key
160
+ # @param [Definition] type
161
+ # @return [Object]
162
+ # @see Dry::Types::Default#evaluate
163
+ # @see Dry::Types::Default::Callable#evaluate
106
164
  def resolve_missing_value(result, key, type)
107
165
  if type.default?
108
166
  result[key] = type.evaluate
@@ -112,7 +170,12 @@ module Dry
112
170
  end
113
171
  end
114
172
 
173
+ # Weak schema provides safe types for every type given in schema hash
174
+ # @see Safe
115
175
  class Weak < Schema
176
+ # @param [Class] primitive
177
+ # @param [Hash] options
178
+ # @see #initialize
116
179
  def self.new(primitive, options)
117
180
  member_types = options.
118
181
  fetch(:member_types).
@@ -121,6 +184,11 @@ module Dry
121
184
  super(primitive, options.merge(member_types: member_types))
122
185
  end
123
186
 
187
+ # @param [Hash] hash
188
+ # @param [#call] block
189
+ # @yieldparam [Failure] failure
190
+ # @yieldreturn [Result]
191
+ # @return [Result]
124
192
  def try(hash, &block)
125
193
  if hash.is_a?(::Hash)
126
194
  super
@@ -131,6 +199,7 @@ module Dry
131
199
  end
132
200
  end
133
201
 
202
+ # {Symbolized} hash will turn string key names into symbols.
134
203
  class Symbolized < Weak
135
204
  private
136
205
 
@@ -1,18 +1,24 @@
1
1
  module Dry
2
2
  module Types
3
3
  module Options
4
+ # @return [Hash]
4
5
  attr_reader :options
5
6
 
7
+ # @see Definition#initialize
6
8
  def initialize(*args, **options)
7
9
  @__args__ = args
8
10
  @options = options
9
11
  @meta = options.fetch(:meta, {})
10
12
  end
11
13
 
14
+ # @param [Hash] new_options
15
+ # @return [Definition]
12
16
  def with(new_options)
13
17
  self.class.new(*@__args__, options.merge(new_options))
14
18
  end
15
19
 
20
+ # @param [Hash] data
21
+ # @return [Hash, Definition]
16
22
  def meta(data = nil)
17
23
  data ? with(meta: @meta.merge(data)) : @meta
18
24
  end
@@ -5,17 +5,21 @@ module Dry
5
5
  class Result
6
6
  include Dry::Equalizer(:input)
7
7
 
8
+ # @return [Object]
8
9
  attr_reader :input
9
10
 
11
+ # @param [Object] input
10
12
  def initialize(input)
11
13
  @input = input
12
14
  end
13
15
 
14
16
  class Success < Result
17
+ # @return [true]
15
18
  def success?
16
19
  true
17
20
  end
18
21
 
22
+ # @return [false]
19
23
  def failure?
20
24
  false
21
25
  end
@@ -24,21 +28,27 @@ module Dry
24
28
  class Failure < Result
25
29
  include Dry::Equalizer(:input, :error)
26
30
 
31
+ # @return [#to_s]
27
32
  attr_reader :error
28
33
 
34
+ # @param [Object] input
35
+ # @param [#to_s] error
29
36
  def initialize(input, error)
30
37
  super(input)
31
38
  @error = error
32
39
  end
33
40
 
41
+ # @return [String]
34
42
  def to_s
35
43
  error.to_s
36
44
  end
37
45
 
46
+ # @return [false]
38
47
  def success?
39
48
  false
40
49
  end
41
50
 
51
+ # @return [true]
42
52
  def failure?
43
53
  true
44
54
  end
@@ -7,6 +7,8 @@ module Dry
7
7
  include Decorator
8
8
  include Builder
9
9
 
10
+ # @param [Object] input
11
+ # @return [Object]
10
12
  def call(input)
11
13
  result = try(input)
12
14
 
@@ -18,6 +20,11 @@ module Dry
18
20
  end
19
21
  alias_method :[], :call
20
22
 
23
+ # @param [Object] input
24
+ # @param [#call] block
25
+ # @yieldparam [Failure] failure
26
+ # @yieldreturn [Result]
27
+ # @return [Result]
21
28
  def try(input, &block)
22
29
  type.try(input, &block)
23
30
  rescue TypeError, ArgumentError => e
@@ -27,6 +34,8 @@ module Dry
27
34
 
28
35
  private
29
36
 
37
+ # @param [Object, Dry::Types::Constructor] response
38
+ # @return [Boolean]
30
39
  def decorate?(response)
31
40
  super || response.kind_of?(Constructor)
32
41
  end
data/lib/dry/types/sum.rb CHANGED
@@ -7,19 +7,26 @@ module Dry
7
7
  include Builder
8
8
  include Options
9
9
 
10
+ # @return [Definition]
10
11
  attr_reader :left
11
12
 
13
+ # @return [Definition]
12
14
  attr_reader :right
13
15
 
14
16
  class Constrained < Sum
17
+ # @return [Dry::Logic::Rule]
15
18
  def rule
16
19
  left.rule | right.rule
17
20
  end
18
21
 
22
+ # @return [true]
19
23
  def constrained?
20
24
  true
21
25
  end
22
26
 
27
+ # @param [Object] input
28
+ # @return [Object]
29
+ # @raise [ConstraintError] if given +input+ not passing {#try}
23
30
  def call(input)
24
31
  try(input) do |result|
25
32
  raise ConstraintError.new(result, input)
@@ -28,28 +35,37 @@ module Dry
28
35
  alias_method :[], :call
29
36
  end
30
37
 
38
+ # @param [Definition] left
39
+ # @param [Definition] right
40
+ # @param [Hash] options
31
41
  def initialize(left, right, options = {})
32
42
  super
33
43
  @left, @right = left, right
34
44
  freeze
35
45
  end
36
46
 
47
+ # @return [String]
37
48
  def name
38
49
  [left, right].map(&:name).join(' | ')
39
50
  end
40
51
 
52
+ # @return [false]
41
53
  def default?
42
54
  false
43
55
  end
44
56
 
57
+ # @return [false]
45
58
  def maybe?
46
59
  false
47
60
  end
48
61
 
62
+ # @return [false]
49
63
  def constrained?
50
64
  false
51
65
  end
52
66
 
67
+ # @param [Object] input
68
+ # @return [Object]
53
69
  def call(input)
54
70
  try(input).input
55
71
  end
@@ -69,10 +85,14 @@ module Dry
69
85
  end
70
86
  end
71
87
 
88
+ # @param [Object] value
89
+ # @return [Boolean]
72
90
  def primitive?(value)
73
91
  left.primitive?(value) || right.primitive?(value)
74
92
  end
75
93
 
94
+ # @param [Object] value
95
+ # @return [Boolean]
76
96
  def valid?(value)
77
97
  left.valid?(value) || right.valid?(value)
78
98
  end
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module Types
3
- VERSION = '0.9.2'.freeze
3
+ VERSION = '0.9.3'.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.9.2
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-11-13 00:00:00.000000000 Z
11
+ date: 2016-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -31,6 +31,9 @@ dependencies:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0.2'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 0.2.1
34
37
  type: :runtime
35
38
  prerelease: false
36
39
  version_requirements: !ruby/object:Gem::Requirement
@@ -38,6 +41,9 @@ dependencies:
38
41
  - - "~>"
39
42
  - !ruby/object:Gem::Version
40
43
  version: '0.2'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 0.2.1
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: dry-container
43
49
  requirement: !ruby/object:Gem::Requirement
@@ -176,6 +182,20 @@ dependencies:
176
182
  - - "~>"
177
183
  - !ruby/object:Gem::Version
178
184
  version: '0.2'
185
+ - !ruby/object:Gem::Dependency
186
+ name: yard
187
+ requirement: !ruby/object:Gem::Requirement
188
+ requirements:
189
+ - - "~>"
190
+ - !ruby/object:Gem::Version
191
+ version: 0.9.5
192
+ type: :development
193
+ prerelease: false
194
+ version_requirements: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - "~>"
197
+ - !ruby/object:Gem::Version
198
+ version: 0.9.5
179
199
  description: Type system for Ruby supporting coercions, constraints and complex types
180
200
  like structs, value objects, enums etc.
181
201
  email:
@@ -187,6 +207,7 @@ files:
187
207
  - ".gitignore"
188
208
  - ".rspec"
189
209
  - ".travis.yml"
210
+ - ".yardopts"
190
211
  - CHANGELOG.md
191
212
  - Gemfile
192
213
  - LICENSE