sinatra-browse 0.2 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +79 -8
- data/lib/sinatra/browse/route.rb +8 -8
- data/lib/sinatra/browse.rb +26 -9
- metadata +1 -2
- data/lib/sinatra/browse/parameter.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 582bf7da2ddf0b18a42136d6fb4c52b8bf929f46
|
4
|
+
data.tar.gz: 4c37bf5a4830a81b5c11c5c4cf4f3f95e17f8252
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b2bd51af3b6e7532122077dd7496e23695946d5b23d17c061fbeff1be7d5507761a3bca5dd6452febdc993a368fc938bb4248edddd6420ab1090d03abdb725c
|
7
|
+
data.tar.gz: 634102de18bd57e1877dc1672b8e5b1df5d0b2db7172de3041c10b7ef6dea538a24f23390e206f26e4ec31cbdd637bf7b55001e95d3e38b9219124a90835b943
|
data/README.md
CHANGED
@@ -96,12 +96,21 @@ param :order, :String, in: ["ascending", "descending"]
|
|
96
96
|
param :alphanumeric, :String, format: /^[0-9A-Za-z]*$/
|
97
97
|
```
|
98
98
|
|
99
|
+
## Parameter transformation
|
100
|
+
|
101
|
+
You can use transform to execute a quick method on any prameter provided. Anything that responds to *to_proc* will do.
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
param :only_caps, :String, transform: :upcase
|
105
|
+
param :power_of_two, :Integer, transform: proc { |n| n * n }
|
106
|
+
```
|
107
|
+
|
99
108
|
## Error handling
|
100
109
|
|
101
110
|
When a validation fails, a standard 400 error will be returned. You can override this and do your own error handling using `on_error`.
|
102
111
|
|
103
112
|
```ruby
|
104
|
-
param :lets_fail, :Integer, in: 1..9, on_error: proc { halt
|
113
|
+
param :lets_fail, :Integer, in: 1..9, on_error: proc { halt 400, "Must be between 1 and 9!" }
|
105
114
|
get 'example_route' do
|
106
115
|
# This is the scope that the on_error proc will be executed in.
|
107
116
|
end
|
@@ -109,20 +118,82 @@ end
|
|
109
118
|
|
110
119
|
If a request is made that fails validation on the *lets_fail* parameter, then the proc provided to `on_error` will be called **in the same scope as your route**. Therefore you have access to Sinatra keywords such as *halt*.
|
111
120
|
|
112
|
-
|
121
|
+
### The error hash
|
113
122
|
|
114
|
-
|
123
|
+
If you want to write a bit more intricate error handling, you can add *the error hash* as an argument to your `on_error` proc. This hash holds some extra information about what exactly went wrong.
|
115
124
|
|
116
125
|
```ruby
|
117
|
-
param :
|
118
|
-
|
126
|
+
param :lets_fail, :Integer, in: 1..9, required: true, on_error: proc { |error_hash|
|
127
|
+
case error_hash[:reason]
|
128
|
+
when :in
|
129
|
+
halt 400, "Must be between 1 and 9!"
|
130
|
+
when :required
|
131
|
+
halt 400, "Why u no give us lets_fail?"
|
132
|
+
end
|
133
|
+
}
|
134
|
+
get 'example_route' do
|
135
|
+
# Some code
|
136
|
+
end
|
137
|
+
```
|
138
|
+
|
139
|
+
The error hash contains the following keys:
|
140
|
+
|
141
|
+
* `:reason` This tells you what validation failed. Possible values could be `:in`, `:required`, `:format`, etc.
|
142
|
+
* `:parameter` The name of the faulty parameter.
|
143
|
+
* `:value` The value our parameter had which caused it to fail validation.
|
144
|
+
* `:type` The type of our parameter. Could be `:String`, `:Integer`, etc.
|
145
|
+
* Any validation keys that were set in the parameter declaration will also be available in the error hash.
|
146
|
+
|
147
|
+
### Overriding default error behaviour
|
148
|
+
|
149
|
+
So we explained how to do error handling for single parameters. Now what if we wanted to set error handling for the entire application? You can do that with the `default_on_error` method.
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
default_on_error do |error_hash|
|
153
|
+
case error_hash[:reason]
|
154
|
+
when :required
|
155
|
+
halt 400, "#{error_hash[:parameter]} is required! provide it!"
|
156
|
+
else
|
157
|
+
_default_on_error(error_hash)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
param :a, :String, in: ["a"], required: true
|
162
|
+
param :b, :String, format: /^bbb$/
|
163
|
+
get "/features/default_error_override" do
|
164
|
+
# Again this is the scope that default_on_error is executed in
|
165
|
+
params.to_json
|
166
|
+
end
|
119
167
|
```
|
168
|
+
|
169
|
+
The block we passed to the `default_on_error` method will be called or every parameter in our application that fails validation and does not have its own `on_error` block. Notice how inside our `default_on_error`
|
170
|
+
|
171
|
+
You might notice that in our example, the `default_on_error` method makes a call to `_default_on_error`. The latter is a fallback to sinatra-browse's standard error behaviour. It's available form both the `default_on_error` block and procs passed to `on_error` in parameter declarations.
|
172
|
+
|
120
173
|
## Removing undefined parameters
|
121
174
|
|
122
175
|
By default sinatra-browse removes all parameters that weren't defined. You can disable this behaviour with the following line.
|
123
176
|
|
124
|
-
|
177
|
+
```ruby
|
178
|
+
disable :remove_undefined_parameters
|
179
|
+
```
|
180
|
+
|
181
|
+
You can also set a `allowed_undefined_parameters` variable to allow for a select few parameters that aren't removed.
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
set allowed_undefined_parameters: [ "id", "username", "password" ]
|
185
|
+
```
|
186
|
+
|
187
|
+
## Named parameters in route patterns
|
188
|
+
|
189
|
+
Unfortunately you are not able to use Sinatra-browse for named parameters in the route definition. Take the following example.
|
190
|
+
|
191
|
+
```ruby
|
192
|
+
get 'foo/:bar' do
|
193
|
+
# some code
|
194
|
+
end
|
195
|
+
```
|
125
196
|
|
126
|
-
You
|
197
|
+
You will ***not*** be able to define the parameter `bar`. This is because Sinatra-browse does its thing in a before block and these parameters aren't added to the `params` hash until the route itself gets executed.
|
127
198
|
|
128
|
-
|
199
|
+
Some exta discussion of this problem can be found [here](https://github.com/sinatra/sinatra/issues/417).
|
data/lib/sinatra/browse/route.rb
CHANGED
@@ -53,17 +53,17 @@
|
|
53
53
|
}
|
54
54
|
end
|
55
55
|
|
56
|
-
def delete_undefined(params,
|
57
|
-
params.delete_if { |i| !(self.has_parameter?(i) ||
|
56
|
+
def delete_undefined(params, allowed)
|
57
|
+
params.delete_if { |i| !(self.has_parameter?(i) || allowed.member?(i)) }
|
58
58
|
end
|
59
59
|
|
60
60
|
def validate(params)
|
61
61
|
@parameters.each { |k,v|
|
62
|
-
return fail_validation v, :required if !params[k] && v[:required]
|
62
|
+
return fail_validation k, params[k], v, :required if !params[k] && v[:required]
|
63
63
|
if params[k]
|
64
|
-
return fail_validation v, :depends_on if v[:depends_on] && !params[v[:depends_on]]
|
65
|
-
return fail_validation v, :in if v[:in] && !v[:in].member?(params[k])
|
66
|
-
return fail_validation v, :format if v[:type] == :String && v[:format] && !(params[k] =~ v[:format])
|
64
|
+
return fail_validation k, params[k], v, :depends_on if v[:depends_on] && !params[v[:depends_on]]
|
65
|
+
return fail_validation k, params[k], v, :in if v[:in] && !v[:in].member?(params[k])
|
66
|
+
return fail_validation k, params[k], v, :format if v[:type] == :String && v[:format] && !(params[k] =~ v[:format])
|
67
67
|
end
|
68
68
|
}
|
69
69
|
|
@@ -86,8 +86,8 @@
|
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
89
|
-
def fail_validation(parameter, reason)
|
90
|
-
{
|
89
|
+
def fail_validation(parameter, value, options, reason)
|
90
|
+
{success: false, reason: reason , parameter: parameter, value: value}.merge(options)
|
91
91
|
end
|
92
92
|
|
93
93
|
def build_name(request_method, path_info)
|
data/lib/sinatra/browse.rb
CHANGED
@@ -46,21 +46,40 @@ module Sinatra::Browse
|
|
46
46
|
browse_routes[new_route.name] = new_route
|
47
47
|
end
|
48
48
|
|
49
|
+
def default_on_error(&blk)
|
50
|
+
@default_on_error = blk if block_given?
|
51
|
+
@default_on_error
|
52
|
+
end
|
53
|
+
|
49
54
|
def self.registered(app)
|
50
55
|
@app = app
|
51
56
|
|
52
57
|
app.enable :remove_undefined_parameters
|
53
|
-
app.set
|
58
|
+
app.set allowed_undefined_parameters: []
|
59
|
+
|
60
|
+
app.disable :show_head_routes
|
61
|
+
|
62
|
+
app.class_eval {
|
63
|
+
def _default_on_error(error_hash)
|
64
|
+
halt 400, {
|
65
|
+
error: "parameter validation failed",
|
66
|
+
parameter: error_hash[:parameter],
|
67
|
+
value: error_hash[:value],
|
68
|
+
reason: error_hash[:reason]
|
69
|
+
}.to_json
|
70
|
+
end
|
71
|
+
}
|
72
|
+
|
73
|
+
app.default_on_error { |error_hash| _default_on_error(error_hash) }
|
54
74
|
|
55
75
|
app.before do
|
56
76
|
browse_route = app.browse_routes_for(request.request_method, request.path_info)
|
57
77
|
|
58
78
|
if browse_route
|
59
79
|
#TODO: Optionally throw error for undefined params
|
60
|
-
#TODO: Make undefined parameter deletion optional per route
|
61
80
|
|
62
81
|
if settings.remove_undefined_parameters
|
63
|
-
browse_route.delete_undefined(params, settings.
|
82
|
+
browse_route.delete_undefined(params, settings.allowed_undefined_parameters)
|
64
83
|
end
|
65
84
|
|
66
85
|
browse_route.coerce_type(params)
|
@@ -68,13 +87,10 @@ module Sinatra::Browse
|
|
68
87
|
validation_result = browse_route.validate(params)
|
69
88
|
unless validation_result[:success]
|
70
89
|
if validation_result[:on_error].respond_to?(:to_proc)
|
71
|
-
|
90
|
+
error_proc = validation_result.delete(:on_error).to_proc
|
91
|
+
instance_exec validation_result, &error_proc
|
72
92
|
else
|
73
|
-
|
74
|
-
error: "parameter validation failed",
|
75
|
-
parameter: validation_result[:name],
|
76
|
-
reason: validation_result[:reason]
|
77
|
-
}.to_json
|
93
|
+
instance_exec validation_result, &app.default_on_error
|
78
94
|
end
|
79
95
|
end
|
80
96
|
browse_route.transform(params)
|
@@ -89,6 +105,7 @@ module Sinatra::Browse
|
|
89
105
|
end
|
90
106
|
|
91
107
|
def self.route_added(verb, path, block)
|
108
|
+
return if verb == "HEAD" && !@app.settings.show_head_routes
|
92
109
|
@app.set_browse_routes_for(verb, path)
|
93
110
|
@app.reset_temp_params
|
94
111
|
@app.desc ""
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sinatra-browse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.3'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Axsh Co. LTD
|
@@ -18,7 +18,6 @@ extra_rdoc_files: []
|
|
18
18
|
files:
|
19
19
|
- lib/sinatra/browse.rb
|
20
20
|
- lib/sinatra/browse/route.rb
|
21
|
-
- lib/sinatra/browse/parameter.rb
|
22
21
|
- lib/sinatra/browse/format.rb
|
23
22
|
- LICENSE
|
24
23
|
- README.md
|
@@ -1,49 +0,0 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
|
3
|
-
module Sinatra::Browse
|
4
|
-
def ValidationError < Exception; end
|
5
|
-
|
6
|
-
class Validation
|
7
|
-
attr_reader :fail_message
|
8
|
-
end
|
9
|
-
|
10
|
-
class In < Validation
|
11
|
-
def fail_message(value, accepted)
|
12
|
-
"Invalid value: '#{value}'. Must be a member of #{accepted.inspect}."
|
13
|
-
end
|
14
|
-
|
15
|
-
def validate(value)
|
16
|
-
end
|
17
|
-
|
18
|
-
def fail(value, accepted)
|
19
|
-
raise ValidationError, fail_message(value, accepted)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class Parameter
|
24
|
-
attr_reader :value
|
25
|
-
|
26
|
-
def initialize(value)
|
27
|
-
@value = coerce(value)
|
28
|
-
end
|
29
|
-
|
30
|
-
def validate()
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
class BPString < Parameter
|
35
|
-
def coerce(v); String(v) end
|
36
|
-
end
|
37
|
-
|
38
|
-
class BPBoolean < Parameter
|
39
|
-
def coerce(v)
|
40
|
-
case v
|
41
|
-
when "y", "yes", "t", "true", "1"
|
42
|
-
true
|
43
|
-
when "n", "no", "f", "false", "0"
|
44
|
-
false
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|