dry-types 1.0.1 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9bb3d91a31885a317b8fda3eef46f77b283abb3781c84124cc7ca0a5a2c30104
4
- data.tar.gz: 88cd356e7878080570e5fa659f1403e01d8bc8a9654b3c5cfaf568c851d8e848
3
+ metadata.gz: 689634e9152c629af622ef69379633b674b6c60b7f5cd87093894de7ee8ce571
4
+ data.tar.gz: a23593e6c4d904343dadd46f919cfead42b45fbe963995380712f4c6a8e719fd
5
5
  SHA512:
6
- metadata.gz: 536386eba753a58a499c473d7f9e54da2bccf8597d80e3e225a036fb37acd886e0e9f75ceff497e81e6cb9a47141c2fdf4753f2bd521bf5a53424f768fc0cf0d
7
- data.tar.gz: f74042df53c00159132ff2675206a393ca73a0d48ab84f7e6d58d56a51082e570932591279705ec993056b8e2720fd4572657b7bcb90596a16a7addaa7ac4bcf
6
+ metadata.gz: 88fd3e79ea403515fe242baa57c6824757bdc0b04f99054a9da2394c745cce54415fc3c260b35e49eed8a5240f78614efe92e052f6e6bde0e1f9b961a04f41ac
7
+ data.tar.gz: 3445b5726dd5325261965409883b6830450f3d710ae2b0a7be411b0d45cb25d3550a25827d9f0661dfbfd0fd55f15954d77335312237c3bf754ca7af5eae6079
@@ -1,8 +1,30 @@
1
+ # 1.1.0 2019-07-02
2
+
3
+ ## Added
4
+
5
+ - New builder method `Interface` constructs a type which accepts objects that respond to the given methods (waiting-for-dev)
6
+ ```ruby
7
+ Types = Dry.Types()
8
+ Types::Callable = Types.Interface(:call)
9
+ Types::Callable.valid?(Object.new) # => false
10
+ Types::Callable.valid?(proc {}) # => true
11
+ ```
12
+ - New types: `coercible.symbol`, `params.symbol`, and `json.symbol`, all use `.to_sym` for coercion (waiting-for-dev)
13
+
14
+ ## Fixed
15
+
16
+ - Converting schema keys to maybe types (flash-gordon)
17
+ - Using `Schema#key` and `Array#member` on constuctors (flash-gordon)
18
+ - Using `meta(omittable: true)` within `transform_types` works again but produces a warning, please migrate to `.omittable` or `.required(false)` (flash-gordon)
19
+ - Bug with a constructror defined on top of enum (flash-gordon)
20
+
21
+ [Compare v1.0.1...v1.1.0](https://github.com/dry-rb/dry-types/compare/v1.0.1...v1.1.0)
22
+
1
23
  # 1.0.1 2019-06-04
2
24
 
3
25
  ## Added
4
26
 
5
- - In the case of failure the constructor block can now pass a different value (flash-gordon)
27
+ - In a case of failure the constructor block can now pass a different value (flash-gordon)
6
28
  ```ruby
7
29
  not_empty_string = Types::String.constructor do |value, &failure|
8
30
  value.strip.empty? ? failure.(nil) : value.strip
@@ -21,6 +43,7 @@
21
43
 
22
44
  - [BREAKING] Behavior of built-in constructor types was changed to be more strict. They will always raise an error on failed coercion (flash-gordon)
23
45
  Compare:
46
+
24
47
  ```ruby
25
48
  # 0.15.0
26
49
  Types::Params::Integer.('foo')
@@ -36,7 +59,9 @@
36
59
  ```ruby
37
60
  Types::Params::Integer.('foo') { :invalid } # => :invalid
38
61
  ```
62
+
39
63
  This makes work with coercions more straightforward and way faster.
64
+
40
65
  - [BREAKING] Safe types were renamed to Lax, this name better serves their purpose. The previous name is available but prints a warning (flash-gordon)
41
66
  - [BREAKING] Metadata is now pushed down to the decorated type. It is not likely you will notice a difference but this a breaking change that enables some use cases in rom related to the usage of default types in relations (flash-gordon)
42
67
  - Nominal types are now completely unconstrained. This fixes some inconsistencies when using them with constraints. `Nominal#try` will always return a successful result, for the previous behavior use `Nominal#try_coerce` or switch to strict types with passing a block to `#call` (flash-gordon)
@@ -159,6 +184,7 @@
159
184
  )
160
185
  ```
161
186
  - Key types have API for making keys omittable and back (flash-gordon)
187
+
162
188
  ```ruby
163
189
  # defining a base schema with optional keys
164
190
  lax_hash = Dry::Types['hash'].with_type_transform { |key| key.required(false) }
@@ -168,8 +194,10 @@
168
194
  # keys in user_schema are not required
169
195
  user_schema = lax_hash.schema(name: 'string', age: 'integer')
170
196
  ```
197
+
171
198
  - `Type#optional?` now recognizes more cases where `nil` is an allowed value (flash-gordon)
172
199
  - `Constructor#{prepend,append}` with `<<` and `>>` as aliases. `Constructor#append` works the same way `Constructor#constrcutor` does. `Constuctor#prepend` chains functions in the reverse order, see examples (flash-gordon)
200
+
173
201
  ```ruby
174
202
  to_int = Types::Coercible::Integer
175
203
  inc = to_int.append { |x| x + 2 }
@@ -178,6 +206,7 @@
178
206
  inc = to_int.prepend { |x| x + "2" }
179
207
  inc.("1") # => "1" -> "12" -> 12
180
208
  ```
209
+
181
210
  - Partial schema application for cases when you want to validate only a subset of keys (flash-gordon)
182
211
  This is useful when you want to update a key or two in an already-validated hash. A perfect example is `Dry::Struct#new` where this feature is now used.
183
212
  ```ruby
@@ -189,14 +218,15 @@
189
218
 
190
219
  ## Fixed
191
220
 
192
- * `Hash::Map` now behaves as a constrained type if its values are constrained (flash-gordon)
193
- * `coercible.integer` now doesn't blow up on invalid strings (exterm)
221
+ - `Hash::Map` now behaves as a constrained type if its values are constrained (flash-gordon)
222
+ - `coercible.integer` now doesn't blow up on invalid strings (exterm)
194
223
 
195
224
  [Compare v0.14.0...v0.15.0](https://github.com/dry-rb/dry-types/compare/v0.14.0...v0.15.0)
196
225
 
197
226
  # v0.14.1 2019-03-25
198
227
 
199
228
  ## Fixed
229
+
200
230
  - `coercible.integer` now doesn't blow up on invalid strings (exterm)
201
231
 
202
232
  [Compare v0.14.0...v0.14.1](https://github.com/dry-rb/dry-types/compare/v0.14.0...v0.14.1)
data/Gemfile CHANGED
@@ -14,13 +14,14 @@ end
14
14
 
15
15
  group :tools do
16
16
  gem 'pry-byebug', platform: :mri
17
+ gem 'rubocop'
17
18
  end
18
19
 
19
20
  group :benchmarks do
21
+ gem 'attrio'
20
22
  gem 'benchmark-ips'
23
+ gem 'dry-struct'
24
+ gem 'fast_attributes'
21
25
  gem 'hotch'
22
26
  gem 'virtus'
23
- gem 'fast_attributes'
24
- gem 'attrio'
25
- gem 'dry-struct'
26
27
  end
data/Rakefile CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "bundler/gem_tasks"
4
- require "rspec/core/rake_task"
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
5
 
6
6
  task :run_specs do
7
7
  require 'rspec/core'
@@ -7,11 +7,13 @@ require 'dry-types'
7
7
 
8
8
  module SchemaBench
9
9
  def self.hash_schema(type)
10
- Dry::Types['nominal.hash'].public_send(type,
11
- email: Dry::Types['nominal.string'],
12
- age: Dry::Types['params.integer'],
13
- admin: Dry::Types['params.bool'],
14
- address: Dry::Types['nominal.hash'].public_send(type,
10
+ Dry::Types['nominal.hash'].public_send(
11
+ type,
12
+ email: Dry::Types['nominal.string'],
13
+ age: Dry::Types['params.integer'],
14
+ admin: Dry::Types['params.bool'],
15
+ address: Dry::Types['nominal.hash'].public_send(
16
+ type,
15
17
  city: Dry::Types['nominal.string'],
16
18
  street: Dry::Types['nominal.string']
17
19
  )
@@ -31,7 +33,7 @@ module SchemaBench
31
33
  age: '20',
32
34
  admin: '1',
33
35
  address: { city: 'NYC', street: 'Street 1/2' }
34
- }
36
+ }.freeze
35
37
  end
36
38
 
37
39
  require 'benchmark/ips'
@@ -13,4 +13,3 @@ Benchmark.ips do |x|
13
13
  x.report("valid input") { schema.(params) }
14
14
  x.compare!
15
15
  end
16
-
@@ -6,7 +6,7 @@ INVALID_INPUT = {
6
6
  name: :John,
7
7
  age: '20',
8
8
  email: nil
9
- }
9
+ }.freeze
10
10
 
11
11
  profile do
12
12
  10_000.times do
@@ -7,7 +7,7 @@ Schema = Dry::Types['params.hash'].schema(
7
7
  age?: 'coercible.integer'
8
8
  ).lax
9
9
 
10
- ValidInput = { email: 'jane@doe.org', age: '19' }
10
+ ValidInput = { email: 'jane@doe.org', age: '19' }.freeze
11
11
 
12
12
  profile do
13
13
  10_000.times do
@@ -6,7 +6,7 @@ VALID_INPUT = {
6
6
  name: 'John',
7
7
  age: 20,
8
8
  email: 'john@doe.com'
9
- }
9
+ }.freeze
10
10
 
11
11
  profile do
12
12
  10_000.times do
@@ -1,47 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- lib = File.expand_path('../lib', __FILE__)
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 = "dry-types"
8
+ spec.name = 'dry-types'
9
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
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 = "https://github.com/dry-rb/dry-types"
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'] = "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"
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 "RubyGems 2.0 or newer is required to protect against public gem pushes."
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 = "exe"
30
+ spec.bindir = 'exe'
31
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"
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-logic', '~> 1.0'
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 "bundler"
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
@@ -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 = %r[(.+)<(.+)>].freeze
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 RuntimeError, "Import Dry.Types, not Dry::Types"
48
+ raise 'Import Dry.Types, not Dry::Types'
49
49
  end
50
50
 
51
51
  # Return container with registered built-in type objects
@@ -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
@@ -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
@@ -75,7 +75,7 @@ module Dry
75
75
  ' Be careful: types will return the same instance of the default'\
76
76
  ' value every time. Call `.freeze` when setting the default'\
77
77
  ' or pass `shared: true` to discard this warning.'\
78
- "\n#{ where }",
78
+ "\n#{where}",
79
79
  tag: :'dry-types'
80
80
  )
81
81
  end
@@ -108,21 +108,21 @@ module Dry
108
108
  Types['nominal.hash'].map(key_type, value_type)
109
109
  end
110
110
 
111
- # # Builds a constrained nominal type accepting any value that
112
- # # responds to given methods
113
- # #
114
- # # @example
115
- # # Types::Callable = Types.Contract(:call)
116
- # # Types::Contact = Types.Contract(:name, :address)
117
- # #
118
- # # @param methods [Array<String, Symbol>] Method names
119
- # #
120
- # # @return [Dry::Types::Contrained]
121
- # def Contract(*methods)
122
- # methods.reduce(Types['nominal.any']) do |type, method|
123
- # type.constrained(respond_to: method)
124
- # end
125
- # end
111
+ # Builds a constrained nominal type accepting any value that
112
+ # responds to given methods
113
+ #
114
+ # @example
115
+ # Types::Callable = Types.Interface(:call)
116
+ # Types::Contact = Types.Interface(:name, :address)
117
+ #
118
+ # @param methods [Array<String, Symbol>] Method names
119
+ #
120
+ # @return [Dry::Types::Contrained]
121
+ def Interface(*methods)
122
+ methods.reduce(Types['nominal.any']) do |type, method|
123
+ type.constrained(respond_to: method)
124
+ end
125
+ end
126
126
  end
127
127
  end
128
128
  end
@@ -36,8 +36,8 @@ module Dry
36
36
  if input.respond_to?(:to_str)
37
37
  begin
38
38
  ::Date.parse(input)
39
- rescue ArgumentError, RangeError => error
40
- CoercionError.handle(error, &block)
39
+ rescue ArgumentError, RangeError => e
40
+ CoercionError.handle(e, &block)
41
41
  end
42
42
  elsif block_given?
43
43
  yield
@@ -57,8 +57,8 @@ module Dry
57
57
  if input.respond_to?(:to_str)
58
58
  begin
59
59
  ::DateTime.parse(input)
60
- rescue ArgumentError => error
61
- CoercionError.handle(error, &block)
60
+ rescue ArgumentError => e
61
+ CoercionError.handle(e, &block)
62
62
  end
63
63
  elsif block_given?
64
64
  yield
@@ -78,8 +78,8 @@ module Dry
78
78
  if input.respond_to?(:to_str)
79
79
  begin
80
80
  ::Time.parse(input)
81
- rescue ArgumentError => error
82
- CoercionError.handle(error, &block)
81
+ rescue ArgumentError => e
82
+ CoercionError.handle(e, &block)
83
83
  end
84
84
  elsif block_given?
85
85
  yield
@@ -88,6 +88,19 @@ module Dry
88
88
  end
89
89
  end
90
90
 
91
+ # @param [#to_sym, Object] input
92
+ #
93
+ # @return [Symbol, Object]
94
+ #
95
+ # @raise CoercionError
96
+ #
97
+ # @api public
98
+ def to_symbol(input, &block)
99
+ input.to_sym
100
+ rescue NoMethodError => e
101
+ CoercionError.handle(e, &block)
102
+ end
103
+
91
104
  private
92
105
 
93
106
  # Checks whether String is empty