dry-types 0.12.3 → 0.14.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.
@@ -0,0 +1,93 @@
1
+ module Dry
2
+ module Types
3
+ class Map < Definition
4
+ def initialize(_primitive, key_type: Types['any'], value_type: Types['any'], meta: EMPTY_HASH)
5
+ super(_primitive, key_type: key_type, value_type: value_type, meta: meta)
6
+ validate_options!
7
+ end
8
+
9
+ # @return [Type]
10
+ def key_type
11
+ options[:key_type]
12
+ end
13
+
14
+ # @return [Type]
15
+ def value_type
16
+ options[:value_type]
17
+ end
18
+
19
+ # @return [String]
20
+ def name
21
+ "Map"
22
+ end
23
+
24
+ # @param [Hash] hash
25
+ # @return [Hash]
26
+ def call(hash)
27
+ try(hash) do |failure|
28
+ raise MapError, failure.error.join("\n")
29
+ end.input
30
+ end
31
+ alias_method :[], :call
32
+
33
+ # @param [Hash] hash
34
+ # @return [Boolean]
35
+ def valid?(hash)
36
+ coerce(hash).success?
37
+ end
38
+ alias_method :===, :valid?
39
+
40
+ # @param [Hash] hash
41
+ # @return [Result]
42
+ def try(hash)
43
+ result = coerce(hash)
44
+ return result if result.success? || !block_given?
45
+ yield(result)
46
+ end
47
+
48
+ # @param meta [Boolean] Whether to dump the meta to the AST
49
+ # @return [Array] An AST representation
50
+ def to_ast(meta: true)
51
+ [:map,
52
+ [key_type.to_ast(meta: true), value_type.to_ast(meta: true),
53
+ meta ? self.meta : EMPTY_HASH]]
54
+ end
55
+
56
+ private
57
+
58
+ def coerce(input)
59
+ return failure(
60
+ input, "#{input.inspect} must be an instance of #{primitive}"
61
+ ) unless primitive?(input)
62
+
63
+ output, failures = {}, []
64
+
65
+ input.each do |k,v|
66
+ res_k = options[:key_type].try(k)
67
+ res_v = options[:value_type].try(v)
68
+ if res_k.failure?
69
+ failures << "input key #{k.inspect} is invalid: #{res_k.error}"
70
+ elsif output.key?(res_k.input)
71
+ failures << "duplicate coerced hash key #{res_k.input.inspect}"
72
+ elsif res_v.failure?
73
+ failures << "input value #{v.inspect} for key #{k.inspect} is invalid: #{res_v.error}"
74
+ else
75
+ output[res_k.input] = res_v.input
76
+ end
77
+ end
78
+
79
+ return success(output) if failures.empty?
80
+
81
+ failure(input, failures)
82
+ end
83
+
84
+ def validate_options!
85
+ %i(key_type value_type).each do |opt|
86
+ type = send(opt)
87
+ next if type.is_a?(Type)
88
+ raise MapError, ":#{opt} must be a #{Type}, got: #{type.inspect}"
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -6,9 +6,9 @@ module Dry
6
6
 
7
7
  # @see Definition#initialize
8
8
  def initialize(*args, meta: EMPTY_HASH, **options)
9
- @__args__ = args
10
- @options = options
11
- @meta = meta
9
+ @__args__ = args.freeze
10
+ @options = options.freeze
11
+ @meta = meta.freeze
12
12
  end
13
13
 
14
14
  # @param [Hash] new_options
@@ -0,0 +1,53 @@
1
+ require 'dry/types/coercions/params'
2
+
3
+ module Dry
4
+ module Types
5
+ register('params.nil') do
6
+ self['nil'].constructor(Coercions::Params.method(:to_nil))
7
+ end
8
+
9
+ register('params.date') do
10
+ self['date'].constructor(Coercions::Params.method(:to_date))
11
+ end
12
+
13
+ register('params.date_time') do
14
+ self['date_time'].constructor(Coercions::Params.method(:to_date_time))
15
+ end
16
+
17
+ register('params.time') do
18
+ self['time'].constructor(Coercions::Params.method(:to_time))
19
+ end
20
+
21
+ register('params.true') do
22
+ self['true'].constructor(Coercions::Params.method(:to_true))
23
+ end
24
+
25
+ register('params.false') do
26
+ self['false'].constructor(Coercions::Params.method(:to_false))
27
+ end
28
+
29
+ register('params.bool') do
30
+ (self['params.true'] | self['params.false']).safe
31
+ end
32
+
33
+ register('params.integer') do
34
+ self['integer'].constructor(Coercions::Params.method(:to_int))
35
+ end
36
+
37
+ register('params.float') do
38
+ self['float'].constructor(Coercions::Params.method(:to_float))
39
+ end
40
+
41
+ register('params.decimal') do
42
+ self['decimal'].constructor(Coercions::Params.method(:to_decimal))
43
+ end
44
+
45
+ register('params.array') do
46
+ self['array'].constructor(Coercions::Params.method(:to_ary)).safe
47
+ end
48
+
49
+ register('params.hash') do
50
+ self['hash'].constructor(Coercions::Params.method(:to_hash)).safe
51
+ end
52
+ end
53
+ end
@@ -4,9 +4,10 @@ module Dry
4
4
  module Types
5
5
  class Safe
6
6
  include Type
7
- include Dry::Equalizer(:type, :options)
7
+ include Dry::Equalizer(:type)
8
8
  include Decorator
9
9
  include Builder
10
+ private :options, :meta
10
11
 
11
12
  # @param [Object] input
12
13
  # @return [Object]
@@ -37,7 +38,7 @@ module Dry
37
38
  #
38
39
  # @see Definition#to_ast
39
40
  def to_ast(meta: true)
40
- [:safe, [type.to_ast, meta ? self.meta : EMPTY_HASH]]
41
+ [:safe, [type.to_ast(meta: meta), EMPTY_HASH]]
41
42
  end
42
43
 
43
44
  # @api public
@@ -56,6 +56,16 @@ RSpec.shared_examples_for 'Dry::Types::Definition#meta' do
56
56
  it 'equalizes on filled meta' do
57
57
  expect(type).to_not eql(type.meta(i_am: 'different'))
58
58
  end
59
+
60
+ it 'is locally immutable' do
61
+ expect(type.meta).to be_a ::Hash
62
+ expect(type.meta).to be_frozen
63
+ expect(type.meta).not_to have_key :immutable_test
64
+ derived = type.with(meta: {immutable_test: 1})
65
+ expect(derived.meta).to be_frozen
66
+ expect(derived.meta).to eql({immutable_test: 1})
67
+ expect(type.meta).not_to have_key :immutable_test
68
+ end
59
69
  end
60
70
 
61
71
  describe '#pristine' do
data/lib/dry/types/sum.rb CHANGED
@@ -55,11 +55,6 @@ module Dry
55
55
  false
56
56
  end
57
57
 
58
- # @return [false]
59
- def maybe?
60
- false
61
- end
62
-
63
58
  # @return [false]
64
59
  def constrained?
65
60
  false
@@ -101,7 +96,7 @@ module Dry
101
96
  end
102
97
  end
103
98
 
104
- def failure(input)
99
+ def failure(input, _error = nil)
105
100
  if !left.valid?(input)
106
101
  left.failure(input, left.try(input).error)
107
102
  else
@@ -128,6 +123,17 @@ module Dry
128
123
  def to_ast(meta: true)
129
124
  [:sum, [left.to_ast(meta: meta), right.to_ast(meta: meta), meta ? self.meta : EMPTY_HASH]]
130
125
  end
126
+
127
+ # @param [Hash] options
128
+ # @return [Constrained,Sum]
129
+ # @see Builder#constrained
130
+ def constrained(options)
131
+ if optional?
132
+ right.constrained(options).optional
133
+ else
134
+ super
135
+ end
136
+ end
131
137
  end
132
138
  end
133
139
  end
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module Types
3
- VERSION = '0.12.3'.freeze
3
+ VERSION = '0.14.1'.freeze
4
4
  end
5
5
  end
data/lib/dry/types.rb CHANGED
@@ -2,33 +2,35 @@ require 'bigdecimal'
2
2
  require 'date'
3
3
  require 'set'
4
4
 
5
- require 'inflecto'
6
5
  require 'concurrent'
7
6
 
8
7
  require 'dry-container'
9
8
  require 'dry-equalizer'
10
9
  require 'dry/core/extensions'
11
10
  require 'dry/core/constants'
11
+ require 'dry/core/class_attributes'
12
12
 
13
13
  require 'dry/types/version'
14
14
  require 'dry/types/container'
15
+ require 'dry/types/inflector'
15
16
  require 'dry/types/type'
16
17
  require 'dry/types/definition'
17
18
  require 'dry/types/constructor'
18
- require 'dry/types/fn_container'
19
19
  require 'dry/types/builder_methods'
20
20
 
21
21
  require 'dry/types/errors'
22
22
 
23
23
  module Dry
24
24
  module Types
25
- extend Dry::Configurable
26
25
  extend Dry::Core::Extensions
26
+ extend Dry::Core::ClassAttributes
27
27
  include Dry::Core::Constants
28
28
 
29
29
  # @!attribute [r] namespace
30
30
  # @return [Container{String => Definition}]
31
- setting :namespace, self
31
+ defines :namespace
32
+
33
+ namespace self
32
34
 
33
35
  TYPE_SPEC_REGEX = %r[(.+)<(.+)>].freeze
34
36
 
@@ -46,7 +48,7 @@ module Dry
46
48
  ' do `include Dry::Types.module` in places where you want to have access'\
47
49
  ' to built-in types'
48
50
 
49
- define_constants(config.namespace, type_keys)
51
+ define_constants(self.namespace, type_keys)
50
52
  end
51
53
 
52
54
  # @return [Container{String => Definition}]
@@ -63,19 +65,11 @@ module Dry
63
65
  # @param [Type] type
64
66
  # @param [#call,nil] block
65
67
  # @return [Container{String => Definition}]
68
+ # @api private
66
69
  def self.register(name, type = nil, &block)
67
70
  container.register(name, type || block.call)
68
71
  end
69
72
 
70
- # Registers given +klass+ in {#container} using +meth+ constructor
71
- # @param [Class] klass
72
- # @param [Symbol] meth
73
- # @return [Container{String => Definition}]
74
- def self.register_class(klass, meth = :new)
75
- type = Definition.new(klass).constructor(klass.method(meth))
76
- container.register(identifier(klass), type)
77
- end
78
-
79
73
  # @param [String,Class] name
80
74
  # @return [Type,Class]
81
75
  def self.[](name)
@@ -108,7 +102,7 @@ module Dry
108
102
  def self.define_constants(namespace, identifiers)
109
103
  names = identifiers.map do |id|
110
104
  parts = id.split('.')
111
- [Inflecto.camelize(parts.pop), parts.map(&Inflecto.method(:camelize))]
105
+ [Inflector.camelize(parts.pop), parts.map(&Inflector.method(:camelize))]
112
106
  end
113
107
 
114
108
  names.map do |(klass, parts)|
@@ -123,7 +117,7 @@ module Dry
123
117
  # @param [#to_s] klass
124
118
  # @return [String]
125
119
  def self.identifier(klass)
126
- Inflecto.underscore(klass).tr('/', '.')
120
+ Inflector.underscore(klass).tr('/', '.')
127
121
  end
128
122
 
129
123
  # @return [Concurrent::Map]
@@ -141,12 +135,12 @@ module Dry
141
135
 
142
136
  # @api private
143
137
  def self.const_missing(const)
144
- underscored = Inflecto.underscore(const)
138
+ underscored = Inflector.underscore(const)
145
139
 
146
140
  if type_keys.any? { |key| key.split('.')[0] == underscored }
147
141
  raise NameError,
148
142
  'dry-types does not define constants for default types. '\
149
- 'You can access the predefined types with [], e.g. Dry::Types["strict.int"] '\
143
+ 'You can access the predefined types with [], e.g. Dry::Types["strict.integer"] '\
150
144
  'or generate a module with types using Dry::Types.module'
151
145
  else
152
146
  super
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.12.3
4
+ version: 0.14.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-06-12 00:00:00.000000000 Z
11
+ date: 2019-03-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -30,116 +30,102 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0.2'
33
+ version: '0.4'
34
34
  - - ">="
35
35
  - !ruby/object:Gem::Version
36
- version: 0.2.1
36
+ version: 0.4.4
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - "~>"
42
42
  - !ruby/object:Gem::Version
43
- version: '0.2'
43
+ version: '0.4'
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: 0.2.1
46
+ version: 0.4.4
47
47
  - !ruby/object:Gem::Dependency
48
- name: dry-container
48
+ name: dry-inflector
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '0.3'
53
+ version: '0.1'
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 0.1.2
54
57
  type: :runtime
55
58
  prerelease: false
56
59
  version_requirements: !ruby/object:Gem::Requirement
57
60
  requirements:
58
61
  - - "~>"
59
62
  - !ruby/object:Gem::Version
60
- version: '0.3'
63
+ version: '0.1'
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 0.1.2
61
67
  - !ruby/object:Gem::Dependency
62
- name: dry-equalizer
68
+ name: dry-container
63
69
  requirement: !ruby/object:Gem::Requirement
64
70
  requirements:
65
71
  - - "~>"
66
72
  - !ruby/object:Gem::Version
67
- version: '0.2'
73
+ version: '0.3'
68
74
  type: :runtime
69
75
  prerelease: false
70
76
  version_requirements: !ruby/object:Gem::Requirement
71
77
  requirements:
72
78
  - - "~>"
73
79
  - !ruby/object:Gem::Version
74
- version: '0.2'
80
+ version: '0.3'
75
81
  - !ruby/object:Gem::Dependency
76
- name: dry-configurable
82
+ name: dry-equalizer
77
83
  requirement: !ruby/object:Gem::Requirement
78
84
  requirements:
79
85
  - - "~>"
80
86
  - !ruby/object:Gem::Version
81
- version: '0.1'
87
+ version: '0.2'
82
88
  type: :runtime
83
89
  prerelease: false
84
90
  version_requirements: !ruby/object:Gem::Requirement
85
91
  requirements:
86
92
  - - "~>"
87
93
  - !ruby/object:Gem::Version
88
- version: '0.1'
94
+ version: '0.2'
89
95
  - !ruby/object:Gem::Dependency
90
96
  name: dry-logic
91
97
  requirement: !ruby/object:Gem::Requirement
92
98
  requirements:
93
- - - "~>"
94
- - !ruby/object:Gem::Version
95
- version: '0.4'
96
- - - ">="
97
- - !ruby/object:Gem::Version
98
- version: 0.4.2
99
- type: :runtime
100
- prerelease: false
101
- version_requirements: !ruby/object:Gem::Requirement
102
- requirements:
103
- - - "~>"
104
- - !ruby/object:Gem::Version
105
- version: '0.4'
106
99
  - - ">="
107
100
  - !ruby/object:Gem::Version
108
- version: 0.4.2
109
- - !ruby/object:Gem::Dependency
110
- name: inflecto
111
- requirement: !ruby/object:Gem::Requirement
112
- requirements:
101
+ version: '0.5'
113
102
  - - "~>"
114
103
  - !ruby/object:Gem::Version
115
- version: 0.0.0
116
- - - ">="
117
- - !ruby/object:Gem::Version
118
- version: 0.0.2
104
+ version: '0.5'
119
105
  type: :runtime
120
106
  prerelease: false
121
107
  version_requirements: !ruby/object:Gem::Requirement
122
108
  requirements:
123
- - - "~>"
124
- - !ruby/object:Gem::Version
125
- version: 0.0.0
126
109
  - - ">="
127
110
  - !ruby/object:Gem::Version
128
- version: 0.0.2
111
+ version: '0.5'
112
+ - - "~>"
113
+ - !ruby/object:Gem::Version
114
+ version: '0.5'
129
115
  - !ruby/object:Gem::Dependency
130
116
  name: bundler
131
117
  requirement: !ruby/object:Gem::Requirement
132
118
  requirements:
133
- - - "~>"
119
+ - - ">="
134
120
  - !ruby/object:Gem::Version
135
- version: '1.6'
121
+ version: '0'
136
122
  type: :development
137
123
  prerelease: false
138
124
  version_requirements: !ruby/object:Gem::Requirement
139
125
  requirements:
140
- - - "~>"
126
+ - - ">="
141
127
  - !ruby/object:Gem::Version
142
- version: '1.6'
128
+ version: '0'
143
129
  - !ruby/object:Gem::Dependency
144
130
  name: rake
145
131
  requirement: !ruby/object:Gem::Requirement
@@ -224,8 +210,11 @@ files:
224
210
  - lib/dry/types/builder.rb
225
211
  - lib/dry/types/builder_methods.rb
226
212
  - lib/dry/types/coercions.rb
227
- - lib/dry/types/coercions/form.rb
228
213
  - lib/dry/types/coercions/json.rb
214
+ - lib/dry/types/coercions/params.rb
215
+ - lib/dry/types/compat.rb
216
+ - lib/dry/types/compat/form_types.rb
217
+ - lib/dry/types/compat/int.rb
229
218
  - lib/dry/types/compiler.rb
230
219
  - lib/dry/types/constrained.rb
231
220
  - lib/dry/types/constrained/coercible.rb
@@ -241,11 +230,14 @@ files:
241
230
  - lib/dry/types/extensions.rb
242
231
  - lib/dry/types/extensions/maybe.rb
243
232
  - lib/dry/types/fn_container.rb
244
- - lib/dry/types/form.rb
245
233
  - lib/dry/types/hash.rb
246
234
  - lib/dry/types/hash/schema.rb
235
+ - lib/dry/types/hash/schema_builder.rb
236
+ - lib/dry/types/inflector.rb
247
237
  - lib/dry/types/json.rb
238
+ - lib/dry/types/map.rb
248
239
  - lib/dry/types/options.rb
240
+ - lib/dry/types/params.rb
249
241
  - lib/dry/types/result.rb
250
242
  - lib/dry/types/safe.rb
251
243
  - lib/dry/types/spec/types.rb
@@ -258,6 +250,9 @@ licenses:
258
250
  - MIT
259
251
  metadata:
260
252
  allowed_push_host: https://rubygems.org
253
+ changelog_uri: https://github.com/dry-rb/dry-types/blob/master/CHANGELOG.md
254
+ source_code_uri: https://github.com/dry-rb/dry-types
255
+ bug_tracker_uri: https://github.com/dry-rb/dry-types/issues
261
256
  post_install_message:
262
257
  rdoc_options: []
263
258
  require_paths:
@@ -266,15 +261,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
266
261
  requirements:
267
262
  - - ">="
268
263
  - !ruby/object:Gem::Version
269
- version: 2.2.0
264
+ version: 2.3.0
270
265
  required_rubygems_version: !ruby/object:Gem::Requirement
271
266
  requirements:
272
267
  - - ">="
273
268
  - !ruby/object:Gem::Version
274
269
  version: '0'
275
270
  requirements: []
276
- rubyforge_project:
277
- rubygems_version: 2.7.6
271
+ rubygems_version: 3.0.1
278
272
  signing_key:
279
273
  specification_version: 4
280
274
  summary: Type system for Ruby supporting coercions, constraints and complex types
@@ -1,53 +0,0 @@
1
- require 'dry/types/coercions/form'
2
-
3
- module Dry
4
- module Types
5
- register('form.nil') do
6
- self['nil'].constructor(Coercions::Form.method(:to_nil))
7
- end
8
-
9
- register('form.date') do
10
- self['date'].constructor(Coercions::Form.method(:to_date))
11
- end
12
-
13
- register('form.date_time') do
14
- self['date_time'].constructor(Coercions::Form.method(:to_date_time))
15
- end
16
-
17
- register('form.time') do
18
- self['time'].constructor(Coercions::Form.method(:to_time))
19
- end
20
-
21
- register('form.true') do
22
- self['true'].constructor(Coercions::Form.method(:to_true))
23
- end
24
-
25
- register('form.false') do
26
- self['false'].constructor(Coercions::Form.method(:to_false))
27
- end
28
-
29
- register('form.bool') do
30
- (self['form.true'] | self['form.false']).safe
31
- end
32
-
33
- register('form.int') do
34
- self['int'].constructor(Coercions::Form.method(:to_int))
35
- end
36
-
37
- register('form.float') do
38
- self['float'].constructor(Coercions::Form.method(:to_float))
39
- end
40
-
41
- register('form.decimal') do
42
- self['decimal'].constructor(Coercions::Form.method(:to_decimal))
43
- end
44
-
45
- register('form.array') do
46
- self['array'].constructor(Coercions::Form.method(:to_ary)).safe
47
- end
48
-
49
- register('form.hash') do
50
- self['hash'].constructor(Coercions::Form.method(:to_hash)).safe
51
- end
52
- end
53
- end