dry-data 0.3.2 → 0.4.0

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: 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