grape 0.3.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of grape might be problematic. Click here for more details.

Files changed (101) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +8 -0
  3. data/.rubocop.yml +70 -0
  4. data/.travis.yml +7 -6
  5. data/CHANGELOG.md +134 -4
  6. data/CONTRIBUTING.md +118 -0
  7. data/Gemfile +5 -2
  8. data/README.md +551 -116
  9. data/RELEASING.md +105 -0
  10. data/Rakefile +29 -8
  11. data/UPGRADING.md +124 -0
  12. data/grape.gemspec +3 -3
  13. data/lib/grape/api.rb +207 -88
  14. data/lib/grape/cookies.rb +4 -8
  15. data/lib/grape/endpoint.rb +198 -144
  16. data/lib/grape/error_formatter/base.rb +5 -7
  17. data/lib/grape/error_formatter/json.rb +3 -5
  18. data/lib/grape/error_formatter/txt.rb +1 -3
  19. data/lib/grape/error_formatter/xml.rb +4 -6
  20. data/lib/grape/exceptions/base.rb +9 -9
  21. data/lib/grape/exceptions/incompatible_option_values.rb +10 -0
  22. data/lib/grape/exceptions/invalid_formatter.rb +1 -4
  23. data/lib/grape/exceptions/invalid_versioner_option.rb +1 -5
  24. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +1 -6
  25. data/lib/grape/exceptions/missing_mime_type.rb +1 -5
  26. data/lib/grape/exceptions/missing_option.rb +1 -4
  27. data/lib/grape/exceptions/missing_vendor_option.rb +1 -4
  28. data/lib/grape/exceptions/unknown_options.rb +1 -5
  29. data/lib/grape/exceptions/unknown_validator.rb +1 -3
  30. data/lib/grape/exceptions/validation.rb +13 -3
  31. data/lib/grape/exceptions/validation_errors.rb +43 -0
  32. data/lib/grape/formatter/base.rb +5 -7
  33. data/lib/grape/formatter/json.rb +0 -3
  34. data/lib/grape/formatter/serializable_hash.rb +15 -15
  35. data/lib/grape/formatter/txt.rb +0 -2
  36. data/lib/grape/formatter/xml.rb +0 -2
  37. data/lib/grape/http/request.rb +26 -0
  38. data/lib/grape/locale/en.yml +8 -5
  39. data/lib/grape/middleware/auth/base.rb +30 -0
  40. data/lib/grape/middleware/auth/basic.rb +3 -20
  41. data/lib/grape/middleware/auth/digest.rb +2 -19
  42. data/lib/grape/middleware/auth/oauth2.rb +31 -24
  43. data/lib/grape/middleware/base.rb +7 -7
  44. data/lib/grape/middleware/error.rb +36 -22
  45. data/lib/grape/middleware/filter.rb +3 -3
  46. data/lib/grape/middleware/formatter.rb +99 -61
  47. data/lib/grape/middleware/globals.rb +13 -0
  48. data/lib/grape/middleware/versioner/accept_version_header.rb +67 -0
  49. data/lib/grape/middleware/versioner/header.rb +22 -16
  50. data/lib/grape/middleware/versioner/param.rb +9 -11
  51. data/lib/grape/middleware/versioner/path.rb +10 -13
  52. data/lib/grape/middleware/versioner.rb +3 -1
  53. data/lib/grape/namespace.rb +23 -0
  54. data/lib/grape/parser/base.rb +3 -5
  55. data/lib/grape/parser/json.rb +0 -2
  56. data/lib/grape/parser/xml.rb +0 -2
  57. data/lib/grape/path.rb +70 -0
  58. data/lib/grape/route.rb +10 -6
  59. data/lib/grape/util/content_types.rb +2 -1
  60. data/lib/grape/util/deep_merge.rb +5 -5
  61. data/lib/grape/util/hash_stack.rb +13 -2
  62. data/lib/grape/validations/coerce.rb +11 -10
  63. data/lib/grape/validations/default.rb +25 -0
  64. data/lib/grape/validations/presence.rb +7 -3
  65. data/lib/grape/validations/regexp.rb +2 -5
  66. data/lib/grape/validations/values.rb +17 -0
  67. data/lib/grape/validations.rb +161 -54
  68. data/lib/grape/version.rb +1 -1
  69. data/lib/grape.rb +19 -4
  70. data/spec/grape/api_spec.rb +897 -268
  71. data/spec/grape/endpoint_spec.rb +283 -66
  72. data/spec/grape/entity_spec.rb +132 -29
  73. data/spec/grape/exceptions/missing_mime_type_spec.rb +3 -9
  74. data/spec/grape/exceptions/validation_errors_spec.rb +19 -0
  75. data/spec/grape/middleware/auth/basic_spec.rb +8 -8
  76. data/spec/grape/middleware/auth/digest_spec.rb +5 -5
  77. data/spec/grape/middleware/auth/oauth2_spec.rb +81 -36
  78. data/spec/grape/middleware/base_spec.rb +8 -13
  79. data/spec/grape/middleware/error_spec.rb +13 -17
  80. data/spec/grape/middleware/exception_spec.rb +47 -27
  81. data/spec/grape/middleware/formatter_spec.rb +103 -41
  82. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +121 -0
  83. data/spec/grape/middleware/versioner/header_spec.rb +76 -51
  84. data/spec/grape/middleware/versioner/param_spec.rb +18 -18
  85. data/spec/grape/middleware/versioner/path_spec.rb +6 -6
  86. data/spec/grape/middleware/versioner_spec.rb +5 -2
  87. data/spec/grape/path_spec.rb +229 -0
  88. data/spec/grape/util/hash_stack_spec.rb +31 -32
  89. data/spec/grape/validations/coerce_spec.rb +116 -51
  90. data/spec/grape/validations/default_spec.rb +123 -0
  91. data/spec/grape/validations/presence_spec.rb +42 -44
  92. data/spec/grape/validations/regexp_spec.rb +9 -9
  93. data/spec/grape/validations/values_spec.rb +138 -0
  94. data/spec/grape/validations/zh-CN.yml +4 -3
  95. data/spec/grape/validations_spec.rb +681 -48
  96. data/spec/shared/versioning_examples.rb +22 -6
  97. data/spec/spec_helper.rb +3 -2
  98. data/spec/support/basic_auth_encode_helpers.rb +0 -1
  99. data/spec/support/content_type_helpers.rb +11 -0
  100. data/spec/support/versioned_helpers.rb +13 -5
  101. metadata +34 -84
data/lib/grape/api.rb CHANGED
@@ -6,14 +6,10 @@ module Grape
6
6
  extend Validations::ClassMethods
7
7
 
8
8
  class << self
9
- attr_reader :route_set
10
- attr_reader :versions
11
- attr_reader :routes
12
- attr_reader :settings
9
+ attr_reader :endpoints, :instance, :routes, :route_set, :settings, :versions
13
10
  attr_writer :logger
14
- attr_reader :endpoints
15
- attr_reader :mountings
16
- attr_reader :instance
11
+
12
+ LOCK = Mutex.new
17
13
 
18
14
  def logger(logger = nil)
19
15
  if logger
@@ -27,13 +23,12 @@ module Grape
27
23
  @settings = Grape::Util::HashStack.new
28
24
  @route_set = Rack::Mount::RouteSet.new
29
25
  @endpoints = []
30
- @mountings = []
31
26
  @routes = nil
32
27
  reset_validations!
33
28
  end
34
29
 
35
30
  def compile
36
- @instance = self.new
31
+ @instance ||= new
37
32
  end
38
33
 
39
34
  def change!
@@ -41,7 +36,7 @@ module Grape
41
36
  end
42
37
 
43
38
  def call(env)
44
- compile unless instance
39
+ LOCK.synchronize { compile } unless instance
45
40
  call!(env)
46
41
  end
47
42
 
@@ -88,12 +83,12 @@ module Grape
88
83
  # version 'v2'
89
84
  #
90
85
  # get '/main' do
91
- # {:some => 'data'}
86
+ # {some: 'data'}
92
87
  # end
93
88
  #
94
89
  # version 'v1' do
95
90
  # get '/main' do
96
- # {:legacy => 'data'}
91
+ # {legacy: 'data'}
97
92
  # end
98
93
  # end
99
94
  # end
@@ -102,7 +97,7 @@ module Grape
102
97
  if args.any?
103
98
  options = args.pop if args.last.is_a? Hash
104
99
  options ||= {}
105
- options = {:using => :path}.merge!(options)
100
+ options = { using: :path }.merge(options)
106
101
 
107
102
  raise Grape::Exceptions::MissingVendorOption.new if options[:using] == :header && !options.has_key?(:vendor)
108
103
 
@@ -118,7 +113,7 @@ module Grape
118
113
 
119
114
  # Add a description to the next namespace or function.
120
115
  def desc(description, options = {})
121
- @last_description = options.merge(:description => description)
116
+ @last_description = options.merge(description: description)
122
117
  end
123
118
 
124
119
  # Specify the default format for the API's serializers.
@@ -154,12 +149,23 @@ module Grape
154
149
  end
155
150
 
156
151
  # Specify a default error formatter.
157
- def default_error_formatter(new_formatter = nil)
158
- new_formatter ? set(:default_error_formatter, new_formatter) : settings[:default_error_formatter]
152
+ def default_error_formatter(new_formatter_name = nil)
153
+ if new_formatter_name
154
+ new_formatter = Grape::ErrorFormatter::Base.formatter_for(new_formatter_name, {})
155
+ set(:default_error_formatter, new_formatter)
156
+ else
157
+ settings[:default_error_formatter]
158
+ end
159
159
  end
160
160
 
161
- def error_formatter(format, new_formatter)
162
- settings.imbue(:error_formatters, format.to_sym => new_formatter)
161
+ def error_formatter(format, options)
162
+ if options.is_a?(Hash) && options.has_key?(:with)
163
+ formatter = options[:with]
164
+ else
165
+ formatter = options
166
+ end
167
+
168
+ settings.imbue(:error_formatters, format.to_sym => formatter)
163
169
  end
164
170
 
165
171
  # Specify additional content-types, e.g.:
@@ -195,15 +201,25 @@ module Grape
195
201
  # @param [Block] block Execution block to handle the given exception.
196
202
  # @param [Hash] options Options for the rescue usage.
197
203
  # @option options [Boolean] :backtrace Include a backtrace in the rescue response.
204
+ # @option options [Boolean] :rescue_subclasses Also rescue subclasses of exception classes
205
+ # @param [Proc] handler Execution proc to handle the given exception as an
206
+ # alternative to passing a block
198
207
  def rescue_from(*args, &block)
199
- if block_given?
200
- args.each do |arg|
201
- imbue(:rescue_handlers, { arg => block })
202
- end
208
+ if args.last.is_a?(Proc)
209
+ handler = args.pop
210
+ elsif block_given?
211
+ handler = block
203
212
  end
204
- imbue(:rescue_options, args.pop) if args.last.is_a?(Hash)
205
- set(:rescue_all, true) and return if args.include?(:all)
206
- imbue(:rescued_errors, args)
213
+
214
+ options = args.last.is_a?(Hash) ? args.pop : {}
215
+ handler ||= proc { options[:with] } if options.has_key?(:with)
216
+
217
+ handler_type = !!options[:rescue_subclasses] ? :rescue_handlers : :base_only_rescue_handlers
218
+ imbue handler_type, Hash[args.map { |arg| [arg, handler] }]
219
+
220
+ imbue(:rescue_options, options)
221
+
222
+ set(:rescue_all, true) if args.include?(:all)
207
223
  end
208
224
 
209
225
  # Allows you to specify a default representation entity for a
@@ -212,10 +228,10 @@ module Grape
212
228
  #
213
229
  # @example
214
230
  # class ExampleAPI < Grape::API
215
- # represent User, :with => Entity::User
231
+ # represent User, with: Entity::User
216
232
  #
217
233
  # get '/me' do
218
- # present current_user # :with => Entity::User is assumed
234
+ # present current_user # with: Entity::User is assumed
219
235
  # end
220
236
  # end
221
237
  #
@@ -254,11 +270,16 @@ module Grape
254
270
  if block_given? || new_mod
255
271
  mod = settings.peek[:helpers] || Module.new
256
272
  if new_mod
273
+ inject_api_helpers_to_mod(new_mod) if new_mod.is_a?(Helpers)
257
274
  mod.class_eval do
258
275
  include new_mod
259
276
  end
260
277
  end
261
- mod.class_eval &block if block_given?
278
+ if block_given?
279
+ inject_api_helpers_to_mod(mod) do
280
+ mod.class_eval(&block)
281
+ end
282
+ end
262
283
  set(:helpers, mod)
263
284
  else
264
285
  mod = Module.new
@@ -274,7 +295,7 @@ module Grape
274
295
  # only `:http_basic`, `:http_digest` and `:oauth2` are supported.
275
296
  def auth(type = nil, options = {}, &block)
276
297
  if type
277
- set(:auth, {:type => type.to_sym, :proc => block}.merge(options))
298
+ set(:auth, { type: type.to_sym, proc: block }.merge(options))
278
299
  else
279
300
  settings[:auth]
280
301
  end
@@ -298,17 +319,18 @@ module Grape
298
319
  def mount(mounts)
299
320
  mounts = { mounts => '/' } unless mounts.respond_to?(:each_pair)
300
321
  mounts.each_pair do |app, path|
301
- if app.respond_to?(:inherit_settings)
322
+ if app.respond_to?(:inherit_settings, true)
302
323
  app_settings = settings.clone
303
- mount_path = Rack::Mount::Utils.normalize_path([ settings[:mount_path], path ].compact.join("/"))
324
+ mount_path = Rack::Mount::Utils.normalize_path([settings[:mount_path], path].compact.join("/"))
304
325
  app_settings.set :mount_path, mount_path
305
326
  app.inherit_settings(app_settings)
306
327
  end
307
- endpoints << Grape::Endpoint.new(settings.clone, {
308
- :method => :any,
309
- :path => path,
310
- :app => app
311
- })
328
+ endpoints << Grape::Endpoint.new(
329
+ settings.clone,
330
+ method: :any,
331
+ path: path,
332
+ app: app
333
+ )
312
334
  end
313
335
  end
314
336
 
@@ -321,14 +343,14 @@ module Grape
321
343
  # @example Defining a basic route.
322
344
  # class MyAPI < Grape::API
323
345
  # route(:any, '/hello') do
324
- # {:hello => 'world'}
346
+ # {hello: 'world'}
325
347
  # end
326
348
  # end
327
349
  def route(methods, paths = ['/'], route_options = {}, &block)
328
350
  endpoint_options = {
329
- :method => methods,
330
- :path => paths,
331
- :route_options => (@namespace_description || {}).deep_merge(@last_description || {}).deep_merge(route_options || {})
351
+ method: methods,
352
+ path: paths,
353
+ route_options: (@namespace_description || {}).deep_merge(@last_description || {}).deep_merge(route_options || {})
332
354
  }
333
355
  endpoints << Grape::Endpoint.new(settings.clone, endpoint_options, &block)
334
356
 
@@ -340,6 +362,10 @@ module Grape
340
362
  imbue(:befores, [block])
341
363
  end
342
364
 
365
+ def before_validation(&block)
366
+ imbue(:before_validations, [block])
367
+ end
368
+
343
369
  def after_validation(&block)
344
370
  imbue(:after_validations, [block])
345
371
  end
@@ -348,28 +374,59 @@ module Grape
348
374
  imbue(:afters, [block])
349
375
  end
350
376
 
351
- def get(paths = ['/'], options = {}, &block); route('GET', paths, options, &block) end
352
- def post(paths = ['/'], options = {}, &block); route('POST', paths, options, &block) end
353
- def put(paths = ['/'], options = {}, &block); route('PUT', paths, options, &block) end
354
- def head(paths = ['/'], options = {}, &block); route('HEAD', paths, options, &block) end
355
- def delete(paths = ['/'], options = {}, &block); route('DELETE', paths, options, &block) end
356
- def options(paths = ['/'], options = {}, &block); route('OPTIONS', paths, options, &block) end
357
- def patch(paths = ['/'], options = {}, &block); route('PATCH', paths, options, &block) end
377
+ def get(paths = ['/'], options = {}, &block)
378
+ route('GET', paths, options, &block)
379
+ end
358
380
 
359
- def namespace(space = nil, &block)
381
+ def post(paths = ['/'], options = {}, &block)
382
+ route('POST', paths, options, &block)
383
+ end
384
+
385
+ def put(paths = ['/'], options = {}, &block)
386
+ route('PUT', paths, options, &block)
387
+ end
388
+
389
+ def head(paths = ['/'], options = {}, &block)
390
+ route('HEAD', paths, options, &block)
391
+ end
392
+
393
+ def delete(paths = ['/'], options = {}, &block)
394
+ route('DELETE', paths, options, &block)
395
+ end
396
+
397
+ def options(paths = ['/'], options = {}, &block)
398
+ route('OPTIONS', paths, options, &block)
399
+ end
400
+
401
+ def patch(paths = ['/'], options = {}, &block)
402
+ route('PATCH', paths, options, &block)
403
+ end
404
+
405
+ def namespace(space = nil, options = {}, &block)
360
406
  if space || block_given?
361
407
  previous_namespace_description = @namespace_description
362
408
  @namespace_description = (@namespace_description || {}).deep_merge(@last_description || {})
363
409
  @last_description = nil
364
410
  nest(block) do
365
- set(:namespace, space.to_s) if space
411
+ set(:namespace, Namespace.new(space, options)) if space
366
412
  end
367
413
  @namespace_description = previous_namespace_description
368
414
  else
369
- Rack::Mount::Utils.normalize_path(settings.stack.map{|s| s[:namespace]}.join('/'))
415
+ Namespace.joined_space_path(settings)
370
416
  end
371
417
  end
372
418
 
419
+ # Thie method allows you to quickly define a parameter route segment
420
+ # in your API.
421
+ #
422
+ # @param param [Symbol] The name of the parameter you wish to declare.
423
+ # @option options [Regexp] You may supply a regular expression that the declared parameter must meet.
424
+ def route_param(param, options = {}, &block)
425
+ options = options.dup
426
+ options[:requirements] = { param.to_sym => options[:requirements] } if options[:requirements].is_a?(Regexp)
427
+ namespace(":#{param}", options, &block)
428
+ end
429
+
373
430
  alias_method :group, :namespace
374
431
  alias_method :resource, :namespace
375
432
  alias_method :resources, :namespace
@@ -398,7 +455,10 @@ module Grape
398
455
  # and arguments that are currently applied to the
399
456
  # application.
400
457
  def middleware
401
- settings.stack.inject([]){|a,s| a += s[:middleware] if s[:middleware]; a}
458
+ settings.stack.inject([]) do |a, s|
459
+ a += s[:middleware] if s[:middleware]
460
+ a
461
+ end
402
462
  end
403
463
 
404
464
  # An array of API routes.
@@ -410,6 +470,14 @@ module Grape
410
470
  @versions ||= []
411
471
  end
412
472
 
473
+ def cascade(value = nil)
474
+ if value.nil?
475
+ settings.has_key?(:cascade) ? !!settings[:cascade] : true
476
+ else
477
+ set(:cascade, value)
478
+ end
479
+ end
480
+
413
481
  protected
414
482
 
415
483
  def prepare_routes
@@ -424,15 +492,15 @@ module Grape
424
492
  # block passed in. Allows for simple 'before' setups
425
493
  # of settings stack pushes.
426
494
  def nest(*blocks, &block)
427
- blocks.reject!{|b| b.nil?}
495
+ blocks.reject! { |b| b.nil? }
428
496
  if blocks.any?
429
497
  settings.push # create a new context to eval the follow
430
- instance_eval &block if block_given?
431
- blocks.each{|b| instance_eval &b}
432
- settings.pop # when finished, we pop the context
498
+ instance_eval(&block) if block_given?
499
+ blocks.each { |b| instance_eval(&b) }
500
+ settings.pop # when finished, we pop the context
433
501
  reset_validations!
434
502
  else
435
- instance_eval &block
503
+ instance_eval(&block)
436
504
  end
437
505
  end
438
506
 
@@ -443,23 +511,32 @@ module Grape
443
511
 
444
512
  def inherit_settings(other_stack)
445
513
  settings.prepend other_stack
446
- endpoints.each{|e| e.settings.prepend(other_stack)}
514
+ endpoints.each do |e|
515
+ e.settings.prepend(other_stack)
516
+ e.options[:app].inherit_settings(other_stack) if e.options[:app].respond_to?(:inherit_settings, true)
517
+ end
518
+ end
519
+
520
+ def inject_api_helpers_to_mod(mod, &block)
521
+ mod.extend(Helpers)
522
+ yield if block_given?
523
+ mod.api_changed(self)
447
524
  end
448
525
  end
449
526
 
450
527
  def initialize
451
528
  @route_set = Rack::Mount::RouteSet.new
529
+ add_head_not_allowed_methods_and_options_methods
452
530
  self.class.endpoints.each do |endpoint|
453
531
  endpoint.mount_in(@route_set)
454
532
  end
455
- add_head_not_allowed_methods
456
533
  @route_set.freeze
457
534
  end
458
535
 
459
536
  def call(env)
460
537
  status, headers, body = @route_set.call(env)
461
538
  headers.delete('X-Cascade') unless cascade?
462
- [ status, headers, body ]
539
+ [status, headers, body]
463
540
  end
464
541
 
465
542
  # Some requests may return a HTTP 404 error if grape cannot find a matching
@@ -471,8 +548,9 @@ module Grape
471
548
  # errors from reaching upstream. This is effectivelly done by unsetting
472
549
  # X-Cascade. Default :cascade is true.
473
550
  def cascade?
474
- cascade = ((self.class.settings || {})[:version_options] || {})[:cascade]
475
- cascade.nil? ? true : cascade
551
+ return !!self.class.settings[:cascade] if self.class.settings.has_key?(:cascade)
552
+ return !!self.class.settings[:version_options][:cascade] if self.class.settings[:version_options] && self.class.settings[:version_options].has_key?(:cascade)
553
+ true
476
554
  end
477
555
 
478
556
  reset!
@@ -483,37 +561,78 @@ module Grape
483
561
  # with a list of HTTP methods that can be called. Also add a route that
484
562
  # will return an HTTP 405 response for any HTTP method that the resource
485
563
  # cannot handle.
486
- def add_head_not_allowed_methods
487
- allowed_methods = Hash.new{|h,k| h[k] = [] }
488
- resources = self.class.endpoints.map do |endpoint|
489
- endpoint.options[:app] && endpoint.options[:app].respond_to?(:endpoints) ?
490
- endpoint.options[:app].endpoints.map(&:routes) :
491
- endpoint.routes
492
- end
493
- resources.flatten.each do |route|
494
- allowed_methods[route.route_compiled] << route.route_method
495
- end
496
- allowed_methods.each do |path_info, methods|
497
- if methods.include?('GET') && ! methods.include?("HEAD") && ! self.class.settings[:do_not_route_head]
498
- methods = methods | [ 'HEAD' ]
499
- end
500
- allow_header = (["OPTIONS"] | methods).join(", ")
501
- unless methods.include?("OPTIONS") || self.class.settings[:do_not_route_options]
502
- @route_set.add_route( proc { [204, { 'Allow' => allow_header }, []]}, {
503
- :path_info => path_info,
504
- :request_method => "OPTIONS"
505
- })
564
+ def add_head_not_allowed_methods_and_options_methods
565
+ methods_per_path = {}
566
+ self.class.endpoints.each do |endpoint|
567
+ routes = endpoint.routes
568
+ routes.each do |route|
569
+ methods_per_path[route.route_path] ||= []
570
+ methods_per_path[route.route_path] << route.route_method
506
571
  end
507
- not_allowed_methods = %w(GET PUT POST DELETE PATCH HEAD) - methods
508
- not_allowed_methods << "OPTIONS" if self.class.settings[:do_not_route_options]
509
- not_allowed_methods.each do |bad_method|
510
- @route_set.add_route( proc { [405, { 'Allow' => allow_header }, []]}, {
511
- :path_info => path_info,
512
- :request_method => bad_method
513
- })
572
+ end
573
+
574
+ # The paths we collected are prepared (cf. Path#prepare), so they
575
+ # contain already versioning information when using path versioning.
576
+ # Disable versioning so adding a route won't prepend versioning
577
+ # informations again.
578
+ without_versioning do
579
+ methods_per_path.each do |path, methods|
580
+ allowed_methods = methods.dup
581
+ unless self.class.settings[:do_not_route_head]
582
+ if allowed_methods.include?('GET')
583
+ allowed_methods = allowed_methods | ['HEAD']
584
+ end
585
+ end
586
+
587
+ allow_header = (['OPTIONS'] | allowed_methods).join(', ')
588
+ unless self.class.settings[:do_not_route_options]
589
+ unless allowed_methods.include?('OPTIONS')
590
+ self.class.options(path, {}) do
591
+ header 'Allow', allow_header
592
+ status 204
593
+ ''
594
+ end
595
+ end
596
+ end
597
+
598
+ not_allowed_methods = %w(GET PUT POST DELETE PATCH HEAD) - allowed_methods
599
+ not_allowed_methods << 'OPTIONS' if self.class.settings[:do_not_route_options]
600
+ self.class.route(not_allowed_methods, path) do
601
+ header 'Allow', allow_header
602
+ status 405
603
+ ''
604
+ end
514
605
  end
515
606
  end
516
607
  end
517
608
 
609
+ def without_versioning(&block)
610
+ self.class.settings.push(version: nil, version_options: nil)
611
+ yield
612
+ self.class.settings.pop
613
+ end
614
+
615
+ # This module extends user defined helpers
616
+ # to provide some API-specific functionality
617
+ module Helpers
618
+ attr_accessor :api
619
+ def params(name, &block)
620
+ @named_params ||= {}
621
+ @named_params.merge! name => block
622
+ end
623
+
624
+ def api_changed(new_api)
625
+ @api = new_api
626
+ process_named_params
627
+ end
628
+
629
+ protected
630
+
631
+ def process_named_params
632
+ if @named_params && @named_params.any?
633
+ api.imbue(:named_params, @named_params)
634
+ end
635
+ end
636
+ end
518
637
  end
519
638
  end
data/lib/grape/cookies.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  module Grape
2
2
  class Cookies
3
-
4
3
  def initialize
5
4
  @cookies = {}
6
5
  @send_cookies = {}
@@ -13,12 +12,10 @@ module Grape
13
12
  end
14
13
 
15
14
  def write(header)
16
- @cookies.select { |key, value|
17
- @send_cookies[key] == true
18
- }.each { |name, value|
19
- cookie_value = value.is_a?(Hash) ? value : { :value => value }
15
+ @cookies.select { |key, value| @send_cookies[key] == true }.each do |name, value|
16
+ cookie_value = value.is_a?(Hash) ? value : { value: value }
20
17
  Rack::Utils.set_cookie_header! header, name, cookie_value
21
- }
18
+ end
22
19
  end
23
20
 
24
21
  def [](name)
@@ -35,9 +32,8 @@ module Grape
35
32
  end
36
33
 
37
34
  def delete(name, opts = {})
38
- options = opts.merge({ :value => 'deleted', :expires => Time.at(0) })
35
+ options = opts.merge(value: 'deleted', expires: Time.at(0))
39
36
  self.[]=(name, options)
40
37
  end
41
-
42
38
  end
43
39
  end