grape 0.6.0 → 0.6.1

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 (84) hide show
  1. checksums.yaml +8 -8
  2. data/.rubocop.yml +65 -0
  3. data/.travis.yml +4 -0
  4. data/CHANGELOG.md +17 -1
  5. data/Gemfile +1 -0
  6. data/README.md +16 -8
  7. data/RELEASING.md +105 -0
  8. data/grape.gemspec +1 -1
  9. data/lib/grape.rb +1 -0
  10. data/lib/grape/api.rb +88 -54
  11. data/lib/grape/cookies.rb +4 -6
  12. data/lib/grape/endpoint.rb +81 -69
  13. data/lib/grape/error_formatter/base.rb +5 -4
  14. data/lib/grape/error_formatter/json.rb +3 -3
  15. data/lib/grape/error_formatter/txt.rb +1 -1
  16. data/lib/grape/error_formatter/xml.rb +4 -4
  17. data/lib/grape/exceptions/base.rb +7 -7
  18. data/lib/grape/exceptions/incompatible_option_values.rb +13 -0
  19. data/lib/grape/exceptions/invalid_formatter.rb +1 -1
  20. data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
  21. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +1 -4
  22. data/lib/grape/exceptions/missing_mime_type.rb +1 -1
  23. data/lib/grape/exceptions/missing_option.rb +1 -1
  24. data/lib/grape/exceptions/missing_vendor_option.rb +1 -1
  25. data/lib/grape/exceptions/unknown_options.rb +1 -1
  26. data/lib/grape/exceptions/unknown_validator.rb +1 -1
  27. data/lib/grape/exceptions/validation.rb +2 -2
  28. data/lib/grape/exceptions/validation_errors.rb +1 -1
  29. data/lib/grape/formatter/base.rb +5 -4
  30. data/lib/grape/formatter/serializable_hash.rb +7 -6
  31. data/lib/grape/http/request.rb +2 -2
  32. data/lib/grape/locale/en.yml +2 -0
  33. data/lib/grape/middleware/auth/base.rb +3 -3
  34. data/lib/grape/middleware/auth/basic.rb +1 -1
  35. data/lib/grape/middleware/auth/oauth2.rb +18 -20
  36. data/lib/grape/middleware/base.rb +1 -1
  37. data/lib/grape/middleware/error.rb +19 -19
  38. data/lib/grape/middleware/filter.rb +3 -3
  39. data/lib/grape/middleware/formatter.rb +29 -23
  40. data/lib/grape/middleware/versioner.rb +1 -1
  41. data/lib/grape/middleware/versioner/accept_version_header.rb +8 -6
  42. data/lib/grape/middleware/versioner/header.rb +16 -14
  43. data/lib/grape/middleware/versioner/param.rb +7 -7
  44. data/lib/grape/middleware/versioner/path.rb +7 -9
  45. data/lib/grape/parser/base.rb +3 -2
  46. data/lib/grape/path.rb +1 -1
  47. data/lib/grape/route.rb +6 -4
  48. data/lib/grape/util/content_types.rb +2 -1
  49. data/lib/grape/util/deep_merge.rb +5 -5
  50. data/lib/grape/util/hash_stack.rb +2 -2
  51. data/lib/grape/validations.rb +34 -30
  52. data/lib/grape/validations/coerce.rb +6 -5
  53. data/lib/grape/validations/default.rb +0 -1
  54. data/lib/grape/validations/presence.rb +1 -1
  55. data/lib/grape/validations/regexp.rb +2 -2
  56. data/lib/grape/validations/values.rb +16 -0
  57. data/lib/grape/version.rb +1 -1
  58. data/spec/grape/api_spec.rb +229 -210
  59. data/spec/grape/endpoint_spec.rb +56 -54
  60. data/spec/grape/entity_spec.rb +31 -33
  61. data/spec/grape/exceptions/missing_mime_type_spec.rb +3 -9
  62. data/spec/grape/middleware/auth/basic_spec.rb +8 -8
  63. data/spec/grape/middleware/auth/digest_spec.rb +5 -5
  64. data/spec/grape/middleware/auth/oauth2_spec.rb +23 -23
  65. data/spec/grape/middleware/base_spec.rb +6 -6
  66. data/spec/grape/middleware/error_spec.rb +11 -15
  67. data/spec/grape/middleware/exception_spec.rb +45 -25
  68. data/spec/grape/middleware/formatter_spec.rb +56 -45
  69. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +25 -25
  70. data/spec/grape/middleware/versioner/header_spec.rb +54 -54
  71. data/spec/grape/middleware/versioner/param_spec.rb +17 -18
  72. data/spec/grape/middleware/versioner/path_spec.rb +6 -6
  73. data/spec/grape/middleware/versioner_spec.rb +1 -1
  74. data/spec/grape/util/hash_stack_spec.rb +26 -27
  75. data/spec/grape/validations/coerce_spec.rb +39 -34
  76. data/spec/grape/validations/default_spec.rb +12 -13
  77. data/spec/grape/validations/presence_spec.rb +18 -22
  78. data/spec/grape/validations/regexp_spec.rb +9 -9
  79. data/spec/grape/validations/values_spec.rb +64 -0
  80. data/spec/grape/validations_spec.rb +127 -70
  81. data/spec/shared/versioning_examples.rb +5 -5
  82. data/spec/support/basic_auth_encode_helpers.rb +0 -1
  83. data/spec/support/versioned_helpers.rb +5 -6
  84. metadata +10 -4
data/lib/grape/cookies.rb CHANGED
@@ -13,12 +13,10 @@ module Grape
13
13
  end
14
14
 
15
15
  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 }
16
+ @cookies.select { |key, value| @send_cookies[key] == true }.each do |name, value|
17
+ cookie_value = value.is_a?(Hash) ? value : { value: value }
20
18
  Rack::Utils.set_cookie_header! header, name, cookie_value
21
- }
19
+ end
22
20
  end
23
21
 
24
22
  def [](name)
@@ -35,7 +33,7 @@ module Grape
35
33
  end
36
34
 
37
35
  def delete(name, opts = {})
38
- options = opts.merge({ :value => 'deleted', :expires => Time.at(0) })
36
+ options = opts.merge(value: 'deleted', expires: Time.at(0))
39
37
  self.[]=(name, options)
40
38
  end
41
39
 
@@ -52,15 +52,15 @@ module Grape
52
52
  end
53
53
 
54
54
  def require_option(options, key)
55
- options.has_key?(key) or raise Grape::Exceptions::MissingOption.new(key)
55
+ raise Grape::Exceptions::MissingOption.new(key) unless options.has_key?(key)
56
56
  end
57
57
 
58
58
  def method_name
59
- [ options[:method],
60
- Namespace.joined_space(settings),
61
- settings.gather(:mount_path).join('/'),
62
- options[:path].join('/')
63
- ].join(" ")
59
+ [options[:method],
60
+ Namespace.joined_space(settings),
61
+ settings.gather(:mount_path).join('/'),
62
+ options[:path].join('/')
63
+ ].join(" ")
64
64
  end
65
65
 
66
66
  def routes
@@ -72,15 +72,15 @@ module Grape
72
72
  endpoints.each { |e| e.mount_in(route_set) }
73
73
  else
74
74
  routes.each do |route|
75
- methods = [ route.route_method ]
76
- if ! settings[:do_not_route_head] && route.route_method == "GET"
75
+ methods = [route.route_method]
76
+ if !settings[:do_not_route_head] && route.route_method == "GET"
77
77
  methods << "HEAD"
78
78
  end
79
79
  methods.each do |method|
80
80
  route_set.add_route(self, {
81
- :path_info => route.route_compiled,
82
- :request_method => method,
83
- }, { :route_info => route })
81
+ path_info: route.route_compiled,
82
+ request_method: method,
83
+ }, { route_info: route })
84
84
  end
85
85
  end
86
86
  end
@@ -105,21 +105,21 @@ module Grape
105
105
  regex = Rack::Mount::RegexpWithNamedGroups.new(path)
106
106
  path_params = {}
107
107
  # named parameters in the api path
108
- named_params = regex.named_captures.map { |nc| nc[0] } - [ 'version', 'format' ]
108
+ named_params = regex.named_captures.map { |nc| nc[0] } - %w{ version format }
109
109
  named_params.each { |named_param| path_params[named_param] = "" }
110
110
  # route parameters declared via desc or appended to the api declaration
111
111
  route_params = (options[:route_options][:params] || {})
112
112
  path_params.merge!(route_params)
113
113
  request_method = (method.to_s.upcase unless method == :any)
114
- routes << Route.new(options[:route_options].clone.merge({
115
- :prefix => settings[:root_prefix],
116
- :version => settings[:version] ? settings[:version].join('|') : nil,
117
- :namespace => namespace,
118
- :method => request_method,
119
- :path => prepared_path,
120
- :params => path_params,
121
- :compiled => path,
122
- })
114
+ routes << Route.new(options[:route_options].clone.merge(
115
+ prefix: settings[:root_prefix],
116
+ version: settings[:version] ? settings[:version].join('|') : nil,
117
+ namespace: namespace,
118
+ method: request_method,
119
+ path: prepared_path,
120
+ params: path_params,
121
+ compiled: path,
122
+ )
123
123
  )
124
124
  end
125
125
  end
@@ -151,7 +151,7 @@ module Grape
151
151
  options[:app].call(env)
152
152
  else
153
153
  builder = build_middleware
154
- builder.run options[:app] || lambda{|env| self.run(env) }
154
+ builder.run options[:app] || lambda { |arg| run(arg) }
155
155
  builder.call(env)
156
156
  end
157
157
  end
@@ -187,10 +187,10 @@ module Grape
187
187
  output_key = options[:stringify] ? parent.to_s : parent.to_sym
188
188
  if params.key?(parent) || options[:include_missing]
189
189
  hash[output_key] = if children
190
- declared(params[parent] || {}, options, Array(children))
191
- else
192
- params[parent]
193
- end
190
+ declared(params[parent] || {}, options, Array(children))
191
+ else
192
+ params[parent]
193
+ end
194
194
  end
195
195
  end
196
196
 
@@ -200,15 +200,17 @@ module Grape
200
200
  end
201
201
 
202
202
  # The API version as specified in the URL.
203
- def version; env['api.version'] end
203
+ def version
204
+ env['api.version']
205
+ end
204
206
 
205
207
  # End the request and display an error to the
206
208
  # end user with the specified message.
207
209
  #
208
210
  # @param message [String] The message to display.
209
211
  # @param status [Integer] the HTTP Status Code. Defaults to 403.
210
- def error!(message, status=403)
211
- throw :error, :message => message, :status => status
212
+ def error!(message, status = 403)
213
+ throw :error, message: message, status: status
212
214
  end
213
215
 
214
216
  # Redirect to a new url.
@@ -217,7 +219,7 @@ module Grape
217
219
  # @param options [Hash] The options used when redirect.
218
220
  # :permanent, default true.
219
221
  def redirect(url, options = {})
220
- merged_options = {:permanent => false }.merge(options)
222
+ merged_options = { permanent: false }.merge(options)
221
223
  if merged_options[:permanent]
222
224
  status 301
223
225
  else
@@ -240,10 +242,10 @@ module Grape
240
242
  else
241
243
  return @status if @status
242
244
  case request.request_method.to_s.upcase
243
- when 'POST'
244
- 201
245
- else
246
- 200
245
+ when 'POST'
246
+ 201
247
+ else
248
+ 200
247
249
  end
248
250
  end
249
251
  end
@@ -273,7 +275,7 @@ module Grape
273
275
  # @example
274
276
  # cookies[:mycookie] = 'mycookie val'
275
277
  # cookies['mycookie-string'] = 'mycookie string val'
276
- # cookies[:more] = { :value => '123', :expires => Time.at(0) }
278
+ # cookies[:more] = { value: '123', expires: Time.at(0) }
277
279
  # cookies.delete :more
278
280
  #
279
281
  def cookies
@@ -310,8 +312,8 @@ module Grape
310
312
  #
311
313
  # get '/users/:id' do
312
314
  # present User.find(params[:id]),
313
- # :with => API::Entities::User,
314
- # :admin => current_user.admin?
315
+ # with: API::Entities::User,
316
+ # admin: current_user.admin?
315
317
  # end
316
318
  def present(*args)
317
319
  options = args.count > 1 ? args.extract_options! : {}
@@ -334,15 +336,15 @@ module Grape
334
336
  root = options.delete(:root)
335
337
 
336
338
  representation = if entity_class
337
- embeds = {:env => env}
338
- embeds[:version] = env['api.version'] if env['api.version']
339
- entity_class.represent(object, embeds.merge(options))
340
- else
341
- object
342
- end
339
+ embeds = { env: env }
340
+ embeds[:version] = env['api.version'] if env['api.version']
341
+ entity_class.represent(object, embeds.merge(options))
342
+ else
343
+ object
344
+ end
343
345
 
344
346
  representation = { root => representation } if root
345
- representation = (@body || {}).merge({key => representation}) if key
347
+ representation = (@body || {}).merge(key => representation) if key
346
348
  body representation
347
349
  end
348
350
 
@@ -375,7 +377,7 @@ module Grape
375
377
  @header = {}
376
378
  @request = Grape::Request.new(@env)
377
379
 
378
- self.extend helpers
380
+ extend helpers
379
381
  cookies.read(@request)
380
382
 
381
383
  run_filters befores
@@ -408,22 +410,22 @@ module Grape
408
410
 
409
411
  b.use Rack::Head
410
412
  b.use Grape::Middleware::Error,
411
- :format => settings[:format],
412
- :default_status => settings[:default_error_status] || 403,
413
- :rescue_all => settings[:rescue_all],
414
- :rescued_errors => aggregate_setting(:rescued_errors),
415
- :default_error_formatter => settings[:default_error_formatter],
416
- :error_formatters => settings[:error_formatters],
417
- :rescue_options => settings[:rescue_options],
418
- :rescue_handlers => merged_setting(:rescue_handlers)
413
+ format: settings[:format],
414
+ default_status: settings[:default_error_status] || 403,
415
+ rescue_all: settings[:rescue_all],
416
+ rescued_errors: aggregate_setting(:rescued_errors),
417
+ default_error_formatter: settings[:default_error_formatter],
418
+ error_formatters: settings[:error_formatters],
419
+ rescue_options: settings[:rescue_options],
420
+ rescue_handlers: merged_setting(:rescue_handlers)
419
421
 
420
422
  aggregate_setting(:middleware).each do |m|
421
423
  m = m.dup
422
424
  block = m.pop if m.last.is_a?(Proc)
423
425
  if block
424
- b.use *m, &block
426
+ b.use(*m, &block)
425
427
  else
426
- b.use *m
428
+ b.use(*m)
427
429
  end
428
430
  end
429
431
 
@@ -432,31 +434,33 @@ module Grape
432
434
 
433
435
  if settings[:version]
434
436
  b.use Grape::Middleware::Versioner.using(settings[:version_options][:using]), {
435
- :versions => settings[:version] ? settings[:version].flatten : nil,
436
- :version_options => settings[:version_options],
437
- :prefix => settings[:root_prefix]
437
+ versions: settings[:version] ? settings[:version].flatten : nil,
438
+ version_options: settings[:version_options],
439
+ prefix: settings[:root_prefix]
438
440
  }
439
441
  end
440
442
 
441
443
  b.use Grape::Middleware::Formatter,
442
- :format => settings[:format],
443
- :default_format => settings[:default_format] || :txt,
444
- :content_types => settings[:content_types],
445
- :formatters => settings[:formatters],
446
- :parsers => settings[:parsers]
444
+ format: settings[:format],
445
+ default_format: settings[:default_format] || :txt,
446
+ content_types: settings[:content_types],
447
+ formatters: settings[:formatters],
448
+ parsers: settings[:parsers]
447
449
 
448
450
  b
449
451
  end
450
452
 
451
453
  def helpers
452
454
  m = Module.new
453
- settings.stack.each{|frame| m.send :include, frame[:helpers] if frame[:helpers]}
455
+ settings.stack.each do |frame|
456
+ m.send :include, frame[:helpers] if frame[:helpers]
457
+ end
454
458
  m
455
459
  end
456
460
 
457
461
  def aggregate_setting(key)
458
462
  settings.stack.inject([]) do |aggregate, frame|
459
- aggregate += (frame[key] || [])
463
+ aggregate + (frame[key] || [])
460
464
  end
461
465
  end
462
466
 
@@ -468,12 +472,20 @@ module Grape
468
472
 
469
473
  def run_filters(filters)
470
474
  (filters || []).each do |filter|
471
- instance_eval &filter
475
+ instance_eval(&filter)
472
476
  end
473
477
  end
474
478
 
475
- def befores; aggregate_setting(:befores) end
476
- def after_validations; aggregate_setting(:after_validations) end
477
- def afters; aggregate_setting(:afters) end
479
+ def befores
480
+ aggregate_setting(:befores)
481
+ end
482
+
483
+ def after_validations
484
+ aggregate_setting(:after_validations)
485
+ end
486
+
487
+ def afters
488
+ aggregate_setting(:afters)
489
+ end
478
490
  end
479
491
  end
@@ -5,10 +5,11 @@ module Grape
5
5
  class << self
6
6
 
7
7
  FORMATTERS = {
8
- :serializable_hash => Grape::ErrorFormatter::Json,
9
- :json => Grape::ErrorFormatter::Json,
10
- :txt => Grape::ErrorFormatter::Txt,
11
- :xml => Grape::ErrorFormatter::Xml
8
+ serializable_hash: Grape::ErrorFormatter::Json,
9
+ json: Grape::ErrorFormatter::Json,
10
+ jsonapi: Grape::ErrorFormatter::Json,
11
+ txt: Grape::ErrorFormatter::Txt,
12
+ xml: Grape::ErrorFormatter::Xml
12
13
  }
13
14
 
14
15
  def formatters(options)
@@ -4,9 +4,9 @@ module Grape
4
4
  class << self
5
5
 
6
6
  def call(message, backtrace, options = {}, env = nil)
7
- result = message.is_a?(Hash) ? message : { :error => message }
8
- if (options[:rescue_options] || {})[:backtrace] && backtrace && ! backtrace.empty?
9
- result = result.merge({ :backtrace => backtrace })
7
+ result = message.is_a?(Hash) ? message : { error: message }
8
+ if (options[:rescue_options] || {})[:backtrace] && backtrace && !backtrace.empty?
9
+ result = result.merge(backtrace: backtrace)
10
10
  end
11
11
  MultiJson.dump(result)
12
12
  end
@@ -5,7 +5,7 @@ module Grape
5
5
 
6
6
  def call(message, backtrace, options = {}, env = nil)
7
7
  result = message.is_a?(Hash) ? MultiJson.dump(message) : message
8
- if (options[:rescue_options] || {})[:backtrace] && backtrace && ! backtrace.empty?
8
+ if (options[:rescue_options] || {})[:backtrace] && backtrace && !backtrace.empty?
9
9
  result += "\r\n "
10
10
  result += backtrace.join("\r\n ")
11
11
  end
@@ -4,11 +4,11 @@ module Grape
4
4
  class << self
5
5
 
6
6
  def call(message, backtrace, options = {}, env = nil)
7
- result = message.is_a?(Hash) ? message : { :message => message }
8
- if (options[:rescue_options] || {})[:backtrace] && backtrace && ! backtrace.empty?
9
- result = result.merge({ :backtrace => backtrace })
7
+ result = message.is_a?(Hash) ? message : { message: message }
8
+ if (options[:rescue_options] || {})[:backtrace] && backtrace && !backtrace.empty?
9
+ result = result.merge(backtrace: backtrace)
10
10
  end
11
- result.respond_to?(:to_xml) ? result.to_xml(:root => :error) : result.to_s
11
+ result.respond_to?(:to_xml) ? result.to_xml(root: :error) : result.to_s
12
12
  end
13
13
 
14
14
  end
@@ -15,20 +15,21 @@ module Grape
15
15
  end
16
16
 
17
17
  def [](index)
18
- self.send(index)
18
+ send index
19
19
  end
20
20
 
21
21
  protected
22
+
22
23
  # TODO: translate attribute first
23
24
  # if BASE_ATTRIBUTES_KEY.key respond to a string message, then short_message is returned
24
25
  # if BASE_ATTRIBUTES_KEY.key respond to a Hash, means it may have problem , summary and resolution
25
- def compose_message(key, attributes = {} )
26
+ def compose_message(key, attributes = {})
26
27
  short_message = translate_message(key, attributes)
27
28
  if short_message.is_a? Hash
28
29
  @problem = problem(key, attributes)
29
30
  @summary = summary(key, attributes)
30
31
  @resolution = resolution(key, attributes)
31
- [ ["Problem", @problem], ["Summary", @summary], ["Resolution", @resolution]].reduce("") do |message, detail_array|
32
+ [["Problem", @problem], ["Summary", @summary], ["Resolution", @resolution]].reduce("") do |message, detail_array|
32
33
  message << "\n#{detail_array[0]}:\n #{detail_array[1]}" unless detail_array[1].blank?
33
34
  message
34
35
  end
@@ -49,18 +50,17 @@ module Grape
49
50
  translate_message("#{key}.resolution", attributes)
50
51
  end
51
52
 
52
-
53
53
  def translate_attribute(key, options = {})
54
- translate("#{BASE_ATTRIBUTES_KEY}.#{key}", { :default => key }.merge(options))
54
+ translate("#{BASE_ATTRIBUTES_KEY}.#{key}", { default: key }.merge(options))
55
55
  end
56
56
 
57
57
  def translate_message(key, options = {})
58
- translate("#{BASE_MESSAGES_KEY}.#{key}", { :default => '' }.merge(options))
58
+ translate("#{BASE_MESSAGES_KEY}.#{key}", { default: '' }.merge(options))
59
59
  end
60
60
 
61
61
  def translate(key, options = {})
62
62
  message = ::I18n.translate(key, options)
63
- message.present? ? message : ::I18n.translate(key, options.merge({:locale => FALLBACK_LOCALE}))
63
+ message.present? ? message : ::I18n.translate(key, options.merge(locale: FALLBACK_LOCALE))
64
64
  end
65
65
 
66
66
  end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+ module Grape
3
+ module Exceptions
4
+ class IncompatibleOptionValues < Base
5
+
6
+ def initialize(option1, value1, option2, value2)
7
+ super(message: compose_message("incompatible_option_values", option1: option1, value1: value1, option2: option2, value2: value2))
8
+ end
9
+
10
+ end
11
+
12
+ end
13
+ end
@@ -4,7 +4,7 @@ module Grape
4
4
  class InvalidFormatter < Base
5
5
 
6
6
  def initialize(klass, to_format)
7
- super(:message => compose_message("invalid_formatter", :klass => klass, :to_format => to_format))
7
+ super(message: compose_message("invalid_formatter", klass: klass, to_format: to_format))
8
8
  end
9
9
 
10
10
  end
@@ -5,7 +5,7 @@ module Grape
5
5
  class InvalidVersionerOption < Base
6
6
 
7
7
  def initialize(strategy)
8
- super(:message => compose_message("invalid_versioner_option", :strategy => strategy))
8
+ super(message: compose_message("invalid_versioner_option", strategy: strategy))
9
9
  end
10
10
 
11
11
  end