dry-types 0.7.0 → 0.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 02e8392346549c5801d50d1fb805951bea41e722
4
- data.tar.gz: 6e4873ce2f3f8f92eb1bbbfccfbe68aed67524c2
3
+ metadata.gz: 8ca173b64639db4a874bc33694d2a8df9f9e0500
4
+ data.tar.gz: 4bcf324022827e5145dc0cbcc4376a0958e5595f
5
5
  SHA512:
6
- metadata.gz: 1153d031efd2277c552a3b47e26395da775d5fa70600bc815c9f1a4658cb8200ba99c595b90c52c8128bd896bb017f2bcd1a0fcf80227bbb57118d2a1305f03d
7
- data.tar.gz: 0d6c974e7bf9fbb552d4abd95e15a51368685507e21eda31909c9b002c43652dd74c08244728242330797be64e5b196bc7f1763c91d204f6b51ad181d69f65a1
6
+ metadata.gz: 4f44642bb9ddfb9911fba8439b5dbcbfaa55bafbd47755c23f6279bc37da155c06e6100c56bdaebc1c783fdccd8e892b14f5b36b6eee9c81d21a3b0a9ebe2971
7
+ data.tar.gz: 5db7721ac8611a08167a91106ad5097db5796fb8664c3f36502ef7ac92706902b3e262bf5c1e9e4c1b20b045df9bfe87073acdd555322bda8b303e9bdb2088a6
@@ -1,3 +1,16 @@
1
+ # v0.7.1 2016-04-06
2
+
3
+ ## Added
4
+
5
+ - `JSON::*` types with JSON-specific coercions (coop)
6
+
7
+ ## Fixed
8
+
9
+ - Schema is properly inherited in Struct (backus)
10
+ - `constructor_type` is properly inherited in Struct (fbernier)
11
+
12
+ [Compare v0.7.0...v0.7.1](https://github.com/dryrb/dry-types/compare/v0.7.0...v0.7.1)
13
+
1
14
  # v0.7.0 2016-03-30
2
15
 
3
16
  Major focus of this release is to make complex type composition possible and improving constraint errors to be more meaningful.
@@ -0,0 +1,35 @@
1
+ module Dry
2
+ module Types
3
+ module Coercions
4
+ EMPTY_STRING = ''.freeze
5
+
6
+ def to_nil(input)
7
+ input unless empty_str?(input)
8
+ end
9
+
10
+ def to_date(input)
11
+ Date.parse(input)
12
+ rescue ArgumentError
13
+ input
14
+ end
15
+
16
+ def to_date_time(input)
17
+ DateTime.parse(input)
18
+ rescue ArgumentError
19
+ input
20
+ end
21
+
22
+ def to_time(input)
23
+ Time.parse(input)
24
+ rescue ArgumentError
25
+ input
26
+ end
27
+
28
+ private
29
+
30
+ def empty_str?(value)
31
+ EMPTY_STRING.eql?(value)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,7 +1,5 @@
1
- require 'date'
2
1
  require 'bigdecimal'
3
2
  require 'bigdecimal/util'
4
- require 'time'
5
3
 
6
4
  module Dry
7
5
  module Types
@@ -11,31 +9,7 @@ module Dry
11
9
  FALSE_VALUES = %w[0 off f false n no].freeze
12
10
  BOOLEAN_MAP = ::Hash[TRUE_VALUES.product([true]) + FALSE_VALUES.product([false])].freeze
13
11
 
14
- def self.to_nil(input)
15
- if input.is_a?(String) && input == ''
16
- nil
17
- else
18
- input
19
- end
20
- end
21
-
22
- def self.to_date(input)
23
- Date.parse(input)
24
- rescue ArgumentError
25
- input
26
- end
27
-
28
- def self.to_date_time(input)
29
- DateTime.parse(input)
30
- rescue ArgumentError
31
- input
32
- end
33
-
34
- def self.to_time(input)
35
- Time.parse(input)
36
- rescue ArgumentError
37
- input
38
- end
12
+ extend Coercions
39
13
 
40
14
  def self.to_true(input)
41
15
  BOOLEAN_MAP.fetch(input, input)
@@ -46,44 +20,36 @@ module Dry
46
20
  end
47
21
 
48
22
  def self.to_int(input)
49
- if input == ''
50
- nil
51
- else
52
- result = input.to_i
23
+ return if empty_str?(input)
24
+
25
+ result = input.to_i
53
26
 
54
- if result === 0 && input != '0'
55
- input
56
- else
57
- result
58
- end
27
+ if result === 0 && !input.eql?('0')
28
+ input
29
+ else
30
+ result
59
31
  end
60
32
  end
61
33
 
62
34
  def self.to_float(input)
63
- if input == ''
64
- nil
65
- else
66
- result = input.to_f
35
+ return if empty_str?(input)
67
36
 
68
- if result == 0.0 && (input != '0' || input != '0.0')
69
- input
70
- else
71
- result
72
- end
37
+ result = input.to_f
38
+
39
+ if result.eql?(0.0) && (!input.eql?('0') && !input.eql?('0.0'))
40
+ input
41
+ else
42
+ result
73
43
  end
74
44
  end
75
45
 
76
46
  def self.to_decimal(input)
77
- if input == ''
78
- nil
79
- else
80
- result = to_float(input)
47
+ result = to_float(input)
81
48
 
82
- if result.is_a?(Float)
83
- result.to_d
84
- else
85
- result
86
- end
49
+ if result.instance_of?(Float)
50
+ result.to_d
51
+ else
52
+ result
87
53
  end
88
54
  end
89
55
  end
@@ -0,0 +1,18 @@
1
+ require 'date'
2
+ require 'bigdecimal'
3
+ require 'bigdecimal/util'
4
+ require 'time'
5
+
6
+ module Dry
7
+ module Types
8
+ module Coercions
9
+ module JSON
10
+ extend Coercions
11
+
12
+ def self.to_decimal(input)
13
+ input.to_d unless empty_str?(input)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -43,6 +43,10 @@ module Dry
43
43
  registry['form.array'].member(call(node))
44
44
  end
45
45
 
46
+ def visit_json_array(node)
47
+ registry['json.array'].member(call(node))
48
+ end
49
+
46
50
  def visit_hash(node)
47
51
  constructor, schema = node
48
52
  merge_with('hash', constructor, schema)
@@ -57,6 +61,15 @@ module Dry
57
61
  end
58
62
  end
59
63
 
64
+ def visit_json_hash(node)
65
+ if node
66
+ constructor, schema = node
67
+ merge_with('json.hash', constructor, schema)
68
+ else
69
+ registry['json.hash']
70
+ end
71
+ end
72
+
60
73
  def visit_key(node)
61
74
  name, types = node
62
75
  { name => visit(types) }
@@ -65,4 +65,6 @@ module Dry
65
65
  end
66
66
  end
67
67
 
68
+ require 'dry/types/coercions'
68
69
  require 'dry/types/form'
70
+ require 'dry/types/json'
@@ -39,12 +39,10 @@ module Dry
39
39
  alias_method :[], :call
40
40
 
41
41
  def try(input, &block)
42
- output = call(input)
43
-
44
- if valid?(output)
45
- success(output)
42
+ if valid?(input)
43
+ success(input)
46
44
  else
47
- failure = failure(output, "#{output.inspect} must be an instance of #{primitive}")
45
+ failure = failure(input, "#{input.inspect} must be an instance of #{primitive}")
48
46
  block ? yield(failure) : failure
49
47
  end
50
48
  end
@@ -18,6 +18,12 @@ module Dry
18
18
 
19
19
  StructError = Class.new(TypeError)
20
20
 
21
+ class RepeatedAttributeError < ArgumentError
22
+ def initialize(key)
23
+ super("Attribute :#{key} has already been defined")
24
+ end
25
+ end
26
+
21
27
  ConstraintError = Class.new(TypeError) do
22
28
  attr_reader :result
23
29
 
@@ -0,0 +1,33 @@
1
+ require 'dry/types/coercions/json'
2
+
3
+ module Dry
4
+ module Types
5
+ register('json.nil') do
6
+ self['nil'].constructor(Coercions::JSON.method(:to_nil))
7
+ end
8
+
9
+ register('json.date') do
10
+ self['date'].constructor(Coercions::JSON.method(:to_date))
11
+ end
12
+
13
+ register('json.date_time') do
14
+ self['date_time'].constructor(Coercions::JSON.method(:to_date_time))
15
+ end
16
+
17
+ register('json.time') do
18
+ self['time'].constructor(Coercions::JSON.method(:to_time))
19
+ end
20
+
21
+ register('json.decimal') do
22
+ self['decimal'].constructor(Coercions::JSON.method(:to_decimal))
23
+ end
24
+
25
+ register('json.array') do
26
+ self['array'].safe
27
+ end
28
+
29
+ register('json.hash') do
30
+ self['hash'].safe
31
+ end
32
+ end
33
+ end
@@ -14,7 +14,7 @@ module Dry
14
14
 
15
15
  def default(value)
16
16
  if value.nil?
17
- raise ArgumentError, "nil cannot be used as a default of an optional type"
17
+ raise ArgumentError, "nil cannot be used as a default of a maybe type"
18
18
  else
19
19
  super
20
20
  end
@@ -8,13 +8,16 @@ module Dry
8
8
  def self.inherited(klass)
9
9
  super
10
10
 
11
- klass.instance_variable_set('@equalizer', Equalizer.new)
11
+ klass.instance_variable_set('@equalizer', Equalizer.new(*schema.keys))
12
+ klass.instance_variable_set('@constructor_type', constructor_type)
12
13
  klass.send(:include, klass.equalizer)
13
14
 
14
15
  unless klass == Value
15
16
  klass.instance_variable_set('@constructor', Types['coercible.hash'])
16
17
  Types.register_class(klass)
17
18
  end
19
+
20
+ klass.attributes({}) unless equal?(Struct)
18
21
  end
19
22
 
20
23
  def self.equalizer
@@ -26,19 +29,32 @@ module Dry
26
29
  end
27
30
 
28
31
  def self.attributes(new_schema)
32
+ check_schema_duplication(new_schema)
33
+
29
34
  prev_schema = schema
30
35
 
31
36
  @schema = prev_schema.merge(new_schema)
32
37
  @constructor = Types['coercible.hash'].public_send(constructor_type, schema)
33
38
 
34
- attr_reader(*(new_schema.keys - prev_schema.keys))
35
- equalizer.instance_variable_get('@keys').concat(schema.keys).uniq!
39
+ attr_reader(*new_schema.keys)
40
+ equalizer.instance_variable_get('@keys').concat(new_schema.keys)
36
41
 
37
42
  self
38
43
  end
39
44
 
40
- def self.constructor_type(type = :strict)
41
- @constructor_type ||= type
45
+ def self.check_schema_duplication(new_schema)
46
+ shared_keys = new_schema.keys & schema.keys
47
+
48
+ fail RepeatedAttributeError, shared_keys.first if shared_keys.any?
49
+ end
50
+ private_class_method :check_schema_duplication
51
+
52
+ def self.constructor_type(type = nil)
53
+ if type
54
+ @constructor_type = type
55
+ else
56
+ @constructor_type || :strict
57
+ end
42
58
  end
43
59
 
44
60
  def self.schema
@@ -47,13 +63,13 @@ module Dry
47
63
  end
48
64
 
49
65
  def self.new(attributes = {})
50
- if attributes.is_a?(self)
66
+ if attributes.instance_of?(self)
51
67
  attributes
52
68
  else
53
69
  super(constructor[attributes])
54
70
  end
55
- rescue SchemaError, SchemaKeyError => e
56
- raise StructError, "[#{self}.new] #{e.message}"
71
+ rescue SchemaError, SchemaKeyError => error
72
+ raise StructError, "[#{self}.new] #{error}"
57
73
  end
58
74
 
59
75
  def initialize(attributes)
@@ -3,7 +3,7 @@ require 'dry/types/struct'
3
3
  module Dry
4
4
  module Types
5
5
  class Value < Struct
6
- def self.new(*, &_block)
6
+ def self.new(*)
7
7
  super.freeze
8
8
  end
9
9
  end
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module Types
3
- VERSION = '0.7.0'.freeze
3
+ VERSION = '0.7.1'.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.7.0
4
+ version: 0.7.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: 2016-03-30 00:00:00.000000000 Z
11
+ date: 2016-04-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -188,7 +188,9 @@ files:
188
188
  - lib/dry/types/array.rb
189
189
  - lib/dry/types/array/member.rb
190
190
  - lib/dry/types/builder.rb
191
+ - lib/dry/types/coercions.rb
191
192
  - lib/dry/types/coercions/form.rb
193
+ - lib/dry/types/coercions/json.rb
192
194
  - lib/dry/types/compiler.rb
193
195
  - lib/dry/types/constrained.rb
194
196
  - lib/dry/types/constrained/coercible.rb
@@ -204,6 +206,7 @@ files:
204
206
  - lib/dry/types/form.rb
205
207
  - lib/dry/types/hash.rb
206
208
  - lib/dry/types/hash/schema.rb
209
+ - lib/dry/types/json.rb
207
210
  - lib/dry/types/maybe.rb
208
211
  - lib/dry/types/options.rb
209
212
  - lib/dry/types/result.rb