rails_param 0.11.2 → 1.0.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 +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:
|