validate_my_routes 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/validate_my_routes.rb +9 -0
- data/lib/validate_my_routes/errors.rb +42 -0
- data/lib/validate_my_routes/validatable.rb +102 -0
- data/lib/validate_my_routes/validate.rb +27 -0
- data/lib/validate_my_routes/validate/convert_to_type.rb +80 -0
- data/lib/validate_my_routes/validate/mixins/macros.rb +51 -0
- data/lib/validate_my_routes/validate/mixins/rules_combinators.rb +30 -0
- data/lib/validate_my_routes/validate/rules.rb +61 -0
- data/lib/validate_my_routes/validate/rules/all_parameters.rb +75 -0
- data/lib/validate_my_routes/validate/rules/anything.rb +13 -0
- data/lib/validate_my_routes/validate/rules/comparable.rb +82 -0
- data/lib/validate_my_routes/validate/rules/compound.rb +41 -0
- data/lib/validate_my_routes/validate/rules/conditional.rb +21 -0
- data/lib/validate_my_routes/validate/rules/enum.rb +21 -0
- data/lib/validate_my_routes/validate/rules/of_type.rb +31 -0
- data/lib/validate_my_routes/validate/rules/required.rb +17 -0
- data/lib/validate_my_routes/validate/rules/transforms.rb +50 -0
- data/lib/validate_my_routes/validate/validation_rule.rb +123 -0
- data/lib/validate_my_routes/validation_rules.rb +29 -0
- data/lib/validate_my_routes/version.rb +4 -0
- metadata +149 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7bbe49d25595b0b18e832e1296bef3e8ba29cc6d
|
4
|
+
data.tar.gz: de5cbfe90139663a05c9055b6696e7a846fa6f30
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fdb2afba0936e7f025cc4f375a01dcc1312e7bfa466c001e1ea4c7031f6474af968919d6d5151fbed68df6fc374e5cbd3a77582e606f00fa035d577627c72976
|
7
|
+
data.tar.gz: fb517bac0d2b6c368e00b024ad5f35ef3f2aa9a8d575cbf5712b3274764938050a385a96d9174b8afe911c61513a195871513dfed0cd6f47410dc0f3be8b3be3
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require_relative 'validate_my_routes/version'
|
2
|
+
require_relative 'validate_my_routes/errors'
|
3
|
+
require_relative 'validate_my_routes/validation_rules'
|
4
|
+
require_relative 'validate_my_routes/validate'
|
5
|
+
require_relative 'validate_my_routes/validatable'
|
6
|
+
|
7
|
+
# General module that defines the base access to ValidateMyRoutes
|
8
|
+
module ValidateMyRoutes
|
9
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module ValidateMyRoutes
|
2
|
+
# Defining errors
|
3
|
+
module Errors
|
4
|
+
# Base error for validate_my_routes
|
5
|
+
class Error < ::RuntimeError; end
|
6
|
+
|
7
|
+
# Raised when type conversion fails
|
8
|
+
class InvalidTypeError < Error; end
|
9
|
+
|
10
|
+
# Raised when rule is not following required protocol
|
11
|
+
class UnsupportedRuleError < Error; end
|
12
|
+
|
13
|
+
# Raised when using validation DSL and missing validation block
|
14
|
+
class MissingValidationDeclarationBlock < Error; end
|
15
|
+
|
16
|
+
# Raised when using validation DSL when validation rule is already defined
|
17
|
+
class ValidationRuleNamingConflict < Error; end
|
18
|
+
|
19
|
+
# Raised when rule is missused
|
20
|
+
class MissusedRuleError < Error; end
|
21
|
+
|
22
|
+
# Basic error raised for validation failures
|
23
|
+
class ValidationError < Error
|
24
|
+
attr_reader :status_code, :message
|
25
|
+
def initialize(message, status_code)
|
26
|
+
super(message)
|
27
|
+
@status_code = status_code
|
28
|
+
@message = message
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Raised when soft failure occurs
|
33
|
+
class ConditionalValidationError < ValidationError; end
|
34
|
+
|
35
|
+
# Raised when exceptions occurs in validation block
|
36
|
+
class ValidationRaisedAnExceptionError < ValidationError
|
37
|
+
def initialize(custom_exception, status_code)
|
38
|
+
super(custom_exception.to_s, status_code)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module ValidateMyRoutes
|
2
|
+
# Route parameters validation extension
|
3
|
+
# To start using it, the extension needs to be registered
|
4
|
+
#
|
5
|
+
# register ValidateMyRoutes::Validatable
|
6
|
+
#
|
7
|
+
# Registering Validatable extension adds two conditions:
|
8
|
+
# - validate_all_params - a list of rules that need to be applied to all parameters together
|
9
|
+
# - validate_params - a hash with parameter names as keys and rules with extra information
|
10
|
+
# in values
|
11
|
+
module Validatable
|
12
|
+
class << self
|
13
|
+
def registered(app)
|
14
|
+
add_validate_params_condition_to app
|
15
|
+
add_validate_all_params_condition_to app
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def add_validate_all_params_condition_to(app)
|
21
|
+
app.set(:validate_all_params) do |*rules|
|
22
|
+
condition do
|
23
|
+
rules.all? { |rule| Validate.validate!(self, rule, params, false) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# rubocop:disable AbcSize
|
29
|
+
def add_validate_params_condition_to(app)
|
30
|
+
app.set(:validate_params) do |*validations|
|
31
|
+
condition do
|
32
|
+
path_validations = validations.select { |_, rule| rule[:path_param] }
|
33
|
+
query_validations = validations.reject { |_, rule| rule[:path_param] }
|
34
|
+
|
35
|
+
[path_validations, query_validations].all? do |param_validations|
|
36
|
+
param_validations.select { |_, rule| rule[:path_param] }.all? do |param_name, rule|
|
37
|
+
value = params[param_name]
|
38
|
+
Validate.validate!(self, rule[:rule], value, rule[:path_param], param_name)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
# rubocop:enable AbcSize
|
46
|
+
|
47
|
+
# Define path parameter with validation for all routes (including nested routes)
|
48
|
+
#
|
49
|
+
# param_validation :service_id, from_enum(%w[a b c])
|
50
|
+
def param_validation(name, rule)
|
51
|
+
Validate::Rules.validate_single_param_rule! rule
|
52
|
+
(@param_validations ||= {})[name.to_sym] = rule
|
53
|
+
end
|
54
|
+
|
55
|
+
# Define all parameters validation for a single route
|
56
|
+
#
|
57
|
+
# all_params_validation at_least_one_of(%i[version class status owner])
|
58
|
+
# get '/' do
|
59
|
+
# # params contain at least one of :version, :class, :status or :owner parameter
|
60
|
+
# end
|
61
|
+
def all_params_validation(rule)
|
62
|
+
Validate::Rules.validate_all_params_rule! rule
|
63
|
+
(@all_params_validation ||= []) << rule
|
64
|
+
end
|
65
|
+
|
66
|
+
# Hook into .route Sinatra method to add validation for parameters
|
67
|
+
def route(verb, route_pattern, conditions = {}, &block)
|
68
|
+
route_path_parameters(route_pattern).each do |name|
|
69
|
+
next unless param_validations.key? name
|
70
|
+
|
71
|
+
rule = param_validations[name]
|
72
|
+
# Add path parameter validation if it was specified
|
73
|
+
(conditions[:validate_params] ||= {})[name] ||= { path_param: true, rule: rule }
|
74
|
+
end
|
75
|
+
|
76
|
+
# Add all params validation if it was specified
|
77
|
+
conditions[:validate_all_params] = @all_params_validation if @all_params_validation
|
78
|
+
@all_params_validation = nil # remove params validation as it is defined on per-route bases
|
79
|
+
|
80
|
+
super(verb, route_pattern, conditions, &block)
|
81
|
+
end
|
82
|
+
|
83
|
+
def route_path_parameters(route_pattern)
|
84
|
+
path_parameters = route_pattern.split('/').map do |part|
|
85
|
+
part.start_with?(':') ? part[1..-1].to_sym : nil
|
86
|
+
end
|
87
|
+
|
88
|
+
path_parameters.flatten.compact.uniq.map(&:to_sym)
|
89
|
+
end
|
90
|
+
|
91
|
+
protected
|
92
|
+
|
93
|
+
def param_validations
|
94
|
+
parameters_defined_in_superclass = {}
|
95
|
+
# For nested routes we need to look for defined parameters with validation in
|
96
|
+
# superclass also.
|
97
|
+
parameters_defined_in_superclass = superclass.param_validations \
|
98
|
+
if superclass.respond_to?(:param_validations, true)
|
99
|
+
parameters_defined_in_superclass.merge(@param_validations || {})
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative 'validate/convert_to_type'
|
2
|
+
require_relative 'validate/rules'
|
3
|
+
|
4
|
+
module ValidateMyRoutes
|
5
|
+
# Module for validation. Provides method to validate value by specified rule.
|
6
|
+
module Validate
|
7
|
+
class << self
|
8
|
+
# Perform validation of a single rule in-place
|
9
|
+
# Note: this method is not validating that rule is for all parameters or just a single
|
10
|
+
# Example:
|
11
|
+
#
|
12
|
+
# get 'some/:id' do |id|
|
13
|
+
# ValidateMyRoutes::Validate.validate!(self, greater_than(5), id.to_i, 'id') do |msg|
|
14
|
+
# halt 400, "Id <#{id}> failed validation: #{msg}"
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
def validate!(app, rule, *args)
|
18
|
+
rule.validate!(app, *args)
|
19
|
+
rescue Errors::ConditionalValidationError
|
20
|
+
false
|
21
|
+
rescue Errors::ValidationError => failure
|
22
|
+
app.halt failure.status_code, failure.message unless block_given?
|
23
|
+
yield failure.message
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
module ValidateMyRoutes
|
4
|
+
module Validate
|
5
|
+
# ConvertToType module provides single method convert_to_type to convert value into type
|
6
|
+
# to_type. Conversion can fail with InvalidTypeError.
|
7
|
+
module ConvertToType
|
8
|
+
class << self
|
9
|
+
Boolean = :Boolean # rubocop:disable Naming/ConstantName
|
10
|
+
SIMPLE_TYPES = [Float, String, Date, Time, DateTime, Integer].freeze
|
11
|
+
COMPOSITE_TYPES = [Array, Hash].freeze
|
12
|
+
BOOLEAN_TYPES = [Boolean, TrueClass, FalseClass].freeze
|
13
|
+
|
14
|
+
def convert_to_type(value, to_type)
|
15
|
+
return value if already_of_type?(value, to_type)
|
16
|
+
|
17
|
+
if SIMPLE_TYPES.include?(to_type)
|
18
|
+
parse_simple_type(value, to_type)
|
19
|
+
elsif COMPOSITE_TYPES.include?(to_type)
|
20
|
+
parse_composite_type(value, to_type)
|
21
|
+
elsif BOOLEAN_TYPES.include?(to_type)
|
22
|
+
parse_boolean(value)
|
23
|
+
else
|
24
|
+
raise_unknown_type(to_type)
|
25
|
+
end
|
26
|
+
rescue ArgumentError
|
27
|
+
raise_with_invalid_type(value, to_type)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def already_of_type?(value, typ)
|
33
|
+
(typ.is_a?(Class) || typ.is_a?(Module)) && value.is_a?(typ)
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse_simple_type(value, to_type)
|
37
|
+
if to_type == Integer
|
38
|
+
Integer(value)
|
39
|
+
elsif [Float, String].include?(to_type)
|
40
|
+
Kernel.send(to_type.to_s.to_sym, value)
|
41
|
+
elsif to_type.respond_to? :parse
|
42
|
+
to_type.parse(value)
|
43
|
+
else
|
44
|
+
raise_unknown_type(to_type)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def parse_composite_type(value, to_type)
|
49
|
+
if to_type == Array
|
50
|
+
value.split(',')
|
51
|
+
elsif to_type == Hash
|
52
|
+
Hash[value.split(',').map { |item| item.split(':') }]
|
53
|
+
else
|
54
|
+
raise_unknown_type(to_type)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def parse_boolean(value)
|
59
|
+
if value.to_s.casecmp('false').zero?
|
60
|
+
false
|
61
|
+
elsif value.to_s.casecmp('true').zero?
|
62
|
+
true
|
63
|
+
else
|
64
|
+
raise_with_invalid_type(value, Boolean)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def raise_with_invalid_type(value, type)
|
69
|
+
raise ValidateMyRoutes::Errors::InvalidTypeError,
|
70
|
+
"'#{value}' is not a valid '#{type}'"
|
71
|
+
end
|
72
|
+
|
73
|
+
def raise_unknown_type(type)
|
74
|
+
raise ValidateMyRoutes::Errors::InvalidTypeError,
|
75
|
+
"don't know how to convert type '#{type}'"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module ValidateMyRoutes
|
2
|
+
module Validate
|
3
|
+
# Helper functions to provide a DSL for creating validation rules
|
4
|
+
module Macros
|
5
|
+
# Define all parameters validation
|
6
|
+
#
|
7
|
+
# validate do |params|
|
8
|
+
# params.key? 'some_parameter_name'
|
9
|
+
# end
|
10
|
+
def validate(&block)
|
11
|
+
define_method(:validate, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Customize validation rule description
|
15
|
+
#
|
16
|
+
# description do
|
17
|
+
# 'this is my custom validation rule description'
|
18
|
+
# end
|
19
|
+
def description(&block)
|
20
|
+
define_method(:description, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Customize message returned when validation fails for all parameters
|
24
|
+
#
|
25
|
+
# failure_message do |params|
|
26
|
+
# "oh no! validation failed for #{params}"
|
27
|
+
# end
|
28
|
+
def failure_message(&block)
|
29
|
+
define_method(:failure_message, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Customize message returned when opposite rule validation fails (not of type A)
|
33
|
+
#
|
34
|
+
# failure_message_when_negated do |params|
|
35
|
+
# "oh no! validation failed for #{params}, but it was not expected"
|
36
|
+
# end
|
37
|
+
def failure_message_when_negated(&block)
|
38
|
+
define_method(:failure_message_when_negated, &block)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Customize http status code of the failure
|
42
|
+
#
|
43
|
+
# failure_code do |in_path|
|
44
|
+
# in_path ? 404 : 400
|
45
|
+
# end
|
46
|
+
def failure_code(&block)
|
47
|
+
define_method(:failure_code, &block)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ValidateMyRoutes
|
2
|
+
module Validate
|
3
|
+
# Helper functions to provide a DSL for creating validation rules
|
4
|
+
module RulesCombinators
|
5
|
+
# Negate the rule to validate opposite expectation
|
6
|
+
#
|
7
|
+
# is_an_integer = of_type(Integer)
|
8
|
+
# is_not_an_integer = of_type(Integer).negate
|
9
|
+
def negate
|
10
|
+
ValidateMyRoutes::ValidationRules.not self
|
11
|
+
end
|
12
|
+
|
13
|
+
# Chain rule with another one to perform both validations
|
14
|
+
# Note that if first rule fails validation, second is ignored
|
15
|
+
#
|
16
|
+
# required.and of_type(Integer)
|
17
|
+
def and(other_rule)
|
18
|
+
ValidateMyRoutes::ValidationRules.and(self, other_rule)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Chain rule with another one to perform one or another validations
|
22
|
+
# Note that second validation will be performed only if first fails
|
23
|
+
#
|
24
|
+
# eql('all').or of_type(Integer)
|
25
|
+
def or(other_rule)
|
26
|
+
ValidateMyRoutes::ValidationRules.or(self, other_rule)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require_relative 'validation_rule'
|
2
|
+
|
3
|
+
require_relative 'rules/compound'
|
4
|
+
require_relative 'rules/anything'
|
5
|
+
require_relative 'rules/comparable'
|
6
|
+
require_relative 'rules/conditional'
|
7
|
+
require_relative 'rules/of_type'
|
8
|
+
require_relative 'rules/required'
|
9
|
+
require_relative 'rules/transforms'
|
10
|
+
require_relative 'rules/enum'
|
11
|
+
require_relative 'rules/all_parameters'
|
12
|
+
|
13
|
+
module ValidateMyRoutes
|
14
|
+
module Validate
|
15
|
+
# Module provides methods to validate if rule is a rule and if it can be used for single
|
16
|
+
# or all parameters validation.
|
17
|
+
module Rules
|
18
|
+
class << self
|
19
|
+
REQUIRED_RULE_METHODS = %i[validate! description rule_type].freeze
|
20
|
+
|
21
|
+
def single_param_rule?(rule)
|
22
|
+
validation_rule?(rule) && %i[single_param general].include?(rule.rule_type)
|
23
|
+
end
|
24
|
+
|
25
|
+
def all_params_rule?(rule)
|
26
|
+
validation_rule?(rule) && %i[all_params general].include?(rule.rule_type)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Validate that rule can be used for single parameter validation
|
30
|
+
#
|
31
|
+
# Example:
|
32
|
+
#
|
33
|
+
# Rules.validate_single_param_rule! required(:q) # => throws an exception
|
34
|
+
def validate_single_param_rule!(rule)
|
35
|
+
return if Rules.single_param_rule?(rule)
|
36
|
+
raise ValidateMyRoutes::Errors::UnsupportedRuleError,
|
37
|
+
"rule #{rule} must implement #{REQUIRED_RULE_METHODS.join(', ')} " \
|
38
|
+
'and be either :generic or :single_param rule type.'
|
39
|
+
end
|
40
|
+
|
41
|
+
# Validate that rule can be used for all parameters validation
|
42
|
+
#
|
43
|
+
# Example:
|
44
|
+
#
|
45
|
+
# Rules.validate_all_params_rule! of_type(Integer) # => throws an exception
|
46
|
+
def validate_all_params_rule!(rule)
|
47
|
+
return if Rules.all_params_rule?(rule)
|
48
|
+
raise ValidateMyRoutes::Errors::UnsupportedRuleError,
|
49
|
+
"rule #{rule} must implement #{REQUIRED_RULE_METHODS.join(', ')} " \
|
50
|
+
'and be either :generic or :all_params rule type.'
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def validation_rule?(rule)
|
56
|
+
REQUIRED_RULE_METHODS.all? { |method_name| rule.respond_to? method_name }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module ValidateMyRoutes
|
2
|
+
module Validate
|
3
|
+
module Rules
|
4
|
+
# Validation rules that designed to be used for validating all parameters
|
5
|
+
# in the route.
|
6
|
+
#
|
7
|
+
# For example if we need to allow specifying "all" or "search" criteria,
|
8
|
+
# but not both at the same time.
|
9
|
+
module AllParameters
|
10
|
+
ValidateMyRoutes::ValidationRules.def_all_params_validator :only_one_of do |names|
|
11
|
+
raise Errors::MissusedRuleError, 'names must be an array' unless names.is_a? Array
|
12
|
+
|
13
|
+
validate do |params|
|
14
|
+
present_parameters_count = names.count { |name| params.key? name.to_s }
|
15
|
+
present_parameters_count <= 1
|
16
|
+
end
|
17
|
+
|
18
|
+
description { "only one of <#{names.join(', ')}> parameters" }
|
19
|
+
|
20
|
+
failure_message do |actual|
|
21
|
+
"was expected to have only one of <#{names.join(', ')}> parameters, " \
|
22
|
+
"but <#{actual.keys.join(', ')}> #{actual.size > 1 ? 'were' : 'was'} provided"
|
23
|
+
end
|
24
|
+
|
25
|
+
failure_message_when_negated do |actual|
|
26
|
+
"was expected to have all of <#{names.join(', ')}> parameters, " \
|
27
|
+
"but <#{actual.keys.join(', ')}> #{actual.size > 1 ? 'were' : 'was'} provided"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
ValidateMyRoutes::ValidationRules.def_all_params_validator :exactly_one_of do |names|
|
32
|
+
raise Errors::MissusedRuleError, 'names must be an array' unless names.is_a? Array
|
33
|
+
|
34
|
+
validate do |params|
|
35
|
+
present_parameters_count = names.count { |name| params.key? name.to_s }
|
36
|
+
present_parameters_count == 1
|
37
|
+
end
|
38
|
+
|
39
|
+
description { "exactly one of <#{names.join(', ')}> parameters" }
|
40
|
+
|
41
|
+
failure_message do |actual|
|
42
|
+
"was expected to have exactly one of <#{names.join(', ')}> parameters, " \
|
43
|
+
"but <#{actual.keys.join(', ')}> #{actual.size > 1 ? 'were' : 'was'} provided"
|
44
|
+
end
|
45
|
+
|
46
|
+
failure_message_when_negated do |actual|
|
47
|
+
"was expected to have none or more than one of <#{names.join(', ')}>, " \
|
48
|
+
"but <#{actual.keys.join(', ')}> #{actual.size > 1 ? 'were' : 'was'} provided"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
ValidateMyRoutes::ValidationRules.def_all_params_validator :at_least_one_of do |names|
|
53
|
+
raise Errors::MissusedRuleError, 'names must be an array' unless names.is_a? Array
|
54
|
+
|
55
|
+
validate do |params|
|
56
|
+
present_parameters_count = names.count { |name| params.key? name.to_s }
|
57
|
+
present_parameters_count >= 1
|
58
|
+
end
|
59
|
+
|
60
|
+
description { "at least one of <#{names.join(', ')}> parameters" }
|
61
|
+
|
62
|
+
failure_message do |actual|
|
63
|
+
"was expected to have at least one of <#{names.join(', ')}> parameters, " \
|
64
|
+
"but <#{actual.keys.join(', ')}> #{actual.size > 1 ? 'were' : 'was'} provided"
|
65
|
+
end
|
66
|
+
|
67
|
+
failure_message_when_negated do |actual|
|
68
|
+
"was expected to have none of <#{names.join(', ')}>, " \
|
69
|
+
"but <#{actual.keys.join(', ')}> #{actual.size > 1 ? 'were' : 'was'} provided"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ValidateMyRoutes
|
2
|
+
module Validate
|
3
|
+
module Rules
|
4
|
+
# Always successful validation rule
|
5
|
+
module Anything
|
6
|
+
ValidateMyRoutes::ValidationRules.def_validation_rule :anything do
|
7
|
+
validate { |*_| true }
|
8
|
+
description { 'anything' }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module ValidateMyRoutes
|
2
|
+
module Validate
|
3
|
+
module Rules
|
4
|
+
# List of comparison rules
|
5
|
+
module Comparable
|
6
|
+
VR = ValidateMyRoutes::ValidationRules
|
7
|
+
|
8
|
+
VR.def_single_param_validator :eql do |expected|
|
9
|
+
validate { |actual, _| actual == expected }
|
10
|
+
description { "equal to <#{expected}>" }
|
11
|
+
failure_message do |actual, name|
|
12
|
+
"was expected #{name} parameter to equal <#{expected}>, but was <#{actual}>"
|
13
|
+
end
|
14
|
+
failure_message_when_negated do |actual, name|
|
15
|
+
"was expected #{name} parameter to not equal <#{expected}>, but was <#{actual}>"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
VR.def_single_param_validator :greater_than do |expected|
|
20
|
+
validate { |actual, _| actual > expected }
|
21
|
+
description { "greater than <#{expected}>" }
|
22
|
+
failure_message do |actual, name|
|
23
|
+
"was expected #{name} parameter to be greater than <#{expected}>, but was <#{actual}>"
|
24
|
+
end
|
25
|
+
failure_message_when_negated do |actual, name|
|
26
|
+
"was expected #{name} parameter to be less than or equal to <#{expected}>, " \
|
27
|
+
"but was <#{actual}>"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
VR.def_single_param_validator :greater_than_or_equal_to do |expected|
|
32
|
+
validate { |actual, _| actual >= expected }
|
33
|
+
description { "greater than or equal to <#{expected}>" }
|
34
|
+
failure_message do |actual, name|
|
35
|
+
"was expected #{name} parameter to be greater than or equal to <#{expected}>, " \
|
36
|
+
"but was <#{actual}>"
|
37
|
+
end
|
38
|
+
failure_message_when_negated do |actual, name|
|
39
|
+
"was expected #{name} parameter to be less than <#{expected}>, but was <#{actual}>"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
VR.def_single_param_validator :less_than do |expected|
|
44
|
+
validate { |actual, _| actual < expected }
|
45
|
+
description { "less than <#{expected}>" }
|
46
|
+
failure_message do |actual, name|
|
47
|
+
"was expected #{name} parameter to be less than <#{expected}>, but was <#{actual}>"
|
48
|
+
end
|
49
|
+
failure_message_when_negated do |actual, name|
|
50
|
+
"was expected #{name} parameter to be greater than or equal to <#{expected}>, " \
|
51
|
+
"but was <#{actual}>"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
VR.def_single_param_validator :less_than_or_equal_to do |expected|
|
56
|
+
validate { |actual, _| actual <= expected }
|
57
|
+
description { "less than or equal to <#{expected}>" }
|
58
|
+
failure_message do |actual, name|
|
59
|
+
"was expected #{name} parameter to be less than or equal to <#{expected}>, " \
|
60
|
+
"but was <#{actual}>"
|
61
|
+
end
|
62
|
+
failure_message_when_negated do |actual, name|
|
63
|
+
"was expected #{name} parameter to be greater than <#{expected}>, but was <#{actual}>"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
VR.def_single_param_validator :between do |min, max|
|
68
|
+
validate { |actual, _| actual >= min && actual <= max }
|
69
|
+
description { "between <#{min}> and <#{max}>" }
|
70
|
+
failure_message do |actual, name|
|
71
|
+
"was expected #{name} parameter to be between <#{min}> and <#{max}>, " \
|
72
|
+
"but was <#{actual}>"
|
73
|
+
end
|
74
|
+
failure_message_when_negated do |actual, name|
|
75
|
+
"was expected #{name} parameter to be less than <#{min}> or greater than <#{max}>, " \
|
76
|
+
"but was <#{actual}>"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ValidateMyRoutes
|
2
|
+
module Validate
|
3
|
+
module Rules
|
4
|
+
# Rules combinators
|
5
|
+
# TODO: add validations to the rules before combining them
|
6
|
+
module Compound
|
7
|
+
ValidateMyRoutes::ValidationRules.def_validation_rule :not do |rule|
|
8
|
+
validate do |*args|
|
9
|
+
begin
|
10
|
+
!check(rule, *args)
|
11
|
+
rescue Errors::ValidationError
|
12
|
+
true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
failure_message { |*args| rule.failure_message_when_negated(*args) }
|
17
|
+
failure_message_when_negated { |*args| rule.failure_message(*args) }
|
18
|
+
description { "NOT #{rule.description}" }
|
19
|
+
failure_code { |*args| rule.failure_code(*args) }
|
20
|
+
end
|
21
|
+
|
22
|
+
ValidateMyRoutes::ValidationRules.def_validation_rule :and do |first_rule, second_rule|
|
23
|
+
validate { |*args| check(first_rule, *args) && check(second_rule, *args) }
|
24
|
+
description { "(#{first_rule.description} AND #{second_rule.description})" }
|
25
|
+
end
|
26
|
+
|
27
|
+
ValidateMyRoutes::ValidationRules.def_validation_rule :or do |first_rule, second_rule|
|
28
|
+
validate do |*args|
|
29
|
+
begin
|
30
|
+
check(first_rule, *args) || check(second_rule, *args)
|
31
|
+
rescue Errors::ValidationError
|
32
|
+
check(second_rule, *args)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
description { "(#{first_rule.description} OR #{second_rule.description})" }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ValidateMyRoutes
|
2
|
+
module Validate
|
3
|
+
module Rules
|
4
|
+
# Validation rule that on failure instruct Sinatra to search for another route instead of
|
5
|
+
# failing with validation error
|
6
|
+
module Conditional
|
7
|
+
ValidateMyRoutes::ValidationRules.def_validation_rule :conditional do |rule|
|
8
|
+
validate do |*args|
|
9
|
+
begin
|
10
|
+
check(rule, *args)
|
11
|
+
rescue Errors::ValidationError => error
|
12
|
+
raise Errors::ConditionalValidationError.new(error.message, error.status_code)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
description { "conditional, #{rule.description}" }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module ValidateMyRoutes
|
2
|
+
module Validate
|
3
|
+
module Rules
|
4
|
+
# Always successful validation rule
|
5
|
+
module Enum
|
6
|
+
ValidateMyRoutes::ValidationRules.def_single_param_validator :from_enum do |values|
|
7
|
+
unless values.respond_to? :include?
|
8
|
+
raise Errors::MissusedRuleError, 'from_enum rule requires #include? method on ' \
|
9
|
+
'expectation'
|
10
|
+
end
|
11
|
+
validate { |actual, _| values.include? actual }
|
12
|
+
failure_message do |actual, name|
|
13
|
+
"parameter <#{name}> was expected to have one of following values: " \
|
14
|
+
"<#{values.join ', '}>, but was <#{actual}>"
|
15
|
+
end
|
16
|
+
description { "of enum type with values: #{values.join(', ')}" }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative '../convert_to_type'
|
2
|
+
|
3
|
+
module ValidateMyRoutes
|
4
|
+
module Validate
|
5
|
+
module Rules
|
6
|
+
# Rule to validate type of parameter
|
7
|
+
module OfType
|
8
|
+
ValidateMyRoutes::ValidationRules.def_single_param_validator :of_type do |typ|
|
9
|
+
validate do |actual, _|
|
10
|
+
begin
|
11
|
+
ConvertToType.convert_to_type(actual, typ)
|
12
|
+
true
|
13
|
+
rescue ValidateMyRoutes::Errors::InvalidTypeError
|
14
|
+
false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
description { "of a type <#{typ}>" }
|
19
|
+
|
20
|
+
failure_message do |actual, name|
|
21
|
+
"was expected #{name} parameter to be of a type <#{typ}>, but was <#{actual}>"
|
22
|
+
end
|
23
|
+
|
24
|
+
failure_message_when_negated do |actual, name|
|
25
|
+
"was expected #{name} parameter to not be of a type <#{typ}>, but was <#{actual}>"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ValidateMyRoutes
|
2
|
+
module Validate
|
3
|
+
module Rules
|
4
|
+
# Validation rule that fails if parameter was not provided
|
5
|
+
module Required
|
6
|
+
ValidateMyRoutes::ValidationRules.def_all_params_validator :required do |parameter_name|
|
7
|
+
validate { |params| params.key? parameter_name.to_s }
|
8
|
+
description { "parameter <#{parameter_name}> is required" }
|
9
|
+
failure_message { |_| "parameter <#{parameter_name}> was expected to be present" }
|
10
|
+
failure_message_when_negated do |_|
|
11
|
+
"parameter <#{parameter_name}> was expected not to be present"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module ValidateMyRoutes
|
2
|
+
module Validate
|
3
|
+
module Rules
|
4
|
+
# Rules that perform transformation of value before sending it to another rule
|
5
|
+
module Transforms
|
6
|
+
ValidateMyRoutes::ValidationRules.def_single_param_validator :value_as do |typ, rule|
|
7
|
+
validate do |actual, name|
|
8
|
+
begin
|
9
|
+
converted_value = ConvertToType.convert_to_type(actual, typ)
|
10
|
+
check(rule, converted_value, name)
|
11
|
+
rescue ValidateMyRoutes::Errors::InvalidTypeError
|
12
|
+
false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
description { rule.description }
|
17
|
+
|
18
|
+
failure_message do |actual, name|
|
19
|
+
"was expected #{name} parameter to be of type <#{typ}>, but was <#{actual}>"
|
20
|
+
end
|
21
|
+
|
22
|
+
failure_message_when_negated do |_, _|
|
23
|
+
# TODO: make sure that not(value_as(...)) can not be used instead of failing here
|
24
|
+
raise Errors::MissusedRuleError, 'value_as does not support negate operation'
|
25
|
+
end
|
26
|
+
|
27
|
+
failure_code { |*args| rule.failure_code(*args) }
|
28
|
+
end
|
29
|
+
|
30
|
+
ValidateMyRoutes::ValidationRules.def_validation_rule :transform do |transformation, rule|
|
31
|
+
description { rule.description }
|
32
|
+
validate do |*args|
|
33
|
+
if args.size == 2
|
34
|
+
# this means single parameter validation with value and name
|
35
|
+
check(rule, transformation.call(args[0]), args[1])
|
36
|
+
elsif args.size == 1
|
37
|
+
# this means all parameters validation with value only
|
38
|
+
check(rule, transformation.call(args[0]))
|
39
|
+
else
|
40
|
+
raise Errors::MissusedRuleError, "Received #{args.size} instead of 1 or 2"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
failure_message { |*args| rule.failure_message(*args) }
|
44
|
+
failure_message_when_negated { |*args| rule.failure_message_when_negated(*args) }
|
45
|
+
failure_code { |*args| rule.failure_code(*args) }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require_relative 'mixins/macros'
|
2
|
+
require_relative 'mixins/rules_combinators'
|
3
|
+
|
4
|
+
module ValidateMyRoutes
|
5
|
+
module Validate
|
6
|
+
# ValidationRule is a base class for all rules
|
7
|
+
class ValidationRule
|
8
|
+
# Add DSL support for declarations in constructor
|
9
|
+
extend Macros
|
10
|
+
include RulesCombinators
|
11
|
+
|
12
|
+
attr_reader :rule_type
|
13
|
+
|
14
|
+
def initialize(rule_name, rule_type, *expected, declarations)
|
15
|
+
self.rule_name = rule_name
|
16
|
+
self.rule_type = rule_type
|
17
|
+
self.app = nil # this is a Sinatra application instance
|
18
|
+
singleton_class.class_exec(*expected, &declarations)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Current method can be used for validation
|
22
|
+
def validate!(app, value, path_param, *args)
|
23
|
+
# save current Sinatra app instance for method lookup on it
|
24
|
+
self.app = app
|
25
|
+
|
26
|
+
self.value = value
|
27
|
+
self.path_param = path_param == true
|
28
|
+
|
29
|
+
validate(value, *args) || fail_validation(failure_message(value, *args))
|
30
|
+
rescue Errors::ValidationError
|
31
|
+
# validation failed, so just re-raise an error to buble it up to the root
|
32
|
+
# re-raising is needed in order to catch all other exceptions to wrap them in
|
33
|
+
# special error
|
34
|
+
raise
|
35
|
+
rescue => ex # rubocop:disable Style/RescueStandardError
|
36
|
+
# unexpected exception happened in validation block, so we should wrap it in special error
|
37
|
+
raise Errors::ValidationRaisedAnExceptionError.new(ex, failure_code(path_param?))
|
38
|
+
end
|
39
|
+
|
40
|
+
def validate(*_args)
|
41
|
+
raise Errors::MissusedRuleError, 'validate method not implemented'
|
42
|
+
end
|
43
|
+
|
44
|
+
def description
|
45
|
+
rule_name.to_s.capitalize.tr('_', ' ')
|
46
|
+
end
|
47
|
+
|
48
|
+
def failure_code(in_path)
|
49
|
+
in_path ? 404 : 400
|
50
|
+
end
|
51
|
+
|
52
|
+
def failure_message(*args)
|
53
|
+
if args.size == 1
|
54
|
+
"parameters were expected to satisfy: #{description} but were <#{args[0]}>"
|
55
|
+
elsif args.size == 2
|
56
|
+
"parameter #{args[1]} was expected to satisfy: #{description} but was <#{args[0]}>"
|
57
|
+
else
|
58
|
+
raise Errors::MissusedRuleError, "failure_message method called with #{args.size} " \
|
59
|
+
'arguments'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def failure_message_when_negated(*args)
|
64
|
+
if args.size == 1
|
65
|
+
"parameters were expected not to satisfy: #{description} but were <#{args[0]}>"
|
66
|
+
elsif args.size == 2
|
67
|
+
"parameter #{args[1]} was expected not to satisfy: #{description} but was <#{args[0]}>"
|
68
|
+
else
|
69
|
+
raise Errors::MissusedRuleError, 'failure_message_when_negated method called with ' \
|
70
|
+
"#{args.size} arguments"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Expand method lookup to the application scope
|
75
|
+
def method_missing(method_name, *args, &block)
|
76
|
+
app && app.respond_to?(method_name) ? app.send(method_name, *args, &block) : super
|
77
|
+
end
|
78
|
+
|
79
|
+
def respond_to_missing?(method_name, include_private = false)
|
80
|
+
super || app.respond_to?(method_name) || super
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
attr_accessor :app, :value, :path_param, :rule_name
|
86
|
+
attr_writer :rule_type
|
87
|
+
|
88
|
+
# Helper method to perform validation of other rules inside validation block
|
89
|
+
#
|
90
|
+
# validate do |params|
|
91
|
+
# # make use of built in validation rules in custom validations
|
92
|
+
# check(of_type(Integer), params[:id], :id)
|
93
|
+
# # or validate all parameters
|
94
|
+
# check(required(:id), params)
|
95
|
+
# end
|
96
|
+
def check(rule, value, *args)
|
97
|
+
if args.empty?
|
98
|
+
ValidateMyRoutes::Validate::Rules.validate_all_params_rule! rule
|
99
|
+
elsif args.size == 1
|
100
|
+
ValidateMyRoutes::Validate::Rules.validate_single_param_rule! rule
|
101
|
+
else
|
102
|
+
raise Errors::MissusedRuleError, "check method called with #{args.size} arguments"
|
103
|
+
end
|
104
|
+
|
105
|
+
rule.validate!(app, value, path_param?, *args)
|
106
|
+
end
|
107
|
+
|
108
|
+
# Helper method to fail validation
|
109
|
+
#
|
110
|
+
# validate do |params|
|
111
|
+
# fail_validation 'no!' if params.size > 1
|
112
|
+
# end
|
113
|
+
def fail_validation(message, code = nil)
|
114
|
+
code ||= failure_code(path_param?)
|
115
|
+
raise Errors::ValidationError.new(message, code)
|
116
|
+
end
|
117
|
+
|
118
|
+
def path_param?
|
119
|
+
path_param
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative './validate/validation_rule'
|
2
|
+
|
3
|
+
module ValidateMyRoutes
|
4
|
+
# Mixin to add custom rules to the application.
|
5
|
+
#
|
6
|
+
# To create custom rule you can extend your class with ValidationRules:
|
7
|
+
# extend ValidateMyRoutes::ValidationRules
|
8
|
+
module ValidationRules
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def def_single_param_validator(name, &declarations)
|
12
|
+
def_validation_rule name, :single_param, &declarations
|
13
|
+
end
|
14
|
+
|
15
|
+
def def_all_params_validator(name, &declarations)
|
16
|
+
def_validation_rule name, :all_params, &declarations
|
17
|
+
end
|
18
|
+
|
19
|
+
def def_validation_rule(name, typ = :general, &declarations)
|
20
|
+
raise Errors::MissingValidationDeclarationBlock unless block_given?
|
21
|
+
raise Errors::ValidationRuleNamingConflict, name.to_sym if respond_to? name.to_sym
|
22
|
+
|
23
|
+
rule = ->(*expected) { Validate::ValidationRule.new(name, typ, *expected, declarations) }
|
24
|
+
|
25
|
+
define_method(name, rule)
|
26
|
+
define_singleton_method(name, rule)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: validate_my_routes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Workday, Ltd.
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-03-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rack-test
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: sinatra
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: ValidateMyRoutes provides a way to annotate Sinatra routes and validate
|
98
|
+
parameters before executing the route
|
99
|
+
email:
|
100
|
+
- prd.eng.os@workday.com
|
101
|
+
executables: []
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- lib/validate_my_routes.rb
|
106
|
+
- lib/validate_my_routes/errors.rb
|
107
|
+
- lib/validate_my_routes/validatable.rb
|
108
|
+
- lib/validate_my_routes/validate.rb
|
109
|
+
- lib/validate_my_routes/validate/convert_to_type.rb
|
110
|
+
- lib/validate_my_routes/validate/mixins/macros.rb
|
111
|
+
- lib/validate_my_routes/validate/mixins/rules_combinators.rb
|
112
|
+
- lib/validate_my_routes/validate/rules.rb
|
113
|
+
- lib/validate_my_routes/validate/rules/all_parameters.rb
|
114
|
+
- lib/validate_my_routes/validate/rules/anything.rb
|
115
|
+
- lib/validate_my_routes/validate/rules/comparable.rb
|
116
|
+
- lib/validate_my_routes/validate/rules/compound.rb
|
117
|
+
- lib/validate_my_routes/validate/rules/conditional.rb
|
118
|
+
- lib/validate_my_routes/validate/rules/enum.rb
|
119
|
+
- lib/validate_my_routes/validate/rules/of_type.rb
|
120
|
+
- lib/validate_my_routes/validate/rules/required.rb
|
121
|
+
- lib/validate_my_routes/validate/rules/transforms.rb
|
122
|
+
- lib/validate_my_routes/validate/validation_rule.rb
|
123
|
+
- lib/validate_my_routes/validation_rules.rb
|
124
|
+
- lib/validate_my_routes/version.rb
|
125
|
+
homepage: https://github.com/Workday/validate_my_routes
|
126
|
+
licenses:
|
127
|
+
- MIT
|
128
|
+
metadata: {}
|
129
|
+
post_install_message:
|
130
|
+
rdoc_options: []
|
131
|
+
require_paths:
|
132
|
+
- lib
|
133
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
requirements: []
|
144
|
+
rubyforge_project:
|
145
|
+
rubygems_version: 2.4.8
|
146
|
+
signing_key:
|
147
|
+
specification_version: 4
|
148
|
+
summary: A simple gem to validate Sinatra routes
|
149
|
+
test_files: []
|