dry-data 0.3.2 → 0.4.0

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
  SHA1:
3
- metadata.gz: 11440d87987301e5ab00e881aca9769d10ca46b6
4
- data.tar.gz: 10aac35f319d13a0f42875976005c32f8feb08f4
3
+ metadata.gz: f8204add8315ec4efed8923ffb753d5e670e56b3
4
+ data.tar.gz: 1a9bd0c932aa43bbdeba519cc00b5bae7ccfdfbd
5
5
  SHA512:
6
- metadata.gz: 7b992fddcabd0940aec06466dff1fc804161183fb579619ea53fb4b38f4ca7229812677001b718f6af8d91e2c99603ae808e5c253e2e9bde93f2dec797b77b99
7
- data.tar.gz: fa2e28003cf3ca3bffbb6f2953a5d8860c312e9fbf5135249432f5f7ecd358f94e8a64938f2e7add69618b66c4c947c84c215338e111d9cc61e73fa94a8dd806
6
+ metadata.gz: 5d0dea2a50e1b8a212c43eec8cd10ca463c53fa1cb8982db307f29fdf397c006fd7febe9c0fbabd2f146f94112f0a1bfcfdde627a94e80ce82a53548b4674876
7
+ data.tar.gz: a364d893f9d2bf9a4aba61970020ded68f136ca3bc8877a06783aa37e7ffcc0e4436acd629ad165cb1448a29460b3dd0b0290df747d1928a1228e7afbfad7646
@@ -1,3 +1,16 @@
1
+ # v0.4.0 2015-12-11
2
+
3
+ ## Added
4
+
5
+ * Support for sum-types with constraint type (solnic)
6
+ * `Dry::Data::Type#optional` for defining optional types (solnic)
7
+
8
+ ## Changed
9
+
10
+ * `Dry::Data['optional']` was **removed** in favor of `Dry::Data::Type#optional` (solnic)
11
+
12
+ [Compare v0.3.2...v0.4.0](https://github.com/dryrb/dry-data/compare/v0.3.2...v0.4.0)
13
+
1
14
  # v0.3.2 2015-12-10
2
15
 
3
16
  ## Added
data/README.md CHANGED
@@ -146,7 +146,7 @@ maybe_int['12.3'] # Some(12.3)
146
146
  You can define your own optional types too:
147
147
 
148
148
  ``` ruby
149
- maybe_string = Dry::Data["optional"] | Dry::Data["string"]
149
+ maybe_string = Dry::Data["string"].optional
150
150
 
151
151
  maybe_string[nil]
152
152
  # => None
@@ -164,6 +164,24 @@ maybe_string['something'].fmap(&:upcase).value
164
164
  # => "SOMETHING"
165
165
  ```
166
166
 
167
+ ### Sum-types
168
+
169
+ You can specify sum types using `|` operator, it is an explicit way of defining
170
+ what are the valid types of a value.
171
+
172
+ In example `dry-data` defines `bool` type which is a sum-type consisting of `true`
173
+ and `false` types which is expressed as `Dry::Data['true'] | Dry::Data['false']`
174
+ (and it has its strict version, too).
175
+
176
+ Another common case is defining that something can be either `nil` or something else:
177
+
178
+ ``` ruby
179
+ nil_or_string = Dry::Data['strict.nil'] | Dry::Data['strict.string']
180
+
181
+ nil_or_string[nil] # => nil
182
+ nil_or_string["hello"] # => "hello"
183
+ ```
184
+
167
185
  ### Constrained Types
168
186
 
169
187
  You can create constrained types that will use validation rules to check if the
@@ -173,7 +191,7 @@ a lower level guarantee that you're not instantiating objects that are broken.
173
191
  All types support constraints API, but not all constraints are suitable for a
174
192
  particular primitive, it's up to you to set up constraints that make sense.
175
193
 
176
- Under the hood it uses `dry-validation`[https://github.com/dryrb/dry-validation]
194
+ Under the hood it uses [`dry-validation`](https://github.com/dryrb/dry-validation)
177
195
  and all of its predicates are supported.
178
196
 
179
197
  IMPORTANT: `dry-data` does not have a runtime dependency on `dry-validation` so
@@ -3,7 +3,7 @@ require 'date'
3
3
  require 'set'
4
4
 
5
5
  require 'inflecto'
6
- require 'thread_safe/cache'
6
+ require 'thread_safe'
7
7
 
8
8
  require 'dry-container'
9
9
  require 'dry-equalizer'
@@ -59,17 +59,23 @@ module Dry
59
59
 
60
60
  def self.[](name)
61
61
  type_map.fetch_or_store(name) do
62
- result = name.match(TYPE_SPEC_REGEX)
63
-
64
62
  type =
65
- if result
66
- type_id, member_id = result[1..2]
67
- container[type_id].member(self[member_id])
68
- else
69
- container[name]
63
+ case name
64
+ when String
65
+ result = name.match(TYPE_SPEC_REGEX)
66
+
67
+ type =
68
+ if result
69
+ type_id, member_id = result[1..2]
70
+ container[type_id].member(self[member_id])
71
+ else
72
+ container[name]
73
+ end
74
+ when Class
75
+ self[identifier(name)]
70
76
  end
71
77
 
72
- type_map[name] = type
78
+ type
73
79
  end
74
80
  end
75
81
 
@@ -0,0 +1,20 @@
1
+ module Dry
2
+ module Data
3
+ class Optional
4
+ attr_reader :type
5
+
6
+ def initialize(type)
7
+ @type = type
8
+ end
9
+
10
+ def valid?(input)
11
+ type.valid?(input)
12
+ end
13
+
14
+ def call(input)
15
+ Maybe(type[input])
16
+ end
17
+ alias_method :[], :call
18
+ end
19
+ end
20
+ end
@@ -2,28 +2,11 @@ require 'kleisli'
2
2
 
3
3
  module Dry
4
4
  module Data
5
- def self.SumType(left, right)
6
- klass =
7
- if left.is_a?(Type::Optional)
8
- SumType::Optional
9
- else
10
- SumType
11
- end
12
- klass.new(left, right)
13
- end
14
-
15
5
  class SumType
16
6
  attr_reader :left
17
7
 
18
8
  attr_reader :right
19
9
 
20
- class Optional < SumType
21
- def call(input)
22
- Maybe(super(input))
23
- end
24
- alias_method :[], :call
25
- end
26
-
27
10
  def initialize(left, right)
28
11
  @left, @right = left, right
29
12
  end
@@ -1,9 +1,9 @@
1
- require 'dry/data/type/optional'
2
1
  require 'dry/data/type/hash'
3
2
  require 'dry/data/type/array'
4
3
  require 'dry/data/type/enum'
5
4
 
6
5
  require 'dry/data/sum_type'
6
+ require 'dry/data/optional'
7
7
 
8
8
  module Dry
9
9
  module Data
@@ -62,6 +62,10 @@ module Dry
62
62
  Enum.new(values, constrained(inclusion: values))
63
63
  end
64
64
 
65
+ def optional
66
+ Optional.new(Data['nil'] | self)
67
+ end
68
+
65
69
  def name
66
70
  primitive.name
67
71
  end
@@ -76,7 +80,7 @@ module Dry
76
80
  end
77
81
 
78
82
  def |(other)
79
- Data.SumType(self, other)
83
+ SumType.new(self, other)
80
84
  end
81
85
  end
82
86
  end
@@ -2,15 +2,23 @@ module Dry
2
2
  module Data
3
3
  class Type
4
4
  class Array < Type
5
- def self.constructor(array_constructor, value_constructor, input)
6
- array_constructor[input].map(&value_constructor)
5
+ def self.constructor(array_constructor, member_constructor, input)
6
+ array_constructor[input].map(&member_constructor)
7
7
  end
8
8
 
9
9
  def member(type)
10
- self.class.new(
11
- self.class.method(:constructor).to_proc.curry.(constructor, type.constructor),
12
- primitive
13
- )
10
+ member_constructor =
11
+ case type
12
+ when Type then type.constructor
13
+ when Class then Data[type].constructor
14
+ else
15
+ raise ArgumentError, "+#{type}+ is an unsupported array member"
16
+ end
17
+
18
+ array_constructor = self.class
19
+ .method(:constructor).to_proc.curry.(constructor, member_constructor)
20
+
21
+ self.class.new(array_constructor, primitive)
14
22
  end
15
23
  end
16
24
  end
@@ -14,13 +14,17 @@ module Dry
14
14
  def call(input)
15
15
  result = super(input)
16
16
 
17
- if rule.(result).success?
17
+ if valid?(result)
18
18
  result
19
19
  else
20
20
  raise ConstraintError, "#{input.inspect} violates constraints"
21
21
  end
22
22
  end
23
23
  alias_method :[], :call
24
+
25
+ def valid?(input)
26
+ super && rule.(input).success?
27
+ end
24
28
  end
25
29
 
26
30
  def constrained(options)
@@ -22,12 +22,6 @@ module Dry
22
22
 
23
23
  ALL_PRIMITIVES = COERCIBLE.merge(NON_COERCIBLE).freeze
24
24
 
25
- # Register optional type
26
- register(
27
- 'optional',
28
- Type::Optional.new(Type.method(:passthrough_constructor), NilClass)
29
- )
30
-
31
25
  # Register built-in primitive types with kernel coercion methods
32
26
  COERCIBLE.each do |name, primitive|
33
27
  register(
@@ -55,12 +49,12 @@ module Dry
55
49
  # Register non-coercible maybe types
56
50
  ALL_PRIMITIVES.each do |name, primitive|
57
51
  next if name == :nil
58
- register("maybe.strict.#{name}", self["optional"] | self["strict.#{name}"])
52
+ register("maybe.strict.#{name}", self["strict.#{name}"].optional)
59
53
  end
60
54
 
61
55
  # Register coercible maybe types
62
56
  COERCIBLE.each do |name, primitive|
63
- register("maybe.coercible.#{name}", self["optional"] | self["coercible.#{name}"])
57
+ register("maybe.coercible.#{name}", self["coercible.#{name}"].optional)
64
58
  end
65
59
 
66
60
  # Register :bool since it's common and not a built-in Ruby type :(
@@ -1,5 +1,5 @@
1
1
  module Dry
2
2
  module Data
3
- VERSION = '0.3.2'.freeze
3
+ VERSION = '0.4.0'.freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-data
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-12-10 00:00:00.000000000 Z
11
+ date: 2015-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thread_safe
@@ -169,6 +169,7 @@ files:
169
169
  - lib/dry/data/constraints.rb
170
170
  - lib/dry/data/container.rb
171
171
  - lib/dry/data/dsl.rb
172
+ - lib/dry/data/optional.rb
172
173
  - lib/dry/data/struct.rb
173
174
  - lib/dry/data/sum_type.rb
174
175
  - lib/dry/data/type.rb
@@ -176,7 +177,6 @@ files:
176
177
  - lib/dry/data/type/constrained.rb
177
178
  - lib/dry/data/type/enum.rb
178
179
  - lib/dry/data/type/hash.rb
179
- - lib/dry/data/type/optional.rb
180
180
  - lib/dry/data/types.rb
181
181
  - lib/dry/data/types/form.rb
182
182
  - lib/dry/data/value.rb
@@ -1,19 +0,0 @@
1
- module Dry
2
- module Data
3
- class Type
4
- class Optional < Type
5
- def |(other)
6
- Data.SumType(self.class.new(constructor, other.primitive), other)
7
- end
8
-
9
- def call(input)
10
- Maybe(input)
11
- end
12
-
13
- def valid?(input)
14
- input.nil? || super
15
- end
16
- end
17
- end
18
- end
19
- end