grape 0.13.0 → 0.14.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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +9 -4
  3. data/CHANGELOG.md +28 -0
  4. data/Gemfile +0 -1
  5. data/Gemfile.lock +166 -0
  6. data/README.md +305 -163
  7. data/Rakefile +30 -33
  8. data/UPGRADING.md +31 -0
  9. data/benchmark/simple.rb +27 -0
  10. data/gemfiles/rack_1.5.2.gemfile +13 -0
  11. data/gemfiles/rails_3.gemfile +2 -2
  12. data/gemfiles/rails_4.gemfile +1 -2
  13. data/grape.gemspec +5 -4
  14. data/lib/grape.rb +9 -5
  15. data/lib/grape/dsl/configuration.rb +5 -2
  16. data/lib/grape/dsl/helpers.rb +8 -3
  17. data/lib/grape/dsl/inside_route.rb +67 -44
  18. data/lib/grape/dsl/parameters.rb +21 -12
  19. data/lib/grape/dsl/request_response.rb +1 -1
  20. data/lib/grape/dsl/routing.rb +3 -4
  21. data/lib/grape/endpoint.rb +63 -28
  22. data/lib/grape/error_formatter/base.rb +6 -6
  23. data/lib/grape/exceptions/base.rb +5 -5
  24. data/lib/grape/exceptions/invalid_version_header.rb +10 -0
  25. data/lib/grape/formatter/serializable_hash.rb +3 -2
  26. data/lib/grape/locale/en.yml +4 -1
  27. data/lib/grape/middleware/auth/base.rb +2 -2
  28. data/lib/grape/middleware/auth/dsl.rb +1 -1
  29. data/lib/grape/middleware/auth/strategies.rb +1 -1
  30. data/lib/grape/middleware/base.rb +7 -4
  31. data/lib/grape/middleware/error.rb +3 -2
  32. data/lib/grape/middleware/filter.rb +1 -1
  33. data/lib/grape/middleware/formatter.rb +47 -44
  34. data/lib/grape/middleware/globals.rb +3 -3
  35. data/lib/grape/middleware/versioner/accept_version_header.rb +5 -7
  36. data/lib/grape/middleware/versioner/header.rb +113 -50
  37. data/lib/grape/middleware/versioner/param.rb +5 -8
  38. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +20 -0
  39. data/lib/grape/middleware/versioner/path.rb +3 -6
  40. data/lib/grape/path.rb +3 -3
  41. data/lib/grape/request.rb +40 -0
  42. data/lib/grape/util/content_types.rb +9 -9
  43. data/lib/grape/util/env.rb +22 -0
  44. data/lib/grape/util/strict_hash_configuration.rb +2 -1
  45. data/lib/grape/validations/attributes_iterator.rb +8 -3
  46. data/lib/grape/validations/params_scope.rb +83 -15
  47. data/lib/grape/validations/types.rb +144 -0
  48. data/lib/grape/validations/types/build_coercer.rb +53 -0
  49. data/lib/grape/validations/types/custom_type_coercer.rb +183 -0
  50. data/lib/grape/validations/types/file.rb +28 -0
  51. data/lib/grape/validations/types/json.rb +65 -0
  52. data/lib/grape/validations/types/multiple_type_coercer.rb +76 -0
  53. data/lib/grape/validations/types/variant_collection_coercer.rb +59 -0
  54. data/lib/grape/validations/types/virtus_collection_patch.rb +16 -0
  55. data/lib/grape/validations/validators/all_or_none.rb +1 -1
  56. data/lib/grape/validations/validators/allow_blank.rb +3 -3
  57. data/lib/grape/validations/validators/base.rb +7 -0
  58. data/lib/grape/validations/validators/coerce.rb +31 -42
  59. data/lib/grape/validations/validators/presence.rb +2 -3
  60. data/lib/grape/validations/validators/regexp.rb +2 -4
  61. data/lib/grape/validations/validators/values.rb +3 -3
  62. data/lib/grape/version.rb +1 -1
  63. data/pkg/grape-0.13.0.gem +0 -0
  64. data/spec/grape/api/custom_validations_spec.rb +5 -4
  65. data/spec/grape/api/deeply_included_options_spec.rb +7 -7
  66. data/spec/grape/api/nested_helpers_spec.rb +4 -2
  67. data/spec/grape/api/shared_helpers_spec.rb +8 -8
  68. data/spec/grape/api_spec.rb +88 -54
  69. data/spec/grape/dsl/configuration_spec.rb +13 -0
  70. data/spec/grape/dsl/helpers_spec.rb +16 -2
  71. data/spec/grape/dsl/inside_route_spec.rb +3 -2
  72. data/spec/grape/dsl/parameters_spec.rb +0 -6
  73. data/spec/grape/dsl/routing_spec.rb +1 -1
  74. data/spec/grape/endpoint_spec.rb +61 -20
  75. data/spec/grape/entity_spec.rb +10 -8
  76. data/spec/grape/exceptions/invalid_accept_header_spec.rb +1 -15
  77. data/spec/grape/integration/rack_spec.rb +3 -2
  78. data/spec/grape/middleware/base_spec.rb +7 -5
  79. data/spec/grape/middleware/error_spec.rb +16 -15
  80. data/spec/grape/middleware/exception_spec.rb +45 -43
  81. data/spec/grape/middleware/formatter_spec.rb +34 -0
  82. data/spec/grape/middleware/versioner/header_spec.rb +79 -47
  83. data/spec/grape/path_spec.rb +10 -10
  84. data/spec/grape/presenters/presenter_spec.rb +2 -2
  85. data/spec/grape/request_spec.rb +100 -0
  86. data/spec/grape/validations/params_scope_spec.rb +11 -9
  87. data/spec/grape/validations/types_spec.rb +95 -0
  88. data/spec/grape/validations/validators/coerce_spec.rb +335 -2
  89. data/spec/grape/validations/validators/values_spec.rb +15 -15
  90. data/spec/grape/validations_spec.rb +53 -24
  91. data/spec/shared/versioning_examples.rb +2 -2
  92. data/spec/spec_helper.rb +0 -1
  93. data/spec/support/versioned_helpers.rb +2 -2
  94. metadata +51 -13
  95. data/.gitignore +0 -46
  96. data/.rspec +0 -2
  97. data/.rubocop.yml +0 -7
  98. data/.rubocop_todo.yml +0 -84
  99. data/.travis.yml +0 -20
  100. data/.yardopts +0 -2
  101. data/lib/grape/http/request.rb +0 -35
  102. data/lib/grape/util/parameter_types.rb +0 -58
  103. data/spec/grape/util/parameter_types_spec.rb +0 -54
@@ -0,0 +1,16 @@
1
+ require 'virtus/attribute/collection'
2
+
3
+ # See https://github.com/solnic/virtus/pull/343
4
+ # This monkey-patch fixes type validation for collections,
5
+ # ensuring that type assertions are applied to collection
6
+ # members.
7
+ #
8
+ # This patch duplicates the code in the above pull request.
9
+ # Once the request, or equivalent functionality, has been
10
+ # published into the +virtus+ gem this file should be deleted.
11
+ Virtus::Attribute::Collection.class_eval do
12
+ # @api public
13
+ def value_coerced?(value)
14
+ super && value.all? { |item| member_type.value_coerced? item }
15
+ end
16
+ end
@@ -13,7 +13,7 @@ module Grape
13
13
  private
14
14
 
15
15
  def only_subset_present
16
- scoped_params.any? { |resource_params| keys_in_common(resource_params).length > 0 && keys_in_common(resource_params).length < attrs.length }
16
+ scoped_params.any? { |resource_params| keys_in_common(resource_params).length > 0 && keys_in_common(resource_params).length < attrs.length }
17
17
  end
18
18
  end
19
19
  end
@@ -21,9 +21,9 @@ module Grape
21
21
 
22
22
  return unless should_validate
23
23
 
24
- unless value == false || value.present?
25
- fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :blank
26
- end
24
+ return if value == false || value.present?
25
+
26
+ fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :blank
27
27
  end
28
28
  end
29
29
  end
@@ -3,6 +3,13 @@ module Grape
3
3
  class Base
4
4
  attr_reader :attrs
5
5
 
6
+ # Creates a new Validator from options specified
7
+ # by a +requires+ or +optional+ directive during
8
+ # parameter definition.
9
+ # @param attrs [Array] names of attributes to which the Validator applies
10
+ # @param options [Object] implementation-dependent Validator options
11
+ # @param required [Boolean] attribute(s) are required or optional
12
+ # @param scope [ParamsScope] parent scope for this Validator
6
13
  def initialize(attrs, options, required, scope)
7
14
  @attrs = Array(attrs)
8
15
  @option = options
@@ -1,13 +1,13 @@
1
1
  module Grape
2
2
  class API
3
- Boolean = Virtus::Attribute::Boolean # rubocop:disable ConstantName
3
+ Boolean = Virtus::Attribute::Boolean
4
4
  end
5
5
 
6
6
  module Validations
7
7
  class CoerceValidator < Base
8
8
  def validate_param!(attr_name, params)
9
9
  fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :coerce unless params.is_a? Hash
10
- new_value = coerce_value(@option, params[attr_name])
10
+ new_value = coerce_value(params[attr_name])
11
11
  if valid_type?(new_value)
12
12
  params[attr_name] = new_value
13
13
  else
@@ -15,61 +15,50 @@ module Grape
15
15
  end
16
16
  end
17
17
 
18
- class InvalidValue; end
19
-
20
18
  private
21
19
 
22
- def _valid_array_type?(type, values)
23
- values.all? do |val|
24
- _valid_single_type?(type, val)
25
- end
26
- end
20
+ def valid_type?(val)
21
+ # Special value to denote coercion failure
22
+ return false if val.instance_of?(Types::InvalidValue)
27
23
 
28
- def _valid_single_type?(klass, val)
29
- # allow nil, to ignore when a parameter is absent
24
+ # Allow nil, to ignore when a parameter is absent
30
25
  return true if val.nil?
31
- if klass == Virtus::Attribute::Boolean
32
- val.is_a?(TrueClass) || val.is_a?(FalseClass) || (val.is_a?(String) && val.empty?)
33
- elsif klass == Rack::Multipart::UploadedFile
34
- val.is_a?(Hashie::Mash) && val.key?(:tempfile)
35
- elsif [DateTime, Date, Numeric].any? { |vclass| vclass >= klass }
36
- return true if val.is_a?(String) && val.empty?
37
- val.is_a?(klass)
38
- else
39
- val.is_a?(klass)
40
- end
41
- end
42
26
 
43
- def valid_type?(val)
44
- if val.instance_of?(InvalidValue)
45
- false
46
- elsif @option.is_a?(Array) || @option.is_a?(Set)
47
- _valid_array_type?(@option.first, val)
48
- else
49
- _valid_single_type?(@option, val)
50
- end
27
+ converter.value_coerced? val
51
28
  end
52
29
 
53
- def coerce_value(type, val)
30
+ def coerce_value(val)
54
31
  # Don't coerce things other than nil to Arrays or Hashes
55
- return val || [] if type == Array
56
- return val || Set.new if type == Set
57
- return val || {} if type == Hash
58
-
59
- # To support custom types that Virtus can't easily coerce, pass in an
60
- # explicit coercer. Custom types must implement a `parse` class method.
61
- converter_options = {}
62
- if ParameterTypes.custom_type?(type)
63
- converter_options[:coercer] = type.method(:parse)
32
+ unless (@option[:method] && !val.nil?) || type.is_a?(Virtus::Attribute)
33
+ return val || [] if type == Array
34
+ return val || Set.new if type == Set
35
+ return val || {} if type == Hash
64
36
  end
65
37
 
66
- converter = Virtus::Attribute.build(type, converter_options)
67
38
  converter.coerce(val)
68
39
 
69
40
  # not the prettiest but some invalid coercion can currently trigger
70
41
  # errors in Virtus (see coerce_spec.rb:75)
71
42
  rescue
72
- InvalidValue.new
43
+ Types::InvalidValue.new
44
+ end
45
+
46
+ # Type to which the parameter will be coerced.
47
+ #
48
+ # @return [Class]
49
+ def type
50
+ @option[:type]
51
+ end
52
+
53
+ # Create and cache the attribute object
54
+ # that will be used for parameter coercion
55
+ # and type checking.
56
+ #
57
+ # See {Types.build_coercer}
58
+ #
59
+ # @return [Virtus::Attribute]
60
+ def converter
61
+ @converter ||= Types.build_coercer(type, @option[:method])
73
62
  end
74
63
  end
75
64
  end
@@ -7,9 +7,8 @@ module Grape
7
7
  end
8
8
 
9
9
  def validate_param!(attr_name, params)
10
- unless params.respond_to?(:key?) && params.key?(attr_name)
11
- fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :presence
12
- end
10
+ return if params.respond_to?(:key?) && params.key?(attr_name)
11
+ fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :presence
13
12
  end
14
13
  end
15
14
  end
@@ -2,10 +2,8 @@ module Grape
2
2
  module Validations
3
3
  class RegexpValidator < Base
4
4
  def validate_param!(attr_name, params)
5
- if params.key?(attr_name) &&
6
- !params[attr_name].nil? && !(params[attr_name].to_s =~ @option)
7
- fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :regexp
8
- end
5
+ return unless params.key?(attr_name) && !params[attr_name].nil? && !(params[attr_name].to_s =~ @option)
6
+ fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :regexp
9
7
  end
10
8
  end
11
9
  end
@@ -7,13 +7,13 @@ module Grape
7
7
  end
8
8
 
9
9
  def validate_param!(attr_name, params)
10
+ return unless params.is_a?(Hash)
10
11
  return unless params[attr_name] || required_for_root_scope?
11
12
 
12
13
  values = @values.is_a?(Proc) ? @values.call : @values
13
14
  param_array = params[attr_name].nil? ? [nil] : Array.wrap(params[attr_name])
14
- unless param_array.all? { |param| values.include?(param) }
15
- fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :values
16
- end
15
+ return if param_array.all? { |param| values.include?(param) }
16
+ fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :values
17
17
  end
18
18
 
19
19
  private
@@ -1,4 +1,4 @@
1
1
  module Grape
2
2
  # The current version of Grape.
3
- VERSION = '0.13.0'
3
+ VERSION = '0.14.0'
4
4
  end
Binary file
@@ -2,10 +2,11 @@ require 'spec_helper'
2
2
 
3
3
  describe Grape::Validations do
4
4
  before do
5
- class DefaultLength < Grape::Validations::Base
6
- def validate_param!(attr_name, params)
7
- @option = params[:max].to_i if params.key?(:max)
8
- unless params[attr_name].length <= @option
5
+ module CustomValidationsSpec
6
+ class DefaultLength < Grape::Validations::Base
7
+ def validate_param!(attr_name, params)
8
+ @option = params[:max].to_i if params.key?(:max)
9
+ return if params[attr_name].length <= @option
9
10
  fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: "must be at the most #{@option} characters long"
10
11
  end
11
12
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- module API
3
+ module DeeplyIncludedOptionsSpec
4
4
  module Defaults
5
5
  extend ActiveSupport::Concern
6
6
  included do
@@ -11,11 +11,11 @@ module API
11
11
  module Admin
12
12
  module Defaults
13
13
  extend ActiveSupport::Concern
14
- include API::Defaults
14
+ include DeeplyIncludedOptionsSpec::Defaults
15
15
  end
16
16
 
17
17
  class Users < Grape::API
18
- include API::Admin::Defaults
18
+ include DeeplyIncludedOptionsSpec::Admin::Defaults
19
19
 
20
20
  resource :users do
21
21
  get do
@@ -24,14 +24,14 @@ module API
24
24
  end
25
25
  end
26
26
  end
27
- end
28
27
 
29
- class Main < Grape::API
30
- mount API::Admin::Users
28
+ class Main < Grape::API
29
+ mount DeeplyIncludedOptionsSpec::Admin::Users
30
+ end
31
31
  end
32
32
 
33
33
  describe Grape::API do
34
- subject { Main }
34
+ subject { DeeplyIncludedOptionsSpec::Main }
35
35
 
36
36
  def app
37
37
  subject
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Grape::API::Helpers do
4
- subject do
4
+ module NestedHelpersSpec
5
5
  module HelperMethods
6
6
  extend Grape::API::Helpers
7
7
  def current_user
@@ -28,8 +28,10 @@ describe Grape::API::Helpers do
28
28
  class Main < Grape::API
29
29
  mount Nested
30
30
  end
31
+ end
31
32
 
32
- Main
33
+ subject do
34
+ NestedHelpersSpec::Main
33
35
  end
34
36
 
35
37
  def app
@@ -1,18 +1,18 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Grape::API::Helpers do
4
- module SharedParams
5
- extend Grape::API::Helpers
4
+ subject do
5
+ shared_params = Module.new do
6
+ extend Grape::API::Helpers
6
7
 
7
- params :pagination do
8
- optional :page, type: Integer
9
- optional :size, type: Integer
8
+ params :pagination do
9
+ optional :page, type: Integer
10
+ optional :size, type: Integer
11
+ end
10
12
  end
11
- end
12
13
 
13
- subject do
14
14
  Class.new(Grape::API) do
15
- helpers SharedParams
15
+ helpers shared_params
16
16
  format :json
17
17
 
18
18
  params do
@@ -537,16 +537,38 @@ describe Grape::API do
537
537
  expect(last_response.headers['Content-Type']).to eql 'text/plain'
538
538
  end
539
539
 
540
- it 'adds an OPTIONS route that returns a 204, an Allow header and a X-Custom-Header' do
541
- subject.before { header 'X-Custom-Header', 'foo' }
542
- subject.get 'example' do
543
- 'example'
540
+ describe 'adds an OPTIONS route that' do
541
+ before do
542
+ subject.before { header 'X-Custom-Header', 'foo' }
543
+ subject.get 'example' do
544
+ 'example'
545
+ end
546
+ options '/example'
547
+ end
548
+
549
+ it 'returns a 204' do
550
+ expect(last_response.status).to eql 204
551
+ end
552
+
553
+ it 'has an empty body' do
554
+ expect(last_response.body).to be_blank
555
+ end
556
+
557
+ it 'has an Allow header' do
558
+ expect(last_response.headers['Allow']).to eql 'OPTIONS, GET, HEAD'
559
+ end
560
+
561
+ it 'has a X-Custom-Header' do
562
+ expect(last_response.headers['X-Custom-Header']).to eql 'foo'
563
+ end
564
+
565
+ it 'has no Content-Type' do
566
+ expect(last_response.content_type).to be_nil
567
+ end
568
+
569
+ it 'has no Content-Length' do
570
+ expect(last_response.content_length).to be_nil
544
571
  end
545
- options '/example'
546
- expect(last_response.status).to eql 204
547
- expect(last_response.body).to eql ''
548
- expect(last_response.headers['Allow']).to eql 'OPTIONS, GET, HEAD'
549
- expect(last_response.headers['X-Custom-Header']).to eql 'foo'
550
572
  end
551
573
 
552
574
  it 'allows HEAD on a GET request' do
@@ -640,7 +662,7 @@ describe Grape::API do
640
662
  end
641
663
 
642
664
  it 'adds a after_validation filter' do
643
- subject.after_validation { @foo = "first #{params[:id] }:#{params[:id].class}" }
665
+ subject.after_validation { @foo = "first #{params[:id]}:#{params[:id].class}" }
644
666
  subject.after_validation { @bar = 'second' }
645
667
  subject.params do
646
668
  requires :id, type: Integer
@@ -787,7 +809,7 @@ describe Grape::API do
787
809
 
788
810
  it 'returns raw data when content type binary' do
789
811
  image_filename = 'grape.png'
790
- file = File.open(image_filename, 'rb') { |io| io.read }
812
+ file = File.open(image_filename, 'rb', &:read)
791
813
  subject.format :binary
792
814
  subject.get('/binary_file') { File.binread(image_filename) }
793
815
  get '/binary_file'
@@ -1066,7 +1088,7 @@ describe Grape::API do
1066
1088
 
1067
1089
  subject.get(:hello) { 'Hello, world.' }
1068
1090
  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
1069
- expect(basic_auth_context).to be_an_instance_of(Grape::Endpoint)
1091
+ expect(basic_auth_context).to be_a_kind_of(Grape::Endpoint)
1070
1092
  end
1071
1093
 
1072
1094
  it 'has access to helper methods' do
@@ -1309,21 +1331,23 @@ describe Grape::API do
1309
1331
 
1310
1332
  context 'CustomError subclass of Grape::Exceptions::Base' do
1311
1333
  before do
1312
- class CustomError < Grape::Exceptions::Base; end
1334
+ module ApiSpec
1335
+ class CustomError < Grape::Exceptions::Base; end
1336
+ end
1313
1337
  end
1314
1338
 
1315
1339
  it 'does not re-raise exceptions of type Grape::Exceptions::Base' do
1316
- subject.get('/custom_exception') { fail CustomError }
1340
+ subject.get('/custom_exception') { fail ApiSpec::CustomError }
1317
1341
 
1318
1342
  expect { get '/custom_exception' }.not_to raise_error
1319
1343
  end
1320
1344
 
1321
1345
  it 'rescues custom grape exceptions' do
1322
- subject.rescue_from CustomError do |e|
1346
+ subject.rescue_from ApiSpec::CustomError do |e|
1323
1347
  rack_response('New Error', e.status)
1324
1348
  end
1325
1349
  subject.get '/custom_error' do
1326
- fail CustomError, status: 400, message: 'Custom Error'
1350
+ fail ApiSpec::CustomError, status: 400, message: 'Custom Error'
1327
1351
  end
1328
1352
 
1329
1353
  get '/custom_error'
@@ -1435,7 +1459,7 @@ describe Grape::API do
1435
1459
 
1436
1460
  describe '.rescue_from klass, lambda' do
1437
1461
  it 'rescues an error with the lambda' do
1438
- subject.rescue_from ArgumentError, -> {
1462
+ subject.rescue_from ArgumentError, lambda {
1439
1463
  rack_response('rescued with a lambda', 400)
1440
1464
  }
1441
1465
  subject.get('/rescue_lambda') { fail ArgumentError }
@@ -1446,7 +1470,7 @@ describe Grape::API do
1446
1470
  end
1447
1471
 
1448
1472
  it 'can execute the lambda with an argument' do
1449
- subject.rescue_from ArgumentError, ->(e) {
1473
+ subject.rescue_from ArgumentError, lambda { |e|
1450
1474
  rack_response(e.message, 400)
1451
1475
  }
1452
1476
  subject.get('/rescue_lambda') { fail ArgumentError, 'lambda takes an argument' }
@@ -1474,21 +1498,23 @@ describe Grape::API do
1474
1498
 
1475
1499
  describe '.rescue_from klass, rescue_subclasses: boolean' do
1476
1500
  before do
1477
- module APIErrors
1478
- class ParentError < StandardError; end
1479
- class ChildError < ParentError; end
1501
+ module ApiSpec
1502
+ module APIErrors
1503
+ class ParentError < StandardError; end
1504
+ class ChildError < ParentError; end
1505
+ end
1480
1506
  end
1481
1507
  end
1482
1508
 
1483
1509
  it 'rescues error as well as subclass errors with rescue_subclasses option set' do
1484
- subject.rescue_from APIErrors::ParentError, rescue_subclasses: true do |e|
1510
+ subject.rescue_from ApiSpec::APIErrors::ParentError, rescue_subclasses: true do |e|
1485
1511
  rack_response("rescued from #{e.class.name}", 500)
1486
1512
  end
1487
1513
  subject.get '/caught_child' do
1488
- fail APIErrors::ChildError
1514
+ fail ApiSpec::APIErrors::ChildError
1489
1515
  end
1490
1516
  subject.get '/caught_parent' do
1491
- fail APIErrors::ParentError
1517
+ fail ApiSpec::APIErrors::ParentError
1492
1518
  end
1493
1519
  subject.get '/uncaught_parent' do
1494
1520
  fail StandardError
@@ -1502,11 +1528,11 @@ describe Grape::API do
1502
1528
  end
1503
1529
 
1504
1530
  it 'sets rescue_subclasses to true by default' do
1505
- subject.rescue_from APIErrors::ParentError do |e|
1531
+ subject.rescue_from ApiSpec::APIErrors::ParentError do |e|
1506
1532
  rack_response("rescued from #{e.class.name}", 500)
1507
1533
  end
1508
1534
  subject.get '/caught_child' do
1509
- fail APIErrors::ChildError
1535
+ fail ApiSpec::APIErrors::ChildError
1510
1536
  end
1511
1537
 
1512
1538
  get '/caught_child'
@@ -1514,13 +1540,13 @@ describe Grape::API do
1514
1540
  end
1515
1541
 
1516
1542
  it 'does not rescue child errors if rescue_subclasses is false' do
1517
- subject.rescue_from APIErrors::ParentError, rescue_subclasses: false do |e|
1543
+ subject.rescue_from ApiSpec::APIErrors::ParentError, rescue_subclasses: false do |e|
1518
1544
  rack_response("rescued from #{e.class.name}", 500)
1519
1545
  end
1520
1546
  subject.get '/uncaught' do
1521
- fail APIErrors::ChildError
1547
+ fail ApiSpec::APIErrors::ChildError
1522
1548
  end
1523
- expect { get '/uncaught' }.to raise_error(APIErrors::ChildError)
1549
+ expect { get '/uncaught' }.to raise_error(ApiSpec::APIErrors::ChildError)
1524
1550
  end
1525
1551
  end
1526
1552
 
@@ -1572,15 +1598,17 @@ describe Grape::API do
1572
1598
 
1573
1599
  context 'class' do
1574
1600
  before :each do
1575
- class CustomErrorFormatter
1576
- def self.call(message, _backtrace, _options, _env)
1577
- "message: #{message} @backtrace"
1601
+ module ApiSpec
1602
+ class CustomErrorFormatter
1603
+ def self.call(message, _backtrace, _options, _env)
1604
+ "message: #{message} @backtrace"
1605
+ end
1578
1606
  end
1579
1607
  end
1580
1608
  end
1581
1609
  it 'returns a custom error format' do
1582
1610
  subject.rescue_from :all, backtrace: true
1583
- subject.error_formatter :txt, CustomErrorFormatter
1611
+ subject.error_formatter :txt, ApiSpec::CustomErrorFormatter
1584
1612
  subject.get '/exception' do
1585
1613
  fail 'rain!'
1586
1614
  end
@@ -1592,16 +1620,18 @@ describe Grape::API do
1592
1620
  describe 'with' do
1593
1621
  context 'class' do
1594
1622
  before :each do
1595
- class CustomErrorFormatter
1596
- def self.call(message, _backtrace, _option, _env)
1597
- "message: #{message} @backtrace"
1623
+ module ApiSpec
1624
+ class CustomErrorFormatter
1625
+ def self.call(message, _backtrace, _option, _env)
1626
+ "message: #{message} @backtrace"
1627
+ end
1598
1628
  end
1599
1629
  end
1600
1630
  end
1601
1631
 
1602
1632
  it 'returns a custom error format' do
1603
1633
  subject.rescue_from :all, backtrace: true
1604
- subject.error_formatter :txt, with: CustomErrorFormatter
1634
+ subject.error_formatter :txt, with: ApiSpec::CustomErrorFormatter
1605
1635
  subject.get('/exception') { fail 'rain!' }
1606
1636
 
1607
1637
  get '/exception'
@@ -1679,8 +1709,8 @@ describe Grape::API do
1679
1709
  describe '.formatter' do
1680
1710
  context 'multiple formatters' do
1681
1711
  before :each do
1682
- subject.formatter :json, ->(object, _env) { "{\"custom_formatter\":\"#{object[:some] }\"}" }
1683
- subject.formatter :txt, ->(object, _env) { "custom_formatter: #{object[:some] }" }
1712
+ subject.formatter :json, ->(object, _env) { "{\"custom_formatter\":\"#{object[:some]}\"}" }
1713
+ subject.formatter :txt, ->(object, _env) { "custom_formatter: #{object[:some]}" }
1684
1714
  subject.get :simple do
1685
1715
  { some: 'hash' }
1686
1716
  end
@@ -1698,7 +1728,7 @@ describe Grape::API do
1698
1728
  before :each do
1699
1729
  subject.content_type :json, 'application/json'
1700
1730
  subject.content_type :custom, 'application/custom'
1701
- subject.formatter :custom, ->(object, _env) { "{\"custom_formatter\":\"#{object[:some] }\"}" }
1731
+ subject.formatter :custom, ->(object, _env) { "{\"custom_formatter\":\"#{object[:some]}\"}" }
1702
1732
  subject.get :simple do
1703
1733
  { some: 'hash' }
1704
1734
  end
@@ -1713,15 +1743,17 @@ describe Grape::API do
1713
1743
  end
1714
1744
  end
1715
1745
  context 'custom formatter class' do
1716
- module CustomFormatter
1717
- def self.call(object, _env)
1718
- "{\"custom_formatter\":\"#{object[:some] }\"}"
1746
+ module ApiSpec
1747
+ module CustomFormatter
1748
+ def self.call(object, _env)
1749
+ "{\"custom_formatter\":\"#{object[:some]}\"}"
1750
+ end
1719
1751
  end
1720
1752
  end
1721
1753
  before :each do
1722
1754
  subject.content_type :json, 'application/json'
1723
1755
  subject.content_type :custom, 'application/custom'
1724
- subject.formatter :custom, CustomFormatter
1756
+ subject.formatter :custom, ApiSpec::CustomFormatter
1725
1757
  subject.get :simple do
1726
1758
  { some: 'hash' }
1727
1759
  end
@@ -1765,15 +1797,17 @@ describe Grape::API do
1765
1797
  end
1766
1798
  end
1767
1799
  context 'custom parser class' do
1768
- module CustomParser
1769
- def self.call(object, _env)
1770
- { object.to_sym => object.to_s.reverse }
1800
+ module ApiSpec
1801
+ module CustomParser
1802
+ def self.call(object, _env)
1803
+ { object.to_sym => object.to_s.reverse }
1804
+ end
1771
1805
  end
1772
1806
  end
1773
1807
  before :each do
1774
1808
  subject.content_type :txt, 'text/plain'
1775
1809
  subject.content_type :custom, 'text/custom'
1776
- subject.parser :custom, CustomParser
1810
+ subject.parser :custom, ApiSpec::CustomParser
1777
1811
  subject.put :simple do
1778
1812
  params[:simple]
1779
1813
  end
@@ -1798,7 +1832,7 @@ describe Grape::API do
1798
1832
  before :each do
1799
1833
  subject.parser :json, nil
1800
1834
  subject.put 'data' do
1801
- "body: #{env['api.request.body'] }"
1835
+ "body: #{env['api.request.body']}"
1802
1836
  end
1803
1837
  end
1804
1838
  it 'does not parse data' do
@@ -2812,10 +2846,10 @@ XML
2812
2846
  end
2813
2847
  it 'hash' do
2814
2848
  subject.get '/example' do
2815
- ActiveSupport::OrderedHash[
2816
- :example1, 'example1',
2817
- :example2, 'example2'
2818
- ]
2849
+ {
2850
+ example1: 'example1',
2851
+ example2: 'example2'
2852
+ }
2819
2853
  end
2820
2854
  get '/example'
2821
2855
  expect(last_response.status).to eq(200)
@@ -2880,7 +2914,7 @@ XML
2880
2914
  [true, false].each do |anchor|
2881
2915
  it "anchor=#{anchor}" do
2882
2916
  subject.route :any, '*path', anchor: anchor do
2883
- error!("Unrecognized request path: #{params[:path] } - #{env['PATH_INFO'] }#{env['SCRIPT_NAME'] }", 404)
2917
+ error!("Unrecognized request path: #{params[:path]} - #{env['PATH_INFO']}#{env['SCRIPT_NAME']}", 404)
2884
2918
  end
2885
2919
  get '/v1/hello'
2886
2920
  expect(last_response.status).to eq(200)