strelka 0.0.1.pre.279 → 0.0.1.pre.284
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.tar.gz.sig +0 -0
- data/ChangeLog +42 -1
- data/Rakefile +1 -1
- data/bin/strelka +1 -1
- data/lib/strelka/app/restresources.rb +127 -51
- data/lib/strelka/httpresponse.rb +2 -1
- data/lib/strelka/httpresponse/negotiation.rb +2 -1
- data/lib/strelka/paramvalidator.rb +36 -23
- data/spec/lib/helpers.rb +2 -0
- data/spec/strelka/app/restresources_spec.rb +42 -13
- data/spec/strelka/httpresponse_spec.rb +4 -0
- data/spec/strelka/paramvalidator_spec.rb +9 -4
- metadata +4 -4
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
|
Binary file
|
data/ChangeLog
CHANGED
|
@@ -1,3 +1,44 @@
|
|
|
1
|
+
2012-07-17 Michael Granger <ged@FaerieMUD.org>
|
|
2
|
+
|
|
3
|
+
* bin/strelka, lib/strelka/app/restresources.rb,
|
|
4
|
+
lib/strelka/httpresponse/negotiation.rb,
|
|
5
|
+
lib/strelka/paramvalidator.rb, spec/lib/helpers.rb,
|
|
6
|
+
spec/strelka/app/restresources_spec.rb,
|
|
7
|
+
spec/strelka/paramvalidator_spec.rb:
|
|
8
|
+
Clean up some :restresources behavior
|
|
9
|
+
[153e65a22805] [tip]
|
|
10
|
+
|
|
11
|
+
2012-07-16 Michael Granger <ged@FaerieMUD.org>
|
|
12
|
+
|
|
13
|
+
* lib/strelka/httpresponse.rb, spec/strelka/httpresponse_spec.rb:
|
|
14
|
+
Bugfix for content-type-less responses
|
|
15
|
+
[3540a46a9b25]
|
|
16
|
+
|
|
17
|
+
2012-07-13 Michael Granger <ged@FaerieMUD.org>
|
|
18
|
+
|
|
19
|
+
* lib/strelka/httpresponse/negotiation.rb:
|
|
20
|
+
Add a default stringifier (#to_s) to
|
|
21
|
+
Strelka::HTTPResponse::Negotiation
|
|
22
|
+
[4fe7c945616b]
|
|
23
|
+
|
|
24
|
+
* lib/strelka/app/restresources.rb:
|
|
25
|
+
Fix the OPTIONS action in the :restresources plugin
|
|
26
|
+
[b832003605e0]
|
|
27
|
+
|
|
28
|
+
* .rvm.gems, Rakefile:
|
|
29
|
+
Bump mongrel2 dependency
|
|
30
|
+
[6149242307af]
|
|
31
|
+
|
|
32
|
+
2012-07-12 Michael Granger <ged@FaerieMUD.org>
|
|
33
|
+
|
|
34
|
+
* .rvm.gems, Rakefile:
|
|
35
|
+
Bump the mongrel2 dependency
|
|
36
|
+
[389401bb6480]
|
|
37
|
+
|
|
38
|
+
* lib/strelka/app/restresources.rb:
|
|
39
|
+
Fix a buggy log message.
|
|
40
|
+
[75f9be31cb8c]
|
|
41
|
+
|
|
1
42
|
2012-07-06 Michael Granger <ged@FaerieMUD.org>
|
|
2
43
|
|
|
3
44
|
* .rvm.gems, Rakefile, lib/strelka/app/templating.rb:
|
|
@@ -6,7 +47,7 @@
|
|
|
6
47
|
- bump Inversion dependency for encoding support
|
|
7
48
|
- Use the default_internal encoding or UTF-8 if that isn't set as the
|
|
8
49
|
encoding of templates loaded by the :templating plugin.
|
|
9
|
-
[4f7bb0f3a8f7]
|
|
50
|
+
[4f7bb0f3a8f7]
|
|
10
51
|
|
|
11
52
|
* Manifest.txt:
|
|
12
53
|
Add multipart-form support files to the manifest
|
data/Rakefile
CHANGED
|
@@ -28,7 +28,7 @@ hoespec = Hoe.spec 'strelka' do
|
|
|
28
28
|
self.dependency 'highline', '~> 1.6'
|
|
29
29
|
self.dependency 'inversion', '~> 0.11'
|
|
30
30
|
self.dependency 'loggability', '~> 0.4'
|
|
31
|
-
self.dependency 'mongrel2', '~> 0.
|
|
31
|
+
self.dependency 'mongrel2', '~> 0.29'
|
|
32
32
|
self.dependency 'pluginfactory', '~> 1.0'
|
|
33
33
|
self.dependency 'sysexits', '~> 1.0'
|
|
34
34
|
self.dependency 'trollop', '~> 1.16'
|
data/bin/strelka
CHANGED
|
@@ -295,8 +295,8 @@ class Strelka::CLICommand
|
|
|
295
295
|
]
|
|
296
296
|
fork do
|
|
297
297
|
self.log.debug " in the child."
|
|
298
|
-
apps = Strelka::App.load( path )
|
|
299
298
|
Strelka.load_config( self.options.config ) if self.options.config
|
|
299
|
+
apps = Strelka::App.load( path )
|
|
300
300
|
self.log.debug " loaded: %p" % [ apps ]
|
|
301
301
|
apps.first.run
|
|
302
302
|
end
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
require 'set'
|
|
6
6
|
require 'sequel'
|
|
7
|
+
require 'sequel/extensions/pretty_table'
|
|
7
8
|
|
|
8
9
|
require 'strelka' unless defined?( Strelka )
|
|
9
10
|
require 'strelka/app' unless defined?( Strelka::App )
|
|
@@ -64,7 +65,8 @@ module Strelka::App::RestResources
|
|
|
64
65
|
|
|
65
66
|
# Class methods to add to classes with REST resources.
|
|
66
67
|
module ClassMethods # :nodoc:
|
|
67
|
-
include Sequel::Inflections
|
|
68
|
+
include Sequel::Inflections,
|
|
69
|
+
Strelka::Constants
|
|
68
70
|
|
|
69
71
|
# Set of verbs that are valid for a resource, keyed by the resource path
|
|
70
72
|
@resource_verbs = Hash.new {|h,k| h[k] = Set.new }
|
|
@@ -83,13 +85,12 @@ module Strelka::App::RestResources
|
|
|
83
85
|
def self::extended( obj )
|
|
84
86
|
super
|
|
85
87
|
|
|
88
|
+
# Enable text tables for text/plain responses
|
|
89
|
+
Sequel.extension( :pretty_table )
|
|
90
|
+
|
|
86
91
|
# Load the plugins this one depends on if they aren't already
|
|
87
92
|
obj.plugins :routing, :negotiation, :parameters
|
|
88
93
|
|
|
89
|
-
# Add validations for the limit and offset parameters
|
|
90
|
-
obj.param :limit, :integer
|
|
91
|
-
obj.param :offset, :integer
|
|
92
|
-
|
|
93
94
|
# Use the 'exclusive' router instead of the more-flexible
|
|
94
95
|
# Mongrel2-style default one
|
|
95
96
|
obj.router :exclusive
|
|
@@ -120,12 +121,20 @@ module Strelka::App::RestResources
|
|
|
120
121
|
self.log.debug "Adding REST resource for %p" % [ rsrcobj ]
|
|
121
122
|
options = self.service_options.merge( options )
|
|
122
123
|
|
|
124
|
+
# Add a parameter for the primary key
|
|
125
|
+
pkey = rsrcobj.primary_key
|
|
126
|
+
pkey_schema = rsrcobj.db_schema[ pkey.to_sym ] or
|
|
127
|
+
raise ArgumentError,
|
|
128
|
+
"cannot generate services for %p: resource has no schema" % [ rsrcobj ]
|
|
129
|
+
self.param( pkey, pkey_schema[:type] ) unless
|
|
130
|
+
self.paramvalidator.param_names.include?( pkey.to_s )
|
|
131
|
+
|
|
123
132
|
# Figure out what the resource name is, and make the route from it
|
|
124
133
|
name = options[:name] || rsrcobj.implicit_table_name
|
|
125
134
|
route = [ options[:prefix], name ].compact.join( '/' )
|
|
126
135
|
|
|
127
|
-
#
|
|
128
|
-
self.
|
|
136
|
+
# Ensure validated parameters are untainted
|
|
137
|
+
self.untaint_all_constraints
|
|
129
138
|
|
|
130
139
|
# Make and install handler methods
|
|
131
140
|
self.log.debug " adding readers"
|
|
@@ -150,17 +159,6 @@ module Strelka::App::RestResources
|
|
|
150
159
|
end
|
|
151
160
|
|
|
152
161
|
|
|
153
|
-
### Add parameter declarations for parameters related to +rsrcobj+.
|
|
154
|
-
def add_parameters( rsrcobj, options )
|
|
155
|
-
self.log.debug "Declaring validations for columns from %p" % [ rsrcobj ]
|
|
156
|
-
self.untaint_all_constraints
|
|
157
|
-
rsrcobj.db_schema.each do |col, config|
|
|
158
|
-
self.log.debug " %s (%p)" % [ col, config[:type] ]
|
|
159
|
-
param col, config[:type]
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
|
|
164
162
|
### Add a handler method for discovery for the specified +rsrcobj+.
|
|
165
163
|
### OPTIONS /resources
|
|
166
164
|
def add_options_handler( route, rsrcobj, options )
|
|
@@ -168,14 +166,29 @@ module Strelka::App::RestResources
|
|
|
168
166
|
self.log.debug "Adding OPTIONS handler for %s (%p)" % [ route, rsrcobj ]
|
|
169
167
|
self.add_route( :OPTIONS, route, options ) do |req|
|
|
170
168
|
self.log.debug "OPTIONS handler!"
|
|
171
|
-
verbs = self.class.resource_verbs[ route ].sort
|
|
172
169
|
res = req.response
|
|
173
170
|
|
|
171
|
+
# Gather up metadata describing the resource
|
|
172
|
+
verbs = self.class.resource_verbs[ route ].sort
|
|
173
|
+
columns = rsrcobj.allowed_columns || rsrcobj.columns
|
|
174
|
+
attributes = columns.each_with_object({}) do |col, hash|
|
|
175
|
+
hash[ col ] = rsrcobj.db_schema[ col ][:type]
|
|
176
|
+
end
|
|
177
|
+
|
|
174
178
|
self.log.debug " making a reply with Allowed: %s" % [ verbs.join(', ') ]
|
|
175
179
|
res.header.allowed = verbs.join(', ')
|
|
176
|
-
res.
|
|
177
|
-
|
|
178
|
-
|
|
180
|
+
res.for( :json, :yaml ) do |req|
|
|
181
|
+
{
|
|
182
|
+
'methods' => verbs,
|
|
183
|
+
'attributes' => attributes,
|
|
184
|
+
}
|
|
185
|
+
end
|
|
186
|
+
res.for( :text ) do
|
|
187
|
+
"Methods: #{verbs.join(', ')}\n" +
|
|
188
|
+
"Attributes: \n" +
|
|
189
|
+
attributes.map {|name,type| " "}
|
|
190
|
+
end
|
|
191
|
+
|
|
179
192
|
|
|
180
193
|
return res
|
|
181
194
|
end
|
|
@@ -184,9 +197,8 @@ module Strelka::App::RestResources
|
|
|
184
197
|
end
|
|
185
198
|
|
|
186
199
|
|
|
187
|
-
### Add a handler method for reading a single instance of the specified +rsrcobj+, which
|
|
188
|
-
### Sequel::Model class or a ducktype-alike.
|
|
189
|
-
### GET /resources/{id}
|
|
200
|
+
### Add a handler method for reading a single instance of the specified +rsrcobj+, which
|
|
201
|
+
### should be a Sequel::Model class or a ducktype-alike. GET /resources/{id}
|
|
190
202
|
def add_read_handler( route_prefix, rsrcobj, options )
|
|
191
203
|
pkey = rsrcobj.primary_key
|
|
192
204
|
route = "#{route_prefix}/:#{pkey}"
|
|
@@ -202,6 +214,7 @@ module Strelka::App::RestResources
|
|
|
202
214
|
|
|
203
215
|
res = req.response
|
|
204
216
|
res.for( :json, :yaml ) { resource }
|
|
217
|
+
res.for( :text ) { Sequel::PrettyTable.string(resource) }
|
|
205
218
|
|
|
206
219
|
return res
|
|
207
220
|
end
|
|
@@ -210,19 +223,36 @@ module Strelka::App::RestResources
|
|
|
210
223
|
end
|
|
211
224
|
|
|
212
225
|
|
|
213
|
-
### Add a handler method for reading a collection of the specified +rsrcobj+, which should
|
|
214
|
-
### Sequel::Model class or a ducktype-alike.
|
|
226
|
+
### Add a handler method for reading a collection of the specified +rsrcobj+, which should
|
|
227
|
+
### be a Sequel::Model class or a ducktype-alike.
|
|
215
228
|
### GET /resources
|
|
216
229
|
def add_collection_read_handler( route, rsrcobj, options )
|
|
217
|
-
self.log.debug "Creating handler for reading collections of %p: GET %s" %
|
|
230
|
+
self.log.debug "Creating handler for reading collections of %p: GET %s" %
|
|
231
|
+
[ rsrcobj, route ]
|
|
232
|
+
|
|
233
|
+
# Make a column regexp for validating the order field
|
|
234
|
+
colunion = Regexp.union( (rsrcobj.allowed_columns || rsrcobj.columns).map(&:to_s) )
|
|
235
|
+
colre = /^(?<column>#{colunion})$/
|
|
236
|
+
|
|
218
237
|
self.add_route( :GET, route, options ) do |req|
|
|
238
|
+
# Add validations for limit, offset, and order parameters
|
|
239
|
+
req.params.add :limit, :integer
|
|
240
|
+
req.params.add :offset, :integer
|
|
241
|
+
req.params.add :order, colre
|
|
242
|
+
|
|
219
243
|
finish_with( HTTP::BAD_REQUEST, req.params.error_messages.join("\n") ) unless
|
|
220
244
|
req.params.okay?
|
|
221
245
|
|
|
222
|
-
limit, offset = req.params.values_at( :limit, :offset )
|
|
246
|
+
limit, offset, order = req.params.values_at( :limit, :offset, :order )
|
|
223
247
|
res = req.response
|
|
224
248
|
|
|
225
249
|
dataset = rsrcobj.dataset
|
|
250
|
+
if order
|
|
251
|
+
order = Array( order ).map( &:to_sym )
|
|
252
|
+
self.log.debug "Ordering result set by %p" % [ order ]
|
|
253
|
+
dataset = dataset.order( *order )
|
|
254
|
+
end
|
|
255
|
+
|
|
226
256
|
if limit
|
|
227
257
|
self.log.debug "Limiting result set to %p records" % [ limit ]
|
|
228
258
|
dataset = dataset.limit( limit, offset )
|
|
@@ -230,6 +260,7 @@ module Strelka::App::RestResources
|
|
|
230
260
|
|
|
231
261
|
self.log.debug "Returning collection: %s" % [ dataset.sql ]
|
|
232
262
|
res.for( :json, :yaml ) { dataset.all }
|
|
263
|
+
res.for( :text ) { Sequel::PrettyTable.string(dataset) }
|
|
233
264
|
|
|
234
265
|
return res
|
|
235
266
|
end
|
|
@@ -241,9 +272,11 @@ module Strelka::App::RestResources
|
|
|
241
272
|
### Add a handler method for creating a new instance of +rsrcobj+.
|
|
242
273
|
### POST /resources
|
|
243
274
|
def add_collection_create_handler( route, rsrcobj, options )
|
|
244
|
-
self.log.debug "Creating handler for creating %p resources: POST %s" %
|
|
275
|
+
self.log.debug "Creating handler for creating %p resources: POST %s" %
|
|
276
|
+
[ rsrcobj, route ]
|
|
245
277
|
|
|
246
278
|
self.add_route( :POST, route, options ) do |req|
|
|
279
|
+
add_resource_params( req, rsrcobj )
|
|
247
280
|
finish_with( HTTP::BAD_REQUEST, req.params.error_messages.join(", ") ) unless
|
|
248
281
|
req.params.okay?
|
|
249
282
|
|
|
@@ -279,8 +312,10 @@ module Strelka::App::RestResources
|
|
|
279
312
|
pkey = rsrcobj.primary_key
|
|
280
313
|
route = "#{route_prefix}/:#{pkey}"
|
|
281
314
|
|
|
282
|
-
self.log.debug "Creating handler for creating %p resources: POST %s" %
|
|
315
|
+
self.log.debug "Creating handler for creating %p resources: POST %s" %
|
|
316
|
+
[ rsrcobj, route ]
|
|
283
317
|
self.add_route( :PUT, route, options ) do |req|
|
|
318
|
+
add_resource_params( req, rsrcobj )
|
|
284
319
|
finish_with( HTTP::BAD_REQUEST, req.params.error_messages.join(", ") ) unless
|
|
285
320
|
req.params.okay?
|
|
286
321
|
|
|
@@ -312,9 +347,11 @@ module Strelka::App::RestResources
|
|
|
312
347
|
### PUT /resources
|
|
313
348
|
def add_collection_update_handler( route, rsrcobj, options )
|
|
314
349
|
pkey = rsrcobj.primary_key
|
|
315
|
-
self.log.debug "Creating handler for updating every %p resources: PUT %s" %
|
|
350
|
+
self.log.debug "Creating handler for updating every %p resources: PUT %s" %
|
|
351
|
+
[ rsrcobj, route ]
|
|
316
352
|
|
|
317
353
|
self.add_route( :PUT, route, options ) do |req|
|
|
354
|
+
add_resource_params( req, rsrcobj )
|
|
318
355
|
finish_with( HTTP::BAD_REQUEST, req.params.error_messages.join(", ") ) unless
|
|
319
356
|
req.params.okay?
|
|
320
357
|
|
|
@@ -341,8 +378,8 @@ module Strelka::App::RestResources
|
|
|
341
378
|
end
|
|
342
379
|
|
|
343
380
|
|
|
344
|
-
### Add a handler method for deleting an instance of +rsrcobj+ with +route_prefix+ as the
|
|
345
|
-
### URI path.
|
|
381
|
+
### Add a handler method for deleting an instance of +rsrcobj+ with +route_prefix+ as the
|
|
382
|
+
### base URI path.
|
|
346
383
|
### DELETE /resources/{id}
|
|
347
384
|
def add_delete_handler( route_prefix, rsrcobj, options )
|
|
348
385
|
pkey = rsrcobj.primary_key
|
|
@@ -442,8 +479,13 @@ module Strelka::App::RestResources
|
|
|
442
479
|
def add_dataset_read_handler( path, rsrcobj, dsname, param, options )
|
|
443
480
|
self.log.debug "Adding dataset method read handler: %s" % [ path ]
|
|
444
481
|
|
|
482
|
+
config = rsrcobj.db_schema[ param ] or
|
|
483
|
+
raise ArgumentError, "no such column %p for %p" % [ col, rsrcobj ]
|
|
484
|
+
param( param, config[:type] )
|
|
485
|
+
|
|
445
486
|
self.add_route( :GET, path, options ) do |req|
|
|
446
|
-
self.log.debug "Resource dataset GET request for dataset %s on %p" %
|
|
487
|
+
self.log.debug "Resource dataset GET request for dataset %s on %p" %
|
|
488
|
+
[ dsname, rsrcobj ]
|
|
447
489
|
finish_with( HTTP::BAD_REQUEST, req.params.error_messages.join("\n") ) unless
|
|
448
490
|
req.params.okay?
|
|
449
491
|
|
|
@@ -464,6 +506,7 @@ module Strelka::App::RestResources
|
|
|
464
506
|
# :TODO: Handle other mediatypes
|
|
465
507
|
self.log.debug " returning collection: %s" % [ dataset.sql ]
|
|
466
508
|
res.for( :json, :yaml ) { dataset.all }
|
|
509
|
+
res.for( :text ) { Sequel::PrettyTable.string(dataset) }
|
|
467
510
|
|
|
468
511
|
return res
|
|
469
512
|
end
|
|
@@ -473,10 +516,18 @@ module Strelka::App::RestResources
|
|
|
473
516
|
### Add a GET route for the specified +association+ of the +rsrcobj+ at the given
|
|
474
517
|
### +path+.
|
|
475
518
|
def add_composite_read_handler( path, rsrcobj, association, options )
|
|
476
|
-
pkey = rsrcobj.primary_key
|
|
477
519
|
self.log.debug "Adding composite read handler for association: %s" % [ association ]
|
|
478
520
|
|
|
521
|
+
pkey = rsrcobj.primary_key
|
|
522
|
+
colunion = Regexp.union( (rsrcobj.allowed_columns || rsrcobj.columns).map(&:to_s) )
|
|
523
|
+
colre = /^(?<column>#{colunion})$/
|
|
524
|
+
|
|
479
525
|
self.add_route( :GET, path, options ) do |req|
|
|
526
|
+
|
|
527
|
+
# Add validations for limit, offset, and order parameters
|
|
528
|
+
req.params.add :limit, :integer
|
|
529
|
+
req.params.add :offset, :integer
|
|
530
|
+
req.params.add :order, colre
|
|
480
531
|
finish_with( HTTP::BAD_REQUEST, req.params.error_messages.join("\n") ) unless
|
|
481
532
|
req.params.okay?
|
|
482
533
|
|
|
@@ -486,24 +537,31 @@ module Strelka::App::RestResources
|
|
|
486
537
|
|
|
487
538
|
# Look up the resource, and if it exists, use it to fetch its associated
|
|
488
539
|
# objects
|
|
489
|
-
rsrcobj
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
540
|
+
resource = rsrcobj[ id ] or
|
|
541
|
+
finish_with( HTTP::NOT_FOUND, "No such %s [%p]" % [rsrcobj.table_name, id] )
|
|
542
|
+
|
|
543
|
+
limit, offset, order = req.params.values_at( :limit, :offset, :order )
|
|
544
|
+
dataset = resource.send( "#{association}_dataset" )
|
|
545
|
+
|
|
546
|
+
# Apply the order parameter if it exists
|
|
547
|
+
if order
|
|
548
|
+
order = Array( order ).map( &:to_sym )
|
|
549
|
+
self.log.debug "Ordering result set by %p" % [ order ]
|
|
550
|
+
dataset = dataset.order( *order )
|
|
551
|
+
end
|
|
500
552
|
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
self.log.debug "
|
|
504
|
-
|
|
553
|
+
# Apply limit and offset parameters if they exist
|
|
554
|
+
if limit
|
|
555
|
+
self.log.debug "Limiting result set to %p records" % [ limit ]
|
|
556
|
+
dataset = dataset.limit( limit, offset )
|
|
505
557
|
end
|
|
506
558
|
|
|
559
|
+
# Fetch and return the records as JSON or YAML
|
|
560
|
+
# :TODO: Handle other mediatypes
|
|
561
|
+
self.log.debug "Returning collection: %s" % [ dataset.sql ]
|
|
562
|
+
res.for( :json, :yaml ) { dataset.all }
|
|
563
|
+
res.for( :text ) { Sequel::PrettyTable.string(dataset) }
|
|
564
|
+
|
|
507
565
|
return res
|
|
508
566
|
end
|
|
509
567
|
end
|
|
@@ -518,4 +576,22 @@ module Strelka::App::RestResources
|
|
|
518
576
|
super
|
|
519
577
|
end
|
|
520
578
|
|
|
579
|
+
|
|
580
|
+
#######
|
|
581
|
+
private
|
|
582
|
+
#######
|
|
583
|
+
|
|
584
|
+
### Add parameter validations for the given +columns+ of the specified resource object +rsrcobj+
|
|
585
|
+
### to the specified +req+uest.
|
|
586
|
+
def add_resource_params( req, rsrcobj, *columns )
|
|
587
|
+
columns = rsrcobj.allowed_columns || rsrcobj.columns if columns.empty?
|
|
588
|
+
|
|
589
|
+
columns.each do |col|
|
|
590
|
+
config = rsrcobj.db_schema[ col ] or
|
|
591
|
+
raise ArgumentError, "no such column %p for %p" % [ col, rsrcobj ]
|
|
592
|
+
req.params.add( col, config[:type] ) unless req.params.param_names.include?( col.to_s )
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
end
|
|
596
|
+
|
|
521
597
|
end # module Strelka::App::RestResources
|
data/lib/strelka/httpresponse.rb
CHANGED
|
@@ -111,7 +111,8 @@ class Strelka::HTTPResponse < Mongrel2::HTTPResponse
|
|
|
111
111
|
|
|
112
112
|
### Add a charset to the content-type header in +headers+ if possible.
|
|
113
113
|
def add_content_type_charset( headers )
|
|
114
|
-
return unless headers.content_type
|
|
114
|
+
return unless headers.content_type &&
|
|
115
|
+
headers.content_type.start_with?( 'text' )
|
|
115
116
|
|
|
116
117
|
charset = self.find_header_charset
|
|
117
118
|
self.log.debug "Setting the charset in the content-type header to: %p" % [ charset.name ]
|
|
@@ -49,6 +49,7 @@ module Strelka::HTTPResponse::Negotiation
|
|
|
49
49
|
STRINGIFIERS = {
|
|
50
50
|
'application/x-yaml' => YAML.method( :dump ),
|
|
51
51
|
'application/json' => Yajl.method( :dump ),
|
|
52
|
+
'text/plain' => Proc.new {|obj| obj.to_s },
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
# Transcoding to Unicode is likely enough to work to warrant auto-transcoding. These
|
|
@@ -333,7 +334,7 @@ module Strelka::HTTPResponse::Negotiation
|
|
|
333
334
|
|
|
334
335
|
new_body = callback.call( mimetype ) or return false
|
|
335
336
|
|
|
336
|
-
self.log.debug " successfully transformed! Setting up response."
|
|
337
|
+
self.log.debug " successfully transformed: %p! Setting up response." % [ new_body ]
|
|
337
338
|
new_body = STRINGIFIERS[ mimetype ].call( new_body ) if
|
|
338
339
|
STRINGIFIERS.key?( mimetype ) && !new_body.is_a?( String )
|
|
339
340
|
|
|
@@ -279,12 +279,18 @@ class Strelka::ParamValidator < ::FormValidator
|
|
|
279
279
|
### a constraint, a description, and one or more flags.
|
|
280
280
|
def add( name, *args, &block )
|
|
281
281
|
name = name.to_s
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
282
|
+
constraint = self.make_param_validator( name, args, &block )
|
|
283
|
+
|
|
284
|
+
# No-op if there's already a parameter with the same name and constraint
|
|
285
|
+
if self.param_names.include?( name )
|
|
286
|
+
return if self.profile[:constraints][ name ] == constraint
|
|
287
|
+
raise ArgumentError,
|
|
288
|
+
"parameter %p is already defined as a '%s'; perhaps you meant to use #override?" %
|
|
289
|
+
[ name, self.profile[:constraints][name] ]
|
|
290
|
+
end
|
|
285
291
|
|
|
286
292
|
self.log.debug "Adding parameter '%s' to profile" % [ name ]
|
|
287
|
-
self.set_param( name, *args, &block )
|
|
293
|
+
self.set_param( name, constraint, *args, &block )
|
|
288
294
|
end
|
|
289
295
|
|
|
290
296
|
|
|
@@ -296,8 +302,30 @@ class Strelka::ParamValidator < ::FormValidator
|
|
|
296
302
|
"no parameter %p defined; perhaps you meant to use #add?" % [name] unless
|
|
297
303
|
self.param_names.include?( name )
|
|
298
304
|
|
|
305
|
+
constraint = self.make_param_validator( name, args, &block )
|
|
299
306
|
self.log.debug "Overriding parameter '%s' in profile" % [ name ]
|
|
300
|
-
self.set_param( name, *args, &block )
|
|
307
|
+
self.set_param( name, constraint, *args, &block )
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
### Extract a validator from the given +args+ and return it.
|
|
312
|
+
def make_param_validator( name, args, &block )
|
|
313
|
+
self.log.debug "Finding param validator out of: %s, %p, %p" % [ name, args, block ]
|
|
314
|
+
args.unshift( block ) if block
|
|
315
|
+
|
|
316
|
+
# Custom validator -- either a callback or a regex
|
|
317
|
+
if args.first.is_a?( Regexp ) || args.first.respond_to?( :call )
|
|
318
|
+
return args.shift
|
|
319
|
+
|
|
320
|
+
# Builtin match validator, either explicit or implied by the name
|
|
321
|
+
else
|
|
322
|
+
return args.shift if args.first.is_a?( Symbol ) && !FLAGS.include?( args.first )
|
|
323
|
+
|
|
324
|
+
raise ArgumentError, "no builtin %p validator" % [ name ] unless
|
|
325
|
+
self.respond_to?( "match_#{name}" )
|
|
326
|
+
return name
|
|
327
|
+
end
|
|
328
|
+
|
|
301
329
|
end
|
|
302
330
|
|
|
303
331
|
|
|
@@ -376,23 +404,8 @@ class Strelka::ParamValidator < ::FormValidator
|
|
|
376
404
|
|
|
377
405
|
### Set the parameter +name+ in the profile to validate using the given +args+,
|
|
378
406
|
### which are the same as the ones passed to #add and #override.
|
|
379
|
-
def set_param( name, *args, &block )
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
# Custom validator -- either a callback or a regex
|
|
383
|
-
if args.first.is_a?( Regexp ) ||
|
|
384
|
-
args.first.respond_to?( :call )
|
|
385
|
-
self.profile[:constraints][ name ] = args.shift
|
|
386
|
-
|
|
387
|
-
# Builtin match validator, either explicit or implied by the name
|
|
388
|
-
else
|
|
389
|
-
constraint = args.shift if args.first.is_a?( Symbol ) && !FLAGS.include?( args.first )
|
|
390
|
-
constraint ||= name
|
|
391
|
-
|
|
392
|
-
raise ArgumentError, "no builtin %p validator" % [ constraint ] unless
|
|
393
|
-
self.respond_to?( "match_#{constraint}" )
|
|
394
|
-
self.profile[:constraints][ name ] = constraint
|
|
395
|
-
end
|
|
407
|
+
def set_param( name, validator, *args, &block )
|
|
408
|
+
self.profile[:constraints][ name ] = validator
|
|
396
409
|
|
|
397
410
|
self.profile[:descriptions][ name ] = args.shift if args.first.is_a?( String )
|
|
398
411
|
|
|
@@ -407,7 +420,7 @@ class Strelka::ParamValidator < ::FormValidator
|
|
|
407
420
|
if args.include?( :untaint )
|
|
408
421
|
self.profile[:untaint_constraint_fields] |= [ name ]
|
|
409
422
|
else
|
|
410
|
-
self.profile[:untaint_constraint_fields].delete(
|
|
423
|
+
self.profile[:untaint_constraint_fields].delete( name )
|
|
411
424
|
end
|
|
412
425
|
|
|
413
426
|
self.revalidate if self.validated?
|
data/spec/lib/helpers.rb
CHANGED
|
@@ -28,7 +28,7 @@ describe Strelka::App::RestResources do
|
|
|
28
28
|
include Mongrel2::Config::DSL
|
|
29
29
|
|
|
30
30
|
before( :all ) do
|
|
31
|
-
setup_logging(
|
|
31
|
+
setup_logging()
|
|
32
32
|
setup_config_db()
|
|
33
33
|
|
|
34
34
|
@request_factory = Mongrel2::RequestFactory.new( route: '/api/v1' )
|
|
@@ -42,7 +42,7 @@ describe Strelka::App::RestResources do
|
|
|
42
42
|
it_should_behave_like( "A Strelka::App Plugin" )
|
|
43
43
|
|
|
44
44
|
|
|
45
|
-
describe "an
|
|
45
|
+
describe "included in an App" do
|
|
46
46
|
|
|
47
47
|
before( :each ) do
|
|
48
48
|
@app = Class.new( Strelka::App ) do
|
|
@@ -54,7 +54,7 @@ describe Strelka::App::RestResources do
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
|
|
57
|
-
it "
|
|
57
|
+
it "keeps track of what resources are mounted where" do
|
|
58
58
|
@app.resource_verbs.should be_a( Hash )
|
|
59
59
|
@app.resource_verbs.should be_empty()
|
|
60
60
|
end
|
|
@@ -70,7 +70,7 @@ describe Strelka::App::RestResources do
|
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
|
73
|
-
it "
|
|
73
|
+
it "keeps track of what resources are mounted where" do
|
|
74
74
|
@app.resource_verbs.should have( 1 ).member
|
|
75
75
|
@app.resource_verbs.should include( 'servers' )
|
|
76
76
|
@app.resource_verbs[ 'servers' ].
|
|
@@ -107,7 +107,7 @@ describe Strelka::App::RestResources do
|
|
|
107
107
|
end
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
-
it "
|
|
110
|
+
it "keeps track of what resources are mounted where" do
|
|
111
111
|
@app.resource_verbs.should have( 1 ).member
|
|
112
112
|
@app.resource_verbs.should include( 'servers' )
|
|
113
113
|
@app.resource_verbs[ 'servers' ].
|
|
@@ -136,17 +136,20 @@ describe Strelka::App::RestResources do
|
|
|
136
136
|
end
|
|
137
137
|
|
|
138
138
|
|
|
139
|
-
describe "
|
|
139
|
+
describe "auto-generates routes:" do
|
|
140
140
|
|
|
141
141
|
before( :each ) do
|
|
142
142
|
# Create two servers in the config db to test with
|
|
143
143
|
server 'test-server' do
|
|
144
|
+
name "Test"
|
|
144
145
|
host 'main'
|
|
145
146
|
host 'monitor'
|
|
146
147
|
host 'adminpanel'
|
|
147
148
|
host 'api'
|
|
148
149
|
end
|
|
149
|
-
server 'step-server'
|
|
150
|
+
server 'step-server' do
|
|
151
|
+
name 'Step'
|
|
152
|
+
end
|
|
150
153
|
|
|
151
154
|
@app.class_eval do
|
|
152
155
|
resource Mongrel2::Config::Server
|
|
@@ -158,7 +161,8 @@ describe Strelka::App::RestResources do
|
|
|
158
161
|
Mongrel2::Config.subclasses.each {|klass| klass.truncate }
|
|
159
162
|
end
|
|
160
163
|
|
|
161
|
-
|
|
164
|
+
|
|
165
|
+
context "OPTIONS route" do
|
|
162
166
|
|
|
163
167
|
it "responds to a top-level OPTIONS request with a resource description (JSON Schema?)"
|
|
164
168
|
|
|
@@ -173,7 +177,7 @@ describe Strelka::App::RestResources do
|
|
|
173
177
|
end # OPTIONS routes
|
|
174
178
|
|
|
175
179
|
|
|
176
|
-
context "GET
|
|
180
|
+
context "GET route" do
|
|
177
181
|
it "has a GET route to fetch the resource collection" do
|
|
178
182
|
req = @request_factory.get( '/api/v1/servers', 'Accept' => 'application/json' )
|
|
179
183
|
res = @app.new.handle( req )
|
|
@@ -209,6 +213,31 @@ describe Strelka::App::RestResources do
|
|
|
209
213
|
body[0]['uuid'].should == 'step-server'
|
|
210
214
|
end
|
|
211
215
|
|
|
216
|
+
it "supports ordering the result by a single column" do
|
|
217
|
+
req = @request_factory.get( '/api/v1/servers?order=name', 'Accept' => 'application/json' )
|
|
218
|
+
res = @app.new.handle( req )
|
|
219
|
+
|
|
220
|
+
res.status.should == HTTP::OK
|
|
221
|
+
res.content_type.should == 'application/json'
|
|
222
|
+
body = Yajl.load( res.body )
|
|
223
|
+
|
|
224
|
+
body.should have( 2 ).members
|
|
225
|
+
body[0]['name'].should == 'Step'
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
it "supports ordering the result by multiple columns" do
|
|
229
|
+
pending "fixing the multi-value paramvalidator bug"
|
|
230
|
+
req = @request_factory.get( '/api/v1/servers?order=id;order=name', 'Accept' => 'application/json' )
|
|
231
|
+
res = @app.new.handle( req )
|
|
232
|
+
|
|
233
|
+
res.status.should == HTTP::OK
|
|
234
|
+
res.content_type.should == 'application/json'
|
|
235
|
+
body = Yajl.load( res.body )
|
|
236
|
+
|
|
237
|
+
body.should have( 2 ).members
|
|
238
|
+
body[0]['name'].should == 'Test'
|
|
239
|
+
end
|
|
240
|
+
|
|
212
241
|
it "has a GET route to fetch a single resource by its ID" do
|
|
213
242
|
req = @request_factory.get( '/api/v1/servers/1', 'Accept' => 'application/json' )
|
|
214
243
|
res = @app.new.handle( req )
|
|
@@ -282,7 +311,7 @@ describe Strelka::App::RestResources do
|
|
|
282
311
|
end # GET routes
|
|
283
312
|
|
|
284
313
|
|
|
285
|
-
context "POST
|
|
314
|
+
context "POST route" do
|
|
286
315
|
|
|
287
316
|
before( :each ) do
|
|
288
317
|
@server_values = {
|
|
@@ -330,7 +359,7 @@ describe Strelka::App::RestResources do
|
|
|
330
359
|
end # POST routes
|
|
331
360
|
|
|
332
361
|
|
|
333
|
-
context "PUT
|
|
362
|
+
context "PUT route" do
|
|
334
363
|
|
|
335
364
|
before( :each ) do
|
|
336
365
|
@posted_values = {
|
|
@@ -368,7 +397,7 @@ describe Strelka::App::RestResources do
|
|
|
368
397
|
end # PUT routes
|
|
369
398
|
|
|
370
399
|
|
|
371
|
-
context "DELETE
|
|
400
|
+
context "DELETE route" do
|
|
372
401
|
|
|
373
402
|
it "has a DELETE route to delete single instances in the resource collection" do
|
|
374
403
|
req = @request_factory.delete( '/api/v1/servers/1' )
|
|
@@ -395,7 +424,7 @@ describe Strelka::App::RestResources do
|
|
|
395
424
|
end # route behaviors
|
|
396
425
|
|
|
397
426
|
|
|
398
|
-
describe "supports inheritance" do
|
|
427
|
+
describe "supports inheritance:" do
|
|
399
428
|
|
|
400
429
|
subject do
|
|
401
430
|
@app.resource( Mongrel2::Config::Server )
|
|
@@ -94,6 +94,10 @@ describe Strelka::HTTPResponse do
|
|
|
94
94
|
@res.header_data.should_not =~ /charset/i
|
|
95
95
|
end
|
|
96
96
|
|
|
97
|
+
it "doesn't try to add an encoding to a response that doesn't have a content type" do
|
|
98
|
+
@res.content_type = nil
|
|
99
|
+
@res.header_data.should_not =~ /charset/
|
|
100
|
+
end
|
|
97
101
|
|
|
98
102
|
it "adds a Content-encoding header if there is one encoding" do
|
|
99
103
|
@res.encodings << 'gzip'
|
|
@@ -57,14 +57,19 @@ describe Strelka::ParamValidator do
|
|
|
57
57
|
@validator.param_names.should include( 'a_field' )
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
it "
|
|
60
|
+
it "ignores identical duplicate constraints to be added twice" do
|
|
61
|
+
@validator.add( :a_field, :string )
|
|
61
62
|
@validator.add( :a_field, :string )
|
|
62
|
-
expect {
|
|
63
|
-
@validator.add( :a_field, :string )
|
|
64
|
-
}.to raise_error( /parameter "a_field" is already defined/i )
|
|
65
63
|
@validator.param_names.should include( 'a_field' )
|
|
66
64
|
end
|
|
67
65
|
|
|
66
|
+
it "throws an error if a constraint is re-added with different values" do
|
|
67
|
+
@validator.add( :a_field, :string )
|
|
68
|
+
expect {
|
|
69
|
+
@validator.add( :a_field, :integer )
|
|
70
|
+
}.to raise_error( /parameter "a_field" is already defined as a 'string'/i )
|
|
71
|
+
end
|
|
72
|
+
|
|
68
73
|
it "allows an existing constraint to be overridden" do
|
|
69
74
|
@validator.add( :a_field, :string )
|
|
70
75
|
@validator.override( :a_field, :integer )
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: strelka
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.1.pre.
|
|
4
|
+
version: 0.0.1.pre.284
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -36,7 +36,7 @@ cert_chain:
|
|
|
36
36
|
YUhDS0xaZFNLai9SSHVUT3QrZ2JsUmV4OEZBaDhOZUEKY21saFhlNDZwWk5K
|
|
37
37
|
Z1dLYnhaYWg4NWpJang5NWhSOHZPSStOQU01aUg5a09xSzEzRHJ4YWNUS1Bo
|
|
38
38
|
cWo1UGp3RgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
|
|
39
|
-
date: 2012-07-
|
|
39
|
+
date: 2012-07-18 00:00:00.000000000 Z
|
|
40
40
|
dependencies:
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: configurability
|
|
@@ -141,7 +141,7 @@ dependencies:
|
|
|
141
141
|
requirements:
|
|
142
142
|
- - ~>
|
|
143
143
|
- !ruby/object:Gem::Version
|
|
144
|
-
version: '0.
|
|
144
|
+
version: '0.29'
|
|
145
145
|
type: :runtime
|
|
146
146
|
prerelease: false
|
|
147
147
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -149,7 +149,7 @@ dependencies:
|
|
|
149
149
|
requirements:
|
|
150
150
|
- - ~>
|
|
151
151
|
- !ruby/object:Gem::Version
|
|
152
|
-
version: '0.
|
|
152
|
+
version: '0.29'
|
|
153
153
|
- !ruby/object:Gem::Dependency
|
|
154
154
|
name: pluginfactory
|
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
metadata.gz.sig
CHANGED
|
Binary file
|