sinatra-param-validator 0.2.0 → 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
  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