dry-types 1.0.1 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9bb3d91a31885a317b8fda3eef46f77b283abb3781c84124cc7ca0a5a2c30104
4
- data.tar.gz: 88cd356e7878080570e5fa659f1403e01d8bc8a9654b3c5cfaf568c851d8e848
3
+ metadata.gz: 4f4827f984803481533626b7ebe6e51fe6b5cf5da3691a7e0f9681c4d321bd1a
4
+ data.tar.gz: 755af2027b59115fd97e1051bdea5eb400ca1a76cf39b19953538e4fb5bb28dc
5
5
  SHA512:
6
- metadata.gz: 536386eba753a58a499c473d7f9e54da2bccf8597d80e3e225a036fb37acd886e0e9f75ceff497e81e6cb9a47141c2fdf4753f2bd521bf5a53424f768fc0cf0d
7
- data.tar.gz: f74042df53c00159132ff2675206a393ca73a0d48ab84f7e6d58d56a51082e570932591279705ec993056b8e2720fd4572657b7bcb90596a16a7addaa7ac4bcf
6
+ metadata.gz: 18aa4a59b9fbe19721d65c57ca91f29b4f3935298e5947182953b9ffe92c7213fe4f209e55d3472a86d3d4645e8e0ccd200e5456af492026570b0f28f9255973
7
+ data.tar.gz: e9b2886e43868b544ec1e4cb9c30949bbd3bec9dba1089dcd08c7ba36e456458a8746ea2537d5241c63322b38505ddc86fecda4035ab0f545e675cbc4188ba15
data/CHANGELOG.md CHANGED
@@ -1,8 +1,38 @@
1
+ # 1.1.1 2019-07-26
2
+
3
+ ## Fixed
4
+
5
+ - A bug where meta was lost for lax array types (flash-gordon)
6
+
7
+ [Compare v1.1.0...v1.1.1](https://github.com/dry-rb/dry-types/compare/v1.1.0...v1.1.1)
8
+
9
+ # 1.1.0 2019-07-02
10
+
11
+ ## Added
12
+
13
+ - New builder method `Interface` constructs a type which accepts objects that respond to the given methods (waiting-for-dev)
14
+ ```ruby
15
+ Types = Dry.Types()
16
+ Types::Callable = Types.Interface(:call)
17
+ Types::Callable.valid?(Object.new) # => false
18
+ Types::Callable.valid?(proc {}) # => true
19
+ ```
20
+ - New types: `coercible.symbol`, `params.symbol`, and `json.symbol`, all use `.to_sym` for coercion (waiting-for-dev)
21
+
22
+ ## Fixed
23
+
24
+ - Converting schema keys to maybe types (flash-gordon)
25
+ - Using `Schema#key` and `Array#member` on constuctors (flash-gordon)
26
+ - Using `meta(omittable: true)` within `transform_types` works again but produces a warning, please migrate to `.omittable` or `.required(false)` (flash-gordon)
27
+ - Bug with a constructror defined on top of enum (flash-gordon)
28
+
29
+ [Compare v1.0.1...v1.1.0](https://github.com/dry-rb/dry-types/compare/v1.0.1...v1.1.0)
30
+
1
31
  # 1.0.1 2019-06-04
2
32
 
3
33
  ## Added
4
34
 
5
- - In the case of failure the constructor block can now pass a different value (flash-gordon)
35
+ - In a case of failure the constructor block can now pass a different value (flash-gordon)
6
36
  ```ruby
7
37
  not_empty_string = Types::String.constructor do |value, &failure|
8
38
  value.strip.empty? ? failure.(nil) : value.strip
@@ -21,6 +51,7 @@
21
51
 
22
52
  - [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
53
  Compare:
54
+
24
55
  ```ruby
25
56
  # 0.15.0
26
57
  Types::Params::Integer.('foo')
@@ -36,7 +67,9 @@
36
67
  ```ruby
37
68
  Types::Params::Integer.('foo') { :invalid } # => :invalid
38
69
  ```
70
+
39
71
  This makes work with coercions more straightforward and way faster.
72
+
40
73
  - [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
74
  - [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
75
  - 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 +192,7 @@
159
192
  )
160
193
  ```
161
194
  - Key types have API for making keys omittable and back (flash-gordon)
195
+
162
196
  ```ruby
163
197
  # defining a base schema with optional keys
164
198
  lax_hash = Dry::Types['hash'].with_type_transform { |key| key.required(false) }
@@ -168,8 +202,10 @@
168
202
  # keys in user_schema are not required
169
203
  user_schema = lax_hash.schema(name: 'string', age: 'integer')
170
204
  ```
205
+
171
206
  - `Type#optional?` now recognizes more cases where `nil` is an allowed value (flash-gordon)
172
207
  - `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)
208
+
173
209
  ```ruby
174
210
  to_int = Types::Coercible::Integer
175
211
  inc = to_int.append { |x| x + 2 }
@@ -178,6 +214,7 @@
178
214
  inc = to_int.prepend { |x| x + "2" }
179
215
  inc.("1") # => "1" -> "12" -> 12
180
216
  ```
217
+
181
218
  - Partial schema application for cases when you want to validate only a subset of keys (flash-gordon)
182
219
  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
220
  ```ruby
@@ -189,14 +226,15 @@
189
226
 
190
227
  ## Fixed
191
228
 
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)
229
+ - `Hash::Map` now behaves as a constrained type if its values are constrained (flash-gordon)
230
+ - `coercible.integer` now doesn't blow up on invalid strings (exterm)
194
231
 
195
232
  [Compare v0.14.0...v0.15.0](https://github.com/dry-rb/dry-types/compare/v0.14.0...v0.15.0)
196
233
 
197
234
  # v0.14.1 2019-03-25
198
235
 
199
236
  ## Fixed
237
+
200
238
  - `coercible.integer` now doesn't blow up on invalid strings (exterm)
201
239
 
202
240
  [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/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  [gem]: https://rubygems.org/gems/dry-types
2
- [travis]: https://travis-ci.org/dry-rb/dry-types
2
+ [travis]: https://travis-ci.com/dry-rb/dry-types
3
3
  [codeclimate]: https://codeclimate.com/github/dry-rb/dry-types
4
4
  [coveralls]: https://coveralls.io/r/dry-rb/dry-types
5
5
  [inchpages]: http://inch-ci.org/github/dry-rb/dry-types
@@ -8,7 +8,7 @@
8
8
  # dry-types [![Join the chat at https://dry-rb.zulipchat.com](https://img.shields.io/badge/dry--rb-join%20chat-%23346b7a.svg)][chat]
9
9
 
10
10
  [![Gem Version](https://badge.fury.io/rb/dry-types.svg)][gem]
11
- [![Build Status](https://travis-ci.org/dry-rb/dry-types.svg?branch=master)][travis]
11
+ [![Build Status](https://travis-ci.com/dry-rb/dry-types.svg?branch=master)][travis]
12
12
  [![Code Climate](https://codeclimate.com/github/dry-rb/dry-types/badges/gpa.svg)][codeclimate]
13
13
  [![Test Coverage](https://codeclimate.com/github/dry-rb/dry-types/badges/coverage.svg)][codeclimate]
14
14
  [![Inline docs](http://inch-ci.org/github/dry-rb/dry-types.svg?branch=master)][inchpages]
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
data/dry-types.gemspec CHANGED
@@ -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
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 = %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
@@ -98,7 +100,7 @@ module Dry
98
100
  #
99
101
  # @api public
100
102
  def lax
101
- Lax.new(Member.new(primitive, { **options, member: member.lax }))
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
@@ -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