rails_param 0.11.2 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -1
- data/lib/rails_param/coercion/array_param.rb +18 -0
- data/lib/rails_param/coercion/big_decimal_param.rb +17 -0
- data/lib/rails_param/coercion/boolean_param.rb +15 -0
- data/lib/rails_param/coercion/float_param.rb +9 -0
- data/lib/rails_param/coercion/hash_param.rb +18 -0
- data/lib/rails_param/coercion/integer_param.rb +9 -0
- data/lib/rails_param/coercion/string_param.rb +9 -0
- data/lib/rails_param/coercion/time_param.rb +17 -0
- data/lib/rails_param/coercion/virtual_param.rb +24 -0
- data/lib/rails_param/coercion.rb +41 -0
- data/lib/rails_param/invalid_parameter_error.rb +17 -0
- data/lib/rails_param/param.rb +2 -174
- data/lib/rails_param/param_evaluator.rb +90 -0
- data/lib/rails_param/parameter.rb +37 -0
- data/lib/rails_param/validator/blank.rb +24 -0
- data/lib/rails_param/validator/custom.rb +13 -0
- data/lib/rails_param/validator/format.rb +31 -0
- data/lib/rails_param/validator/in.rb +20 -0
- data/lib/rails_param/validator/is.rb +15 -0
- data/lib/rails_param/validator/max.rb +15 -0
- data/lib/rails_param/validator/max_length.rb +15 -0
- data/lib/rails_param/validator/min.rb +15 -0
- data/lib/rails_param/validator/min_length.rb +15 -0
- data/lib/rails_param/validator/required.rb +15 -0
- data/lib/rails_param/validator.rb +63 -0
- data/lib/rails_param/version.rb +1 -1
- data/lib/rails_param.rb +4 -1
- metadata +26 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d0d3e366d59b97f9e8453e2721f975afe0cbed9b29de26c35e786552707a3586
|
4
|
+
data.tar.gz: ed1a7c052cd69b75e2551cce07c2004094b0b95307490d72b88185a0da693c79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f70757e8463748ec31be8f61176a80fb1da2460af184c8a096a2abf928cf1c3507d77290e4a7f38f979829bad259e850afc4a1f0c31fd0f5bcd3fccad46834f4
|
7
|
+
data.tar.gz: 12074dad3f21ba4d0e1afd8bbc9db9ad827486dbe014f930c89d7fcc07ebed7c192da0aa31fe8b85041947541e1410d600d7ee630a5128522fc4da98b8bfd809
|
data/README.md
CHANGED
@@ -26,6 +26,10 @@ All the credits go to [@mattt](https://twitter.com/mattt).
|
|
26
26
|
|
27
27
|
It has all the features of the sinatra-param gem, I used bang methods (like param!) to indicate that they are destructive as they change the controller params object and may raise an exception.
|
28
28
|
|
29
|
+
## Upgrading
|
30
|
+
|
31
|
+
Find a list of breaking changes in [UPGRADING](UPGRADING.md).
|
32
|
+
|
29
33
|
## Installation
|
30
34
|
|
31
35
|
As usual, in your Gemfile...
|
@@ -67,7 +71,7 @@ By declaring parameter types, incoming parameters will automatically be transfor
|
|
67
71
|
|
68
72
|
### Validations
|
69
73
|
|
70
|
-
Encapsulate business logic in a consistent way with validations. If a parameter does not satisfy a particular condition, an exception (RailsParam::
|
74
|
+
Encapsulate business logic in a consistent way with validations. If a parameter does not satisfy a particular condition, an exception (RailsParam::InvalidParameterError) is raised.
|
71
75
|
You may use the [rescue_from](http://api.rubyonrails.org/classes/ActiveSupport/Rescuable/ClassMethods.html#method-i-rescue_from) method in your controller to catch this kind of exception.
|
72
76
|
|
73
77
|
- `required`
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module RailsParam
|
2
|
+
class Coercion
|
3
|
+
class ArrayParam < VirtualParam
|
4
|
+
def coerce
|
5
|
+
return param if param.is_a?(Array)
|
6
|
+
|
7
|
+
Array(param.split(options[:delimiter] || ","))
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def argument_validation
|
13
|
+
raise ArgumentError unless type == Array
|
14
|
+
raise ArgumentError unless param.respond_to?(:split)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RailsParam
|
2
|
+
class Coercion
|
3
|
+
class BigDecimalParam < VirtualParam
|
4
|
+
DEFAULT_PRECISION = 14
|
5
|
+
|
6
|
+
def coerce
|
7
|
+
stripped_param = if param.is_a?(String)
|
8
|
+
param.delete('$,').strip.to_f
|
9
|
+
else
|
10
|
+
param
|
11
|
+
end
|
12
|
+
|
13
|
+
BigDecimal(stripped_param, options[:precision] || DEFAULT_PRECISION)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RailsParam
|
2
|
+
class Coercion
|
3
|
+
class BooleanParam < VirtualParam
|
4
|
+
FALSEY = /^(false|f|no|n|0)$/i.freeze
|
5
|
+
TRUTHY = /^(true|t|yes|y|1)$/i.freeze
|
6
|
+
|
7
|
+
def coerce
|
8
|
+
return false if FALSEY === param.to_s
|
9
|
+
return true if TRUTHY === param.to_s
|
10
|
+
|
11
|
+
raise ArgumentError
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module RailsParam
|
2
|
+
class Coercion
|
3
|
+
class HashParam < VirtualParam
|
4
|
+
def coerce
|
5
|
+
return param if param.is_a?(ActionController::Parameters)
|
6
|
+
raise ArgumentError unless param.respond_to?(:split)
|
7
|
+
|
8
|
+
Hash[param.split(options[:delimiter] || ",").map { |c| c.split(options[:separator] || ":") }]
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def argument_validation
|
14
|
+
raise ArgumentError unless type == Hash
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RailsParam
|
2
|
+
class Coercion
|
3
|
+
class TimeParam < VirtualParam
|
4
|
+
def coerce
|
5
|
+
return type.strptime(param, options[:format]) if options[:format].present?
|
6
|
+
|
7
|
+
type.parse(param)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def argument_validation
|
13
|
+
raise ArgumentError unless type.respond_to?(:parse)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module RailsParam
|
2
|
+
class Coercion
|
3
|
+
class VirtualParam
|
4
|
+
attr_reader :param, :options, :type
|
5
|
+
|
6
|
+
def initialize(param:, options: nil, type: nil)
|
7
|
+
@param = param
|
8
|
+
@options = options
|
9
|
+
@type = type
|
10
|
+
argument_validation
|
11
|
+
end
|
12
|
+
|
13
|
+
def coerce
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def argument_validation
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module RailsParam
|
2
|
+
class Coercion
|
3
|
+
attr_reader :coercion, :param
|
4
|
+
|
5
|
+
PARAM_TYPE_MAPPING = {
|
6
|
+
Integer => IntegerParam,
|
7
|
+
Float => FloatParam,
|
8
|
+
String => StringParam,
|
9
|
+
Array => ArrayParam,
|
10
|
+
Hash => HashParam,
|
11
|
+
BigDecimal => BigDecimalParam,
|
12
|
+
Date => TimeParam,
|
13
|
+
DateTime => TimeParam,
|
14
|
+
Time => TimeParam,
|
15
|
+
TrueClass => BooleanParam,
|
16
|
+
FalseClass => BooleanParam,
|
17
|
+
boolean: BooleanParam
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
TIME_TYPES = [Date, DateTime, Time].freeze
|
21
|
+
BOOLEAN_TYPES = [TrueClass, FalseClass, :boolean].freeze
|
22
|
+
|
23
|
+
def initialize(param, type, options)
|
24
|
+
@param = param
|
25
|
+
@coercion = klass_for(type).new(param: param, options: options, type: type)
|
26
|
+
end
|
27
|
+
|
28
|
+
def klass_for(type)
|
29
|
+
klass = PARAM_TYPE_MAPPING[type]
|
30
|
+
return klass if klass
|
31
|
+
|
32
|
+
raise TypeError
|
33
|
+
end
|
34
|
+
|
35
|
+
def coerce
|
36
|
+
return nil if param.nil?
|
37
|
+
|
38
|
+
coercion.coerce
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module RailsParam
|
2
|
+
class InvalidParameterError < StandardError
|
3
|
+
attr_accessor :param, :options
|
4
|
+
|
5
|
+
def initialize(message, param: nil, options: {})
|
6
|
+
self.param = param
|
7
|
+
self.options = options
|
8
|
+
super(message)
|
9
|
+
end
|
10
|
+
|
11
|
+
def message
|
12
|
+
return options[:message] if options.is_a?(Hash) && options.key?(:message)
|
13
|
+
|
14
|
+
super
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/rails_param/param.rb
CHANGED
@@ -1,177 +1,5 @@
|
|
1
1
|
module RailsParam
|
2
|
-
|
3
|
-
|
4
|
-
DEFAULT_PRECISION = 14
|
5
|
-
TIME_TYPES = [Date, DateTime, Time].freeze
|
6
|
-
STRING_OR_TIME_TYPES = ([String] + TIME_TYPES).freeze
|
7
|
-
|
8
|
-
class InvalidParameterError < StandardError
|
9
|
-
attr_accessor :param, :options
|
10
|
-
|
11
|
-
def message
|
12
|
-
return options[:message] if options.is_a?(Hash) && options.key?(:message)
|
13
|
-
super
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
class MockController
|
18
|
-
include RailsParam::Param
|
19
|
-
attr_accessor :params
|
20
|
-
end
|
21
|
-
|
22
|
-
def param!(name, type, options = {}, &block)
|
23
|
-
name = name.to_s unless name.is_a? Integer # keep index for validating elements
|
24
|
-
|
25
|
-
return unless params.include?(name) || check_param_presence?(options[:default]) || options[:required]
|
26
|
-
|
27
|
-
begin
|
28
|
-
params[name] = coerce(params[name], type, options)
|
29
|
-
|
30
|
-
# set default
|
31
|
-
if params[name].nil? && check_param_presence?(options[:default])
|
32
|
-
params[name] = options[:default].respond_to?(:call) ? options[:default].call : options[:default]
|
33
|
-
end
|
34
|
-
|
35
|
-
# validate presence
|
36
|
-
if params[name].nil? && options[:required]
|
37
|
-
raise InvalidParameterError, "Parameter #{name} is required"
|
38
|
-
end
|
39
|
-
|
40
|
-
# apply transformation
|
41
|
-
if params.include?(name) && options[:transform]
|
42
|
-
params[name] = options[:transform].to_proc.call(params[name])
|
43
|
-
end
|
44
|
-
|
45
|
-
# validate
|
46
|
-
validate!(params[name], name, options)
|
47
|
-
|
48
|
-
if block_given?
|
49
|
-
if type == Array
|
50
|
-
params[name].each_with_index do |element, i|
|
51
|
-
if element.is_a?(Hash) || element.is_a?(ActionController::Parameters)
|
52
|
-
recurse element, &block
|
53
|
-
else
|
54
|
-
params[name][i] = recurse({ i => element }, i, &block) # supply index as key unless value is hash
|
55
|
-
end
|
56
|
-
end
|
57
|
-
else
|
58
|
-
recurse params[name], &block
|
59
|
-
end
|
60
|
-
end
|
61
|
-
params[name]
|
62
|
-
|
63
|
-
rescue InvalidParameterError => exception
|
64
|
-
exception.param ||= name
|
65
|
-
exception.options ||= options
|
66
|
-
raise exception
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
# TODO: should we reintegrate this method?
|
71
|
-
# def one_of!(*names)
|
72
|
-
# count = 0
|
73
|
-
# names.each do |name|
|
74
|
-
# if params[name] and params[name].present?
|
75
|
-
# count += 1
|
76
|
-
# next unless count > 1
|
77
|
-
#
|
78
|
-
# error = "Parameters #{names.join(', ')} are mutually exclusive"
|
79
|
-
# if content_type and content_type.match(mime_type(:json))
|
80
|
-
# error = {message: error}.to_json
|
81
|
-
# end
|
82
|
-
#
|
83
|
-
# # do something with error object
|
84
|
-
# end
|
85
|
-
# end
|
86
|
-
# end
|
87
|
-
|
88
|
-
private
|
89
|
-
|
90
|
-
def check_param_presence? param
|
91
|
-
not param.nil?
|
92
|
-
end
|
93
|
-
|
94
|
-
def recurse(params, index = nil)
|
95
|
-
raise InvalidParameterError, 'no block given' unless block_given?
|
96
|
-
controller = RailsParam::Param::MockController.new
|
97
|
-
controller.params = params
|
98
|
-
yield(controller, index)
|
99
|
-
end
|
100
|
-
|
101
|
-
def coerce(param, type, options = {})
|
102
|
-
begin
|
103
|
-
return nil if param.nil?
|
104
|
-
return param if (param.is_a?(type) rescue false)
|
105
|
-
if (param.is_a?(Array) && type != Array) || ((param.is_a?(Hash) || param.is_a?(ActionController::Parameters)) && type != Hash)
|
106
|
-
raise ArgumentError
|
107
|
-
end
|
108
|
-
return param if (param.is_a?(ActionController::Parameters) && type == Hash rescue false)
|
109
|
-
return Integer(param) if type == Integer
|
110
|
-
return Float(param) if type == Float
|
111
|
-
return String(param) if type == String
|
112
|
-
if TIME_TYPES.include? type
|
113
|
-
if options[:format].present?
|
114
|
-
return type.strptime(param, options[:format])
|
115
|
-
else
|
116
|
-
return type.parse(param)
|
117
|
-
end
|
118
|
-
end
|
119
|
-
raise ArgumentError if (type == Array || type == Hash) && !param.respond_to?(:split)
|
120
|
-
return Array(param.split(options[:delimiter] || ",")) if type == Array
|
121
|
-
return Hash[param.split(options[:delimiter] || ",").map { |c| c.split(options[:separator] || ":") }] if type == Hash
|
122
|
-
if type == TrueClass || type == FalseClass || type == :boolean
|
123
|
-
return false if /^(false|f|no|n|0)$/i === param.to_s
|
124
|
-
return true if /^(true|t|yes|y|1)$/i === param.to_s
|
125
|
-
|
126
|
-
raise ArgumentError
|
127
|
-
end
|
128
|
-
if type == BigDecimal
|
129
|
-
param = param.delete('$,').strip.to_f if param.is_a?(String)
|
130
|
-
return BigDecimal(param, (options[:precision] || DEFAULT_PRECISION))
|
131
|
-
end
|
132
|
-
return nil
|
133
|
-
rescue ArgumentError, TypeError
|
134
|
-
raise InvalidParameterError, "'#{param}' is not a valid #{type}"
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def validate!(param, param_name, options)
|
139
|
-
options.each do |key, value|
|
140
|
-
case key
|
141
|
-
when :blank
|
142
|
-
raise InvalidParameterError, "Parameter #{param_name} cannot be blank" if !value && case param
|
143
|
-
when String
|
144
|
-
!(/\S/ === param)
|
145
|
-
when Array, Hash, ActionController::Parameters
|
146
|
-
param.empty?
|
147
|
-
else
|
148
|
-
param.nil?
|
149
|
-
end
|
150
|
-
when :format
|
151
|
-
raise InvalidParameterError, "Parameter #{param_name} must be a string if using the format validation" unless STRING_OR_TIME_TYPES.any? { |cls| param.kind_of? cls }
|
152
|
-
raise InvalidParameterError, "Parameter #{param_name} must match format #{value}" if param.kind_of?(String) && param !~ value
|
153
|
-
when :is
|
154
|
-
raise InvalidParameterError, "Parameter #{param_name} must be #{value}" unless param === value
|
155
|
-
when :in, :within, :range
|
156
|
-
raise InvalidParameterError, "Parameter #{param_name} must be within #{value}" unless param.nil? || case value
|
157
|
-
when Range
|
158
|
-
value.include?(param)
|
159
|
-
else
|
160
|
-
Array(value).include?(param)
|
161
|
-
end
|
162
|
-
when :min
|
163
|
-
raise InvalidParameterError, "Parameter #{param_name} cannot be less than #{value}" unless param.nil? || value <= param
|
164
|
-
when :max
|
165
|
-
raise InvalidParameterError, "Parameter #{param_name} cannot be greater than #{value}" unless param.nil? || value >= param
|
166
|
-
when :min_length
|
167
|
-
raise InvalidParameterError, "Parameter #{param_name} cannot have length less than #{value}" unless param.nil? || value <= param.length
|
168
|
-
when :max_length
|
169
|
-
raise InvalidParameterError, "Parameter #{param_name} cannot have length greater than #{value}" unless param.nil? || value >= param.length
|
170
|
-
when :custom
|
171
|
-
value.call(param)
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
2
|
+
def param!(name, type, options = {}, &block)
|
3
|
+
ParamEvaluator.new(params).param!(name, type, options, &block)
|
176
4
|
end
|
177
5
|
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module RailsParam
|
2
|
+
class ParamEvaluator
|
3
|
+
attr_accessor :params
|
4
|
+
|
5
|
+
def initialize(params)
|
6
|
+
@params = params
|
7
|
+
end
|
8
|
+
|
9
|
+
def param!(name, type, options = {}, &block)
|
10
|
+
name = name.is_a?(Integer)? name : name.to_s
|
11
|
+
return unless params.include?(name) || check_param_presence?(options[:default]) || options[:required]
|
12
|
+
|
13
|
+
# coerce value
|
14
|
+
coerced_value = coerce(
|
15
|
+
params[name],
|
16
|
+
type,
|
17
|
+
options
|
18
|
+
)
|
19
|
+
parameter = RailsParam::Parameter.new(
|
20
|
+
name: name,
|
21
|
+
value: coerced_value,
|
22
|
+
type: type,
|
23
|
+
options: options,
|
24
|
+
&block
|
25
|
+
)
|
26
|
+
|
27
|
+
parameter.set_default if parameter.should_set_default?
|
28
|
+
|
29
|
+
# validate presence
|
30
|
+
if params[name].nil? && options[:required]
|
31
|
+
raise InvalidParameterError.new(
|
32
|
+
"Parameter #{name} is required",
|
33
|
+
param: name,
|
34
|
+
options: options
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
recurse_on_parameter(parameter, &block) if block_given?
|
39
|
+
|
40
|
+
# apply transformation
|
41
|
+
parameter.transform if params.include?(name) && options[:transform]
|
42
|
+
|
43
|
+
# validate
|
44
|
+
validate!(parameter)
|
45
|
+
|
46
|
+
# set params value
|
47
|
+
params[name] = parameter.value
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def recurse_on_parameter(parameter, &block)
|
53
|
+
if parameter.type == Array
|
54
|
+
parameter.value.each_with_index do |element, i|
|
55
|
+
if element.is_a?(Hash) || element.is_a?(ActionController::Parameters)
|
56
|
+
recurse element, &block
|
57
|
+
else
|
58
|
+
parameter.value[i] = recurse({ i => element }, i, &block) # supply index as key unless value is hash
|
59
|
+
end
|
60
|
+
end
|
61
|
+
else
|
62
|
+
recurse parameter.value, &block
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def recurse(element, index = nil)
|
67
|
+
raise InvalidParameterError, 'no block given' unless block_given?
|
68
|
+
|
69
|
+
yield(ParamEvaluator.new(element), index)
|
70
|
+
end
|
71
|
+
|
72
|
+
def check_param_presence? param
|
73
|
+
!param.nil?
|
74
|
+
end
|
75
|
+
|
76
|
+
def coerce(param, type, options = {})
|
77
|
+
begin
|
78
|
+
return param if (param.is_a?(type) rescue false)
|
79
|
+
|
80
|
+
Coercion.new(param, type, options).coerce
|
81
|
+
rescue ArgumentError, TypeError
|
82
|
+
raise InvalidParameterError, "'#{param}' is not a valid #{type}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def validate!(param)
|
87
|
+
param.validate
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RailsParam
|
2
|
+
class Parameter
|
3
|
+
attr_accessor :name, :value, :options, :type
|
4
|
+
|
5
|
+
TIME_TYPES = [Date, DateTime, Time].freeze
|
6
|
+
STRING_OR_TIME_TYPES = ([String] + TIME_TYPES).freeze
|
7
|
+
|
8
|
+
def initialize(name:, value:, options: {}, type: nil)
|
9
|
+
@name = name
|
10
|
+
@value = value
|
11
|
+
@options = options
|
12
|
+
@type = type
|
13
|
+
end
|
14
|
+
|
15
|
+
def should_set_default?
|
16
|
+
value.nil? && check_param_presence?(options[:default])
|
17
|
+
end
|
18
|
+
|
19
|
+
def set_default
|
20
|
+
self.value = options[:default].respond_to?(:call) ? options[:default].call : options[:default]
|
21
|
+
end
|
22
|
+
|
23
|
+
def transform
|
24
|
+
self.value = options[:transform].to_proc.call(value)
|
25
|
+
end
|
26
|
+
|
27
|
+
def validate
|
28
|
+
Validator.new(self).validate!
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def check_param_presence?(param)
|
34
|
+
!param.nil?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module RailsParam
|
2
|
+
class Validator
|
3
|
+
class Blank < Validator
|
4
|
+
def valid_value?
|
5
|
+
return false if parameter.options[:blank]
|
6
|
+
|
7
|
+
case value
|
8
|
+
when String
|
9
|
+
(/\S/ === value)
|
10
|
+
when Array, Hash, ActionController::Parameters
|
11
|
+
!value.empty?
|
12
|
+
else
|
13
|
+
!value.nil?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def error_message
|
20
|
+
"Parameter #{name} cannot be blank"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RailsParam
|
2
|
+
class Validator
|
3
|
+
class Format < Validator
|
4
|
+
def valid_value?
|
5
|
+
matches_time_types? || string_in_format?
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
TIME_TYPES = [Date, DateTime, Time].freeze
|
11
|
+
STRING_OR_TIME_TYPES = ([String] + TIME_TYPES).freeze
|
12
|
+
|
13
|
+
def error_message
|
14
|
+
"Parameter #{name} must be a string if using the format validation" unless matches_string_or_time_types?
|
15
|
+
"Parameter #{name} must match format #{options[:format]}" unless string_in_format?
|
16
|
+
end
|
17
|
+
|
18
|
+
def matches_time_types?
|
19
|
+
TIME_TYPES.any? { |cls| value.is_a? cls }
|
20
|
+
end
|
21
|
+
|
22
|
+
def matches_string_or_time_types?
|
23
|
+
STRING_OR_TIME_TYPES.any? { |cls| value.is_a? cls }
|
24
|
+
end
|
25
|
+
|
26
|
+
def string_in_format?
|
27
|
+
value =~ options[:format] && value.kind_of?(String)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module RailsParam
|
2
|
+
class Validator
|
3
|
+
class In < Validator
|
4
|
+
def valid_value?
|
5
|
+
value.nil? || case options[:in]
|
6
|
+
when Range
|
7
|
+
options[:in].include?(value)
|
8
|
+
else
|
9
|
+
Array(options[:in]).include?(value)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def error_message
|
16
|
+
"Parameter #{parameter.name} must be within #{parameter.options[:in]}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RailsParam
|
2
|
+
class Validator
|
3
|
+
class MaxLength < Validator
|
4
|
+
def valid_value?
|
5
|
+
value.nil? || options[:max_length] >= value.length
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def error_message
|
11
|
+
"Parameter #{name} cannot have length greater than #{options[:max_length]}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module RailsParam
|
2
|
+
class Validator
|
3
|
+
class MinLength < Validator
|
4
|
+
def valid_value?
|
5
|
+
value.nil? || options[:min_length] <= value.length
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def error_message
|
11
|
+
"Parameter #{name} cannot have length less than #{options[:min_length]}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module RailsParam
|
4
|
+
class Validator
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
attr_reader :parameter
|
8
|
+
|
9
|
+
def_delegators :parameter, :name, :options, :value
|
10
|
+
|
11
|
+
VALIDATABLE_OPTIONS = [
|
12
|
+
:blank,
|
13
|
+
:custom,
|
14
|
+
:format,
|
15
|
+
:in,
|
16
|
+
:is,
|
17
|
+
:max_length,
|
18
|
+
:max,
|
19
|
+
:min_length,
|
20
|
+
:min,
|
21
|
+
:required
|
22
|
+
].freeze
|
23
|
+
|
24
|
+
def initialize(parameter)
|
25
|
+
@parameter = parameter
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate!
|
29
|
+
options.each_key do |key|
|
30
|
+
next unless VALIDATABLE_OPTIONS.include? key
|
31
|
+
|
32
|
+
class_name = camelize(key)
|
33
|
+
Validator.const_get(class_name).new(parameter).valid!
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def valid!
|
38
|
+
return if valid_value?
|
39
|
+
|
40
|
+
raise InvalidParameterError.new(
|
41
|
+
error_message,
|
42
|
+
param: name,
|
43
|
+
options: options
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def camelize(term)
|
50
|
+
string = term.to_s
|
51
|
+
string.split('_').collect(&:capitalize).join
|
52
|
+
end
|
53
|
+
|
54
|
+
def error_message
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def valid_value?
|
59
|
+
# Should be overwritten in subclass
|
60
|
+
false
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/rails_param/version.rb
CHANGED
data/lib/rails_param.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require 'rails_param/param'
|
2
|
+
Dir[File.join(__dir__, 'rails_param/validator', '*.rb')].sort.each { |file| require file }
|
3
|
+
Dir[File.join(__dir__, 'rails_param/coercion', '*.rb')].sort.reverse.each { |file| require file }
|
4
|
+
Dir[File.join(__dir__, 'rails_param', '*.rb')].sort.each { |file| require file }
|
2
5
|
|
3
6
|
ActiveSupport.on_load(:action_controller) do
|
4
|
-
include RailsParam
|
7
|
+
include RailsParam
|
5
8
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_param
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nicolas Blanco
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -88,7 +88,31 @@ extra_rdoc_files: []
|
|
88
88
|
files:
|
89
89
|
- README.md
|
90
90
|
- lib/rails_param.rb
|
91
|
+
- lib/rails_param/coercion.rb
|
92
|
+
- lib/rails_param/coercion/array_param.rb
|
93
|
+
- lib/rails_param/coercion/big_decimal_param.rb
|
94
|
+
- lib/rails_param/coercion/boolean_param.rb
|
95
|
+
- lib/rails_param/coercion/float_param.rb
|
96
|
+
- lib/rails_param/coercion/hash_param.rb
|
97
|
+
- lib/rails_param/coercion/integer_param.rb
|
98
|
+
- lib/rails_param/coercion/string_param.rb
|
99
|
+
- lib/rails_param/coercion/time_param.rb
|
100
|
+
- lib/rails_param/coercion/virtual_param.rb
|
101
|
+
- lib/rails_param/invalid_parameter_error.rb
|
91
102
|
- lib/rails_param/param.rb
|
103
|
+
- lib/rails_param/param_evaluator.rb
|
104
|
+
- lib/rails_param/parameter.rb
|
105
|
+
- lib/rails_param/validator.rb
|
106
|
+
- lib/rails_param/validator/blank.rb
|
107
|
+
- lib/rails_param/validator/custom.rb
|
108
|
+
- lib/rails_param/validator/format.rb
|
109
|
+
- lib/rails_param/validator/in.rb
|
110
|
+
- lib/rails_param/validator/is.rb
|
111
|
+
- lib/rails_param/validator/max.rb
|
112
|
+
- lib/rails_param/validator/max_length.rb
|
113
|
+
- lib/rails_param/validator/min.rb
|
114
|
+
- lib/rails_param/validator/min_length.rb
|
115
|
+
- lib/rails_param/validator/required.rb
|
92
116
|
- lib/rails_param/version.rb
|
93
117
|
homepage: http://github.com/nicolasblanco/rails_param
|
94
118
|
licenses:
|