sinatra-params-validator 0.0.1
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.
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +116 -0
- data/VERSION +1 -0
- data/lib/rack/validator/sinatra.rb +234 -0
- data/sinatra-params-validator.gemspec +14 -0
- metadata +54 -0
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 tsov, lube8uy
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
# sinatra-params-validator
|
2
|
+
========================
|
3
|
+
|
4
|
+
## Description
|
5
|
+
|
6
|
+
This sinatra module validates the incoming parameter and lets you configure the pattern.
|
7
|
+
Once it's registered with your sinatra app, it will act as a before filter, that validates your parameters.
|
8
|
+
You can configure it with the newly available sinatra method `validation_required`.
|
9
|
+
|
10
|
+
## Sinatra Module
|
11
|
+
|
12
|
+
Configure your routes to require parameters and validate their values. If the
|
13
|
+
validator finds errors, it will execute sinatras halt method, which will prevent
|
14
|
+
invocation of your sinatra code block, and set the response status to 400. The missing
|
15
|
+
or invalid parameters can be found in the environment variable, like in the example
|
16
|
+
below. That means you can customize your own error responses, for example by catching the errors
|
17
|
+
with some middleware.
|
18
|
+
|
19
|
+
### Examples
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
require 'sinatra'
|
23
|
+
|
24
|
+
class App < Sinatra::Base
|
25
|
+
register Rack::Validator::Sinatra
|
26
|
+
|
27
|
+
helpers do
|
28
|
+
def missing_parameters
|
29
|
+
@env['validator.missing']
|
30
|
+
end
|
31
|
+
|
32
|
+
def invalid_parameters
|
33
|
+
@env['validator.invalid']
|
34
|
+
end
|
35
|
+
|
36
|
+
def messages
|
37
|
+
@env['validator.messages']
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
after do
|
42
|
+
puts missing_parameters
|
43
|
+
puts invalid_parameters
|
44
|
+
puts messages
|
45
|
+
puts params
|
46
|
+
end
|
47
|
+
|
48
|
+
validation_required :GET, '/', :params => [
|
49
|
+
{ :name => :name, :required => true },
|
50
|
+
{ :name => :email, :type => :email, :required => true },
|
51
|
+
{ :name => :age, :range => [ 0, 120 ], :default => 1000 },
|
52
|
+
{ :name => :latitude, :type => :float, :default => 0.0 },
|
53
|
+
{ :name => :longitude, :type => :float, :default => 0.0 },
|
54
|
+
{ :name => :message },
|
55
|
+
{ :name => :price, :matches => /^[\d]*.[\d]{2}$/ }
|
56
|
+
]
|
57
|
+
|
58
|
+
get '/' do
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
validation_required :POST, '/group', :params => [
|
63
|
+
{ :name => :name, :required => true }
|
64
|
+
]
|
65
|
+
|
66
|
+
post '/group' do
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
Try it out yourself and run this in the root directory `rackup example/app.rb`.
|
74
|
+
|
75
|
+
## Validator class
|
76
|
+
|
77
|
+
A class with several methods to validate and clean data from sinatra params holder.
|
78
|
+
Can be used for an adopter for other libraries/frameworks, like rails.
|
79
|
+
|
80
|
+
### Examples
|
81
|
+
|
82
|
+
Initialize class in lazy mode, this means that once a validation fail the following ones are not executed:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
validator = Rack::Validator.new(params)
|
86
|
+
#required_3 is not present
|
87
|
+
validator.required [:required_1, :required_2, :required_3]
|
88
|
+
validator.trim
|
89
|
+
validator.downcase [:required_2, :other_param]
|
90
|
+
validator.is_in_range 3, 32, :required_1
|
91
|
+
validator.is_email :contact
|
92
|
+
validator.matches /[a-z]{2}_[A-Z]{2}|[a-z]{2}/i, :locale
|
93
|
+
|
94
|
+
if validator.has_errors?
|
95
|
+
p validator.messages.join('|')
|
96
|
+
#Inputs "required_3 is required"
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
If you want to get all the errors at the end of the validation calls pass false as second parameter in the constructor:
|
101
|
+
validator = Rack::Validator.new(params, true)
|
102
|
+
|
103
|
+
Available methods:
|
104
|
+
|
105
|
+
* trim
|
106
|
+
* downcase
|
107
|
+
* required
|
108
|
+
* is_integer
|
109
|
+
* is_float
|
110
|
+
* is_greater_equal_than
|
111
|
+
* is_in_range
|
112
|
+
* is_less_equal_than
|
113
|
+
* is_email
|
114
|
+
* matches
|
115
|
+
|
116
|
+
To see more examples check tests/params_validator_spec.rb
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
@@ -0,0 +1,234 @@
|
|
1
|
+
require 'rack'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
class Validator
|
5
|
+
|
6
|
+
attr_reader :invalid_params
|
7
|
+
attr_reader :missing_params
|
8
|
+
attr_reader :messages
|
9
|
+
attr_accessor :lazy_mode
|
10
|
+
|
11
|
+
def initialize(params, lazy_mode = true)
|
12
|
+
@params = params
|
13
|
+
@invalid_params = []
|
14
|
+
@missing_params = []
|
15
|
+
@messages = []
|
16
|
+
@lazy_mode = lazy_mode
|
17
|
+
end
|
18
|
+
|
19
|
+
def has_errors?
|
20
|
+
@invalid_params.length > 0 or @missing_params.length > 0
|
21
|
+
end
|
22
|
+
|
23
|
+
def trim
|
24
|
+
@params.each_key { |k| @params[k] = @params[k].strip if @params[k]}
|
25
|
+
end
|
26
|
+
|
27
|
+
def downcase(keys)
|
28
|
+
keys.each { |k| @params[k.to_s] = @params[k.to_s].to_s.downcase if @params[k.to_s]}
|
29
|
+
end
|
30
|
+
|
31
|
+
def required(keys)
|
32
|
+
if lazy_check_disabled
|
33
|
+
keys.each { |k|
|
34
|
+
k = k.to_s
|
35
|
+
unless @params.has_key?(k)
|
36
|
+
@invalid_params.push(k)
|
37
|
+
@missing_params.push(k)
|
38
|
+
@messages.push("#{k} is required")
|
39
|
+
end
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def is_integer(key)
|
45
|
+
if lazy_check_disabled
|
46
|
+
key = key.to_s
|
47
|
+
value = @params[key]
|
48
|
+
unless is_valid_integer(value)
|
49
|
+
@invalid_params.push(key)
|
50
|
+
@messages.push("#{key} is not an integer")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def is_float(key)
|
56
|
+
if lazy_check_disabled
|
57
|
+
key = key.to_s
|
58
|
+
value = @params[key]
|
59
|
+
unless is_valid_float(value)
|
60
|
+
@invalid_params.push(key)
|
61
|
+
@messages.push("#{key} is not a float")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def is_greater_equal_than(min, key)
|
67
|
+
if lazy_check_disabled
|
68
|
+
key = key.to_s
|
69
|
+
if !is_valid_float(@params[key])
|
70
|
+
if !@params[key] || @params[key].length < min
|
71
|
+
@invalid_params.push(key)
|
72
|
+
@messages.push("#{key} length is less than #{min}")
|
73
|
+
end
|
74
|
+
else
|
75
|
+
value = is_valid_integer(@params[key]) ? @params[key].to_i : @params[key].to_f
|
76
|
+
if !value || value < min
|
77
|
+
@invalid_params.push(key)
|
78
|
+
@messages.push("#{key} is less than #{min}")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def is_in_range(min, max, key)
|
85
|
+
if lazy_check_disabled
|
86
|
+
key = key.to_s
|
87
|
+
unless is_valid_float(@params[key])
|
88
|
+
if !@params[key] || @params[key].length < min || @params[key].length > max
|
89
|
+
@invalid_params.push(key)
|
90
|
+
@messages.push("#{key} length is not in range #{min},#{max}")
|
91
|
+
end
|
92
|
+
else
|
93
|
+
value = is_valid_integer(@params[key]) ? @params[key].to_i : @params[key].to_f
|
94
|
+
if !value || value < min || value > max
|
95
|
+
@invalid_params.push(key)
|
96
|
+
@messages.push("#{key} is not in range #{min},#{max}")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def is_less_equal_than(max, key)
|
103
|
+
if lazy_check_disabled
|
104
|
+
key = key.to_s
|
105
|
+
unless is_valid_float(@params[key])
|
106
|
+
if !@params[key] || @params[key].length > max
|
107
|
+
@invalid_params.push(key)
|
108
|
+
@messages.push("#{key} length is greater than #{max}")
|
109
|
+
end
|
110
|
+
else
|
111
|
+
value = is_valid_integer(@params[key]) ? @params[key].to_i : @params[key].to_f
|
112
|
+
if !value || value > max
|
113
|
+
@invalid_params.push(key)
|
114
|
+
@messages.push("#{key} is greater than #{max}")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def is_email(key)
|
121
|
+
if lazy_check_disabled
|
122
|
+
key = key.to_s
|
123
|
+
unless @params[key].to_s[/^\S+@\S+\.\S+$/]
|
124
|
+
@invalid_params.push(key)
|
125
|
+
@messages.push("#{key} is not a valid email")
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def matches(regexp, key)
|
131
|
+
if lazy_check_disabled
|
132
|
+
key = key.to_s
|
133
|
+
unless @params[key] =~ regexp
|
134
|
+
@invalid_params.push(key)
|
135
|
+
@messages.push("#{key} is not a valid expression")
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def lazy_check_disabled
|
143
|
+
return !@lazy_mode || !has_errors?
|
144
|
+
end
|
145
|
+
|
146
|
+
def is_valid_integer(value)
|
147
|
+
key = key.to_s
|
148
|
+
value.to_i.to_s == value.to_s
|
149
|
+
end
|
150
|
+
|
151
|
+
def is_valid_float(value)
|
152
|
+
key = key.to_s
|
153
|
+
value.to_f.to_s == value.to_s || is_valid_integer(value)
|
154
|
+
end
|
155
|
+
|
156
|
+
module Sinatra
|
157
|
+
|
158
|
+
def validation_required(method, path, options = { })
|
159
|
+
before path do
|
160
|
+
validate_parameters(options) if same_method? method
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
module Helpers
|
165
|
+
def same_method?(method)
|
166
|
+
@env['REQUEST_METHOD'] == method.to_s
|
167
|
+
end
|
168
|
+
|
169
|
+
# TODO: Needs a general cleanup!!!
|
170
|
+
def validate_parameters(options)
|
171
|
+
validator = Rack::Validator.new params, false
|
172
|
+
required_params = [ ]
|
173
|
+
integer_params = [ ]
|
174
|
+
float_params = [ ]
|
175
|
+
email_params = [ ]
|
176
|
+
range_params = [ ]
|
177
|
+
matches_params = [ ]
|
178
|
+
default_params = [ ]
|
179
|
+
|
180
|
+
options[:params].each do |param|
|
181
|
+
required_params << (param[:name]) if param[:required]
|
182
|
+
integer_params << (param) if param[:type] == :integer
|
183
|
+
float_params << (param) if param[:type] == :float
|
184
|
+
email_params << (param) if param[:type] == :email
|
185
|
+
range_params << (param) if param[:range]
|
186
|
+
matches_params << (param) if param[:matches]
|
187
|
+
default_params << (param) if param[:default]
|
188
|
+
end
|
189
|
+
|
190
|
+
validator.required required_params
|
191
|
+
integer_params.each do |param|
|
192
|
+
validator.is_integer param[:name] unless params[param[:name].to_s].nil?
|
193
|
+
end
|
194
|
+
float_params.each do |param|
|
195
|
+
validator.is_float param[:name] unless params[param[:name].to_s].nil?
|
196
|
+
end
|
197
|
+
email_params.each do |param|
|
198
|
+
validator.is_email param[:name] unless params[param[:name].to_s].nil?
|
199
|
+
end
|
200
|
+
range_params.each do |param|
|
201
|
+
validator.is_in_range param[:range].first, param[:range].last, param[:name] unless params[param[:name].to_s].nil?
|
202
|
+
end
|
203
|
+
matches_params.each do |param|
|
204
|
+
validator.matches param[:matches], param[:name] unless params[param[:name].to_s].nil?
|
205
|
+
end
|
206
|
+
|
207
|
+
default_params.each do |param|
|
208
|
+
if params[param[:name].to_s].nil?
|
209
|
+
params[param[:name].to_s] = param[:default]
|
210
|
+
validator.invalid_params.delete param[:name]
|
211
|
+
validator.missing_params.delete param[:name]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
if validator.has_errors?
|
216
|
+
@env['validator.missing'] = validator.missing_params
|
217
|
+
@env['validator.invalid'] = validator.invalid_params
|
218
|
+
@env['validator.messages'] = validator.messages
|
219
|
+
halt missing_params!
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def missing_params!
|
224
|
+
@response.status = 400
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def self.registered(base)
|
229
|
+
base.helpers Helpers
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
$: << File.dirname(__FILE__) + "/lib"
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "sinatra-params-validator"
|
5
|
+
spec.version = IO.read("VERSION")
|
6
|
+
spec.authors = ["tsov", "lube8buy"]
|
7
|
+
spec.email = "tsov@me.com"
|
8
|
+
spec.homepage = "http://github.com/tsov/#{spec.name}"
|
9
|
+
spec.summary = "A Sinatra Module to validate incoming parameters"
|
10
|
+
spec.description = "This sinatra module validates the incoming parameter and lets you configure the pattern."
|
11
|
+
|
12
|
+
spec.files = Dir["lib/**/*", "VERSION", "LICENSE", "README.md", "Gemfile", "*.gemspec"]
|
13
|
+
spec.license = "MIT"
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sinatra-params-validator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- tsov
|
9
|
+
- lube8buy
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2013-05-30 00:00:00.000000000 Z
|
14
|
+
dependencies: []
|
15
|
+
description: This sinatra module validates the incoming parameter and lets you configure
|
16
|
+
the pattern.
|
17
|
+
email: tsov@me.com
|
18
|
+
executables: []
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- lib/rack/validator/sinatra.rb
|
23
|
+
- VERSION
|
24
|
+
- LICENSE
|
25
|
+
- README.md
|
26
|
+
- Gemfile
|
27
|
+
- sinatra-params-validator.gemspec
|
28
|
+
homepage: http://github.com/tsov/sinatra-params-validator
|
29
|
+
licenses:
|
30
|
+
- MIT
|
31
|
+
post_install_message:
|
32
|
+
rdoc_options: []
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubyforge_project:
|
49
|
+
rubygems_version: 1.8.24
|
50
|
+
signing_key:
|
51
|
+
specification_version: 3
|
52
|
+
summary: A Sinatra Module to validate incoming parameters
|
53
|
+
test_files: []
|
54
|
+
has_rdoc:
|