strelka 0.0.1.pre.279 → 0.0.1.pre.284

Sign up to get free protection for your applications and to get access to all the features.
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] [tip]
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.28'
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
- # Set up parameters
128
- self.add_parameters( rsrcobj, options )
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.content_type = 'text/plain'
177
- res.body = ''
178
- res.status = HTTP::OK
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 should be a
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 be a
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" % [ rsrcobj, route ]
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" % [ rsrcobj, route ]
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" % [ rsrcobj, route ]
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" % [ rsrcobj, route ]
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 base
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" % [ dsname, rsrcobj ]
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.db.transaction do
490
- resource = rsrcobj[ id ] or
491
- finish_with( HTTP::NOT_FOUND, "No such %s [%p]" % [rsrcobj.table_name, id] )
492
-
493
- # Apply limit and offset parameters if they exist
494
- limit, offset = req.params.values_at( :limit, :offset )
495
- dataset = resource.send( "#{association}_dataset" )
496
- if limit
497
- self.log.debug "Limiting result set to %p records" % [ limit ]
498
- dataset = dataset.limit( limit, offset )
499
- end
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
- # Fetch and return the records as JSON or YAML
502
- # :TODO: Handle other mediatypes
503
- self.log.debug "Returning collection: %s" % [ dataset.sql ]
504
- res.for( :json, :yaml ) { dataset.all }
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
@@ -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.start_with?( 'text' )
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
- raise ArgumentError,
283
- "parameter %p is already defined; perhaps you meant to use #override?" % [name] if
284
- self.param_names.include?( name )
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
- args.unshift( block ) if block
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( :name )
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
@@ -41,6 +41,8 @@ require 'strelka'
41
41
 
42
42
  require 'spec/lib/constants'
43
43
 
44
+ Loggability.format_with( :color ) if $stdout.tty?
45
+
44
46
 
45
47
  ### RSpec helper functions.
46
48
  module Strelka::SpecHelpers
@@ -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( :fatal )
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 including App" do
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 "knows what resources are mounted where" do
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 "knows about the mounted resource" do
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 "knows about the mounted resource" do
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 "route behaviors" do
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
- context "OPTIONS routes" do
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 routes" do
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 routes" do
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 routes" do
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 routes" do
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 "doesn't allow a constraint to be added twice" do
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.279
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-12 00:00:00.000000000 Z
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.28'
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.28'
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