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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e1d4bf01c2fc021ccffa526f54dbffdcb6c08670e70a85727293265a38d47d33
4
- data.tar.gz: 11ff7e9d518d43152c5a8a8c6bf02ffa6737dd666d77d94c5d667ca4b27a7d50
3
+ metadata.gz: 9ec70915468a81f1e76fd79fa968c819a708c8d65040b2feee9da121f6f21458
4
+ data.tar.gz: 1ba022fe06b37bac5d8d59aa263420cd5069cc481a215c43dbb58c5b2e665093
5
5
  SHA512:
6
- metadata.gz: 6de0dbefbe0fc3620826d4d84b5fdd70363c0794621701596a1962f475fdbd2cead1cba392e546cb9f7fe86bb34339ec77210ce7559f0eb615022d9352fdc72d
7
- data.tar.gz: 51b957814dfdda10fef8beb2291f4d8527a6d606c7158396bb90b99c3b45c43ddb1c37443b5f5cdc651f589bdbd563b1c42eb403a7c04ce52969fe878de8a5e4
6
+ metadata.gz: 35b14bb7ffa1339d748fb21cc66bb545ff231dde3f78798282199adfc72f192af22cba0e86e9780750948ebc0129f83805bd54a52918596097bd041fb943d603
7
+ data.tar.gz: 781d9b48dc23b59c32cf24ed7c174e3c04c2dca8de0edaafeada7321e244776cc5a32ddf668888a5a6540518f796362f02adc4eec3d8bd5977c6aaa3a0d96181
data/.gitignore CHANGED
@@ -6,6 +6,7 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /*.gem
9
10
 
10
11
  # rspec failure tracking
11
12
  .rspec_status
data/Gemfile.lock CHANGED
@@ -1,9 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- broi-input (0.1.0)
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.0)
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
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/input`. To experiment with that code, run `bin/console` for an interactive prompt.
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
- TODO: Delete this and the text above, and describe your gem
5
+ Example:
6
6
 
7
- ## Installation
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
- Add this line to your application's Gemfile:
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
- gem 'input'
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
- And then execute:
32
+ ### Soft input struct
16
33
 
17
- $ bundle
34
+ Regardless of the validation result, you can always obtain soft input result by calling `input` on the result:
18
35
 
19
- Or install it yourself as:
36
+ ```ruby
37
+ PurchaseInput.(product: 'Apple').input
38
+ #=> <#PurchaseInput|soft product=#Value('Apple')>
20
39
 
21
- $ gem install input
40
+ PurchaseInput.(product: 123).input
41
+ #=> <#PurchaseInput|soft product=#InvalidValue(123)>
42
+ ```
22
43
 
23
- ## Usage
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
- TODO: Write usage instructions here
46
+ ### Strict input
26
47
 
27
- ## Development
48
+ You can turn soft input into a strict input by calling `valid!`. Strict input is just typical Dry::Struct:
28
49
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
50
+ ```ruby
51
+ PurchaseInput.(product: 'Apple').input.valid!
52
+ #=> <#PurchaseInput product='Apple'>
30
53
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
54
+ PurchaseInput.(product: 123).input.valid!
55
+ #! raises: Broi::Input::Invalid
56
+ ```
32
57
 
33
- ## Contributing
58
+ ### Validation errors
34
59
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/input. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
60
+ Errors can be collected directly from the processing result.
36
61
 
37
- ## License
62
+ ```ruby
63
+ PurchaseInput.(product: 'Apple').errors
64
+ #=> {}
38
65
 
39
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
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.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 = %q{Destructure incoming user input onto dry struct}
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").reject { |f| f.match(%r{^(test|spec|features)/}) }
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,16 @@
1
+ module Broi
2
+ class Input < Dry::Struct::Value
3
+ class Failure < Dry::Monads::Failure
4
+ def initialize(input, errors)
5
+ @input = input
6
+ super(errors)
7
+ end
8
+
9
+ attr_reader :input
10
+
11
+ def errors
12
+ failure
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,5 @@
1
+ module Broi
2
+ class Input < Dry::Struct::Value
3
+ Invalid = Class.new(StandardError)
4
+ end
5
+ end
@@ -0,0 +1,17 @@
1
+ module Broi
2
+ class Input < Dry::Struct::Value
3
+ class InvalidValue < Dry::Monads::Failure
4
+ def inspect
5
+ "#InvalidValue(#{failure.inspect})"
6
+ end
7
+
8
+ def valid?
9
+ false
10
+ end
11
+
12
+ def invalid?
13
+ true
14
+ end
15
+ end
16
+ end
17
+ 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,13 @@
1
+ module Broi
2
+ class Input < Dry::Struct::Value
3
+ class Success < Dry::Monads::Success
4
+ def input
5
+ value!
6
+ end
7
+
8
+ def errors
9
+ {}
10
+ end
11
+ end
12
+ end
13
+ 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
@@ -0,0 +1,17 @@
1
+ module Broi
2
+ class Input < Dry::Struct::Value
3
+ class Value < Dry::Monads::Success
4
+ def inspect
5
+ "#Value(#{value!.inspect})"
6
+ end
7
+
8
+ def valid?
9
+ true
10
+ end
11
+
12
+ def invalid?
13
+ false
14
+ end
15
+ end
16
+ end
17
+ 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
- def attribute(name, type = nil, **opts, &block)
17
- type ||= Types::Any
18
- type = type.optional.meta(omittable: true)
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
- Dry::Monads::Success.new new(result.output)
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
- Dry::Monads::Failure.new result.errors
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.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-03 00:00:00.000000000 Z
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
- description: Destructure incoming user input onto dry struct
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