broi-input 0.1.1 → 0.1.2
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 +4 -4
- data/.gitignore +1 -0
- data/Gemfile.lock +3 -13
- data/README.md +48 -21
- data/input.gemspec +6 -3
- data/lib/broi/input/failure.rb +16 -0
- data/lib/broi/input/invalid_error.rb +5 -0
- data/lib/broi/input/invalid_value.rb +17 -0
- data/lib/broi/input/soft.rb +54 -0
- data/lib/broi/input/success.rb +13 -0
- data/lib/broi/input/utils.rb +32 -0
- data/lib/broi/input/value.rb +17 -0
- data/lib/broi/input.rb +38 -7
- metadata +38 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ec70915468a81f1e76fd79fa968c819a708c8d65040b2feee9da121f6f21458
|
4
|
+
data.tar.gz: 1ba022fe06b37bac5d8d59aa263420cd5069cc481a215c43dbb58c5b2e665093
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35b14bb7ffa1339d748fb21cc66bb545ff231dde3f78798282199adfc72f192af22cba0e86e9780750948ebc0129f83805bd54a52918596097bd041fb943d603
|
7
|
+
data.tar.gz: 781d9b48dc23b59c32cf24ed7c174e3c04c2dca8de0edaafeada7321e244776cc5a32ddf668888a5a6540518f796362f02adc4eec3d8bd5977c6aaa3a0d96181
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
broi-input (0.1.
|
4
|
+
broi-input (0.1.1)
|
5
|
+
dry-monads (~> 1.0)
|
5
6
|
dry-struct (~> 0.5)
|
6
|
-
dry-transaction (~> 0.13)
|
7
7
|
dry-validation (~> 0.12)
|
8
8
|
|
9
9
|
GEM
|
@@ -21,16 +21,11 @@ GEM
|
|
21
21
|
dry-core (0.4.7)
|
22
22
|
concurrent-ruby (~> 1.0)
|
23
23
|
dry-equalizer (0.2.1)
|
24
|
-
dry-events (0.1.0)
|
25
|
-
concurrent-ruby (~> 1.0)
|
26
|
-
dry-core (~> 0.4)
|
27
|
-
dry-equalizer (~> 0.2)
|
28
24
|
dry-inflector (0.1.2)
|
29
25
|
dry-logic (0.4.2)
|
30
26
|
dry-container (~> 0.2, >= 0.2.6)
|
31
27
|
dry-core (~> 0.2)
|
32
28
|
dry-equalizer (~> 0.2)
|
33
|
-
dry-matcher (0.7.0)
|
34
29
|
dry-monads (1.0.0)
|
35
30
|
concurrent-ruby (~> 1.0)
|
36
31
|
dry-core (~> 0.4, >= 0.4.4)
|
@@ -40,11 +35,6 @@ GEM
|
|
40
35
|
dry-equalizer (~> 0.2)
|
41
36
|
dry-types (~> 0.13)
|
42
37
|
ice_nine (~> 0.11)
|
43
|
-
dry-transaction (0.13.0)
|
44
|
-
dry-container (>= 0.2.8)
|
45
|
-
dry-events (>= 0.1.0)
|
46
|
-
dry-matcher (>= 0.7.0)
|
47
|
-
dry-monads (>= 0.4.0)
|
48
38
|
dry-types (0.13.2)
|
49
39
|
concurrent-ruby (~> 1.0)
|
50
40
|
dry-container (~> 0.3)
|
@@ -52,7 +42,7 @@ GEM
|
|
52
42
|
dry-equalizer (~> 0.2)
|
53
43
|
dry-inflector (~> 0.1, >= 0.1.2)
|
54
44
|
dry-logic (~> 0.4, >= 0.4.2)
|
55
|
-
dry-validation (0.12.
|
45
|
+
dry-validation (0.12.1)
|
56
46
|
concurrent-ruby (~> 1.0)
|
57
47
|
dry-configurable (~> 0.1, >= 0.1.3)
|
58
48
|
dry-core (~> 0.2, >= 0.2.1)
|
data/README.md
CHANGED
@@ -1,43 +1,70 @@
|
|
1
|
-
# Input
|
1
|
+
# Broi::Input
|
2
2
|
|
3
|
-
|
3
|
+
This library provides flexible API to deal with incoming ruby messages. It converts incoming hash onto predefined, structured object by passing it through predefined input validations.
|
4
4
|
|
5
|
-
|
5
|
+
Example:
|
6
6
|
|
7
|
-
|
7
|
+
```ruby
|
8
|
+
class PurchaseInput < Broi::Input
|
9
|
+
attribute :product
|
10
|
+
attribute :count, default: 1
|
11
|
+
|
12
|
+
validate do
|
13
|
+
required(:product).filled(:str?)
|
14
|
+
optional(:count).maybe(:int?)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
```
|
18
|
+
|
19
|
+
###Processing incoming hash
|
8
20
|
|
9
|
-
|
21
|
+
You instantiate the input by executing `call` method which, depending on the validation resutls, returns an instance of Broi::Input::Success/Failure.
|
10
22
|
|
11
23
|
```ruby
|
12
|
-
|
24
|
+
PurchaseInput.(product: 'Apple')
|
25
|
+
#=> #Success(<#PurchaseInput|soft product=#Value('Apple')>)
|
26
|
+
|
27
|
+
|
28
|
+
PurchaseInput.(product: 123)
|
29
|
+
#=> Failure({:product => ["must be string"])
|
13
30
|
```
|
14
31
|
|
15
|
-
|
32
|
+
### Soft input struct
|
16
33
|
|
17
|
-
|
34
|
+
Regardless of the validation result, you can always obtain soft input result by calling `input` on the result:
|
18
35
|
|
19
|
-
|
36
|
+
```ruby
|
37
|
+
PurchaseInput.(product: 'Apple').input
|
38
|
+
#=> <#PurchaseInput|soft product=#Value('Apple')>
|
20
39
|
|
21
|
-
|
40
|
+
PurchaseInput.(product: 123).input
|
41
|
+
#=> <#PurchaseInput|soft product=#InvalidValue(123)>
|
42
|
+
```
|
22
43
|
|
23
|
-
|
44
|
+
All the values accessible through the soft input are either `Broi::Input::Value`/`InvalidValue` and they respond to `valid?` and `invalid?` methods.
|
24
45
|
|
25
|
-
|
46
|
+
### Strict input
|
26
47
|
|
27
|
-
|
48
|
+
You can turn soft input into a strict input by calling `valid!`. Strict input is just typical Dry::Struct:
|
28
49
|
|
29
|
-
|
50
|
+
```ruby
|
51
|
+
PurchaseInput.(product: 'Apple').input.valid!
|
52
|
+
#=> <#PurchaseInput product='Apple'>
|
30
53
|
|
31
|
-
|
54
|
+
PurchaseInput.(product: 123).input.valid!
|
55
|
+
#! raises: Broi::Input::Invalid
|
56
|
+
```
|
32
57
|
|
33
|
-
|
58
|
+
### Validation errors
|
34
59
|
|
35
|
-
|
60
|
+
Errors can be collected directly from the processing result.
|
36
61
|
|
37
|
-
|
62
|
+
```ruby
|
63
|
+
PurchaseInput.(product: 'Apple').errors
|
64
|
+
#=> {}
|
38
65
|
|
39
|
-
|
66
|
+
PurchaseInput.(product: 123).errors
|
67
|
+
#=> {:product => ["must be string"])
|
68
|
+
```
|
40
69
|
|
41
|
-
## Code of Conduct
|
42
70
|
|
43
|
-
Everyone interacting in the Input project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/input/blob/master/CODE_OF_CONDUCT.md).
|
data/input.gemspec
CHANGED
@@ -4,17 +4,18 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = 'broi-input'
|
7
|
-
spec.version = '0.1.
|
7
|
+
spec.version = '0.1.2'
|
8
8
|
spec.authors = ['broisatse']
|
9
9
|
spec.email = ['sklajn@gmail.com']
|
10
10
|
|
11
11
|
spec.summary = 'Simple ruby object to handle user inputs'
|
12
|
-
spec.description =
|
12
|
+
spec.description = 'Destructures incoming user input onto dry struct'
|
13
13
|
spec.homepage = 'https://github.com/BroiSatse/broi-input'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
16
16
|
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
17
|
-
`git ls-files -z`.split("\x0")
|
17
|
+
`git ls-files -z`.split("\x0")
|
18
|
+
.reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
19
|
end
|
19
20
|
spec.bindir = 'exe'
|
20
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
@@ -22,10 +23,12 @@ Gem::Specification.new do |spec|
|
|
22
23
|
|
23
24
|
spec.add_dependency 'dry-validation', '~> 0.12'
|
24
25
|
spec.add_dependency 'dry-struct', '~> 0.5'
|
26
|
+
spec.add_dependency 'dry-monads', '~> 1.0'
|
25
27
|
|
26
28
|
|
27
29
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
28
30
|
spec.add_development_dependency 'rake', '~> 10.0'
|
29
31
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
30
32
|
spec.add_development_dependency 'pry', '~> 0.11'
|
33
|
+
spec.add_development_dependency 'byebug'
|
31
34
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'broi/input/invalid_error'
|
2
|
+
|
3
|
+
module Broi
|
4
|
+
class Input < Dry::Struct::Value
|
5
|
+
module SoftInput
|
6
|
+
def self.included(mod)
|
7
|
+
mod.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
def valid!
|
11
|
+
self.class.superclass.new Utils.deep_transform_values(attributes, &:value!)
|
12
|
+
rescue Dry::Monads::UnwrapError
|
13
|
+
raise Invalid, 'Called `valid!` on invalid soft input!'
|
14
|
+
end
|
15
|
+
|
16
|
+
def strict?
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
module ClassMethods
|
21
|
+
def inspect
|
22
|
+
"#{superclass.name}|soft"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module Soft
|
28
|
+
class << self
|
29
|
+
def [](klass)
|
30
|
+
register[klass]
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def register
|
36
|
+
@register ||= Hash.new do |hash, klass|
|
37
|
+
hash[klass] = Class.new(klass).include(SoftInput)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.call(input_class, attrs, errors)
|
43
|
+
attrs = input_class.input[attrs]
|
44
|
+
input = Utils.deep_merge(attrs, errors) do |target, _error|
|
45
|
+
InvalidValue.new(target)
|
46
|
+
end
|
47
|
+
input = Utils.deep_transform_values(input) do |value|
|
48
|
+
value.is_a?(InvalidValue) ? value : Value.new(value)
|
49
|
+
end
|
50
|
+
self[input_class].new(input)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Broi
|
2
|
+
class Input < Dry::Struct::Value
|
3
|
+
module Utils
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def deep_transform_values(object, &block)
|
7
|
+
if object.is_a?(Hash)
|
8
|
+
object.transform_values { |value| deep_transform_values(value, &block) }
|
9
|
+
else
|
10
|
+
block.(object)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def deep_merge(target, source, &block)
|
15
|
+
if target.is_a?(Hash) && source.is_a?(Hash)
|
16
|
+
keys = (target.keys + source.keys).uniq
|
17
|
+
keys.map do |key|
|
18
|
+
value = if [target, source].all? { |h| h.key? key }
|
19
|
+
deep_merge(target[key], source[key], &block)
|
20
|
+
else
|
21
|
+
[target[key], source[key]].compact.first
|
22
|
+
end
|
23
|
+
[key, value]
|
24
|
+
end.to_h
|
25
|
+
else
|
26
|
+
block ||= ->(_target, source) { source }
|
27
|
+
block.(target, source)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/broi/input.rb
CHANGED
@@ -1,10 +1,18 @@
|
|
1
1
|
require 'dry-struct'
|
2
|
-
require 'dry/transaction'
|
3
2
|
require 'dry/validation'
|
3
|
+
require 'dry/monads/result'
|
4
|
+
|
5
|
+
require 'broi/input/success'
|
6
|
+
require 'broi/input/failure'
|
7
|
+
require 'broi/input/utils'
|
8
|
+
require 'broi/input/value'
|
9
|
+
require 'broi/input/invalid_value'
|
10
|
+
require 'broi/input/soft'
|
11
|
+
|
12
|
+
require 'byebug'
|
4
13
|
|
5
14
|
module Broi
|
6
15
|
class Input < Dry::Struct::Value
|
7
|
-
# include Dry::Transaction
|
8
16
|
|
9
17
|
module Types
|
10
18
|
include Dry::Types.module
|
@@ -12,10 +20,14 @@ module Broi
|
|
12
20
|
|
13
21
|
transform_keys(&:to_sym)
|
14
22
|
|
23
|
+
def strict?
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
15
27
|
class << self
|
16
|
-
|
17
|
-
|
18
|
-
type =
|
28
|
+
|
29
|
+
def attribute(name, **opts, &block)
|
30
|
+
type = Types::Any.optional.meta(omittable: true)
|
19
31
|
type = type.default(opts[:default]) if opts.has_key?(:default)
|
20
32
|
super(name, type, &block)
|
21
33
|
end
|
@@ -30,10 +42,29 @@ module Broi
|
|
30
42
|
|
31
43
|
def call(params = {})
|
32
44
|
result = validation.(params)
|
45
|
+
input = Soft.(self, result.output, result.errors)
|
46
|
+
# output = input[result.output]
|
47
|
+
# input = Utils.deep_merge(output, result.errors) do |target, _error|
|
48
|
+
# InvalidValue.new(target)
|
49
|
+
# end
|
50
|
+
# input = Utils.deep_transform_values(input) do |value|
|
51
|
+
# value.is_a?(InvalidValue) ? value : Value.new(value)
|
52
|
+
# end
|
53
|
+
# input = new(input)
|
33
54
|
if result.success?
|
34
|
-
|
55
|
+
Success.new(input)
|
56
|
+
else
|
57
|
+
Failure.new(input, result.errors)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def merge_error(input_value, error)
|
64
|
+
if input_value.is_a? Hash
|
65
|
+
|
35
66
|
else
|
36
|
-
|
67
|
+
error ? InvalidValue.new : input_value
|
37
68
|
end
|
38
69
|
end
|
39
70
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: broi-input
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- broisatse
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-07-
|
11
|
+
date: 2018-07-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-validation
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dry-monads
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: bundler
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,7 +108,21 @@ dependencies:
|
|
94
108
|
- - "~>"
|
95
109
|
- !ruby/object:Gem::Version
|
96
110
|
version: '0.11'
|
97
|
-
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: byebug
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: Destructures incoming user input onto dry struct
|
98
126
|
email:
|
99
127
|
- sklajn@gmail.com
|
100
128
|
executables: []
|
@@ -114,6 +142,13 @@ files:
|
|
114
142
|
- bin/setup
|
115
143
|
- input.gemspec
|
116
144
|
- lib/broi/input.rb
|
145
|
+
- lib/broi/input/failure.rb
|
146
|
+
- lib/broi/input/invalid_error.rb
|
147
|
+
- lib/broi/input/invalid_value.rb
|
148
|
+
- lib/broi/input/soft.rb
|
149
|
+
- lib/broi/input/success.rb
|
150
|
+
- lib/broi/input/utils.rb
|
151
|
+
- lib/broi/input/value.rb
|
117
152
|
homepage: https://github.com/BroiSatse/broi-input
|
118
153
|
licenses:
|
119
154
|
- MIT
|