gate 0.4.1 → 0.5.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: 534592273859c465d6782fd466fe95b2c3a43950
4
- data.tar.gz: 0737964adad3f9807f9886faae5ebb28ca26a3e0
3
+ metadata.gz: 0c5b6793497535f1a64c445c3dc79f96d51ab755
4
+ data.tar.gz: 8cb64c61b215efbb182cf7a8bc830d1c0d2e5f66
5
5
  SHA512:
6
- metadata.gz: f974fec5ea5b17c290b3c018ef20b5e42469caafb206cc67912c1d400b2cbdc5902d6e6708e3cbf50a1f7356af1e55c97d6bf7e13d12bc5892bc3fb90c2fb5cd
7
- data.tar.gz: 12d81ec727fd3f7063622daf3b4043f6fe5ba9d5ec51c186751932dce367e7c5a341bebfb854538df2b00a75e024c3fcf0f0c2e72f3fed595949071996786a42
6
+ metadata.gz: 522271efbce236d5a3b71fd5c695dd59fe2a21b823482bba9979481636dafe3247b4dbd5462998500a7e0df74f0546669d7886df80c3e5765dedb26de8b139c0
7
+ data.tar.gz: e6d172ccbee95ec78413c106a6c7fac857f092e11d6eaeaa353e5dc3b9d0a303ee264f2b2bcf42e771c869528682f95f0883ad0cf0704b4c4dd22ca873191c59
@@ -0,0 +1,9 @@
1
+ version: 2
2
+ jobs:
3
+ build:
4
+ docker:
5
+ - image: circleci/ruby:2.5.0
6
+ steps:
7
+ - checkout
8
+ - run: gem install bundler
9
+ - run: bundle exec rake
@@ -1,8 +1,4 @@
1
- engines:
1
+ version: 2
2
+ plugins:
2
3
  rubocop:
3
4
  enabled: true
4
- bundler-audit:
5
- enabled: true
6
- ratings:
7
- paths:
8
- - "lib/**"
data/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
  [![Code Climate](https://codeclimate.com/github/monterail/gate/badges/gpa.svg)](https://codeclimate.com/github/monterail/gate)
7
7
  [![Test Coverage](https://codeclimate.com/github/monterail/gate/badges/coverage.svg)](https://codeclimate.com/github/monterail/gate/coverage)
8
8
 
9
- Gate is a small library which allows you to define allowed structure for user input with required and optional parameters and to coerce them into defined types.
9
+ Gate is a small wrapper on [dry-validation](http://dry-rb.org/gems/dry-validation/) that might be used as Command in CQRS pattern. It will raise `InvalidCommand` error for invalid input and provide simple struct with access to coerced input.
10
10
 
11
11
  ## Installation
12
12
 
@@ -29,38 +29,31 @@ Or install it yourself as:
29
29
  Define structure
30
30
 
31
31
  ```ruby
32
- gate = Gate.rules do
33
- required :id, :Integer
34
- required :message do
35
- required :title # :String by default
36
- optional :value, :Decimal
37
- optional :anything, :Any # Just pass through original value
32
+ class DoSomethingCommand
33
+ include Gate::Command
34
+
35
+ schema do
36
+ required(:id).filled
37
+ required(:message).schema do
38
+ required(:title).filled
39
+ optional(:value).maybe(:decimal?)
40
+ end
38
41
  end
39
42
  end
40
43
  ```
41
44
 
42
- Verify it
45
+ Use it
43
46
 
44
47
  ```ruby
45
- result = gate.verify(params)
46
- result.valid? # => true / false
47
- result.attributes # => hash with only allowed parameters
48
- result.errors # => hash { key => error }
49
- ```
50
-
51
- If you need to handle `nil` values you can use `allow_nil` flag:
52
-
53
- ```ruby
54
- gate = Gate.rules do
55
- required :id, :Integer, allow_nil: true
56
- required :message, allow_nil: true do
57
- required :title
58
- optional :value, :Decimal
59
- end
48
+ begin
49
+ cmd = DoSomethingCommand.with(params)
50
+ cmd.id
51
+ cmd.message
52
+ rescue DoSomethingCommand::InvalidCommand => e
53
+ e.errors # => hash { key => [errors] }
60
54
  end
61
55
  ```
62
56
 
63
-
64
57
  ## Development
65
58
 
66
59
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Jan Dudulski"]
10
10
  spec.email = ["jan@dudulski.pl"]
11
11
 
12
- spec.summary = "Handling user input with ease"
12
+ spec.summary = "CQRS Command"
13
13
  spec.description = "Validate and coerce user input against defined structure."
14
14
  spec.homepage = "https://github.com/monterail/gate"
15
15
  spec.license = "MIT"
@@ -17,12 +17,11 @@ Gem::Specification.new do |spec|
17
17
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^test/}) }
18
18
  spec.require_paths = ["lib"]
19
19
 
20
- spec.add_runtime_dependency "coercible", "~> 1.0"
21
- spec.add_runtime_dependency "axiom-types", "~> 0.1"
20
+ spec.add_runtime_dependency "dry-validation", "~> 0.11"
22
21
 
23
- spec.add_development_dependency "bundler", "~> 1.9"
24
- spec.add_development_dependency "rake", "~> 10.0"
25
- spec.add_development_dependency "pry", "~> 0.10"
26
- spec.add_development_dependency "minitest", "~> 5.7"
27
- spec.add_development_dependency "codeclimate-test-reporter", "~> 0.4"
22
+ spec.add_development_dependency "bundler", "~> 1.16"
23
+ spec.add_development_dependency "rake", "~> 12.0"
24
+ spec.add_development_dependency "pry", "~> 0.11"
25
+ spec.add_development_dependency "minitest", "~> 5.11"
26
+ spec.add_development_dependency "codeclimate-test-reporter", "~> 1.0"
28
27
  end
@@ -1,21 +1,8 @@
1
1
  module Gate
2
- class CoercionError < StandardError; end
3
-
4
- def self.rules(&block)
5
- configuration = Configuration.new(&block)
6
-
7
- Guard.new(configuration)
8
- end
2
+ InvalidCommand = Class.new(StandardError)
9
3
  end
10
4
 
11
- require "axiom-types"
12
- require "coercible"
13
- require "forwardable"
14
- require "set"
5
+ require "dry-validation"
15
6
 
16
- require "gate/coercer"
17
- require "gate/coercer/any"
18
- require "gate/configuration"
19
- require "gate/guard"
20
- require "gate/result"
7
+ require "gate/command"
21
8
  require "gate/version"
@@ -0,0 +1,47 @@
1
+ module Gate
2
+ module Command
3
+ SchemaAlreadyRegistered = Class.new(StandardError)
4
+ SchemaNotDefined = Class.new(StandardError)
5
+
6
+ class InvalidCommand < StandardError
7
+ attr_reader :errors
8
+
9
+ def initialize(errors)
10
+ @errors = errors
11
+ super("Invalid command")
12
+ end
13
+ end
14
+
15
+ def self.included(base)
16
+ base.send(:extend, ClassMethods)
17
+ base.send(:attr_reader, :result)
18
+ end
19
+
20
+ def initialize(data)
21
+ @result = data
22
+ end
23
+
24
+ module ClassMethods
25
+ def schema(&block)
26
+ if block_given?
27
+ raise SchemaAlreadyRegistered if @schema
28
+ @schema = Dry::Validation.Form(&block)
29
+ @schema.rules.keys.each do |name|
30
+ define_method(name) do
31
+ result[name]
32
+ end
33
+ end
34
+ else
35
+ raise SchemaNotDefined unless @schema
36
+ @schema
37
+ end
38
+ end
39
+
40
+ def with(input)
41
+ result = schema.(input)
42
+ raise InvalidCommand, result.messages if result.failure?
43
+ new result.output
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,3 +1,3 @@
1
1
  module Gate
2
- VERSION = "0.4.1"
2
+ VERSION = "0.5.0"
3
3
  end
metadata CHANGED
@@ -1,113 +1,99 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Dudulski
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-23 00:00:00.000000000 Z
11
+ date: 2018-03-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: coercible
14
+ name: dry-validation
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.0'
19
+ version: '0.11'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.0'
27
- - !ruby/object:Gem::Dependency
28
- name: axiom-types
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '0.1'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '0.1'
26
+ version: '0.11'
41
27
  - !ruby/object:Gem::Dependency
42
28
  name: bundler
43
29
  requirement: !ruby/object:Gem::Requirement
44
30
  requirements:
45
31
  - - "~>"
46
32
  - !ruby/object:Gem::Version
47
- version: '1.9'
33
+ version: '1.16'
48
34
  type: :development
49
35
  prerelease: false
50
36
  version_requirements: !ruby/object:Gem::Requirement
51
37
  requirements:
52
38
  - - "~>"
53
39
  - !ruby/object:Gem::Version
54
- version: '1.9'
40
+ version: '1.16'
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: rake
57
43
  requirement: !ruby/object:Gem::Requirement
58
44
  requirements:
59
45
  - - "~>"
60
46
  - !ruby/object:Gem::Version
61
- version: '10.0'
47
+ version: '12.0'
62
48
  type: :development
63
49
  prerelease: false
64
50
  version_requirements: !ruby/object:Gem::Requirement
65
51
  requirements:
66
52
  - - "~>"
67
53
  - !ruby/object:Gem::Version
68
- version: '10.0'
54
+ version: '12.0'
69
55
  - !ruby/object:Gem::Dependency
70
56
  name: pry
71
57
  requirement: !ruby/object:Gem::Requirement
72
58
  requirements:
73
59
  - - "~>"
74
60
  - !ruby/object:Gem::Version
75
- version: '0.10'
61
+ version: '0.11'
76
62
  type: :development
77
63
  prerelease: false
78
64
  version_requirements: !ruby/object:Gem::Requirement
79
65
  requirements:
80
66
  - - "~>"
81
67
  - !ruby/object:Gem::Version
82
- version: '0.10'
68
+ version: '0.11'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: minitest
85
71
  requirement: !ruby/object:Gem::Requirement
86
72
  requirements:
87
73
  - - "~>"
88
74
  - !ruby/object:Gem::Version
89
- version: '5.7'
75
+ version: '5.11'
90
76
  type: :development
91
77
  prerelease: false
92
78
  version_requirements: !ruby/object:Gem::Requirement
93
79
  requirements:
94
80
  - - "~>"
95
81
  - !ruby/object:Gem::Version
96
- version: '5.7'
82
+ version: '5.11'
97
83
  - !ruby/object:Gem::Dependency
98
84
  name: codeclimate-test-reporter
99
85
  requirement: !ruby/object:Gem::Requirement
100
86
  requirements:
101
87
  - - "~>"
102
88
  - !ruby/object:Gem::Version
103
- version: '0.4'
89
+ version: '1.0'
104
90
  type: :development
105
91
  prerelease: false
106
92
  version_requirements: !ruby/object:Gem::Requirement
107
93
  requirements:
108
94
  - - "~>"
109
95
  - !ruby/object:Gem::Version
110
- version: '0.4'
96
+ version: '1.0'
111
97
  description: Validate and coerce user input against defined structure.
112
98
  email:
113
99
  - jan@dudulski.pl
@@ -115,6 +101,7 @@ executables: []
115
101
  extensions: []
116
102
  extra_rdoc_files: []
117
103
  files:
104
+ - ".circleci/config.yml"
118
105
  - ".codeclimate.yml"
119
106
  - ".gitignore"
120
107
  - ".rubocop.yml"
@@ -125,14 +112,9 @@ files:
125
112
  - Rakefile
126
113
  - bin/console
127
114
  - bin/setup
128
- - circle.yml
129
115
  - gate.gemspec
130
116
  - lib/gate.rb
131
- - lib/gate/coercer.rb
132
- - lib/gate/coercer/any.rb
133
- - lib/gate/configuration.rb
134
- - lib/gate/guard.rb
135
- - lib/gate/result.rb
117
+ - lib/gate/command.rb
136
118
  - lib/gate/version.rb
137
119
  homepage: https://github.com/monterail/gate
138
120
  licenses:
@@ -154,8 +136,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
136
  version: '0'
155
137
  requirements: []
156
138
  rubyforge_project:
157
- rubygems_version: 2.4.5.1
139
+ rubygems_version: 2.6.14
158
140
  signing_key:
159
141
  specification_version: 4
160
- summary: Handling user input with ease
142
+ summary: CQRS Command
161
143
  test_files: []
data/circle.yml DELETED
@@ -1,3 +0,0 @@
1
- machine:
2
- ruby:
3
- version: 2.2.0
@@ -1,48 +0,0 @@
1
- module Gate
2
- class Coercer
3
- PRIMITIVES = [TrueClass, FalseClass, Array, Hash, Numeric]
4
-
5
- def initialize(engine, type, allow_nil: false)
6
- unless coercible?(type)
7
- fail CoercionError, "Doesn't know how to coerce into #{type}"
8
- end
9
-
10
- @engine = engine
11
- @type = type
12
- @allow_nil = allow_nil
13
- end
14
-
15
- def coerce(input)
16
- engine[detect_input_type(input)].public_send(coercion_method, input)
17
- rescue Coercible::UnsupportedCoercion
18
- raise CoercionError, "Doesn't know how to coerce #{input} into #{type}"
19
- end
20
-
21
- def allow_nil?
22
- @allow_nil
23
- end
24
-
25
- private
26
-
27
- attr_reader :engine, :type
28
-
29
- def coercible?(type)
30
- type == :Any or Axiom::Types.const_defined?(type)
31
- end
32
-
33
- def detect_input_type(input)
34
- case input
35
- when *PRIMITIVES, Any
36
- input.class
37
- else
38
- String
39
- end
40
- end
41
-
42
- def coercion_method
43
- return :to_any if type == :Any
44
-
45
- Axiom::Types.const_get(type).coercion_method
46
- end
47
- end
48
- end
@@ -1,7 +0,0 @@
1
- require 'coercible'
2
-
3
- class Gate::Coercer::Any < Coercible::Coercer::Object
4
- def to_any(value)
5
- value
6
- end
7
- end
@@ -1,55 +0,0 @@
1
- module Gate
2
- class Configuration
3
- extend Forwardable
4
-
5
- attr_reader :coercer
6
- attr_reader :required_set, :optional_set, :nested_set
7
- attr_reader :rules
8
-
9
- def_delegator :@rules, :reduce
10
-
11
- def initialize(coercer: Coercible::Coercer.new, allow_nil: false, &block)
12
- @coercer = coercer
13
- @required_set = Set.new
14
- @optional_set = Set.new
15
- @nested_set = Set.new
16
- @rules = {}
17
- @allow_nil = allow_nil
18
-
19
- instance_eval(&block)
20
- end
21
-
22
- def required?(name)
23
- required_set.include?(name)
24
- end
25
-
26
- def allow_nil?
27
- @allow_nil
28
- end
29
-
30
- private
31
-
32
- def required(name, type = :String, allow_nil: false, &block)
33
- required_set.add(name)
34
- register(name, type, allow_nil: allow_nil, &block)
35
- end
36
-
37
- def optional(name, type = :String, allow_nil: false, &block)
38
- optional_set.add(name)
39
- register(name, type, allow_nil: allow_nil, &block)
40
- end
41
-
42
- def register(name, type, allow_nil:, &block)
43
- @rules[name] = setup_rule(name, type, allow_nil: allow_nil, &block)
44
- end
45
-
46
- def setup_rule(name, type, allow_nil:, &block)
47
- if block_given?
48
- nested_set.add(name)
49
- Configuration.new(coercer: coercer, allow_nil: allow_nil, &block)
50
- else
51
- Coercer.new(coercer, type, allow_nil: allow_nil)
52
- end
53
- end
54
- end
55
- end
@@ -1,67 +0,0 @@
1
- module Gate
2
- class Guard
3
- attr_reader :configuration
4
-
5
- def initialize(configuration)
6
- @configuration = configuration
7
- end
8
-
9
- def verify(input)
10
- configuration.reduce(Result.new) do |result, (name, rule)|
11
- Result.new(_verify(input, name, rule, result))
12
- end
13
- end
14
-
15
- private
16
-
17
- def _verify(input, name, rule, result)
18
- case
19
- when input.key?(name)
20
- coerced = handle(input[name], name, rule)
21
- update(result, coerced)
22
- when configuration.required?(name)
23
- errors = result.errors.merge(name => :missing)
24
- update(result, errors: errors)
25
- else
26
- result.to_h
27
- end
28
- end
29
-
30
- def handle(input, name, rule)
31
- case
32
- when input.nil?
33
- coerce_nil(name, rule)
34
- when rule.is_a?(Gate::Configuration)
35
- coerce_nested(input, name, rule)
36
- else
37
- coerce(input, name, rule)
38
- end
39
- end
40
-
41
- def coerce(input, name, rule)
42
- { attributes: { name => rule.coerce(input) } }
43
- rescue CoercionError
44
- # TODO: log error
45
- { errors: { name => :coercion_error } }
46
- end
47
-
48
- def coerce_nested(input, name, rule)
49
- result = Gate::Guard.new(rule).verify(input)
50
- { attributes: { name => result.attributes },
51
- errors: { name => result.errors } }
52
- end
53
-
54
- def coerce_nil(name, rule)
55
- if rule.allow_nil?
56
- { attributes: { name => nil } }
57
- else
58
- { errors: { name => :nil_not_allowed } }
59
- end
60
- end
61
-
62
- def update(result, attributes: {}, errors: {})
63
- { attributes: result.attributes.merge(attributes),
64
- errors: result.errors.merge(errors) }
65
- end
66
- end
67
- end
@@ -1,39 +0,0 @@
1
- module Gate
2
- class Result
3
- attr_reader :attributes
4
-
5
- def initialize(attributes: {}, errors: {})
6
- @attributes = attributes
7
- @errors = errors
8
- end
9
-
10
- def valid?
11
- errors.empty?
12
- end
13
-
14
- def errors
15
- _errors(@errors)
16
- end
17
-
18
- def to_h
19
- {
20
- attributes: attributes,
21
- errors: @errors
22
- }
23
- end
24
-
25
- private
26
-
27
- def _errors(hash)
28
- hash.each_with_object({}) do |(k, v), result|
29
- if v.is_a?(Hash)
30
- nested = _errors(v)
31
-
32
- result[k] = nested if nested.any?
33
- else
34
- result[k] = v
35
- end
36
- end
37
- end
38
- end
39
- end