dry-types 0.12.3 → 0.14.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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