grape 0.9.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of grape might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -66
- data/.rubocop_todo.yml +78 -17
- data/.travis.yml +7 -3
- data/Appraisals +7 -0
- data/CHANGELOG.md +24 -0
- data/CONTRIBUTING.md +7 -0
- data/Gemfile +1 -7
- data/Guardfile +1 -1
- data/README.md +560 -94
- data/RELEASING.md +1 -1
- data/Rakefile +10 -11
- data/UPGRADING.md +211 -3
- data/gemfiles/rails_3.gemfile +14 -0
- data/gemfiles/rails_4.gemfile +14 -0
- data/grape.gemspec +10 -9
- data/lib/backports/active_support/deep_dup.rb +49 -0
- data/lib/backports/active_support/duplicable.rb +88 -0
- data/lib/grape.rb +29 -2
- data/lib/grape/api.rb +59 -65
- data/lib/grape/dsl/api.rb +19 -0
- data/lib/grape/dsl/callbacks.rb +6 -4
- data/lib/grape/dsl/configuration.rb +49 -5
- data/lib/grape/dsl/helpers.rb +7 -8
- data/lib/grape/dsl/inside_route.rb +22 -10
- data/lib/grape/dsl/middleware.rb +5 -5
- data/lib/grape/dsl/parameters.rb +6 -2
- data/lib/grape/dsl/request_response.rb +23 -20
- data/lib/grape/dsl/routing.rb +52 -49
- data/lib/grape/dsl/settings.rb +110 -0
- data/lib/grape/dsl/validations.rb +14 -6
- data/lib/grape/endpoint.rb +104 -88
- data/lib/grape/exceptions/base.rb +2 -2
- data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
- data/lib/grape/exceptions/invalid_formatter.rb +1 -1
- data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
- data/lib/grape/exceptions/invalid_with_option_for_represent.rb +1 -1
- data/lib/grape/exceptions/missing_mime_type.rb +1 -1
- data/lib/grape/exceptions/missing_option.rb +1 -1
- data/lib/grape/exceptions/missing_vendor_option.rb +1 -1
- data/lib/grape/exceptions/unknown_options.rb +1 -1
- data/lib/grape/exceptions/unknown_validator.rb +1 -1
- data/lib/grape/exceptions/validation.rb +1 -1
- data/lib/grape/exceptions/validation_errors.rb +2 -2
- data/lib/grape/formatter/serializable_hash.rb +1 -1
- data/lib/grape/formatter/xml.rb +1 -1
- data/lib/grape/locale/en.yml +2 -0
- data/lib/grape/middleware/auth/dsl.rb +26 -21
- data/lib/grape/middleware/auth/strategies.rb +1 -1
- data/lib/grape/middleware/auth/strategy_info.rb +0 -2
- data/lib/grape/middleware/base.rb +2 -2
- data/lib/grape/middleware/error.rb +1 -1
- data/lib/grape/middleware/formatter.rb +5 -5
- data/lib/grape/middleware/versioner.rb +1 -1
- data/lib/grape/middleware/versioner/header.rb +3 -3
- data/lib/grape/middleware/versioner/param.rb +2 -2
- data/lib/grape/middleware/versioner/path.rb +1 -1
- data/lib/grape/namespace.rb +1 -1
- data/lib/grape/path.rb +9 -3
- data/lib/grape/util/content_types.rb +16 -8
- data/lib/grape/util/inheritable_setting.rb +74 -0
- data/lib/grape/util/inheritable_values.rb +51 -0
- data/lib/grape/util/stackable_values.rb +52 -0
- data/lib/grape/util/strict_hash_configuration.rb +106 -0
- data/lib/grape/validations.rb +0 -220
- data/lib/grape/validations/attributes_iterator.rb +21 -0
- data/lib/grape/validations/params_scope.rb +176 -0
- data/lib/grape/validations/validators/all_or_none.rb +20 -0
- data/lib/grape/validations/validators/allow_blank.rb +30 -0
- data/lib/grape/validations/validators/at_least_one_of.rb +20 -0
- data/lib/grape/validations/validators/base.rb +37 -0
- data/lib/grape/validations/{coerce.rb → validators/coerce.rb} +3 -3
- data/lib/grape/validations/{default.rb → validators/default.rb} +1 -1
- data/lib/grape/validations/validators/exactly_one_of.rb +20 -0
- data/lib/grape/validations/validators/multiple_params_base.rb +26 -0
- data/lib/grape/validations/validators/mutual_exclusion.rb +25 -0
- data/lib/grape/validations/{presence.rb → validators/presence.rb} +2 -2
- data/lib/grape/validations/validators/regexp.rb +12 -0
- data/lib/grape/validations/validators/values.rb +26 -0
- data/lib/grape/version.rb +1 -1
- data/spec/grape/api_spec.rb +522 -343
- data/spec/grape/dsl/callbacks_spec.rb +4 -4
- data/spec/grape/dsl/configuration_spec.rb +48 -9
- data/spec/grape/dsl/helpers_spec.rb +6 -13
- data/spec/grape/dsl/inside_route_spec.rb +43 -4
- data/spec/grape/dsl/middleware_spec.rb +1 -10
- data/spec/grape/dsl/parameters_spec.rb +8 -1
- data/spec/grape/dsl/request_response_spec.rb +16 -22
- data/spec/grape/dsl/routing_spec.rb +21 -5
- data/spec/grape/dsl/settings_spec.rb +219 -0
- data/spec/grape/dsl/validations_spec.rb +8 -11
- data/spec/grape/endpoint_spec.rb +115 -86
- data/spec/grape/entity_spec.rb +33 -33
- data/spec/grape/exceptions/invalid_formatter_spec.rb +3 -5
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +4 -6
- data/spec/grape/exceptions/missing_mime_type_spec.rb +5 -6
- data/spec/grape/exceptions/missing_option_spec.rb +3 -5
- data/spec/grape/exceptions/unknown_options_spec.rb +3 -5
- data/spec/grape/exceptions/unknown_validator_spec.rb +3 -5
- data/spec/grape/exceptions/validation_errors_spec.rb +5 -5
- data/spec/grape/loading_spec.rb +44 -0
- data/spec/grape/middleware/auth/base_spec.rb +0 -4
- data/spec/grape/middleware/auth/dsl_spec.rb +2 -4
- data/spec/grape/middleware/auth/strategies_spec.rb +5 -6
- data/spec/grape/middleware/exception_spec.rb +8 -10
- data/spec/grape/middleware/formatter_spec.rb +13 -15
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +10 -10
- data/spec/grape/middleware/versioner/header_spec.rb +25 -25
- data/spec/grape/middleware/versioner/param_spec.rb +15 -17
- data/spec/grape/middleware/versioner/path_spec.rb +1 -2
- data/spec/grape/middleware/versioner_spec.rb +0 -1
- data/spec/grape/path_spec.rb +66 -45
- data/spec/grape/util/inheritable_setting_spec.rb +217 -0
- data/spec/grape/util/inheritable_values_spec.rb +63 -0
- data/spec/grape/util/stackable_values_spec.rb +115 -0
- data/spec/grape/util/strict_hash_configuration_spec.rb +38 -0
- data/spec/grape/validations/attributes_iterator_spec.rb +4 -0
- data/spec/grape/validations/params_scope_spec.rb +57 -0
- data/spec/grape/validations/validators/all_or_none_spec.rb +60 -0
- data/spec/grape/validations/validators/allow_blank_spec.rb +170 -0
- data/spec/grape/validations/{at_least_one_of_spec.rb → validators/at_least_one_of_spec.rb} +7 -3
- data/spec/grape/validations/{coerce_spec.rb → validators/coerce_spec.rb} +8 -11
- data/spec/grape/validations/{default_spec.rb → validators/default_spec.rb} +7 -9
- data/spec/grape/validations/{exactly_one_of_spec.rb → validators/exactly_one_of_spec.rb} +15 -11
- data/spec/grape/validations/{mutual_exclusion_spec.rb → validators/mutual_exclusion_spec.rb} +11 -9
- data/spec/grape/validations/{presence_spec.rb → validators/presence_spec.rb} +30 -30
- data/spec/grape/validations/{regexp_spec.rb → validators/regexp_spec.rb} +2 -4
- data/spec/grape/validations/{values_spec.rb → validators/values_spec.rb} +95 -23
- data/spec/grape/validations/{zh-CN.yml → validators/zh-CN.yml} +0 -0
- data/spec/grape/validations_spec.rb +335 -70
- data/spec/shared/versioning_examples.rb +7 -8
- data/spec/spec_helper.rb +2 -0
- data/spec/support/basic_auth_encode_helpers.rb +1 -1
- data/spec/support/content_type_helpers.rb +1 -1
- data/spec/support/versioned_helpers.rb +3 -3
- metadata +80 -33
- data/lib/grape/util/deep_merge.rb +0 -23
- data/lib/grape/util/hash_stack.rb +0 -120
- data/lib/grape/validations/at_least_one_of.rb +0 -25
- data/lib/grape/validations/exactly_one_of.rb +0 -26
- data/lib/grape/validations/mutual_exclusion.rb +0 -25
- data/lib/grape/validations/regexp.rb +0 -12
- data/lib/grape/validations/values.rb +0 -23
- data/spec/grape/util/hash_stack_spec.rb +0 -132
| @@ -9,7 +9,7 @@ describe Grape::Middleware::Auth::Strategies do | |
| 9 9 | 
             
                  Rack::Builder.new do |b|
         | 
| 10 10 | 
             
                    b.use Grape::Middleware::Error
         | 
| 11 11 | 
             
                    b.use(Grape::Middleware::Auth::Base, type: :http_basic, proc: proc)
         | 
| 12 | 
            -
                    b.run lambda { |env| [200, {}, [ | 
| 12 | 
            +
                    b.run lambda { |env| [200, {}, ['Hello there.']] }
         | 
| 13 13 | 
             
                  end
         | 
| 14 14 | 
             
                end
         | 
| 15 15 |  | 
| @@ -34,8 +34,8 @@ describe Grape::Middleware::Auth::Strategies do | |
| 34 34 | 
             
                RSpec::Matchers.define :be_challenge do
         | 
| 35 35 | 
             
                  match do |actual_response|
         | 
| 36 36 | 
             
                    actual_response.status == 401 &&
         | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 37 | 
            +
                      actual_response['WWW-Authenticate'] =~ /^Digest / &&
         | 
| 38 | 
            +
                      actual_response.body.empty?
         | 
| 39 39 | 
             
                  end
         | 
| 40 40 | 
             
                end
         | 
| 41 41 |  | 
| @@ -66,16 +66,15 @@ describe Grape::Middleware::Auth::Strategies do | |
| 66 66 | 
             
                end
         | 
| 67 67 |  | 
| 68 68 | 
             
                it 'authenticates if given valid creds' do
         | 
| 69 | 
            -
                  digest_authorize  | 
| 69 | 
            +
                  digest_authorize 'foo', 'bar'
         | 
| 70 70 | 
             
                  get '/test'
         | 
| 71 71 | 
             
                  expect(last_response.status).to eq(200)
         | 
| 72 72 | 
             
                end
         | 
| 73 73 |  | 
| 74 74 | 
             
                it 'throws a 401 if given invalid creds' do
         | 
| 75 | 
            -
                  digest_authorize  | 
| 75 | 
            +
                  digest_authorize 'bar', 'foo'
         | 
| 76 76 | 
             
                  get '/test'
         | 
| 77 77 | 
             
                  expect(last_response.status).to eq(401)
         | 
| 78 78 | 
             
                end
         | 
| 79 79 | 
             
              end
         | 
| 80 | 
            -
             | 
| 81 80 | 
             
            end
         | 
| @@ -2,12 +2,11 @@ require 'spec_helper' | |
| 2 2 | 
             
            require 'active_support/core_ext/hash'
         | 
| 3 3 |  | 
| 4 4 | 
             
            describe Grape::Middleware::Error do
         | 
| 5 | 
            -
             | 
| 6 5 | 
             
              # raises a text exception
         | 
| 7 6 | 
             
              class ExceptionApp
         | 
| 8 7 | 
             
                class << self
         | 
| 9 8 | 
             
                  def call(env)
         | 
| 10 | 
            -
                     | 
| 9 | 
            +
                    fail 'rain!'
         | 
| 11 10 | 
             
                  end
         | 
| 12 11 | 
             
                end
         | 
| 13 12 | 
             
              end
         | 
| @@ -16,11 +15,11 @@ describe Grape::Middleware::Error do | |
| 16 15 | 
             
              class ErrorHashApp
         | 
| 17 16 | 
             
                class << self
         | 
| 18 17 | 
             
                  def error!(message, status)
         | 
| 19 | 
            -
                    throw :error, message: { error: message, detail:  | 
| 18 | 
            +
                    throw :error, message: { error: message, detail: 'missing widget' }, status: status
         | 
| 20 19 | 
             
                  end
         | 
| 21 20 |  | 
| 22 21 | 
             
                  def call(env)
         | 
| 23 | 
            -
                    error!( | 
| 22 | 
            +
                    error!('rain!', 401)
         | 
| 24 23 | 
             
                  end
         | 
| 25 24 | 
             
                end
         | 
| 26 25 | 
             
              end
         | 
| @@ -33,7 +32,7 @@ describe Grape::Middleware::Error do | |
| 33 32 | 
             
                  end
         | 
| 34 33 |  | 
| 35 34 | 
             
                  def call(env)
         | 
| 36 | 
            -
                    error!( | 
| 35 | 
            +
                    error!('Access Denied', 401)
         | 
| 37 36 | 
             
                  end
         | 
| 38 37 | 
             
                end
         | 
| 39 38 | 
             
              end
         | 
| @@ -45,7 +44,7 @@ describe Grape::Middleware::Error do | |
| 45 44 | 
             
              class CustomErrorApp
         | 
| 46 45 | 
             
                class << self
         | 
| 47 46 | 
             
                  def call(env)
         | 
| 48 | 
            -
                     | 
| 47 | 
            +
                    fail CustomError, status: 400, message: 'failed validation'
         | 
| 49 48 | 
             
                  end
         | 
| 50 49 | 
             
                end
         | 
| 51 50 | 
             
              end
         | 
| @@ -69,7 +68,7 @@ describe Grape::Middleware::Error do | |
| 69 68 | 
             
                    run ExceptionApp
         | 
| 70 69 | 
             
                  end
         | 
| 71 70 | 
             
                  get '/'
         | 
| 72 | 
            -
                  expect(last_response.body).to eq( | 
| 71 | 
            +
                  expect(last_response.body).to eq('rain!')
         | 
| 73 72 | 
             
                end
         | 
| 74 73 |  | 
| 75 74 | 
             
                it 'defaults to a 500 status' do
         | 
| @@ -161,9 +160,9 @@ describe Grape::Middleware::Error do | |
| 161 160 | 
             
                    use Grape::Middleware::Error, rescue_all: true,
         | 
| 162 161 | 
             
                                                  format: :custom,
         | 
| 163 162 | 
             
                                                  error_formatters: {
         | 
| 164 | 
            -
                                                    custom: lambda  | 
| 163 | 
            +
                                                    custom: lambda do |message, backtrace, options, env|
         | 
| 165 164 | 
             
                                                      { custom_formatter: message }.inspect
         | 
| 166 | 
            -
                                                     | 
| 165 | 
            +
                                                    end
         | 
| 167 166 | 
             
                                                  }
         | 
| 168 167 | 
             
                    run ExceptionApp
         | 
| 169 168 | 
             
                  end
         | 
| @@ -192,6 +191,5 @@ describe Grape::Middleware::Error do | |
| 192 191 | 
             
                  expect(last_response.status).to eq(400)
         | 
| 193 192 | 
             
                  expect(last_response.body).to eq('failed validation')
         | 
| 194 193 | 
             
                end
         | 
| 195 | 
            -
             | 
| 196 194 | 
             
              end
         | 
| 197 195 | 
             
            end
         | 
| @@ -4,11 +4,11 @@ describe Grape::Middleware::Formatter do | |
| 4 4 | 
             
              subject { Grape::Middleware::Formatter.new(app) }
         | 
| 5 5 | 
             
              before { allow(subject).to receive(:dup).and_return(subject) }
         | 
| 6 6 |  | 
| 7 | 
            -
              let(:app) { lambda { |env| [200, {}, [@body || {  | 
| 7 | 
            +
              let(:app) { lambda { |env| [200, {}, [@body || { 'foo' => 'bar' }]] } }
         | 
| 8 8 |  | 
| 9 9 | 
             
              context 'serialization' do
         | 
| 10 10 | 
             
                it 'looks at the bodies for possibly serializable data' do
         | 
| 11 | 
            -
                  @body = {  | 
| 11 | 
            +
                  @body = { 'abc' => 'def' }
         | 
| 12 12 | 
             
                  _, _, bodies = *subject.call('PATH_INFO' => '/somewhere', 'HTTP_ACCEPT' => 'application/json')
         | 
| 13 13 | 
             
                  bodies.each { |b| expect(b).to eq(MultiJson.dump(@body)) }
         | 
| 14 14 | 
             
                end
         | 
| @@ -36,10 +36,10 @@ describe Grape::Middleware::Formatter do | |
| 36 36 | 
             
                end
         | 
| 37 37 |  | 
| 38 38 | 
             
                it 'calls #to_xml if the content type is xml' do
         | 
| 39 | 
            -
                  @body =  | 
| 39 | 
            +
                  @body = 'string'
         | 
| 40 40 | 
             
                  @body.instance_eval do
         | 
| 41 41 | 
             
                    def to_xml
         | 
| 42 | 
            -
                       | 
| 42 | 
            +
                      '<bar/>'
         | 
| 43 43 | 
             
                    end
         | 
| 44 44 | 
             
                  end
         | 
| 45 45 |  | 
| @@ -54,24 +54,23 @@ describe Grape::Middleware::Formatter do | |
| 54 54 | 
             
                end
         | 
| 55 55 |  | 
| 56 56 | 
             
                it 'rescues formatter-specific exceptions' do
         | 
| 57 | 
            -
                  allow(formatter).to receive(:call) {  | 
| 57 | 
            +
                  allow(formatter).to receive(:call) { fail Grape::Exceptions::InvalidFormatter.new(String, 'xml') }
         | 
| 58 58 |  | 
| 59 | 
            -
                  expect  | 
| 59 | 
            +
                  expect do
         | 
| 60 60 | 
             
                    catch(:error) { subject.call('PATH_INFO' => '/somewhere.xml', 'HTTP_ACCEPT' => 'application/json') }
         | 
| 61 | 
            -
                   | 
| 61 | 
            +
                  end.to_not raise_error
         | 
| 62 62 | 
             
                end
         | 
| 63 63 |  | 
| 64 64 | 
             
                it 'does not rescue other exceptions' do
         | 
| 65 | 
            -
                  allow(formatter).to receive(:call) {  | 
| 65 | 
            +
                  allow(formatter).to receive(:call) { fail StandardError }
         | 
| 66 66 |  | 
| 67 | 
            -
                  expect  | 
| 67 | 
            +
                  expect do
         | 
| 68 68 | 
             
                    catch(:error) { subject.call('PATH_INFO' => '/somewhere.xml', 'HTTP_ACCEPT' => 'application/json') }
         | 
| 69 | 
            -
                   | 
| 69 | 
            +
                  end.to raise_error
         | 
| 70 70 | 
             
                end
         | 
| 71 71 | 
             
              end
         | 
| 72 72 |  | 
| 73 73 | 
             
              context 'detection' do
         | 
| 74 | 
            -
             | 
| 75 74 | 
             
                it 'uses the xml extension if one is provided' do
         | 
| 76 75 | 
             
                  subject.call('PATH_INFO' => '/info.xml')
         | 
| 77 76 | 
             
                  expect(subject.env['api.format']).to eq(:xml)
         | 
| @@ -186,8 +185,8 @@ describe Grape::Middleware::Formatter do | |
| 186 185 | 
             
              end
         | 
| 187 186 |  | 
| 188 187 | 
             
              context 'input' do
         | 
| 189 | 
            -
                 | 
| 190 | 
            -
                  [ | 
| 188 | 
            +
                %w(POST PATCH PUT DELETE).each do |method|
         | 
| 189 | 
            +
                  ['application/json', 'application/json; charset=utf-8'].each do |content_type|
         | 
| 191 190 | 
             
                    context content_type do
         | 
| 192 191 | 
             
                      it 'parses the body from #{method} and copies values into rack.request.form_hash' do
         | 
| 193 192 | 
             
                        io = StringIO.new('{"is_boolean":true,"string":"thing"}')
         | 
| @@ -215,7 +214,7 @@ describe Grape::Middleware::Formatter do | |
| 215 214 | 
             
                    expect(subject.env['rack.request.form_hash']['is_boolean']).to be true
         | 
| 216 215 | 
             
                    expect(subject.env['rack.request.form_hash']['string']).to eq('thing')
         | 
| 217 216 | 
             
                  end
         | 
| 218 | 
            -
                  it  | 
| 217 | 
            +
                  it 'rewinds IO' do
         | 
| 219 218 | 
             
                    io = StringIO.new('{"is_boolean":true,"string":"thing"}')
         | 
| 220 219 | 
             
                    io.read
         | 
| 221 220 | 
             
                    subject.call(
         | 
| @@ -254,5 +253,4 @@ describe Grape::Middleware::Formatter do | |
| 254 253 | 
             
                  end
         | 
| 255 254 | 
             
                end
         | 
| 256 255 | 
             
              end
         | 
| 257 | 
            -
             | 
| 258 256 | 
             
            end
         | 
| @@ -30,9 +30,9 @@ describe Grape::Middleware::Versioner::AcceptVersionHeader do | |
| 30 30 | 
             
                end
         | 
| 31 31 |  | 
| 32 32 | 
             
                it 'fails with 406 Not Acceptable if version is not supported' do
         | 
| 33 | 
            -
                  expect  | 
| 33 | 
            +
                  expect do
         | 
| 34 34 | 
             
                    subject.call('HTTP_ACCEPT_VERSION' => 'v2').last
         | 
| 35 | 
            -
                   | 
| 35 | 
            +
                  end.to throw_symbol(
         | 
| 36 36 | 
             
                    :error,
         | 
| 37 37 | 
             
                    status: 406,
         | 
| 38 38 | 
             
                    headers: { 'X-Cascade' => 'pass' },
         | 
| @@ -59,9 +59,9 @@ describe Grape::Middleware::Versioner::AcceptVersionHeader do | |
| 59 59 | 
             
                end
         | 
| 60 60 |  | 
| 61 61 | 
             
                it 'fails with 406 Not Acceptable if header is not set' do
         | 
| 62 | 
            -
                  expect  | 
| 62 | 
            +
                  expect do
         | 
| 63 63 | 
             
                    subject.call({}).last
         | 
| 64 | 
            -
                   | 
| 64 | 
            +
                  end.to throw_symbol(
         | 
| 65 65 | 
             
                    :error,
         | 
| 66 66 | 
             
                    status: 406,
         | 
| 67 67 | 
             
                    headers: { 'X-Cascade' => 'pass' },
         | 
| @@ -70,9 +70,9 @@ describe Grape::Middleware::Versioner::AcceptVersionHeader do | |
| 70 70 | 
             
                end
         | 
| 71 71 |  | 
| 72 72 | 
             
                it 'fails with 406 Not Acceptable if header is empty' do
         | 
| 73 | 
            -
                  expect  | 
| 73 | 
            +
                  expect do
         | 
| 74 74 | 
             
                    subject.call('HTTP_ACCEPT_VERSION' => '').last
         | 
| 75 | 
            -
                   | 
| 75 | 
            +
                  end.to throw_symbol(
         | 
| 76 76 | 
             
                    :error,
         | 
| 77 77 | 
             
                    status: 406,
         | 
| 78 78 | 
             
                    headers: { 'X-Cascade' => 'pass' },
         | 
| @@ -93,9 +93,9 @@ describe Grape::Middleware::Versioner::AcceptVersionHeader do | |
| 93 93 | 
             
                end
         | 
| 94 94 |  | 
| 95 95 | 
             
                it 'fails with 406 Not Acceptable if header is not set' do
         | 
| 96 | 
            -
                  expect  | 
| 96 | 
            +
                  expect do
         | 
| 97 97 | 
             
                    subject.call({}).last
         | 
| 98 | 
            -
                   | 
| 98 | 
            +
                  end.to throw_symbol(
         | 
| 99 99 | 
             
                    :error,
         | 
| 100 100 | 
             
                    status: 406,
         | 
| 101 101 | 
             
                    headers: {},
         | 
| @@ -104,9 +104,9 @@ describe Grape::Middleware::Versioner::AcceptVersionHeader do | |
| 104 104 | 
             
                end
         | 
| 105 105 |  | 
| 106 106 | 
             
                it 'fails with 406 Not Acceptable if header is empty' do
         | 
| 107 | 
            -
                  expect  | 
| 107 | 
            +
                  expect do
         | 
| 108 108 | 
             
                    subject.call('HTTP_ACCEPT_VERSION' => '').last
         | 
| 109 | 
            -
                   | 
| 109 | 
            +
                  end.to throw_symbol(
         | 
| 110 110 | 
             
                    :error,
         | 
| 111 111 | 
             
                    status: 406,
         | 
| 112 112 | 
             
                    headers: {},
         | 
| @@ -84,9 +84,9 @@ describe Grape::Middleware::Versioner::Header do | |
| 84 84 | 
             
                end
         | 
| 85 85 |  | 
| 86 86 | 
             
                it 'fails with 406 Not Acceptable if vendor is invalid' do
         | 
| 87 | 
            -
                  expect  | 
| 87 | 
            +
                  expect do
         | 
| 88 88 | 
             
                    subject.call('HTTP_ACCEPT' => 'application/vnd.othervendor+json').last
         | 
| 89 | 
            -
                   | 
| 89 | 
            +
                  end.to throw_symbol(
         | 
| 90 90 | 
             
                    :error,
         | 
| 91 91 | 
             
                    status: 406,
         | 
| 92 92 | 
             
                    headers: { 'X-Cascade' => 'pass' },
         | 
| @@ -112,9 +112,9 @@ describe Grape::Middleware::Versioner::Header do | |
| 112 112 | 
             
                  end
         | 
| 113 113 |  | 
| 114 114 | 
             
                  it 'fails with 406 Not Acceptable if vendor is invalid' do
         | 
| 115 | 
            -
                    expect  | 
| 115 | 
            +
                    expect do
         | 
| 116 116 | 
             
                      subject.call('HTTP_ACCEPT' => 'application/vnd.othervendor-v1+json').last
         | 
| 117 | 
            -
                     | 
| 117 | 
            +
                    end.to throw_symbol(
         | 
| 118 118 | 
             
                      :error,
         | 
| 119 119 | 
             
                      status: 406,
         | 
| 120 120 | 
             
                      headers: { 'X-Cascade' => 'pass' },
         | 
| @@ -142,9 +142,9 @@ describe Grape::Middleware::Versioner::Header do | |
| 142 142 | 
             
                end
         | 
| 143 143 |  | 
| 144 144 | 
             
                it 'fails with 406 Not Acceptable if version is invalid' do
         | 
| 145 | 
            -
                  expect  | 
| 145 | 
            +
                  expect do
         | 
| 146 146 | 
             
                    subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v2+json').last
         | 
| 147 | 
            -
                   | 
| 147 | 
            +
                  end.to throw_symbol(
         | 
| 148 148 | 
             
                    :error,
         | 
| 149 149 | 
             
                    status: 406,
         | 
| 150 150 | 
             
                    headers: { 'X-Cascade' => 'pass' },
         | 
| @@ -171,9 +171,9 @@ describe Grape::Middleware::Versioner::Header do | |
| 171 171 | 
             
                end
         | 
| 172 172 |  | 
| 173 173 | 
             
                it 'fails with 406 Not Acceptable if header is not set' do
         | 
| 174 | 
            -
                  expect  | 
| 174 | 
            +
                  expect do
         | 
| 175 175 | 
             
                    subject.call({}).last
         | 
| 176 | 
            -
                   | 
| 176 | 
            +
                  end.to throw_symbol(
         | 
| 177 177 | 
             
                    :error,
         | 
| 178 178 | 
             
                    status: 406,
         | 
| 179 179 | 
             
                    headers: { 'X-Cascade' => 'pass' },
         | 
| @@ -182,9 +182,9 @@ describe Grape::Middleware::Versioner::Header do | |
| 182 182 | 
             
                end
         | 
| 183 183 |  | 
| 184 184 | 
             
                it 'fails with 406 Not Acceptable if header is empty' do
         | 
| 185 | 
            -
                  expect  | 
| 185 | 
            +
                  expect do
         | 
| 186 186 | 
             
                    subject.call('HTTP_ACCEPT' => '').last
         | 
| 187 | 
            -
                   | 
| 187 | 
            +
                  end.to throw_symbol(
         | 
| 188 188 | 
             
                    :error,
         | 
| 189 189 | 
             
                    status: 406,
         | 
| 190 190 | 
             
                    headers: { 'X-Cascade' => 'pass' },
         | 
| @@ -193,9 +193,9 @@ describe Grape::Middleware::Versioner::Header do | |
| 193 193 | 
             
                end
         | 
| 194 194 |  | 
| 195 195 | 
             
                it 'fails with 406 Not Acceptable if type is a range' do
         | 
| 196 | 
            -
                  expect  | 
| 196 | 
            +
                  expect do
         | 
| 197 197 | 
             
                    subject.call('HTTP_ACCEPT' => '*/*').last
         | 
| 198 | 
            -
                   | 
| 198 | 
            +
                  end.to throw_symbol(
         | 
| 199 199 | 
             
                    :error,
         | 
| 200 200 | 
             
                    status: 406,
         | 
| 201 201 | 
             
                    headers: { 'X-Cascade' => 'pass' },
         | 
| @@ -204,9 +204,9 @@ describe Grape::Middleware::Versioner::Header do | |
| 204 204 | 
             
                end
         | 
| 205 205 |  | 
| 206 206 | 
             
                it 'fails with 406 Not Acceptable if subtype is a range' do
         | 
| 207 | 
            -
                  expect  | 
| 207 | 
            +
                  expect do
         | 
| 208 208 | 
             
                    subject.call('HTTP_ACCEPT' => 'application/*').last
         | 
| 209 | 
            -
                   | 
| 209 | 
            +
                  end.to throw_symbol(
         | 
| 210 210 | 
             
                    :error,
         | 
| 211 211 | 
             
                    status: 406,
         | 
| 212 212 | 
             
                    headers: { 'X-Cascade' => 'pass' },
         | 
| @@ -227,9 +227,9 @@ describe Grape::Middleware::Versioner::Header do | |
| 227 227 | 
             
                end
         | 
| 228 228 |  | 
| 229 229 | 
             
                it 'fails with 406 Not Acceptable if header is not set' do
         | 
| 230 | 
            -
                  expect  | 
| 230 | 
            +
                  expect do
         | 
| 231 231 | 
             
                    subject.call({}).last
         | 
| 232 | 
            -
                   | 
| 232 | 
            +
                  end.to throw_symbol(
         | 
| 233 233 | 
             
                    :error,
         | 
| 234 234 | 
             
                    status: 406,
         | 
| 235 235 | 
             
                    headers: {},
         | 
| @@ -238,9 +238,9 @@ describe Grape::Middleware::Versioner::Header do | |
| 238 238 | 
             
                end
         | 
| 239 239 |  | 
| 240 240 | 
             
                it 'fails with 406 Not Acceptable if header is empty' do
         | 
| 241 | 
            -
                  expect  | 
| 241 | 
            +
                  expect do
         | 
| 242 242 | 
             
                    subject.call('HTTP_ACCEPT' => '').last
         | 
| 243 | 
            -
                   | 
| 243 | 
            +
                  end.to throw_symbol(
         | 
| 244 244 | 
             
                    :error,
         | 
| 245 245 | 
             
                    status: 406,
         | 
| 246 246 | 
             
                    headers: {},
         | 
| @@ -249,9 +249,9 @@ describe Grape::Middleware::Versioner::Header do | |
| 249 249 | 
             
                end
         | 
| 250 250 |  | 
| 251 251 | 
             
                it 'fails with 406 Not Acceptable if type is a range' do
         | 
| 252 | 
            -
                  expect  | 
| 252 | 
            +
                  expect do
         | 
| 253 253 | 
             
                    subject.call('HTTP_ACCEPT' => '*/*').last
         | 
| 254 | 
            -
                   | 
| 254 | 
            +
                  end.to throw_symbol(
         | 
| 255 255 | 
             
                    :error,
         | 
| 256 256 | 
             
                    status: 406,
         | 
| 257 257 | 
             
                    headers: {},
         | 
| @@ -260,9 +260,9 @@ describe Grape::Middleware::Versioner::Header do | |
| 260 260 | 
             
                end
         | 
| 261 261 |  | 
| 262 262 | 
             
                it 'fails with 406 Not Acceptable if subtype is a range' do
         | 
| 263 | 
            -
                  expect  | 
| 263 | 
            +
                  expect do
         | 
| 264 264 | 
             
                    subject.call('HTTP_ACCEPT' => 'application/*').last
         | 
| 265 | 
            -
                   | 
| 265 | 
            +
                  end.to throw_symbol(
         | 
| 266 266 | 
             
                    :error,
         | 
| 267 267 | 
             
                    status: 406,
         | 
| 268 268 | 
             
                    headers: {},
         | 
| @@ -277,7 +277,7 @@ describe Grape::Middleware::Versioner::Header do | |
| 277 277 |  | 
| 278 278 | 
             
              context 'when multiple versions are specified' do
         | 
| 279 279 | 
             
                before do
         | 
| 280 | 
            -
                  @options[:versions] =  | 
| 280 | 
            +
                  @options[:versions] = %w(v1 v2)
         | 
| 281 281 | 
             
                end
         | 
| 282 282 |  | 
| 283 283 | 
             
                it 'succeeds with v1' do
         | 
| @@ -289,9 +289,9 @@ describe Grape::Middleware::Versioner::Header do | |
| 289 289 | 
             
                end
         | 
| 290 290 |  | 
| 291 291 | 
             
                it 'fails with another version' do
         | 
| 292 | 
            -
                  expect  | 
| 292 | 
            +
                  expect do
         | 
| 293 293 | 
             
                    subject.call('HTTP_ACCEPT' => 'application/vnd.vendor-v3+json')
         | 
| 294 | 
            -
                   | 
| 294 | 
            +
                  end.to throw_symbol(
         | 
| 295 295 | 
             
                    :error,
         | 
| 296 296 | 
             
                    status: 406,
         | 
| 297 297 | 
             
                    headers: { 'X-Cascade' => 'pass' },
         | 
| @@ -1,48 +1,47 @@ | |
| 1 1 | 
             
            require 'spec_helper'
         | 
| 2 2 |  | 
| 3 3 | 
             
            describe Grape::Middleware::Versioner::Param do
         | 
| 4 | 
            -
             | 
| 5 4 | 
             
              let(:app) { lambda { |env| [200, env, env['api.version']] } }
         | 
| 6 5 | 
             
              subject { Grape::Middleware::Versioner::Param.new(app, @options || {}) }
         | 
| 7 6 |  | 
| 8 7 | 
             
              it 'sets the API version based on the default param (apiver)' do
         | 
| 9 | 
            -
                env = Rack::MockRequest.env_for( | 
| 10 | 
            -
                expect(subject.call(env)[1][ | 
| 8 | 
            +
                env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
         | 
| 9 | 
            +
                expect(subject.call(env)[1]['api.version']).to eq('v1')
         | 
| 11 10 | 
             
              end
         | 
| 12 11 |  | 
| 13 12 | 
             
              it 'cuts (only) the version out of the params' do
         | 
| 14 | 
            -
                env = Rack::MockRequest.env_for( | 
| 13 | 
            +
                env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1', 'other_param' => '5' })
         | 
| 15 14 | 
             
                env['rack.request.query_hash'] = Rack::Utils.parse_nested_query(env['QUERY_STRING'])
         | 
| 16 | 
            -
                expect(subject.call(env)[1]['rack.request.query_hash'][ | 
| 17 | 
            -
                expect(subject.call(env)[1]['rack.request.query_hash'][ | 
| 15 | 
            +
                expect(subject.call(env)[1]['rack.request.query_hash']['apiver']).to be_nil
         | 
| 16 | 
            +
                expect(subject.call(env)[1]['rack.request.query_hash']['other_param']).to eq('5')
         | 
| 18 17 | 
             
              end
         | 
| 19 18 |  | 
| 20 19 | 
             
              it 'provides a nil version if no version is given' do
         | 
| 21 | 
            -
                env = Rack::MockRequest.env_for( | 
| 20 | 
            +
                env = Rack::MockRequest.env_for('/')
         | 
| 22 21 | 
             
                expect(subject.call(env).last).to be_nil
         | 
| 23 22 | 
             
              end
         | 
| 24 23 |  | 
| 25 24 | 
             
              context 'with specified parameter name' do
         | 
| 26 25 | 
             
                before { @options = { parameter: 'v' } }
         | 
| 27 26 | 
             
                it 'sets the API version based on the custom parameter name' do
         | 
| 28 | 
            -
                  env = Rack::MockRequest.env_for( | 
| 29 | 
            -
                  expect(subject.call(env)[1][ | 
| 27 | 
            +
                  env = Rack::MockRequest.env_for('/awesome', params: { 'v' => 'v1' })
         | 
| 28 | 
            +
                  expect(subject.call(env)[1]['api.version']).to eq('v1')
         | 
| 30 29 | 
             
                end
         | 
| 31 30 | 
             
                it 'does not set the API version based on the default param' do
         | 
| 32 | 
            -
                  env = Rack::MockRequest.env_for( | 
| 33 | 
            -
                  expect(subject.call(env)[1][ | 
| 31 | 
            +
                  env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
         | 
| 32 | 
            +
                  expect(subject.call(env)[1]['api.version']).to be_nil
         | 
| 34 33 | 
             
                end
         | 
| 35 34 | 
             
              end
         | 
| 36 35 |  | 
| 37 36 | 
             
              context 'with specified versions' do
         | 
| 38 | 
            -
                before { @options = { versions:  | 
| 37 | 
            +
                before { @options = { versions: %w(v1 v2) } }
         | 
| 39 38 | 
             
                it 'throws an error if a non-allowed version is specified' do
         | 
| 40 | 
            -
                  env = Rack::MockRequest.env_for( | 
| 39 | 
            +
                  env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v3' })
         | 
| 41 40 | 
             
                  expect(catch(:error) { subject.call(env) }[:status]).to eq(404)
         | 
| 42 41 | 
             
                end
         | 
| 43 42 | 
             
                it 'allows versions that have been specified' do
         | 
| 44 | 
            -
                  env = Rack::MockRequest.env_for( | 
| 45 | 
            -
                  expect(subject.call(env)[1][ | 
| 43 | 
            +
                  env = Rack::MockRequest.env_for('/awesome', params: { 'apiver' => 'v1' })
         | 
| 44 | 
            +
                  expect(subject.call(env)[1]['api.version']).to eq('v1')
         | 
| 46 45 | 
             
                end
         | 
| 47 46 | 
             
              end
         | 
| 48 47 |  | 
| @@ -51,8 +50,7 @@ describe Grape::Middleware::Versioner::Param do | |
| 51 50 | 
             
                  versions: ['v1'],
         | 
| 52 51 | 
             
                  version_options: { using: :header }
         | 
| 53 52 | 
             
                }
         | 
| 54 | 
            -
                env = Rack::MockRequest.env_for( | 
| 53 | 
            +
                env = Rack::MockRequest.env_for('/awesome', params: {})
         | 
| 55 54 | 
             
                expect(subject.call(env).first).to eq(200)
         | 
| 56 55 | 
             
              end
         | 
| 57 | 
            -
             | 
| 58 56 | 
             
            end
         |