sinatra-param-validator 0.2.0 → 0.5.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
  SHA256:
3
- metadata.gz: dda1b5487b870b26f4b2ca5c6a575a57c91441ac319b78567295ab0b4517a8bc
4
- data.tar.gz: 331f3cace8d87a35fa410ae28c3df15e07f851d276ad2a2173ce799572cfae04
3
+ metadata.gz: 1312fa49d8b256875f1c6de21269a7be31ab1c3f2ca0a5efdb9902c31b5406d4
4
+ data.tar.gz: 4b483ce648a24026e26964b0cdd358a4f1256ffe7dc810770e8dbf2b98204306
5
5
  SHA512:
6
- metadata.gz: caceb492da8562135850ecf1c7a77ecd4fd850ab31d714ff1fa555c4316e63074aa7ed9f75e331336ddf30c1921a5d3cc2f895447d7ec76f3767b46448e6a7c4
7
- data.tar.gz: 729686317687d72ff23ce570991a88e6731314320f3e702ba631c7452b75e117997fc30207c2cee7be52c1aa458424311666b734061bb7c3aefb6911b07a9dc2
6
+ metadata.gz: 2714270e73581d5beb88eb136516fc1d5275d05ebe2a3c5efca08d54b64bb2bcda467cb45cb4ab3fa7fee063606171356f9fe869cbedc0950afc7b92cb5dc8eb
7
+ data.tar.gz: 692691bde5e786c23897080967004fc5fb5b695d49942fd671db69ef6ec91c00771a0afbfc5e69954b5e22f8e585829c8e08a04b6a954cf14ec46b1c19dfdf8c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.5.0] - 2022-06-09
4
+
5
+ - Allow the validator to be passed to the block for a valid parameter
6
+
7
+ ## [0.4.0] - 2022-06-09
8
+
9
+ - Allow custom error messages to be used when validation fails
10
+ - Ensure running multiple validations for a single parameter merges the errors correctly
11
+ - Allow validations to run code if successful
12
+ - Allow exceptions to be raised by the parameter block to indicate failure
13
+ - Allow parameters to be passed to validators
14
+
15
+ ## [0.3.0] - 2022-06-08
16
+
17
+ - Don't create entries in `params` for parameters that are not passed
18
+ - Don't set validator type during definition
19
+ - Add unique validator conditionals for each validator:
20
+ - validate
21
+ - validate_form
22
+ - validate_url_param
23
+
24
+ ## [0.2.0] - 2022-06-08
25
+
26
+ - Add validators:
27
+ - Standard
28
+ - URL Parameter
29
+ - Form
30
+ - Add parameters:
31
+ - Array
32
+ - Boolean
33
+ - Date
34
+ - Float
35
+ - Hash
36
+ - Integer
37
+ - String
38
+ - Time
39
+ - Add rules:
40
+ - All or none of
41
+ - Any of
42
+ - One of
43
+
3
44
  ## [0.1.0] - 2022-05-16
4
45
 
5
46
  - Initial release
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sinatra-param-validator (0.2.0)
4
+ sinatra-param-validator (0.5.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -15,7 +15,7 @@ If bundler is not being used to manage dependencies, install the gem by executin
15
15
  ## Sample Usage
16
16
 
17
17
  ```ruby
18
- validator identifier: :user_id do
18
+ validator :user_id do
19
19
  param :id, Integer, required: true
20
20
  end
21
21
 
@@ -23,7 +23,7 @@ get '/user/:id', validate: :user_id do
23
23
  # ...
24
24
  end
25
25
 
26
- validator identifier: :new_user do
26
+ validator :new_user do
27
27
  param :name, String, required: true
28
28
  param :age, Integer, required: true, min: 0
29
29
  end
@@ -86,6 +86,44 @@ All parameters have the following validations available:
86
86
 
87
87
  * `min` / `max`
88
88
 
89
+ ## Custom Messages
90
+
91
+ It is possible to return a custom error message when a validation fails:
92
+
93
+ ```ruby
94
+ param :number, Integer, required: true, message: 'The number is required'
95
+ ```
96
+
97
+ It is also possible to run multiple validations against a single parameter.
98
+ This can be useful if different failures require different messages.
99
+
100
+ ```ruby
101
+ param :number, Integer, required: true, message: 'The number is required'
102
+ param :number, Integer, min: 100, message: 'The number is not large enough'
103
+ ```
104
+
105
+ ## Validation blocks
106
+
107
+ It is possible to run code after a validation succeeds, by passing a block to `param`:
108
+
109
+ ```ruby
110
+ param :number, Integer, required: true do
111
+ # ...
112
+ end
113
+ ```
114
+
115
+ If you wish to indicate a validation failure within a block, raise `Sinatra::ParameterValidator::InvalidParameterError`
116
+ with a message, and it will be passed through as an error for the parameter.
117
+
118
+ If you need to do further validation with your parameter, the validator can be passed to the block:
119
+
120
+ ```ruby
121
+
122
+ param :number, Integer, required: true do |validator|
123
+ validator.param :digit, Integer, min: params[:number]
124
+ end
125
+ ```
126
+
89
127
  ## Rules
90
128
 
91
129
  Rules work on multiple parameters:
@@ -113,12 +151,30 @@ There are two other provided validators, that handle failure differently:
113
151
  * will provide a JSON object with errors to an XHR request
114
152
  * will `halt 400`
115
153
 
116
- These validators can be set when a validator is defined:
154
+ These validators can be invoked with a different conditional on the route:
117
155
 
118
156
  ```ruby
119
- validator type: :form, identifier: :new_user do
120
- param :name, String, required: true
121
- param :age, Integer, required: true, min: 0
157
+ post '/new-user', validate_form: :new_user do
158
+ # ...
159
+ end
160
+
161
+ get '/user/:id', validate_url_param: :user_id do
162
+ # ...
163
+ end
164
+ ```
165
+
166
+ ## Validators with parameters
167
+
168
+ It is possible to define a validator with a parameter.
169
+ To call the validator, you can use the `vi` helper to wrap a validator identifier with arguments:
170
+
171
+ ```ruby
172
+ validator :number do |min|
173
+ param :id, Integer, min: min
174
+ end
175
+
176
+ post '/number', validate: vi(:new_user, 10) do
177
+ # ...
122
178
  end
123
179
  ```
124
180
 
@@ -13,9 +13,11 @@ module Sinatra
13
13
  raise "Filter params failed: #{e}"
14
14
  end
15
15
 
16
- def validate(identifier, args = {})
17
- validator = settings.validator_definitions.get(identifier)
18
- validator.run(self, *args)
16
+ def validate(klass, identifier)
17
+ identifier = Identifier.new(identifier) if identifier.is_a? Symbol
18
+ definition = settings.validator_definitions.get(identifier.identifier)
19
+ validator = klass.new(&definition)
20
+ validator.run(self, *identifier.args)
19
21
  validator.handle_failure(self) unless validator.success?
20
22
  end
21
23
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sinatra
4
+ module ParamValidator
5
+ # Class to hold a validator identifier plus arguments
6
+ class Identifier
7
+ attr_reader :identifier, :args
8
+
9
+ def initialize(identifier, *args)
10
+ @identifier = identifier
11
+ @args = args
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sinatra
4
+ module ParamValidator
5
+ # Error raised when validation fails
6
+ class InvalidParameterError < StandardError
7
+ end
8
+ end
9
+ end
@@ -9,13 +9,17 @@ module Sinatra
9
9
 
10
10
  def initialize(value, **options)
11
11
  @errors = []
12
- @coerced = coerce value
13
12
  @options = options
14
13
 
14
+ begin
15
+ @coerced = coerce value
16
+ rescue ArgumentError
17
+ @errors.push "'#{value}' is not a valid #{self.class}"
18
+ return
19
+ end
20
+
15
21
  validate_options
16
22
  validate unless nil_and_ok?
17
- rescue ArgumentError
18
- @errors.push "'#{value}' is not a valid #{self.class}"
19
23
  end
20
24
 
21
25
  def valid?
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'delegate'
4
4
 
5
+ require_relative 'invalid_parameter_error'
5
6
  require_relative 'parameter'
6
7
  require_relative 'rule'
7
8
 
@@ -11,18 +12,26 @@ module Sinatra
11
12
  class Parser < SimpleDelegator
12
13
  attr_reader :errors
13
14
 
14
- def initialize(definition, context)
15
+ def initialize(definition, context, *args)
15
16
  super(context)
16
17
  @context = context
17
18
  @errors = {}
18
19
 
19
- instance_exec({}, &definition)
20
+ instance_exec(*args, &definition)
20
21
  end
21
22
 
22
- def param(key, type, **args)
23
+ def add_error(key, error)
24
+ @errors[key] = @errors.fetch(key, []).concat(Array(error))
25
+ end
26
+
27
+ def param(key, type, message: nil, **args, &block)
23
28
  parameter = Parameter.new(@context.params[key], type, **args)
24
- @context.params[key] = parameter.coerced
25
- @errors[key] = parameter.errors unless parameter.valid?
29
+ @context.params[key] = parameter.coerced if @context.params.key?(key) && parameter.coerced
30
+ if parameter.valid?
31
+ run_block(key, block) if block
32
+ else
33
+ add_error key, message || parameter.errors
34
+ end
26
35
  rescue NameError
27
36
  raise 'Invalid parameter type'
28
37
  end
@@ -36,6 +45,13 @@ module Sinatra
36
45
  rescue NameError
37
46
  raise 'Invalid rule type'
38
47
  end
48
+
49
+ def run_block(key, block)
50
+ args = block.arity == 1 ? [self] : []
51
+ @context.instance_exec(*args, &block)
52
+ rescue InvalidParameterError => e
53
+ add_error key, e.message
54
+ end
39
55
  end
40
56
  end
41
57
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sinatra
4
+ module ParamValidator
5
+ # Helpers for validating parameters
6
+ module SnakeCase
7
+ def snake_case(string)
8
+ string.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
9
+ end
10
+ end
11
+ end
12
+ end
@@ -6,9 +6,9 @@ module Sinatra
6
6
  class ValidationFailedError < StandardError
7
7
  attr_reader :errors
8
8
 
9
- def initialize(errors, msg = nil)
9
+ def initialize(errors)
10
10
  @errors = errors
11
- super(msg)
11
+ super("Validation failed: #{errors}")
12
12
  end
13
13
  end
14
14
  end
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'validation_failed_error'
4
- require_relative 'validator/form'
5
- require_relative 'validator/url_param'
6
-
7
3
  module Sinatra
8
4
  module ParamValidator
9
5
  # Definition of a single validator
@@ -19,13 +15,28 @@ module Sinatra
19
15
  raise ValidationFailedError, @errors
20
16
  end
21
17
 
22
- def run(context)
23
- @errors = Parser.new(@definition, context).errors
18
+ def run(context, *args)
19
+ @errors = Parser.new(@definition, context, *args).errors
24
20
  end
25
21
 
26
22
  def success?
27
23
  @errors.empty?
28
24
  end
25
+
26
+ @validators = []
27
+
28
+ class << self
29
+ attr_reader :validators
30
+
31
+ def inherited(subclass)
32
+ super
33
+ @validators << subclass
34
+ end
35
+ end
29
36
  end
30
37
  end
31
38
  end
39
+
40
+ require_relative 'validation_failed_error'
41
+ require_relative 'validator/form'
42
+ require_relative 'validator/url_param'
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Sinatra
4
4
  module ParamValidator
5
- VERSION = '0.2.0'
5
+ VERSION = '0.5.0'
6
6
  end
7
7
  end
@@ -1,8 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'param_validator/camelize'
3
4
  require_relative 'param_validator/definitions'
4
5
  require_relative 'param_validator/helpers'
6
+ require_relative 'param_validator/identifier'
5
7
  require_relative 'param_validator/parser'
8
+ require_relative 'param_validator/snake_case'
6
9
  require_relative 'param_validator/validator'
7
10
  require_relative 'param_validator/version'
8
11
 
@@ -11,19 +14,33 @@ module Sinatra
11
14
  module ParamValidator
12
15
  include Camelize
13
16
 
14
- def validator(identifier:, type: nil, &definition)
15
- class_name = 'Sinatra::ParamValidator::Validator'
16
- class_name = "#{class_name}::#{camelize(type)}" unless type.nil?
17
- settings.validator_definitions.add(identifier, Object.const_get(class_name).new(&definition))
17
+ def validator(identifier, &definition)
18
+ settings.validator_definitions.add(identifier, definition)
18
19
  end
19
20
 
20
- def self.registered(app)
21
- app.helpers Helpers
22
- app.before { filter_params }
23
- app.set(:validator_definitions, Definitions.new)
24
- app.set(:validate) do |*identifiers|
25
- condition do
26
- identifiers.each { |identifier| validate identifier }
21
+ def vi(identifier, *args)
22
+ Identifier.new(identifier, *args)
23
+ end
24
+
25
+ class << self
26
+ include SnakeCase
27
+
28
+ def registered(app)
29
+ app.helpers Helpers
30
+ app.before { filter_params }
31
+ app.set(:validator_definitions, Definitions.new)
32
+ validator_conditional app, :validate, Sinatra::ParamValidator::Validator
33
+
34
+ Sinatra::ParamValidator::Validator.validators.each do |validator|
35
+ validator_conditional app, :"validate_#{snake_case(validator.to_s.split('::').last)}", validator
36
+ end
37
+ end
38
+
39
+ def validator_conditional(app, name, klass)
40
+ app.set(name) do |*identifiers|
41
+ condition do
42
+ identifiers.each { |identifier| validate klass, identifier }
43
+ end
27
44
  end
28
45
  end
29
46
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sinatra-param-validator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rick Selby
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-08 00:00:00.000000000 Z
11
+ date: 2022-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack-test
@@ -142,6 +142,8 @@ files:
142
142
  - lib/sinatra/param_validator/camelize.rb
143
143
  - lib/sinatra/param_validator/definitions.rb
144
144
  - lib/sinatra/param_validator/helpers.rb
145
+ - lib/sinatra/param_validator/identifier.rb
146
+ - lib/sinatra/param_validator/invalid_parameter_error.rb
145
147
  - lib/sinatra/param_validator/parameter.rb
146
148
  - lib/sinatra/param_validator/parameter/array.rb
147
149
  - lib/sinatra/param_validator/parameter/boolean.rb
@@ -157,6 +159,7 @@ files:
157
159
  - lib/sinatra/param_validator/rule/all_or_none_of.rb
158
160
  - lib/sinatra/param_validator/rule/any_of.rb
159
161
  - lib/sinatra/param_validator/rule/one_of.rb
162
+ - lib/sinatra/param_validator/snake_case.rb
160
163
  - lib/sinatra/param_validator/validation_failed_error.rb
161
164
  - lib/sinatra/param_validator/validator.rb
162
165
  - lib/sinatra/param_validator/validator/form.rb