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
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            module Grape
         | 
| 2 | 
            +
              module Validations
         | 
| 3 | 
            +
                require 'grape/validations/validators/multiple_params_base'
         | 
| 4 | 
            +
                class AllOrNoneOfValidator < MultipleParamsBase
         | 
| 5 | 
            +
                  def validate!(params)
         | 
| 6 | 
            +
                    super
         | 
| 7 | 
            +
                    if scope_requires_params && only_subset_present
         | 
| 8 | 
            +
                      fail Grape::Exceptions::Validation, params: all_keys, message_key: :all_or_none
         | 
| 9 | 
            +
                    end
         | 
| 10 | 
            +
                    params
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  private
         | 
| 14 | 
            +
             | 
| 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  }
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            module Grape
         | 
| 2 | 
            +
              module Validations
         | 
| 3 | 
            +
                class AllowBlankValidator < Base
         | 
| 4 | 
            +
                  def validate_param!(attr_name, params)
         | 
| 5 | 
            +
                    return if @option || !params.is_a?(Hash)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                    value = params[attr_name]
         | 
| 8 | 
            +
                    value = value.strip if value.respond_to?(:strip)
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                    key_exists = params.key?(attr_name)
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    if @scope.root?
         | 
| 13 | 
            +
                      # root scope. validate if it's a required param. if it's optional, validate only if key exists in hash
         | 
| 14 | 
            +
                      should_validate = @required || key_exists
         | 
| 15 | 
            +
                    else # nested scope
         | 
| 16 | 
            +
                      should_validate = # required param, and scope contains some values (if scoping element contains no values, treat as blank)
         | 
| 17 | 
            +
                        (@required && params.present?) ||
         | 
| 18 | 
            +
                        # optional param but key inside scoping element exists
         | 
| 19 | 
            +
                        (!@required && params.key?(attr_name))
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                    return unless should_validate
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                    unless value.present?
         | 
| 25 | 
            +
                      fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :blank
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            module Grape
         | 
| 2 | 
            +
              module Validations
         | 
| 3 | 
            +
                require 'grape/validations/validators/multiple_params_base'
         | 
| 4 | 
            +
                class AtLeastOneOfValidator < MultipleParamsBase
         | 
| 5 | 
            +
                  def validate!(params)
         | 
| 6 | 
            +
                    super
         | 
| 7 | 
            +
                    if scope_requires_params && no_exclusive_params_are_present
         | 
| 8 | 
            +
                      fail Grape::Exceptions::Validation, params: all_keys, message_key: :at_least_one
         | 
| 9 | 
            +
                    end
         | 
| 10 | 
            +
                    params
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  private
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def no_exclusive_params_are_present
         | 
| 16 | 
            +
                    scoped_params.any? { |resource_params| keys_in_common(resource_params).empty? }
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            module Grape
         | 
| 2 | 
            +
              module Validations
         | 
| 3 | 
            +
                class Base
         | 
| 4 | 
            +
                  attr_reader :attrs
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def initialize(attrs, options, required, scope)
         | 
| 7 | 
            +
                    @attrs = Array(attrs)
         | 
| 8 | 
            +
                    @option = options
         | 
| 9 | 
            +
                    @required = required
         | 
| 10 | 
            +
                    @scope = scope
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def validate!(params)
         | 
| 14 | 
            +
                    attributes = AttributesIterator.new(self, @scope, params)
         | 
| 15 | 
            +
                    attributes.each do |resource_params, attr_name|
         | 
| 16 | 
            +
                      if @required || (resource_params.respond_to?(:key?) && resource_params.key?(attr_name))
         | 
| 17 | 
            +
                        validate_param!(attr_name, resource_params)
         | 
| 18 | 
            +
                      end
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  def self.convert_to_short_name(klass)
         | 
| 23 | 
            +
                    ret = klass.name.gsub(/::/, '/')
         | 
| 24 | 
            +
                          .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
         | 
| 25 | 
            +
                          .gsub(/([a-z\d])([A-Z])/, '\1_\2')
         | 
| 26 | 
            +
                          .tr('-', '_')
         | 
| 27 | 
            +
                          .downcase
         | 
| 28 | 
            +
                    File.basename(ret, '_validator')
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  def self.inherited(klass)
         | 
| 32 | 
            +
                    short_name = convert_to_short_name(klass)
         | 
| 33 | 
            +
                    Validations.register_validator(short_name, klass)
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
            end
         | 
| @@ -4,14 +4,14 @@ module Grape | |
| 4 4 | 
             
              end
         | 
| 5 5 |  | 
| 6 6 | 
             
              module Validations
         | 
| 7 | 
            -
                class CoerceValidator <  | 
| 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 10 | 
             
                    new_value = coerce_value(@option, params[attr_name])
         | 
| 11 11 | 
             
                    if valid_type?(new_value)
         | 
| 12 12 | 
             
                      params[attr_name] = new_value
         | 
| 13 13 | 
             
                    else
         | 
| 14 | 
            -
                       | 
| 14 | 
            +
                      fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :coerce
         | 
| 15 15 | 
             
                    end
         | 
| 16 16 | 
             
                  end
         | 
| 17 17 |  | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            module Grape
         | 
| 2 | 
            +
              module Validations
         | 
| 3 | 
            +
                require 'grape/validations/validators/mutual_exclusion'
         | 
| 4 | 
            +
                class ExactlyOneOfValidator < MutualExclusionValidator
         | 
| 5 | 
            +
                  def validate!(params)
         | 
| 6 | 
            +
                    super
         | 
| 7 | 
            +
                    if scope_requires_params && none_of_restricted_params_is_present
         | 
| 8 | 
            +
                      fail Grape::Exceptions::Validation, params: all_keys, message_key: :exactly_one
         | 
| 9 | 
            +
                    end
         | 
| 10 | 
            +
                    params
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  private
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def none_of_restricted_params_is_present
         | 
| 16 | 
            +
                    scoped_params.any? { |resource_params| keys_in_common(resource_params).empty? }
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            module Grape
         | 
| 2 | 
            +
              module Validations
         | 
| 3 | 
            +
                class MultipleParamsBase < Base
         | 
| 4 | 
            +
                  attr_reader :scoped_params
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                  def validate!(params)
         | 
| 7 | 
            +
                    @scoped_params = [@scope.params(params)].flatten
         | 
| 8 | 
            +
                    params
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  private
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def scope_requires_params
         | 
| 14 | 
            +
                    @scope.required? || scoped_params.any?(&:any?)
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def keys_in_common(resource_params)
         | 
| 18 | 
            +
                    (all_keys & resource_params.stringify_keys.keys).map(&:to_s)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def all_keys
         | 
| 22 | 
            +
                    attrs.map(&:to_s)
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
| @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            module Grape
         | 
| 2 | 
            +
              module Validations
         | 
| 3 | 
            +
                require 'grape/validations/validators/multiple_params_base'
         | 
| 4 | 
            +
                class MutualExclusionValidator < MultipleParamsBase
         | 
| 5 | 
            +
                  attr_reader :processing_keys_in_common
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                  def validate!(params)
         | 
| 8 | 
            +
                    super
         | 
| 9 | 
            +
                    if two_or_more_exclusive_params_are_present
         | 
| 10 | 
            +
                      fail Grape::Exceptions::Validation, params: processing_keys_in_common, message_key: :mutual_exclusion
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
                    params
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  private
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  def two_or_more_exclusive_params_are_present
         | 
| 18 | 
            +
                    scoped_params.any? do |resource_params|
         | 
| 19 | 
            +
                      @processing_keys_in_common = keys_in_common(resource_params)
         | 
| 20 | 
            +
                      @processing_keys_in_common.length > 1
         | 
| 21 | 
            +
                    end
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
            end
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            module Grape
         | 
| 2 2 | 
             
              module Validations
         | 
| 3 | 
            -
                class PresenceValidator <  | 
| 3 | 
            +
                class PresenceValidator < Base
         | 
| 4 4 | 
             
                  def validate!(params)
         | 
| 5 5 | 
             
                    return unless @scope.should_validate?(params)
         | 
| 6 6 | 
             
                    super
         | 
| @@ -8,7 +8,7 @@ module Grape | |
| 8 8 |  | 
| 9 9 | 
             
                  def validate_param!(attr_name, params)
         | 
| 10 10 | 
             
                    unless params.respond_to?(:key?) && params.key?(attr_name)
         | 
| 11 | 
            -
                       | 
| 11 | 
            +
                      fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :presence
         | 
| 12 12 | 
             
                    end
         | 
| 13 13 | 
             
                  end
         | 
| 14 14 | 
             
                end
         | 
| @@ -0,0 +1,12 @@ | |
| 1 | 
            +
            module Grape
         | 
| 2 | 
            +
              module Validations
         | 
| 3 | 
            +
                class RegexpValidator < Base
         | 
| 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
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
            end
         | 
| @@ -0,0 +1,26 @@ | |
| 1 | 
            +
            module Grape
         | 
| 2 | 
            +
              module Validations
         | 
| 3 | 
            +
                class ValuesValidator < Base
         | 
| 4 | 
            +
                  def initialize(attrs, options, required, scope)
         | 
| 5 | 
            +
                    @values = options
         | 
| 6 | 
            +
                    super
         | 
| 7 | 
            +
                  end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def validate_param!(attr_name, params)
         | 
| 10 | 
            +
                    return unless params[attr_name] || required_for_root_scope?
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    values = @values.is_a?(Proc) ? @values.call : @values
         | 
| 13 | 
            +
                    param_array = params[attr_name].nil? ? [nil] : Array.wrap(params[attr_name])
         | 
| 14 | 
            +
                    unless (param_array - values).empty?
         | 
| 15 | 
            +
                      fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :values
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  private
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  def required_for_root_scope?
         | 
| 22 | 
            +
                    @required && @scope.root?
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
              end
         | 
| 26 | 
            +
            end
         | 
    
        data/lib/grape/version.rb
    CHANGED
    
    
    
        data/spec/grape/api_spec.rb
    CHANGED
    
    | @@ -13,25 +13,45 @@ describe Grape::API do | |
| 13 13 | 
             
                it 'routes root through with the prefix' do
         | 
| 14 14 | 
             
                  subject.prefix 'awesome/sauce'
         | 
| 15 15 | 
             
                  subject.get do
         | 
| 16 | 
            -
                     | 
| 16 | 
            +
                    'Hello there.'
         | 
| 17 17 | 
             
                  end
         | 
| 18 18 |  | 
| 19 19 | 
             
                  get 'awesome/sauce/'
         | 
| 20 | 
            -
                  expect(last_response. | 
| 20 | 
            +
                  expect(last_response.status).to eql 200
         | 
| 21 | 
            +
                  expect(last_response.body).to eql 'Hello there.'
         | 
| 21 22 | 
             
                end
         | 
| 22 23 |  | 
| 23 24 | 
             
                it 'routes through with the prefix' do
         | 
| 24 25 | 
             
                  subject.prefix 'awesome/sauce'
         | 
| 25 26 | 
             
                  subject.get :hello do
         | 
| 26 | 
            -
                     | 
| 27 | 
            +
                    'Hello there.'
         | 
| 27 28 | 
             
                  end
         | 
| 28 29 |  | 
| 29 30 | 
             
                  get 'awesome/sauce/hello'
         | 
| 30 | 
            -
                  expect(last_response.body).to eql  | 
| 31 | 
            +
                  expect(last_response.body).to eql 'Hello there.'
         | 
| 31 32 |  | 
| 32 33 | 
             
                  get '/hello'
         | 
| 33 34 | 
             
                  expect(last_response.status).to eql 404
         | 
| 34 35 | 
             
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                it 'supports OPTIONS' do
         | 
| 38 | 
            +
                  subject.prefix 'awesome/sauce'
         | 
| 39 | 
            +
                  subject.get do
         | 
| 40 | 
            +
                    'Hello there.'
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  options 'awesome/sauce'
         | 
| 44 | 
            +
                  expect(last_response.status).to eql 204
         | 
| 45 | 
            +
                  expect(last_response.body).to be_blank
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                it 'disallows POST' do
         | 
| 49 | 
            +
                  subject.prefix 'awesome/sauce'
         | 
| 50 | 
            +
                  subject.get
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  post 'awesome/sauce'
         | 
| 53 | 
            +
                  expect(last_response.status).to eql 405
         | 
| 54 | 
            +
                end
         | 
| 35 55 | 
             
              end
         | 
| 36 56 |  | 
| 37 57 | 
             
              describe '.version' do
         | 
| @@ -64,7 +84,7 @@ describe Grape::API do | |
| 64 84 | 
             
                  let(:macro_options) do
         | 
| 65 85 | 
             
                    {
         | 
| 66 86 | 
             
                      using: :param,
         | 
| 67 | 
            -
                      parameter:  | 
| 87 | 
            +
                      parameter: 'apiver'
         | 
| 68 88 | 
             
                    }
         | 
| 69 89 | 
             
                  end
         | 
| 70 90 | 
             
                end
         | 
| @@ -116,7 +136,7 @@ describe Grape::API do | |
| 116 136 | 
             
                it 'adds the association to the :representations setting' do
         | 
| 117 137 | 
             
                  klass = Class.new
         | 
| 118 138 | 
             
                  subject.represent Object, with: klass
         | 
| 119 | 
            -
                  expect(subject. | 
| 139 | 
            +
                  expect(Grape::DSL::Configuration.stacked_hash_to_hash(subject.namespace_stackable(:representations))[Object]).to eq(klass)
         | 
| 120 140 | 
             
                end
         | 
| 121 141 | 
             
              end
         | 
| 122 142 |  | 
| @@ -126,7 +146,7 @@ describe Grape::API do | |
| 126 146 | 
             
                  subject.namespace :awesome do
         | 
| 127 147 | 
             
                    internal_namespace = namespace
         | 
| 128 148 | 
             
                  end
         | 
| 129 | 
            -
                  expect(internal_namespace).to eql( | 
| 149 | 
            +
                  expect(internal_namespace).to eql('/awesome')
         | 
| 130 150 | 
             
                end
         | 
| 131 151 |  | 
| 132 152 | 
             
                it 'comes after the prefix and version' do
         | 
| @@ -134,11 +154,11 @@ describe Grape::API do | |
| 134 154 | 
             
                  subject.version 'v1', using: :path
         | 
| 135 155 |  | 
| 136 156 | 
             
                  subject.namespace :awesome do
         | 
| 137 | 
            -
                    get('/hello') {  | 
| 157 | 
            +
                    get('/hello') { 'worked' }
         | 
| 138 158 | 
             
                  end
         | 
| 139 159 |  | 
| 140 | 
            -
                  get  | 
| 141 | 
            -
                  expect(last_response.body).to eq( | 
| 160 | 
            +
                  get '/rad/v1/awesome/hello'
         | 
| 161 | 
            +
                  expect(last_response.body).to eq('worked')
         | 
| 142 162 | 
             
                end
         | 
| 143 163 |  | 
| 144 164 | 
             
                it 'cancels itself after the block is over' do
         | 
| @@ -146,7 +166,7 @@ describe Grape::API do | |
| 146 166 | 
             
                  subject.namespace :awesome do
         | 
| 147 167 | 
             
                    internal_namespace = namespace
         | 
| 148 168 | 
             
                  end
         | 
| 149 | 
            -
                  expect(subject.namespace).to eql( | 
| 169 | 
            +
                  expect(subject.namespace).to eql('/')
         | 
| 150 170 | 
             
                end
         | 
| 151 171 |  | 
| 152 172 | 
             
                it 'is stackable' do
         | 
| @@ -173,21 +193,21 @@ describe Grape::API do | |
| 173 193 | 
             
                    end
         | 
| 174 194 | 
             
                  end
         | 
| 175 195 | 
             
                  get '/members/23'
         | 
| 176 | 
            -
                  expect(last_response.body).to eq( | 
| 196 | 
            +
                  expect(last_response.body).to eq('23')
         | 
| 177 197 | 
             
                  expect(inner_namespace).to eq('/members/:member_id')
         | 
| 178 198 | 
             
                end
         | 
| 179 199 |  | 
| 180 200 | 
             
                it 'is callable with nil just to push onto the stack' do
         | 
| 181 201 | 
             
                  subject.namespace do
         | 
| 182 202 | 
             
                    version 'v2', using: :path
         | 
| 183 | 
            -
                    get('/hello') {  | 
| 203 | 
            +
                    get('/hello') { 'inner' }
         | 
| 184 204 | 
             
                  end
         | 
| 185 | 
            -
                  subject.get('/hello') {  | 
| 205 | 
            +
                  subject.get('/hello') { 'outer' }
         | 
| 186 206 |  | 
| 187 207 | 
             
                  get '/v2/hello'
         | 
| 188 | 
            -
                  expect(last_response.body).to eq( | 
| 208 | 
            +
                  expect(last_response.body).to eq('inner')
         | 
| 189 209 | 
             
                  get '/hello'
         | 
| 190 | 
            -
                  expect(last_response.body).to eq( | 
| 210 | 
            +
                  expect(last_response.body).to eq('outer')
         | 
| 191 211 | 
             
                end
         | 
| 192 212 |  | 
| 193 213 | 
             
                %w(group resource resources segment).each do |als|
         | 
| @@ -196,7 +216,7 @@ describe Grape::API do | |
| 196 216 | 
             
                    subject.send(als, :awesome) do
         | 
| 197 217 | 
             
                      inner_namespace = namespace
         | 
| 198 218 | 
             
                    end
         | 
| 199 | 
            -
                    expect(inner_namespace).to eq  | 
| 219 | 
            +
                    expect(inner_namespace).to eq '/awesome'
         | 
| 200 220 | 
             
                  end
         | 
| 201 221 | 
             
                end
         | 
| 202 222 | 
             
              end
         | 
| @@ -235,10 +255,10 @@ describe Grape::API do | |
| 235 255 | 
             
                it 'allows for no path' do
         | 
| 236 256 | 
             
                  subject.namespace :votes do
         | 
| 237 257 | 
             
                    get do
         | 
| 238 | 
            -
                       | 
| 258 | 
            +
                      'Votes'
         | 
| 239 259 | 
             
                    end
         | 
| 240 260 | 
             
                    post do
         | 
| 241 | 
            -
                       | 
| 261 | 
            +
                      'Created a Vote'
         | 
| 242 262 | 
             
                    end
         | 
| 243 263 | 
             
                  end
         | 
| 244 264 |  | 
| @@ -249,21 +269,23 @@ describe Grape::API do | |
| 249 269 | 
             
                end
         | 
| 250 270 |  | 
| 251 271 | 
             
                it 'handles empty calls' do
         | 
| 252 | 
            -
                  subject.get  | 
| 253 | 
            -
                  get  | 
| 254 | 
            -
                  expect(last_response.body).to eql  | 
| 272 | 
            +
                  subject.get '/'
         | 
| 273 | 
            +
                  get '/'
         | 
| 274 | 
            +
                  expect(last_response.body).to eql ''
         | 
| 255 275 | 
             
                end
         | 
| 256 276 |  | 
| 257 277 | 
             
                describe 'root routes should work with' do
         | 
| 258 278 | 
             
                  before do
         | 
| 259 279 | 
             
                    subject.format :txt
         | 
| 280 | 
            +
                    subject.content_type :json, 'application/json'
         | 
| 281 | 
            +
                    subject.formatter :json, ->(object, env) { object }
         | 
| 260 282 | 
             
                    def subject.enable_root_route!
         | 
| 261 | 
            -
                      get( | 
| 283 | 
            +
                      get('/') { 'root' }
         | 
| 262 284 | 
             
                    end
         | 
| 263 285 | 
             
                  end
         | 
| 264 286 |  | 
| 265 287 | 
             
                  after do
         | 
| 266 | 
            -
                    expect(last_response.body).to eql  | 
| 288 | 
            +
                    expect(last_response.body).to eql 'root'
         | 
| 267 289 | 
             
                  end
         | 
| 268 290 |  | 
| 269 291 | 
             
                  describe 'path versioned APIs' do
         | 
| @@ -273,11 +295,11 @@ describe Grape::API do | |
| 273 295 | 
             
                    end
         | 
| 274 296 |  | 
| 275 297 | 
             
                    it 'without a format' do
         | 
| 276 | 
            -
                      versioned_get  | 
| 298 | 
            +
                      versioned_get '/', 'v1', using: :path
         | 
| 277 299 | 
             
                    end
         | 
| 278 300 |  | 
| 279 301 | 
             
                    it 'with a format' do
         | 
| 280 | 
            -
                      get  | 
| 302 | 
            +
                      get '/v1/.json'
         | 
| 281 303 | 
             
                    end
         | 
| 282 304 | 
             
                  end
         | 
| 283 305 |  | 
| @@ -285,41 +307,41 @@ describe Grape::API do | |
| 285 307 | 
             
                    subject.version 'v1', using: :header, vendor: 'test'
         | 
| 286 308 | 
             
                    subject.enable_root_route!
         | 
| 287 309 |  | 
| 288 | 
            -
                    versioned_get  | 
| 310 | 
            +
                    versioned_get '/', 'v1', using: :header, vendor: 'test'
         | 
| 289 311 | 
             
                  end
         | 
| 290 312 |  | 
| 291 313 | 
             
                  it 'header versioned APIs with multiple headers' do
         | 
| 292 | 
            -
                    subject.version  | 
| 314 | 
            +
                    subject.version %w(v1 v2), using: :header, vendor: 'test'
         | 
| 293 315 | 
             
                    subject.enable_root_route!
         | 
| 294 316 |  | 
| 295 | 
            -
                    versioned_get  | 
| 296 | 
            -
                    versioned_get  | 
| 317 | 
            +
                    versioned_get '/', 'v1', using: :header, vendor: 'test'
         | 
| 318 | 
            +
                    versioned_get '/', 'v2', using: :header, vendor: 'test'
         | 
| 297 319 | 
             
                  end
         | 
| 298 320 |  | 
| 299 321 | 
             
                  it 'param versioned APIs' do
         | 
| 300 322 | 
             
                    subject.version 'v1', using: :param
         | 
| 301 323 | 
             
                    subject.enable_root_route!
         | 
| 302 324 |  | 
| 303 | 
            -
                    versioned_get  | 
| 325 | 
            +
                    versioned_get '/', 'v1', using: :param
         | 
| 304 326 | 
             
                  end
         | 
| 305 327 |  | 
| 306 328 | 
             
                  it 'Accept-Version header versioned APIs' do
         | 
| 307 329 | 
             
                    subject.version 'v1', using: :accept_version_header
         | 
| 308 330 | 
             
                    subject.enable_root_route!
         | 
| 309 331 |  | 
| 310 | 
            -
                    versioned_get  | 
| 332 | 
            +
                    versioned_get '/', 'v1', using: :accept_version_header
         | 
| 311 333 | 
             
                  end
         | 
| 312 334 |  | 
| 313 335 | 
             
                  it 'unversioned APIs' do
         | 
| 314 336 | 
             
                    subject.enable_root_route!
         | 
| 315 337 |  | 
| 316 | 
            -
                    get  | 
| 338 | 
            +
                    get '/'
         | 
| 317 339 | 
             
                  end
         | 
| 318 340 | 
             
                end
         | 
| 319 341 |  | 
| 320 342 | 
             
                it 'allows for multiple paths' do
         | 
| 321 | 
            -
                  subject.get([ | 
| 322 | 
            -
                     | 
| 343 | 
            +
                  subject.get(['/abc', '/def']) do
         | 
| 344 | 
            +
                    'foo'
         | 
| 323 345 | 
             
                  end
         | 
| 324 346 |  | 
| 325 347 | 
             
                  get '/abc'
         | 
| @@ -330,10 +352,10 @@ describe Grape::API do | |
| 330 352 |  | 
| 331 353 | 
             
                context 'format' do
         | 
| 332 354 | 
             
                  before(:each) do
         | 
| 333 | 
            -
                    allow_any_instance_of(Object).to receive(:to_json).and_return( | 
| 334 | 
            -
                    allow_any_instance_of(Object).to receive(:to_txt).and_return( | 
| 355 | 
            +
                    allow_any_instance_of(Object).to receive(:to_json).and_return('abc')
         | 
| 356 | 
            +
                    allow_any_instance_of(Object).to receive(:to_txt).and_return('def')
         | 
| 335 357 |  | 
| 336 | 
            -
                    subject.get( | 
| 358 | 
            +
                    subject.get('/abc') do
         | 
| 337 359 | 
             
                      Object.new
         | 
| 338 360 | 
             
                    end
         | 
| 339 361 | 
             
                  end
         | 
| @@ -353,7 +375,7 @@ describe Grape::API do | |
| 353 375 |  | 
| 354 376 | 
             
                it 'allows for format without corrupting a param' do
         | 
| 355 377 | 
             
                  subject.get('/:id') do
         | 
| 356 | 
            -
                    {  | 
| 378 | 
            +
                    { 'id' => params[:id] }
         | 
| 357 379 | 
             
                  end
         | 
| 358 380 |  | 
| 359 381 | 
             
                  get '/awesome.json'
         | 
| @@ -363,7 +385,7 @@ describe Grape::API do | |
| 363 385 | 
             
                it 'allows for format in namespace with no path' do
         | 
| 364 386 | 
             
                  subject.namespace :abc do
         | 
| 365 387 | 
             
                    get do
         | 
| 366 | 
            -
                      [ | 
| 388 | 
            +
                      ['json']
         | 
| 367 389 | 
             
                    end
         | 
| 368 390 | 
             
                  end
         | 
| 369 391 |  | 
| @@ -373,7 +395,7 @@ describe Grape::API do | |
| 373 395 |  | 
| 374 396 | 
             
                it 'allows for multiple verbs' do
         | 
| 375 397 | 
             
                  subject.route([:get, :post], '/abc') do
         | 
| 376 | 
            -
                     | 
| 398 | 
            +
                    'hiya'
         | 
| 377 399 | 
             
                  end
         | 
| 378 400 |  | 
| 379 401 | 
             
                  subject.endpoints.first.routes.each do |route|
         | 
| @@ -399,7 +421,7 @@ describe Grape::API do | |
| 399 421 | 
             
                        expect(last_response.body).to eql MultiJson.dump(object)
         | 
| 400 422 | 
             
                        expect(last_request.params).to eql Hash.new
         | 
| 401 423 | 
             
                      end
         | 
| 402 | 
            -
                      it  | 
| 424 | 
            +
                      it 'stores input in api.request.input' do
         | 
| 403 425 | 
             
                        subject.format :json
         | 
| 404 426 | 
             
                        subject.send(verb) do
         | 
| 405 427 | 
             
                          env['api.request.input']
         | 
| @@ -408,8 +430,8 @@ describe Grape::API do | |
| 408 430 | 
             
                        expect(last_response.status).to eq(verb == :post ? 201 : 200)
         | 
| 409 431 | 
             
                        expect(last_response.body).to eql MultiJson.dump(object).to_json
         | 
| 410 432 | 
             
                      end
         | 
| 411 | 
            -
                      context  | 
| 412 | 
            -
                        it  | 
| 433 | 
            +
                      context 'chunked transfer encoding' do
         | 
| 434 | 
            +
                        it 'stores input in api.request.input' do
         | 
| 413 435 | 
             
                          subject.format :json
         | 
| 414 436 | 
             
                          subject.send(verb) do
         | 
| 415 437 | 
             
                            env['api.request.input']
         | 
| @@ -424,16 +446,15 @@ describe Grape::API do | |
| 424 446 | 
             
                end
         | 
| 425 447 |  | 
| 426 448 | 
             
                it 'allows for multipart paths' do
         | 
| 427 | 
            -
             | 
| 428 449 | 
             
                  subject.route([:get, :post], '/:id/first') do
         | 
| 429 | 
            -
                     | 
| 450 | 
            +
                    'first'
         | 
| 430 451 | 
             
                  end
         | 
| 431 452 |  | 
| 432 453 | 
             
                  subject.route([:get, :post], '/:id') do
         | 
| 433 | 
            -
                     | 
| 454 | 
            +
                    'ola'
         | 
| 434 455 | 
             
                  end
         | 
| 435 456 | 
             
                  subject.route([:get, :post], '/:id/first/second') do
         | 
| 436 | 
            -
                     | 
| 457 | 
            +
                    'second'
         | 
| 437 458 | 
             
                  end
         | 
| 438 459 |  | 
| 439 460 | 
             
                  get '/1'
         | 
| @@ -446,12 +467,11 @@ describe Grape::API do | |
| 446 467 | 
             
                  expect(last_response.body).to eql 'first'
         | 
| 447 468 | 
             
                  get '/1/first/second'
         | 
| 448 469 | 
             
                  expect(last_response.body).to eql 'second'
         | 
| 449 | 
            -
             | 
| 450 470 | 
             
                end
         | 
| 451 471 |  | 
| 452 472 | 
             
                it 'allows for :any as a verb' do
         | 
| 453 473 | 
             
                  subject.route(:any, '/abc') do
         | 
| 454 | 
            -
                     | 
| 474 | 
            +
                    'lol'
         | 
| 455 475 | 
             
                  end
         | 
| 456 476 |  | 
| 457 477 | 
             
                  %w(get post put delete options patch).each do |m|
         | 
| @@ -476,7 +496,7 @@ describe Grape::API do | |
| 476 496 |  | 
| 477 497 | 
             
                it 'returns a 201 response code for POST by default' do
         | 
| 478 498 | 
             
                  subject.post('example') do
         | 
| 479 | 
            -
                     | 
| 499 | 
            +
                    'Created'
         | 
| 480 500 | 
             
                  end
         | 
| 481 501 |  | 
| 482 502 | 
             
                  post '/example'
         | 
| @@ -487,7 +507,7 @@ describe Grape::API do | |
| 487 507 | 
             
                it 'returns a 405 for an unsupported method with an X-Custom-Header' do
         | 
| 488 508 | 
             
                  subject.before { header 'X-Custom-Header', 'foo' }
         | 
| 489 509 | 
             
                  subject.get 'example' do
         | 
| 490 | 
            -
                     | 
| 510 | 
            +
                    'example'
         | 
| 491 511 | 
             
                  end
         | 
| 492 512 | 
             
                  put '/example'
         | 
| 493 513 | 
             
                  expect(last_response.status).to eql 405
         | 
| @@ -497,10 +517,10 @@ describe Grape::API do | |
| 497 517 |  | 
| 498 518 | 
             
                specify '405 responses includes an Allow header specifying supported methods' do
         | 
| 499 519 | 
             
                  subject.get 'example' do
         | 
| 500 | 
            -
                     | 
| 520 | 
            +
                    'example'
         | 
| 501 521 | 
             
                  end
         | 
| 502 522 | 
             
                  subject.post 'example' do
         | 
| 503 | 
            -
                     | 
| 523 | 
            +
                    'example'
         | 
| 504 524 | 
             
                  end
         | 
| 505 525 | 
             
                  put '/example'
         | 
| 506 526 | 
             
                  expect(last_response.headers['Allow']).to eql 'OPTIONS, GET, POST, HEAD'
         | 
| @@ -508,10 +528,10 @@ describe Grape::API do | |
| 508 528 |  | 
| 509 529 | 
             
                specify '405 responses includes an Content-Type header' do
         | 
| 510 530 | 
             
                  subject.get 'example' do
         | 
| 511 | 
            -
                     | 
| 531 | 
            +
                    'example'
         | 
| 512 532 | 
             
                  end
         | 
| 513 533 | 
             
                  subject.post 'example' do
         | 
| 514 | 
            -
                     | 
| 534 | 
            +
                    'example'
         | 
| 515 535 | 
             
                  end
         | 
| 516 536 | 
             
                  put '/example'
         | 
| 517 537 | 
             
                  expect(last_response.headers['Content-Type']).to eql 'text/plain'
         | 
| @@ -520,7 +540,7 @@ describe Grape::API do | |
| 520 540 | 
             
                it 'adds an OPTIONS route that returns a 204, an Allow header and a X-Custom-Header' do
         | 
| 521 541 | 
             
                  subject.before { header 'X-Custom-Header', 'foo' }
         | 
| 522 542 | 
             
                  subject.get 'example' do
         | 
| 523 | 
            -
                     | 
| 543 | 
            +
                    'example'
         | 
| 524 544 | 
             
                  end
         | 
| 525 545 | 
             
                  options '/example'
         | 
| 526 546 | 
             
                  expect(last_response.status).to eql 204
         | 
| @@ -531,7 +551,7 @@ describe Grape::API do | |
| 531 551 |  | 
| 532 552 | 
             
                it 'allows HEAD on a GET request' do
         | 
| 533 553 | 
             
                  subject.get 'example' do
         | 
| 534 | 
            -
                     | 
| 554 | 
            +
                    'example'
         | 
| 535 555 | 
             
                  end
         | 
| 536 556 | 
             
                  head '/example'
         | 
| 537 557 | 
             
                  expect(last_response.status).to eql 200
         | 
| @@ -543,18 +563,18 @@ describe Grape::API do | |
| 543 563 | 
             
                    error! 'nothing to see here', 400
         | 
| 544 564 | 
             
                  end
         | 
| 545 565 | 
             
                  subject.get 'example' do
         | 
| 546 | 
            -
                     | 
| 566 | 
            +
                    'example'
         | 
| 547 567 | 
             
                  end
         | 
| 548 568 | 
             
                  head '/example'
         | 
| 549 569 | 
             
                  expect(last_response.status).to eql 400
         | 
| 550 570 | 
             
                end
         | 
| 551 571 | 
             
              end
         | 
| 552 572 |  | 
| 553 | 
            -
              context  | 
| 573 | 
            +
              context 'do_not_route_head!' do
         | 
| 554 574 | 
             
                before :each do
         | 
| 555 575 | 
             
                  subject.do_not_route_head!
         | 
| 556 576 | 
             
                  subject.get 'example' do
         | 
| 557 | 
            -
                     | 
| 577 | 
            +
                    'example'
         | 
| 558 578 | 
             
                  end
         | 
| 559 579 | 
             
                end
         | 
| 560 580 | 
             
                it 'options does not contain HEAD' do
         | 
| @@ -569,11 +589,11 @@ describe Grape::API do | |
| 569 589 | 
             
                end
         | 
| 570 590 | 
             
              end
         | 
| 571 591 |  | 
| 572 | 
            -
              context  | 
| 592 | 
            +
              context 'do_not_route_options!' do
         | 
| 573 593 | 
             
                before :each do
         | 
| 574 594 | 
             
                  subject.do_not_route_options!
         | 
| 575 595 | 
             
                  subject.get 'example' do
         | 
| 576 | 
            -
                     | 
| 596 | 
            +
                    'example'
         | 
| 577 597 | 
             
                  end
         | 
| 578 598 | 
             
                end
         | 
| 579 599 | 
             
                it 'options does not exist' do
         | 
| @@ -629,7 +649,7 @@ describe Grape::API do | |
| 629 649 | 
             
                    "#{@foo} #{@bar}"
         | 
| 630 650 | 
             
                  end
         | 
| 631 651 |  | 
| 632 | 
            -
                  get '/', id:  | 
| 652 | 
            +
                  get '/', id: '32'
         | 
| 633 653 | 
             
                  expect(last_response.body).to eql 'first 32:Fixnum second'
         | 
| 634 654 | 
             
                end
         | 
| 635 655 |  | 
| @@ -737,17 +757,42 @@ describe Grape::API do | |
| 737 757 |  | 
| 738 758 | 
             
              context 'format' do
         | 
| 739 759 | 
             
                before do
         | 
| 740 | 
            -
                  subject.get( | 
| 760 | 
            +
                  subject.get('/foo') { 'bar' }
         | 
| 741 761 | 
             
                end
         | 
| 742 762 |  | 
| 743 763 | 
             
                it 'sets content type for txt format' do
         | 
| 744 764 | 
             
                  get '/foo'
         | 
| 745 | 
            -
                  expect(last_response.headers['Content-Type']).to  | 
| 765 | 
            +
                  expect(last_response.headers['Content-Type']).to eq('text/plain')
         | 
| 766 | 
            +
                end
         | 
| 767 | 
            +
             | 
| 768 | 
            +
                it 'sets content type for xml' do
         | 
| 769 | 
            +
                  get '/foo.xml'
         | 
| 770 | 
            +
                  expect(last_response.headers['Content-Type']).to eq('application/xml')
         | 
| 746 771 | 
             
                end
         | 
| 747 772 |  | 
| 748 773 | 
             
                it 'sets content type for json' do
         | 
| 749 774 | 
             
                  get '/foo.json'
         | 
| 750 | 
            -
                  expect(last_response.headers['Content-Type']).to  | 
| 775 | 
            +
                  expect(last_response.headers['Content-Type']).to eq('application/json')
         | 
| 776 | 
            +
                end
         | 
| 777 | 
            +
             | 
| 778 | 
            +
                it 'sets content type for serializable hash format' do
         | 
| 779 | 
            +
                  get '/foo.serializable_hash'
         | 
| 780 | 
            +
                  expect(last_response.headers['Content-Type']).to eq('application/json')
         | 
| 781 | 
            +
                end
         | 
| 782 | 
            +
             | 
| 783 | 
            +
                it 'sets content type for binary format' do
         | 
| 784 | 
            +
                  get '/foo.binary'
         | 
| 785 | 
            +
                  expect(last_response.headers['Content-Type']).to eq('application/octet-stream')
         | 
| 786 | 
            +
                end
         | 
| 787 | 
            +
             | 
| 788 | 
            +
                it 'returns raw data when content type binary' do
         | 
| 789 | 
            +
                  image_filename = 'grape.png'
         | 
| 790 | 
            +
                  file = File.open(image_filename, 'rb') { |io| io.read }
         | 
| 791 | 
            +
                  subject.format :binary
         | 
| 792 | 
            +
                  subject.get('/binary_file') { File.binread(image_filename) }
         | 
| 793 | 
            +
                  get '/binary_file'
         | 
| 794 | 
            +
                  expect(last_response.headers['Content-Type']).to eq('application/octet-stream')
         | 
| 795 | 
            +
                  expect(last_response.body).to eq(file)
         | 
| 751 796 | 
             
                end
         | 
| 752 797 |  | 
| 753 798 | 
             
                it 'sets content type for error' do
         | 
| @@ -756,24 +801,24 @@ describe Grape::API do | |
| 756 801 | 
             
                  expect(last_response.headers['Content-Type']).to eql 'text/plain'
         | 
| 757 802 | 
             
                end
         | 
| 758 803 |  | 
| 759 | 
            -
                it 'sets content type for error' do
         | 
| 804 | 
            +
                it 'sets content type for json error' do
         | 
| 760 805 | 
             
                  subject.format :json
         | 
| 761 806 | 
             
                  subject.get('/error') { error!('error in json', 500) }
         | 
| 762 | 
            -
                  get '/error | 
| 807 | 
            +
                  get '/error'
         | 
| 763 808 | 
             
                  expect(last_response.headers['Content-Type']).to eql 'application/json'
         | 
| 764 809 | 
             
                end
         | 
| 765 810 |  | 
| 766 | 
            -
                it 'sets content type for xml' do
         | 
| 811 | 
            +
                it 'sets content type for xml error' do
         | 
| 767 812 | 
             
                  subject.format :xml
         | 
| 768 813 | 
             
                  subject.get('/error') { error!('error in xml', 500) }
         | 
| 769 | 
            -
                  get '/error | 
| 814 | 
            +
                  get '/error'
         | 
| 770 815 | 
             
                  expect(last_response.headers['Content-Type']).to eql 'application/xml'
         | 
| 771 816 | 
             
                end
         | 
| 772 817 |  | 
| 773 818 | 
             
                context 'with a custom content_type' do
         | 
| 774 819 | 
             
                  before do
         | 
| 775 820 | 
             
                    subject.content_type :custom, 'application/custom'
         | 
| 776 | 
            -
                    subject.formatter :custom,  | 
| 821 | 
            +
                    subject.formatter :custom, ->(object, env) { 'custom' }
         | 
| 777 822 |  | 
| 778 823 | 
             
                    subject.get('/custom') { 'bar' }
         | 
| 779 824 | 
             
                    subject.get('/error') { error!('error in custom', 500) }
         | 
| @@ -792,21 +837,21 @@ describe Grape::API do | |
| 792 837 |  | 
| 793 838 | 
             
                context 'env["api.format"]' do
         | 
| 794 839 | 
             
                  before do
         | 
| 795 | 
            -
                    subject.post  | 
| 840 | 
            +
                    subject.post 'attachment' do
         | 
| 796 841 | 
             
                      filename = params[:file][:filename]
         | 
| 797 842 | 
             
                      content_type MIME::Types.type_for(filename)[0].to_s
         | 
| 798 843 | 
             
                      env['api.format'] = :binary # there's no formatter for :binary, data will be returned "as is"
         | 
| 799 | 
            -
                      header  | 
| 844 | 
            +
                      header 'Content-Disposition', "attachment; filename*=UTF-8''#{URI.escape(filename)}"
         | 
| 800 845 | 
             
                      params[:file][:tempfile].read
         | 
| 801 846 | 
             
                    end
         | 
| 802 847 | 
             
                  end
         | 
| 803 848 |  | 
| 804 849 | 
             
                  ['/attachment.png', 'attachment'].each do |url|
         | 
| 805 850 | 
             
                    it "uploads and downloads a PNG file via #{url}" do
         | 
| 806 | 
            -
                      image_filename =  | 
| 851 | 
            +
                      image_filename = 'grape.png'
         | 
| 807 852 | 
             
                      post url, file: Rack::Test::UploadedFile.new(image_filename, 'image/png', true)
         | 
| 808 853 | 
             
                      expect(last_response.status).to eq(201)
         | 
| 809 | 
            -
                      expect(last_response.headers['Content-Type']).to eq( | 
| 854 | 
            +
                      expect(last_response.headers['Content-Type']).to eq('image/png')
         | 
| 810 855 | 
             
                      expect(last_response.headers['Content-Disposition']).to eq("attachment; filename*=UTF-8''grape.png")
         | 
| 811 856 | 
             
                      File.open(image_filename, 'rb') do |io|
         | 
| 812 857 | 
             
                        expect(last_response.body).to eq io.read
         | 
| @@ -814,11 +859,11 @@ describe Grape::API do | |
| 814 859 | 
             
                    end
         | 
| 815 860 | 
             
                  end
         | 
| 816 861 |  | 
| 817 | 
            -
                  it  | 
| 862 | 
            +
                  it 'uploads and downloads a Ruby file' do
         | 
| 818 863 | 
             
                    filename = __FILE__
         | 
| 819 | 
            -
                    post  | 
| 864 | 
            +
                    post '/attachment.rb', file: Rack::Test::UploadedFile.new(filename, 'application/x-ruby', true)
         | 
| 820 865 | 
             
                    expect(last_response.status).to eq(201)
         | 
| 821 | 
            -
                    expect(last_response.headers['Content-Type']).to eq( | 
| 866 | 
            +
                    expect(last_response.headers['Content-Type']).to eq('application/x-ruby')
         | 
| 822 867 | 
             
                    expect(last_response.headers['Content-Disposition']).to eq("attachment; filename*=UTF-8''api_spec.rb")
         | 
| 823 868 | 
             
                    File.open(filename, 'rb') do |io|
         | 
| 824 869 | 
             
                      expect(last_response.body).to eq io.read
         | 
| @@ -847,20 +892,14 @@ describe Grape::API do | |
| 847 892 |  | 
| 848 893 | 
             
                describe '.middleware' do
         | 
| 849 894 | 
             
                  it 'includes middleware arguments from settings' do
         | 
| 850 | 
            -
                     | 
| 851 | 
            -
                    allow(settings).to receive(:stack).and_return([{ middleware: [[ApiSpec::PhonyMiddleware, 'abc', 123]] }])
         | 
| 852 | 
            -
                    allow(subject).to receive(:settings).and_return(settings)
         | 
| 895 | 
            +
                    subject.use ApiSpec::PhonyMiddleware, 'abc', 123
         | 
| 853 896 | 
             
                    expect(subject.middleware).to eql [[ApiSpec::PhonyMiddleware, 'abc', 123]]
         | 
| 854 897 | 
             
                  end
         | 
| 855 898 |  | 
| 856 899 | 
             
                  it 'includes all middleware from stacked settings' do
         | 
| 857 | 
            -
                     | 
| 858 | 
            -
                     | 
| 859 | 
            -
             | 
| 860 | 
            -
                      { middleware: [[ApiSpec::PhonyMiddleware, 'foo']] }
         | 
| 861 | 
            -
                    ]
         | 
| 862 | 
            -
             | 
| 863 | 
            -
                    allow(subject).to receive(:settings).and_return(settings)
         | 
| 900 | 
            +
                    subject.use ApiSpec::PhonyMiddleware, 123
         | 
| 901 | 
            +
                    subject.use ApiSpec::PhonyMiddleware, 'abc'
         | 
| 902 | 
            +
                    subject.use ApiSpec::PhonyMiddleware, 'foo'
         | 
| 864 903 |  | 
| 865 904 | 
             
                    expect(subject.middleware).to eql [
         | 
| 866 905 | 
             
                      [ApiSpec::PhonyMiddleware, 123],
         | 
| @@ -899,13 +938,13 @@ describe Grape::API do | |
| 899 938 | 
             
                  end
         | 
| 900 939 |  | 
| 901 940 | 
             
                  it 'adds a block if one is given' do
         | 
| 902 | 
            -
                    block =  | 
| 941 | 
            +
                    block = -> {}
         | 
| 903 942 | 
             
                    subject.use ApiSpec::PhonyMiddleware, &block
         | 
| 904 943 | 
             
                    expect(subject.middleware).to eql [[ApiSpec::PhonyMiddleware, block]]
         | 
| 905 944 | 
             
                  end
         | 
| 906 945 |  | 
| 907 946 | 
             
                  it 'uses a block if one is given' do
         | 
| 908 | 
            -
                    block =  | 
| 947 | 
            +
                    block = -> {}
         | 
| 909 948 | 
             
                    subject.use ApiSpec::PhonyMiddleware, &block
         | 
| 910 949 | 
             
                    subject.get '/' do
         | 
| 911 950 | 
             
                      env['phony.block'].inspect
         | 
| @@ -916,7 +955,7 @@ describe Grape::API do | |
| 916 955 | 
             
                  end
         | 
| 917 956 |  | 
| 918 957 | 
             
                  it 'does not destroy the middleware settings on multiple runs' do
         | 
| 919 | 
            -
                    block =  | 
| 958 | 
            +
                    block = -> {}
         | 
| 920 959 | 
             
                    subject.use ApiSpec::PhonyMiddleware, &block
         | 
| 921 960 | 
             
                    subject.get '/' do
         | 
| 922 961 | 
             
                      env['phony.block'].inspect
         | 
| @@ -931,15 +970,15 @@ describe Grape::API do | |
| 931 970 | 
             
                  it 'mounts behind error middleware' do
         | 
| 932 971 | 
             
                    m = Class.new(Grape::Middleware::Base) do
         | 
| 933 972 | 
             
                      def before
         | 
| 934 | 
            -
                        throw :error, message:  | 
| 973 | 
            +
                        throw :error, message: 'Caught in the Net', status: 400
         | 
| 935 974 | 
             
                      end
         | 
| 936 975 | 
             
                    end
         | 
| 937 976 | 
             
                    subject.use m
         | 
| 938 | 
            -
                    subject.get  | 
| 977 | 
            +
                    subject.get '/' do
         | 
| 939 978 | 
             
                    end
         | 
| 940 | 
            -
                    get  | 
| 979 | 
            +
                    get '/'
         | 
| 941 980 | 
             
                    expect(last_response.status).to eq(400)
         | 
| 942 | 
            -
                    expect(last_response.body).to eq( | 
| 981 | 
            +
                    expect(last_response.body).to eq('Caught in the Net')
         | 
| 943 982 | 
             
                  end
         | 
| 944 983 | 
             
                end
         | 
| 945 984 | 
             
              end
         | 
| @@ -948,7 +987,7 @@ describe Grape::API do | |
| 948 987 | 
             
                  subject.http_basic do |u, p|
         | 
| 949 988 | 
             
                    u == 'allow'
         | 
| 950 989 | 
             
                  end
         | 
| 951 | 
            -
                  subject.get(:hello) {  | 
| 990 | 
            +
                  subject.get(:hello) { 'Hello, world.' }
         | 
| 952 991 | 
             
                  get '/hello'
         | 
| 953 992 | 
             
                  expect(last_response.status).to eql 401
         | 
| 954 993 | 
             
                  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
         | 
| @@ -956,13 +995,13 @@ describe Grape::API do | |
| 956 995 | 
             
                end
         | 
| 957 996 |  | 
| 958 997 | 
             
                it 'is scopable' do
         | 
| 959 | 
            -
                  subject.get(:hello) {  | 
| 998 | 
            +
                  subject.get(:hello) { 'Hello, world.' }
         | 
| 960 999 | 
             
                  subject.namespace :admin do
         | 
| 961 1000 | 
             
                    http_basic do |u, p|
         | 
| 962 1001 | 
             
                      u == 'allow'
         | 
| 963 1002 | 
             
                    end
         | 
| 964 1003 |  | 
| 965 | 
            -
                    get(:hello) {  | 
| 1004 | 
            +
                    get(:hello) { 'Hello, world.' }
         | 
| 966 1005 | 
             
                  end
         | 
| 967 1006 |  | 
| 968 1007 | 
             
                  get '/hello'
         | 
| @@ -976,7 +1015,7 @@ describe Grape::API do | |
| 976 1015 | 
             
                    u == 'allow'
         | 
| 977 1016 | 
             
                  end
         | 
| 978 1017 |  | 
| 979 | 
            -
                  subject.get(:hello) {  | 
| 1018 | 
            +
                  subject.get(:hello) { 'Hello, world.' }
         | 
| 980 1019 | 
             
                  get '/hello'
         | 
| 981 1020 | 
             
                  expect(last_response.status).to eql 401
         | 
| 982 1021 | 
             
                  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
         | 
| @@ -992,7 +1031,7 @@ describe Grape::API do | |
| 992 1031 | 
             
                    u == 'allow'
         | 
| 993 1032 | 
             
                  end
         | 
| 994 1033 |  | 
| 995 | 
            -
                  subject.get(:hello) {  | 
| 1034 | 
            +
                  subject.get(:hello) { 'Hello, world.' }
         | 
| 996 1035 | 
             
                  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
         | 
| 997 1036 | 
             
                  expect(basic_auth_context).to be_an_instance_of(Grape::Endpoint)
         | 
| 998 1037 | 
             
                end
         | 
| @@ -1008,7 +1047,7 @@ describe Grape::API do | |
| 1008 1047 | 
             
                    authorize(u, p)
         | 
| 1009 1048 | 
             
                  end
         | 
| 1010 1049 |  | 
| 1011 | 
            -
                  subject.get(:hello) {  | 
| 1050 | 
            +
                  subject.get(:hello) { 'Hello, world.' }
         | 
| 1012 1051 | 
             
                  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
         | 
| 1013 1052 | 
             
                  expect(last_response.status).to eql 200
         | 
| 1014 1053 | 
             
                  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('disallow', 'whatever')
         | 
| @@ -1017,7 +1056,7 @@ describe Grape::API do | |
| 1017 1056 |  | 
| 1018 1057 | 
             
                it 'can set instance variables accessible to routes' do
         | 
| 1019 1058 | 
             
                  subject.http_basic do |u, p|
         | 
| 1020 | 
            -
                    @hello =  | 
| 1059 | 
            +
                    @hello = 'Hello, world.'
         | 
| 1021 1060 |  | 
| 1022 1061 | 
             
                    u == 'allow'
         | 
| 1023 1062 | 
             
                  end
         | 
| @@ -1025,11 +1064,20 @@ describe Grape::API do | |
| 1025 1064 | 
             
                  subject.get(:hello) { @hello }
         | 
| 1026 1065 | 
             
                  get '/hello', {}, 'HTTP_AUTHORIZATION' => encode_basic_auth('allow', 'whatever')
         | 
| 1027 1066 | 
             
                  expect(last_response.status).to eql 200
         | 
| 1028 | 
            -
                  expect(last_response.body).to eql  | 
| 1067 | 
            +
                  expect(last_response.body).to eql 'Hello, world.'
         | 
| 1029 1068 | 
             
                end
         | 
| 1030 1069 | 
             
              end
         | 
| 1031 1070 |  | 
| 1032 1071 | 
             
              describe '.logger' do
         | 
| 1072 | 
            +
                subject do
         | 
| 1073 | 
            +
                  Class.new(Grape::API) do
         | 
| 1074 | 
            +
                    def self.io
         | 
| 1075 | 
            +
                      @io ||= StringIO.new
         | 
| 1076 | 
            +
                    end
         | 
| 1077 | 
            +
                    logger ::Logger.new(io)
         | 
| 1078 | 
            +
                  end
         | 
| 1079 | 
            +
                end
         | 
| 1080 | 
            +
             | 
| 1033 1081 | 
             
                it 'returns an instance of Logger class by default' do
         | 
| 1034 1082 | 
             
                  expect(subject.logger.class).to eql Logger
         | 
| 1035 1083 | 
             
                end
         | 
| @@ -1038,14 +1086,18 @@ describe Grape::API do | |
| 1038 1086 | 
             
                  mylogger = Class.new
         | 
| 1039 1087 | 
             
                  subject.logger mylogger
         | 
| 1040 1088 | 
             
                  expect(mylogger).to receive(:info).exactly(1).times
         | 
| 1041 | 
            -
                  subject.logger.info  | 
| 1089 | 
            +
                  subject.logger.info 'this will be logged'
         | 
| 1042 1090 | 
             
                end
         | 
| 1043 1091 |  | 
| 1044 | 
            -
                it  | 
| 1092 | 
            +
                it 'defaults to a standard logger log format' do
         | 
| 1045 1093 | 
             
                  t = Time.at(100)
         | 
| 1046 1094 | 
             
                  allow(Time).to receive(:now).and_return(t)
         | 
| 1047 | 
            -
                   | 
| 1048 | 
            -
             | 
| 1095 | 
            +
                  if ActiveSupport::VERSION::MAJOR >= 4
         | 
| 1096 | 
            +
                    expect(subject.io).to receive(:write).with("I, [#{Logger::Formatter.new.send(:format_datetime, t)}\##{Process.pid}]  INFO -- : this will be logged\n")
         | 
| 1097 | 
            +
                  else
         | 
| 1098 | 
            +
                    expect(subject.io).to receive(:write).with("this will be logged\n")
         | 
| 1099 | 
            +
                  end
         | 
| 1100 | 
            +
                  subject.logger.info 'this will be logged'
         | 
| 1049 1101 | 
             
                end
         | 
| 1050 1102 | 
             
              end
         | 
| 1051 1103 |  | 
| @@ -1053,7 +1105,7 @@ describe Grape::API do | |
| 1053 1105 | 
             
                it 'is accessible from the endpoint' do
         | 
| 1054 1106 | 
             
                  subject.helpers do
         | 
| 1055 1107 | 
             
                    def hello
         | 
| 1056 | 
            -
                       | 
| 1108 | 
            +
                      'Hello, world.'
         | 
| 1057 1109 | 
             
                    end
         | 
| 1058 1110 | 
             
                  end
         | 
| 1059 1111 |  | 
| @@ -1117,7 +1169,7 @@ describe Grape::API do | |
| 1117 1169 | 
             
                it 'allows for modules' do
         | 
| 1118 1170 | 
             
                  mod = Module.new do
         | 
| 1119 1171 | 
             
                    def hello
         | 
| 1120 | 
            -
                       | 
| 1172 | 
            +
                      'Hello, world.'
         | 
| 1121 1173 | 
             
                    end
         | 
| 1122 1174 | 
             
                  end
         | 
| 1123 1175 | 
             
                  subject.helpers mod
         | 
| @@ -1184,7 +1236,7 @@ describe Grape::API do | |
| 1184 1236 | 
             
              describe '.rescue_from' do
         | 
| 1185 1237 | 
             
                it 'does not rescue errors when rescue_from is not set' do
         | 
| 1186 1238 | 
             
                  subject.get '/exception' do
         | 
| 1187 | 
            -
                     | 
| 1239 | 
            +
                    fail 'rain!'
         | 
| 1188 1240 | 
             
                  end
         | 
| 1189 1241 | 
             
                  expect { get '/exception' }.to raise_error
         | 
| 1190 1242 | 
             
                end
         | 
| @@ -1192,16 +1244,29 @@ describe Grape::API do | |
| 1192 1244 | 
             
                it 'rescues all errors if rescue_from :all is called' do
         | 
| 1193 1245 | 
             
                  subject.rescue_from :all
         | 
| 1194 1246 | 
             
                  subject.get '/exception' do
         | 
| 1195 | 
            -
                     | 
| 1247 | 
            +
                    fail 'rain!'
         | 
| 1248 | 
            +
                  end
         | 
| 1249 | 
            +
                  get '/exception'
         | 
| 1250 | 
            +
                  expect(last_response.status).to eql 500
         | 
| 1251 | 
            +
                  expect(last_response.body).to eq 'rain!'
         | 
| 1252 | 
            +
                end
         | 
| 1253 | 
            +
             | 
| 1254 | 
            +
                it 'rescues all errors with a json formatter' do
         | 
| 1255 | 
            +
                  subject.format :json
         | 
| 1256 | 
            +
                  subject.default_format :json
         | 
| 1257 | 
            +
                  subject.rescue_from :all
         | 
| 1258 | 
            +
                  subject.get '/exception' do
         | 
| 1259 | 
            +
                    fail 'rain!'
         | 
| 1196 1260 | 
             
                  end
         | 
| 1197 1261 | 
             
                  get '/exception'
         | 
| 1198 1262 | 
             
                  expect(last_response.status).to eql 500
         | 
| 1263 | 
            +
                  expect(last_response.body).to eq({ error: 'rain!' }.to_json)
         | 
| 1199 1264 | 
             
                end
         | 
| 1200 1265 |  | 
| 1201 1266 | 
             
                it 'rescues only certain errors if rescue_from is called with specific errors' do
         | 
| 1202 1267 | 
             
                  subject.rescue_from ArgumentError
         | 
| 1203 | 
            -
                  subject.get('/rescued') {  | 
| 1204 | 
            -
                  subject.get('/unrescued') {  | 
| 1268 | 
            +
                  subject.get('/rescued') { fail ArgumentError }
         | 
| 1269 | 
            +
                  subject.get('/unrescued') { fail 'beefcake' }
         | 
| 1205 1270 |  | 
| 1206 1271 | 
             
                  get '/rescued'
         | 
| 1207 1272 | 
             
                  expect(last_response.status).to eql 500
         | 
| @@ -1215,7 +1280,7 @@ describe Grape::API do | |
| 1215 1280 | 
             
                  end
         | 
| 1216 1281 |  | 
| 1217 1282 | 
             
                  it 'does not re-raise exceptions of type Grape::Exceptions::Base' do
         | 
| 1218 | 
            -
                    subject.get('/custom_exception') {  | 
| 1283 | 
            +
                    subject.get('/custom_exception') { fail CustomError }
         | 
| 1219 1284 |  | 
| 1220 1285 | 
             
                    expect { get '/custom_exception' }.not_to raise_error
         | 
| 1221 1286 | 
             
                  end
         | 
| @@ -1225,7 +1290,7 @@ describe Grape::API do | |
| 1225 1290 | 
             
                      rack_response('New Error', e.status)
         | 
| 1226 1291 | 
             
                    end
         | 
| 1227 1292 | 
             
                    subject.get '/custom_error' do
         | 
| 1228 | 
            -
                       | 
| 1293 | 
            +
                      fail CustomError, status: 400, message: 'Custom Error'
         | 
| 1229 1294 | 
             
                    end
         | 
| 1230 1295 |  | 
| 1231 1296 | 
             
                    get '/custom_error'
         | 
| @@ -1236,7 +1301,7 @@ describe Grape::API do | |
| 1236 1301 |  | 
| 1237 1302 | 
             
                it 'can rescue exceptions raised in the formatter' do
         | 
| 1238 1303 | 
             
                  formatter = double(:formatter)
         | 
| 1239 | 
            -
                  allow(formatter).to receive(:call) {  | 
| 1304 | 
            +
                  allow(formatter).to receive(:call) { fail StandardError }
         | 
| 1240 1305 | 
             
                  allow(Grape::Formatter::Base).to receive(:formatter_for) { formatter }
         | 
| 1241 1306 |  | 
| 1242 1307 | 
             
                  subject.rescue_from :all do |e|
         | 
| @@ -1256,7 +1321,7 @@ describe Grape::API do | |
| 1256 1321 | 
             
                    rack_response("rescued from #{e.message}", 202)
         | 
| 1257 1322 | 
             
                  end
         | 
| 1258 1323 | 
             
                  subject.get '/exception' do
         | 
| 1259 | 
            -
                     | 
| 1324 | 
            +
                    fail 'rain!'
         | 
| 1260 1325 | 
             
                  end
         | 
| 1261 1326 | 
             
                  get '/exception'
         | 
| 1262 1327 | 
             
                  expect(last_response.status).to eql 202
         | 
| @@ -1275,7 +1340,7 @@ describe Grape::API do | |
| 1275 1340 | 
             
                      rack_response("rescued from #{e.class.name}", 500)
         | 
| 1276 1341 | 
             
                    end
         | 
| 1277 1342 | 
             
                    subject.get '/exception' do
         | 
| 1278 | 
            -
                       | 
| 1343 | 
            +
                      fail ConnectionError
         | 
| 1279 1344 | 
             
                    end
         | 
| 1280 1345 | 
             
                    get '/exception'
         | 
| 1281 1346 | 
             
                    expect(last_response.status).to eql 500
         | 
| @@ -1286,7 +1351,7 @@ describe Grape::API do | |
| 1286 1351 | 
             
                      rack_response("rescued from #{e.class.name}", 500)
         | 
| 1287 1352 | 
             
                    end
         | 
| 1288 1353 | 
             
                    subject.get '/exception' do
         | 
| 1289 | 
            -
                       | 
| 1354 | 
            +
                      fail ConnectionError
         | 
| 1290 1355 | 
             
                    end
         | 
| 1291 1356 | 
             
                    get '/exception'
         | 
| 1292 1357 | 
             
                    expect(last_response.status).to eql 500
         | 
| @@ -1297,7 +1362,7 @@ describe Grape::API do | |
| 1297 1362 | 
             
                      rack_response("rescued from #{e.class.name}", 500)
         | 
| 1298 1363 | 
             
                    end
         | 
| 1299 1364 | 
             
                    subject.get '/exception' do
         | 
| 1300 | 
            -
                       | 
| 1365 | 
            +
                      fail ConnectionError
         | 
| 1301 1366 | 
             
                    end
         | 
| 1302 1367 | 
             
                    get '/exception'
         | 
| 1303 1368 | 
             
                    expect(last_response.status).to eql 500
         | 
| @@ -1311,10 +1376,10 @@ describe Grape::API do | |
| 1311 1376 | 
             
                      rack_response("rescued from #{e.class.name}", 500)
         | 
| 1312 1377 | 
             
                    end
         | 
| 1313 1378 | 
             
                    subject.get '/connection' do
         | 
| 1314 | 
            -
                       | 
| 1379 | 
            +
                      fail ConnectionError
         | 
| 1315 1380 | 
             
                    end
         | 
| 1316 1381 | 
             
                    subject.get '/database' do
         | 
| 1317 | 
            -
                       | 
| 1382 | 
            +
                      fail DatabaseError
         | 
| 1318 1383 | 
             
                    end
         | 
| 1319 1384 | 
             
                    get '/connection'
         | 
| 1320 1385 | 
             
                    expect(last_response.status).to eql 500
         | 
| @@ -1328,7 +1393,7 @@ describe Grape::API do | |
| 1328 1393 | 
             
                      rack_response("rescued from #{e.class.name}", 500)
         | 
| 1329 1394 | 
             
                    end
         | 
| 1330 1395 | 
             
                    subject.get '/uncaught' do
         | 
| 1331 | 
            -
                       | 
| 1396 | 
            +
                      fail CommunicationError
         | 
| 1332 1397 | 
             
                    end
         | 
| 1333 1398 | 
             
                    expect { get '/uncaught' }.to raise_error(CommunicationError)
         | 
| 1334 1399 | 
             
                  end
         | 
| @@ -1337,21 +1402,21 @@ describe Grape::API do | |
| 1337 1402 |  | 
| 1338 1403 | 
             
              describe '.rescue_from klass, lambda' do
         | 
| 1339 1404 | 
             
                it 'rescues an error with the lambda' do
         | 
| 1340 | 
            -
                  subject.rescue_from ArgumentError,  | 
| 1341 | 
            -
                    rack_response( | 
| 1405 | 
            +
                  subject.rescue_from ArgumentError, -> {
         | 
| 1406 | 
            +
                    rack_response('rescued with a lambda', 400)
         | 
| 1342 1407 | 
             
                  }
         | 
| 1343 | 
            -
                  subject.get('/rescue_lambda') {  | 
| 1408 | 
            +
                  subject.get('/rescue_lambda') { fail ArgumentError }
         | 
| 1344 1409 |  | 
| 1345 1410 | 
             
                  get '/rescue_lambda'
         | 
| 1346 1411 | 
             
                  expect(last_response.status).to eq(400)
         | 
| 1347 | 
            -
                  expect(last_response.body).to eq( | 
| 1412 | 
            +
                  expect(last_response.body).to eq('rescued with a lambda')
         | 
| 1348 1413 | 
             
                end
         | 
| 1349 1414 |  | 
| 1350 1415 | 
             
                it 'can execute the lambda with an argument' do
         | 
| 1351 | 
            -
                  subject.rescue_from ArgumentError,  | 
| 1416 | 
            +
                  subject.rescue_from ArgumentError, ->(e) {
         | 
| 1352 1417 | 
             
                    rack_response(e.message, 400)
         | 
| 1353 1418 | 
             
                  }
         | 
| 1354 | 
            -
                  subject.get('/rescue_lambda') {  | 
| 1419 | 
            +
                  subject.get('/rescue_lambda') { fail ArgumentError, 'lambda takes an argument' }
         | 
| 1355 1420 |  | 
| 1356 1421 | 
             
                  get '/rescue_lambda'
         | 
| 1357 1422 | 
             
                  expect(last_response.status).to eq(400)
         | 
| @@ -1366,7 +1431,7 @@ describe Grape::API do | |
| 1366 1431 | 
             
                  end
         | 
| 1367 1432 |  | 
| 1368 1433 | 
             
                  subject.rescue_from ArgumentError, with: rescue_arg_error
         | 
| 1369 | 
            -
                  subject.get('/rescue_method') {  | 
| 1434 | 
            +
                  subject.get('/rescue_method') { fail ArgumentError }
         | 
| 1370 1435 |  | 
| 1371 1436 | 
             
                  get '/rescue_method'
         | 
| 1372 1437 | 
             
                  expect(last_response.status).to eq(400)
         | 
| @@ -1387,13 +1452,13 @@ describe Grape::API do | |
| 1387 1452 | 
             
                    rack_response("rescued from #{e.class.name}", 500)
         | 
| 1388 1453 | 
             
                  end
         | 
| 1389 1454 | 
             
                  subject.get '/caught_child' do
         | 
| 1390 | 
            -
                     | 
| 1455 | 
            +
                    fail APIErrors::ChildError
         | 
| 1391 1456 | 
             
                  end
         | 
| 1392 1457 | 
             
                  subject.get '/caught_parent' do
         | 
| 1393 | 
            -
                     | 
| 1458 | 
            +
                    fail APIErrors::ParentError
         | 
| 1394 1459 | 
             
                  end
         | 
| 1395 1460 | 
             
                  subject.get '/uncaught_parent' do
         | 
| 1396 | 
            -
                     | 
| 1461 | 
            +
                    fail StandardError
         | 
| 1397 1462 | 
             
                  end
         | 
| 1398 1463 |  | 
| 1399 1464 | 
             
                  get '/caught_child'
         | 
| @@ -1408,7 +1473,7 @@ describe Grape::API do | |
| 1408 1473 | 
             
                    rack_response("rescued from #{e.class.name}", 500)
         | 
| 1409 1474 | 
             
                  end
         | 
| 1410 1475 | 
             
                  subject.get '/caught_child' do
         | 
| 1411 | 
            -
                     | 
| 1476 | 
            +
                    fail APIErrors::ChildError
         | 
| 1412 1477 | 
             
                  end
         | 
| 1413 1478 |  | 
| 1414 1479 | 
             
                  get '/caught_child'
         | 
| @@ -1420,7 +1485,7 @@ describe Grape::API do | |
| 1420 1485 | 
             
                    rack_response("rescued from #{e.class.name}", 500)
         | 
| 1421 1486 | 
             
                  end
         | 
| 1422 1487 | 
             
                  subject.get '/uncaught' do
         | 
| 1423 | 
            -
                     | 
| 1488 | 
            +
                    fail APIErrors::ChildError
         | 
| 1424 1489 | 
             
                  end
         | 
| 1425 1490 | 
             
                  expect { get '/uncaught' }.to raise_error(APIErrors::ChildError)
         | 
| 1426 1491 | 
             
                end
         | 
| @@ -1431,17 +1496,17 @@ describe Grape::API do | |
| 1431 1496 | 
             
                  subject.rescue_from :all
         | 
| 1432 1497 | 
             
                  subject.format :txt
         | 
| 1433 1498 | 
             
                  subject.get '/exception' do
         | 
| 1434 | 
            -
                     | 
| 1499 | 
            +
                    fail 'rain!'
         | 
| 1435 1500 | 
             
                  end
         | 
| 1436 1501 | 
             
                  get '/exception'
         | 
| 1437 | 
            -
                  expect(last_response.body).to eql  | 
| 1502 | 
            +
                  expect(last_response.body).to eql 'rain!'
         | 
| 1438 1503 | 
             
                end
         | 
| 1439 1504 |  | 
| 1440 1505 | 
             
                it 'rescues all errors and return :txt with backtrace' do
         | 
| 1441 1506 | 
             
                  subject.rescue_from :all, backtrace: true
         | 
| 1442 1507 | 
             
                  subject.format :txt
         | 
| 1443 1508 | 
             
                  subject.get '/exception' do
         | 
| 1444 | 
            -
                     | 
| 1509 | 
            +
                    fail 'rain!'
         | 
| 1445 1510 | 
             
                  end
         | 
| 1446 1511 | 
             
                  get '/exception'
         | 
| 1447 1512 | 
             
                  expect(last_response.body.start_with?("rain!\r\n")).to be true
         | 
| @@ -1449,22 +1514,22 @@ describe Grape::API do | |
| 1449 1514 |  | 
| 1450 1515 | 
             
                it 'rescues all errors with a default formatter' do
         | 
| 1451 1516 | 
             
                  subject.default_format :foo
         | 
| 1452 | 
            -
                  subject.content_type :foo,  | 
| 1517 | 
            +
                  subject.content_type :foo, 'text/foo'
         | 
| 1453 1518 | 
             
                  subject.rescue_from :all
         | 
| 1454 1519 | 
             
                  subject.get '/exception' do
         | 
| 1455 | 
            -
                     | 
| 1520 | 
            +
                    fail 'rain!'
         | 
| 1456 1521 | 
             
                  end
         | 
| 1457 1522 | 
             
                  get '/exception.foo'
         | 
| 1458 | 
            -
                  expect(last_response.body).to start_with  | 
| 1523 | 
            +
                  expect(last_response.body).to start_with 'rain!'
         | 
| 1459 1524 | 
             
                end
         | 
| 1460 1525 |  | 
| 1461 1526 | 
             
                it 'defaults the error formatter to format' do
         | 
| 1462 1527 | 
             
                  subject.format :json
         | 
| 1463 1528 | 
             
                  subject.rescue_from :all
         | 
| 1464 | 
            -
                  subject.content_type :json,  | 
| 1465 | 
            -
                  subject.content_type :foo,  | 
| 1529 | 
            +
                  subject.content_type :json, 'application/json'
         | 
| 1530 | 
            +
                  subject.content_type :foo, 'text/foo'
         | 
| 1466 1531 | 
             
                  subject.get '/exception' do
         | 
| 1467 | 
            -
                     | 
| 1532 | 
            +
                    fail 'rain!'
         | 
| 1468 1533 | 
             
                  end
         | 
| 1469 1534 | 
             
                  get '/exception.json'
         | 
| 1470 1535 | 
             
                  expect(last_response.body).to eq('{"error":"rain!"}')
         | 
| @@ -1484,10 +1549,10 @@ describe Grape::API do | |
| 1484 1549 | 
             
                    subject.rescue_from :all, backtrace: true
         | 
| 1485 1550 | 
             
                    subject.error_formatter :txt, CustomErrorFormatter
         | 
| 1486 1551 | 
             
                    subject.get '/exception' do
         | 
| 1487 | 
            -
                       | 
| 1552 | 
            +
                      fail 'rain!'
         | 
| 1488 1553 | 
             
                    end
         | 
| 1489 1554 | 
             
                    get '/exception'
         | 
| 1490 | 
            -
                    expect(last_response.body).to eq( | 
| 1555 | 
            +
                    expect(last_response.body).to eq('message: rain! @backtrace')
         | 
| 1491 1556 | 
             
                  end
         | 
| 1492 1557 | 
             
                end
         | 
| 1493 1558 |  | 
| @@ -1504,7 +1569,7 @@ describe Grape::API do | |
| 1504 1569 | 
             
                    it 'returns a custom error format' do
         | 
| 1505 1570 | 
             
                      subject.rescue_from :all, backtrace: true
         | 
| 1506 1571 | 
             
                      subject.error_formatter :txt, with: CustomErrorFormatter
         | 
| 1507 | 
            -
                      subject.get('/exception') {  | 
| 1572 | 
            +
                      subject.get('/exception') { fail 'rain!' }
         | 
| 1508 1573 |  | 
| 1509 1574 | 
             
                      get '/exception'
         | 
| 1510 1575 | 
             
                      expect(last_response.body).to eq('message: rain! @backtrace')
         | 
| @@ -1516,7 +1581,7 @@ describe Grape::API do | |
| 1516 1581 | 
             
                  subject.rescue_from :all
         | 
| 1517 1582 | 
             
                  subject.format :json
         | 
| 1518 1583 | 
             
                  subject.get '/exception' do
         | 
| 1519 | 
            -
                     | 
| 1584 | 
            +
                    fail 'rain!'
         | 
| 1520 1585 | 
             
                  end
         | 
| 1521 1586 | 
             
                  get '/exception'
         | 
| 1522 1587 | 
             
                  expect(last_response.body).to eql '{"error":"rain!"}'
         | 
| @@ -1525,25 +1590,25 @@ describe Grape::API do | |
| 1525 1590 | 
             
                  subject.rescue_from :all, backtrace: true
         | 
| 1526 1591 | 
             
                  subject.format :json
         | 
| 1527 1592 | 
             
                  subject.get '/exception' do
         | 
| 1528 | 
            -
                     | 
| 1593 | 
            +
                    fail 'rain!'
         | 
| 1529 1594 | 
             
                  end
         | 
| 1530 1595 | 
             
                  get '/exception'
         | 
| 1531 1596 | 
             
                  json = MultiJson.load(last_response.body)
         | 
| 1532 | 
            -
                  expect(json[ | 
| 1533 | 
            -
                  expect(json[ | 
| 1597 | 
            +
                  expect(json['error']).to eql 'rain!'
         | 
| 1598 | 
            +
                  expect(json['backtrace'].length).to be > 0
         | 
| 1534 1599 | 
             
                end
         | 
| 1535 1600 | 
             
                it 'rescues error! and return txt' do
         | 
| 1536 1601 | 
             
                  subject.format :txt
         | 
| 1537 1602 | 
             
                  subject.get '/error' do
         | 
| 1538 | 
            -
                    error!( | 
| 1603 | 
            +
                    error!('Access Denied', 401)
         | 
| 1539 1604 | 
             
                  end
         | 
| 1540 1605 | 
             
                  get '/error'
         | 
| 1541 | 
            -
                  expect(last_response.body).to eql  | 
| 1606 | 
            +
                  expect(last_response.body).to eql 'Access Denied'
         | 
| 1542 1607 | 
             
                end
         | 
| 1543 1608 | 
             
                it 'rescues error! and return json' do
         | 
| 1544 1609 | 
             
                  subject.format :json
         | 
| 1545 1610 | 
             
                  subject.get '/error' do
         | 
| 1546 | 
            -
                    error!( | 
| 1611 | 
            +
                    error!('Access Denied', 401)
         | 
| 1547 1612 | 
             
                  end
         | 
| 1548 1613 | 
             
                  get '/error'
         | 
| 1549 1614 | 
             
                  expect(last_response.body).to eql '{"error":"Access Denied"}'
         | 
| @@ -1552,25 +1617,25 @@ describe Grape::API do | |
| 1552 1617 |  | 
| 1553 1618 | 
             
              describe '.content_type' do
         | 
| 1554 1619 | 
             
                it 'sets additional content-type' do
         | 
| 1555 | 
            -
                  subject.content_type :xls,  | 
| 1620 | 
            +
                  subject.content_type :xls, 'application/vnd.ms-excel'
         | 
| 1556 1621 | 
             
                  subject.get :excel do
         | 
| 1557 | 
            -
                     | 
| 1622 | 
            +
                    'some binary content'
         | 
| 1558 1623 | 
             
                  end
         | 
| 1559 1624 | 
             
                  get '/excel.xls'
         | 
| 1560 | 
            -
                  expect(last_response.content_type).to eq( | 
| 1625 | 
            +
                  expect(last_response.content_type).to eq('application/vnd.ms-excel')
         | 
| 1561 1626 | 
             
                end
         | 
| 1562 1627 | 
             
                it 'allows to override content-type' do
         | 
| 1563 1628 | 
             
                  subject.get :content do
         | 
| 1564 | 
            -
                    content_type  | 
| 1565 | 
            -
                     | 
| 1629 | 
            +
                    content_type 'text/javascript'
         | 
| 1630 | 
            +
                    'var x = 1;'
         | 
| 1566 1631 | 
             
                  end
         | 
| 1567 1632 | 
             
                  get '/content'
         | 
| 1568 | 
            -
                  expect(last_response.content_type).to eq( | 
| 1633 | 
            +
                  expect(last_response.content_type).to eq('text/javascript')
         | 
| 1569 1634 | 
             
                end
         | 
| 1570 1635 | 
             
                it 'removes existing content types' do
         | 
| 1571 | 
            -
                  subject.content_type :xls,  | 
| 1636 | 
            +
                  subject.content_type :xls, 'application/vnd.ms-excel'
         | 
| 1572 1637 | 
             
                  subject.get :excel do
         | 
| 1573 | 
            -
                     | 
| 1638 | 
            +
                    'some binary content'
         | 
| 1574 1639 | 
             
                  end
         | 
| 1575 1640 | 
             
                  get '/excel.json'
         | 
| 1576 1641 | 
             
                  expect(last_response.status).to eq(406)
         | 
| @@ -1581,8 +1646,8 @@ describe Grape::API do | |
| 1581 1646 | 
             
              describe '.formatter' do
         | 
| 1582 1647 | 
             
                context 'multiple formatters' do
         | 
| 1583 1648 | 
             
                  before :each do
         | 
| 1584 | 
            -
                    subject.formatter :json,  | 
| 1585 | 
            -
                    subject.formatter :txt,  | 
| 1649 | 
            +
                    subject.formatter :json, ->(object, env) { "{\"custom_formatter\":\"#{object[:some] }\"}" }
         | 
| 1650 | 
            +
                    subject.formatter :txt, ->(object, env) { "custom_formatter: #{object[:some] }" }
         | 
| 1586 1651 | 
             
                    subject.get :simple do
         | 
| 1587 1652 | 
             
                      { some: 'hash' }
         | 
| 1588 1653 | 
             
                    end
         | 
| @@ -1600,7 +1665,7 @@ describe Grape::API do | |
| 1600 1665 | 
             
                  before :each do
         | 
| 1601 1666 | 
             
                    subject.content_type :json, 'application/json'
         | 
| 1602 1667 | 
             
                    subject.content_type :custom, 'application/custom'
         | 
| 1603 | 
            -
                    subject.formatter :custom,  | 
| 1668 | 
            +
                    subject.formatter :custom, ->(object, env) { "{\"custom_formatter\":\"#{object[:some] }\"}" }
         | 
| 1604 1669 | 
             
                    subject.get :simple do
         | 
| 1605 1670 | 
             
                      { some: 'hash' }
         | 
| 1606 1671 | 
             
                    end
         | 
| @@ -1645,24 +1710,24 @@ describe Grape::API do | |
| 1645 1710 | 
             
                  subject.post '/data' do
         | 
| 1646 1711 | 
             
                    { x: params[:x] }
         | 
| 1647 1712 | 
             
                  end
         | 
| 1648 | 
            -
                  post  | 
| 1713 | 
            +
                  post '/data', '{"x":42}', 'CONTENT_TYPE' => 'application/json'
         | 
| 1649 1714 | 
             
                  expect(last_response.status).to eq(201)
         | 
| 1650 1715 | 
             
                  expect(last_response.body).to eq('{"x":42}')
         | 
| 1651 1716 | 
             
                end
         | 
| 1652 1717 | 
             
                context 'lambda parser' do
         | 
| 1653 1718 | 
             
                  before :each do
         | 
| 1654 | 
            -
                    subject.content_type :txt,  | 
| 1655 | 
            -
                    subject.content_type :custom,  | 
| 1656 | 
            -
                    subject.parser :custom,  | 
| 1719 | 
            +
                    subject.content_type :txt, 'text/plain'
         | 
| 1720 | 
            +
                    subject.content_type :custom, 'text/custom'
         | 
| 1721 | 
            +
                    subject.parser :custom, ->(object, env) { { object.to_sym => object.to_s.reverse } }
         | 
| 1657 1722 | 
             
                    subject.put :simple do
         | 
| 1658 1723 | 
             
                      params[:simple]
         | 
| 1659 1724 | 
             
                    end
         | 
| 1660 1725 | 
             
                  end
         | 
| 1661 | 
            -
                  [ | 
| 1726 | 
            +
                  ['text/custom', 'text/custom; charset=UTF-8'].each do |content_type|
         | 
| 1662 1727 | 
             
                    it "uses parser for #{content_type}" do
         | 
| 1663 | 
            -
                      put '/simple',  | 
| 1728 | 
            +
                      put '/simple', 'simple', 'CONTENT_TYPE' => content_type
         | 
| 1664 1729 | 
             
                      expect(last_response.status).to eq(200)
         | 
| 1665 | 
            -
                      expect(last_response.body).to eql  | 
| 1730 | 
            +
                      expect(last_response.body).to eql 'elpmis'
         | 
| 1666 1731 | 
             
                    end
         | 
| 1667 1732 | 
             
                  end
         | 
| 1668 1733 | 
             
                end
         | 
| @@ -1673,40 +1738,40 @@ describe Grape::API do | |
| 1673 1738 | 
             
                    end
         | 
| 1674 1739 | 
             
                  end
         | 
| 1675 1740 | 
             
                  before :each do
         | 
| 1676 | 
            -
                    subject.content_type :txt,  | 
| 1677 | 
            -
                    subject.content_type :custom,  | 
| 1741 | 
            +
                    subject.content_type :txt, 'text/plain'
         | 
| 1742 | 
            +
                    subject.content_type :custom, 'text/custom'
         | 
| 1678 1743 | 
             
                    subject.parser :custom, CustomParser
         | 
| 1679 1744 | 
             
                    subject.put :simple do
         | 
| 1680 1745 | 
             
                      params[:simple]
         | 
| 1681 1746 | 
             
                    end
         | 
| 1682 1747 | 
             
                  end
         | 
| 1683 1748 | 
             
                  it 'uses custom parser' do
         | 
| 1684 | 
            -
                    put '/simple',  | 
| 1749 | 
            +
                    put '/simple', 'simple', 'CONTENT_TYPE' => 'text/custom'
         | 
| 1685 1750 | 
             
                    expect(last_response.status).to eq(200)
         | 
| 1686 | 
            -
                    expect(last_response.body).to eql  | 
| 1751 | 
            +
                    expect(last_response.body).to eql 'elpmis'
         | 
| 1687 1752 | 
             
                  end
         | 
| 1688 1753 | 
             
                end
         | 
| 1689 | 
            -
                context  | 
| 1754 | 
            +
                context 'multi_xml' do
         | 
| 1690 1755 | 
             
                  it "doesn't parse yaml" do
         | 
| 1691 1756 | 
             
                    subject.put :yaml do
         | 
| 1692 1757 | 
             
                      params[:tag]
         | 
| 1693 1758 | 
             
                    end
         | 
| 1694 | 
            -
                    put '/yaml', '<tag type="symbol">a123</tag>',  | 
| 1759 | 
            +
                    put '/yaml', '<tag type="symbol">a123</tag>', 'CONTENT_TYPE' => 'application/xml'
         | 
| 1695 1760 | 
             
                    expect(last_response.status).to eq(400)
         | 
| 1696 1761 | 
             
                    expect(last_response.body).to eql 'Disallowed type attribute: "symbol"'
         | 
| 1697 1762 | 
             
                  end
         | 
| 1698 1763 | 
             
                end
         | 
| 1699 | 
            -
                context  | 
| 1764 | 
            +
                context 'none parser class' do
         | 
| 1700 1765 | 
             
                  before :each do
         | 
| 1701 1766 | 
             
                    subject.parser :json, nil
         | 
| 1702 | 
            -
                    subject.put  | 
| 1767 | 
            +
                    subject.put 'data' do
         | 
| 1703 1768 | 
             
                      "body: #{env['api.request.body'] }"
         | 
| 1704 1769 | 
             
                    end
         | 
| 1705 1770 | 
             
                  end
         | 
| 1706 | 
            -
                  it  | 
| 1707 | 
            -
                    put '/data', 'not valid json',  | 
| 1771 | 
            +
                  it 'does not parse data' do
         | 
| 1772 | 
            +
                    put '/data', 'not valid json', 'CONTENT_TYPE' => 'application/json'
         | 
| 1708 1773 | 
             
                    expect(last_response.status).to eq(200)
         | 
| 1709 | 
            -
                    expect(last_response.body).to eq( | 
| 1774 | 
            +
                    expect(last_response.body).to eq('body: not valid json')
         | 
| 1710 1775 | 
             
                  end
         | 
| 1711 1776 | 
             
                end
         | 
| 1712 1777 | 
             
              end
         | 
| @@ -1720,7 +1785,7 @@ describe Grape::API do | |
| 1720 1785 | 
             
                  subject.get '/data' do
         | 
| 1721 1786 | 
             
                    { x: 42 }
         | 
| 1722 1787 | 
             
                  end
         | 
| 1723 | 
            -
                  get  | 
| 1788 | 
            +
                  get '/data'
         | 
| 1724 1789 | 
             
                  expect(last_response.status).to eq(200)
         | 
| 1725 1790 | 
             
                  expect(last_response.body).to eq('{"x":42}')
         | 
| 1726 1791 | 
             
                end
         | 
| @@ -1728,7 +1793,7 @@ describe Grape::API do | |
| 1728 1793 | 
             
                  subject.post '/data' do
         | 
| 1729 1794 | 
             
                    { x: params[:x] }
         | 
| 1730 1795 | 
             
                  end
         | 
| 1731 | 
            -
                  post  | 
| 1796 | 
            +
                  post '/data', '{"x":42}', 'CONTENT_TYPE' => ''
         | 
| 1732 1797 | 
             
                  expect(last_response.status).to eq(201)
         | 
| 1733 1798 | 
             
                  expect(last_response.body).to eq('{"x":42}')
         | 
| 1734 1799 | 
             
                end
         | 
| @@ -1739,7 +1804,7 @@ describe Grape::API do | |
| 1739 1804 | 
             
                  subject.rescue_from :all
         | 
| 1740 1805 | 
             
                  subject.default_error_status 200
         | 
| 1741 1806 | 
             
                  subject.get '/exception' do
         | 
| 1742 | 
            -
                     | 
| 1807 | 
            +
                    fail 'rain!'
         | 
| 1743 1808 | 
             
                  end
         | 
| 1744 1809 | 
             
                  get '/exception'
         | 
| 1745 1810 | 
             
                  expect(last_response.status).to eql 200
         | 
| @@ -1747,7 +1812,7 @@ describe Grape::API do | |
| 1747 1812 | 
             
                it 'has a default error status' do
         | 
| 1748 1813 | 
             
                  subject.rescue_from :all
         | 
| 1749 1814 | 
             
                  subject.get '/exception' do
         | 
| 1750 | 
            -
                     | 
| 1815 | 
            +
                    fail 'rain!'
         | 
| 1751 1816 | 
             
                  end
         | 
| 1752 1817 | 
             
                  get '/exception'
         | 
| 1753 1818 | 
             
                  expect(last_response.status).to eql 500
         | 
| @@ -1756,7 +1821,7 @@ describe Grape::API do | |
| 1756 1821 | 
             
                  subject.rescue_from :all
         | 
| 1757 1822 | 
             
                  subject.default_error_status 400
         | 
| 1758 1823 | 
             
                  subject.get '/exception' do
         | 
| 1759 | 
            -
                    error!  | 
| 1824 | 
            +
                    error! 'rain!'
         | 
| 1760 1825 | 
             
                  end
         | 
| 1761 1826 | 
             
                  get '/exception'
         | 
| 1762 1827 | 
             
                  expect(last_response.status).to eql 400
         | 
| @@ -1817,8 +1882,8 @@ describe Grape::API do | |
| 1817 1882 | 
             
                    expect(subject.routes.size).to eq(1)
         | 
| 1818 1883 | 
             
                    route = subject.routes[0]
         | 
| 1819 1884 | 
             
                    expect(route.route_version).to be_nil
         | 
| 1820 | 
            -
                    expect(route.route_path).to eq( | 
| 1821 | 
            -
                    expect(route.route_method).to eq( | 
| 1885 | 
            +
                    expect(route.route_path).to eq('/ping(.:format)')
         | 
| 1886 | 
            +
                    expect(route.route_method).to eq('GET')
         | 
| 1822 1887 | 
             
                  end
         | 
| 1823 1888 | 
             
                end
         | 
| 1824 1889 | 
             
                describe 'api structure with two versions and a namespace' do
         | 
| @@ -1842,19 +1907,19 @@ describe Grape::API do | |
| 1842 1907 | 
             
                    expect(subject.version).to eq('v2')
         | 
| 1843 1908 | 
             
                  end
         | 
| 1844 1909 | 
             
                  it 'returns versions' do
         | 
| 1845 | 
            -
                    expect(subject.versions).to eq( | 
| 1910 | 
            +
                    expect(subject.versions).to eq(%w(v1 v2))
         | 
| 1846 1911 | 
             
                  end
         | 
| 1847 1912 | 
             
                  it 'sets route paths' do
         | 
| 1848 1913 | 
             
                    expect(subject.routes.size).to be >= 2
         | 
| 1849 | 
            -
                    expect(subject.routes[0].route_path).to eq( | 
| 1850 | 
            -
                    expect(subject.routes[1].route_path).to eq( | 
| 1914 | 
            +
                    expect(subject.routes[0].route_path).to eq('/:version/version(.:format)')
         | 
| 1915 | 
            +
                    expect(subject.routes[1].route_path).to eq('/p/:version/n1/n2/version(.:format)')
         | 
| 1851 1916 | 
             
                  end
         | 
| 1852 1917 | 
             
                  it 'sets route versions' do
         | 
| 1853 1918 | 
             
                    expect(subject.routes[0].route_version).to eq('v1')
         | 
| 1854 1919 | 
             
                    expect(subject.routes[1].route_version).to eq('v2')
         | 
| 1855 1920 | 
             
                  end
         | 
| 1856 1921 | 
             
                  it 'sets a nested namespace' do
         | 
| 1857 | 
            -
                    expect(subject.routes[1].route_namespace).to eq( | 
| 1922 | 
            +
                    expect(subject.routes[1].route_namespace).to eq('/n1/n2')
         | 
| 1858 1923 | 
             
                  end
         | 
| 1859 1924 | 
             
                  it 'sets prefix' do
         | 
| 1860 1925 | 
             
                    expect(subject.routes[1].route_prefix).to eq('p')
         | 
| @@ -1862,24 +1927,108 @@ describe Grape::API do | |
| 1862 1927 | 
             
                end
         | 
| 1863 1928 | 
             
                describe 'api structure with additional parameters' do
         | 
| 1864 1929 | 
             
                  before(:each) do
         | 
| 1865 | 
            -
                    subject. | 
| 1930 | 
            +
                    subject.params do
         | 
| 1931 | 
            +
                      requires :token, desc: 'a token'
         | 
| 1932 | 
            +
                      optional :limit, desc: 'the limit'
         | 
| 1933 | 
            +
                    end
         | 
| 1934 | 
            +
                    subject.get 'split/:string' do
         | 
| 1866 1935 | 
             
                      params[:string].split(params[:token], (params[:limit] || 0).to_i)
         | 
| 1867 1936 | 
             
                    end
         | 
| 1868 1937 | 
             
                  end
         | 
| 1869 1938 | 
             
                  it 'splits a string' do
         | 
| 1870 | 
            -
                    get  | 
| 1939 | 
            +
                    get '/split/a,b,c.json', token: ','
         | 
| 1871 1940 | 
             
                    expect(last_response.body).to eq('["a","b","c"]')
         | 
| 1872 1941 | 
             
                  end
         | 
| 1873 1942 | 
             
                  it 'splits a string with limit' do
         | 
| 1874 | 
            -
                    get  | 
| 1943 | 
            +
                    get '/split/a,b,c.json', token: ',', limit: '2'
         | 
| 1875 1944 | 
             
                    expect(last_response.body).to eq('["a","b,c"]')
         | 
| 1876 1945 | 
             
                  end
         | 
| 1877 1946 | 
             
                  it 'sets route_params' do
         | 
| 1878 1947 | 
             
                    expect(subject.routes.map { |route|
         | 
| 1879 | 
            -
                      { params: route.route_params | 
| 1948 | 
            +
                      { params: route.route_params }
         | 
| 1880 1949 | 
             
                    }).to eq [
         | 
| 1881 | 
            -
                      { | 
| 1882 | 
            -
             | 
| 1950 | 
            +
                      {
         | 
| 1951 | 
            +
                        params: {
         | 
| 1952 | 
            +
                          'string' => '',
         | 
| 1953 | 
            +
                          'token' => { required: true, desc: 'a token' },
         | 
| 1954 | 
            +
                          'limit' => { required: false, desc: 'the limit' }
         | 
| 1955 | 
            +
                        }
         | 
| 1956 | 
            +
                      }
         | 
| 1957 | 
            +
                    ]
         | 
| 1958 | 
            +
                  end
         | 
| 1959 | 
            +
                end
         | 
| 1960 | 
            +
                describe 'api structure with multiple apis' do
         | 
| 1961 | 
            +
                  before(:each) do
         | 
| 1962 | 
            +
                    subject.params do
         | 
| 1963 | 
            +
                      requires :one, desc: 'a token'
         | 
| 1964 | 
            +
                      optional :two, desc: 'the limit'
         | 
| 1965 | 
            +
                    end
         | 
| 1966 | 
            +
                    subject.get 'one' do
         | 
| 1967 | 
            +
                    end
         | 
| 1968 | 
            +
             | 
| 1969 | 
            +
                    subject.params do
         | 
| 1970 | 
            +
                      requires :three, desc: 'a token'
         | 
| 1971 | 
            +
                      optional :four, desc: 'the limit'
         | 
| 1972 | 
            +
                    end
         | 
| 1973 | 
            +
                    subject.get 'two' do
         | 
| 1974 | 
            +
                    end
         | 
| 1975 | 
            +
                  end
         | 
| 1976 | 
            +
                  it 'sets route_params' do
         | 
| 1977 | 
            +
                    expect(subject.routes.map { |route|
         | 
| 1978 | 
            +
                      { params: route.route_params }
         | 
| 1979 | 
            +
                    }).to eq [
         | 
| 1980 | 
            +
                      {
         | 
| 1981 | 
            +
                        params: {
         | 
| 1982 | 
            +
                          'one' => { required: true, desc: 'a token' },
         | 
| 1983 | 
            +
                          'two' => { required: false, desc: 'the limit' }
         | 
| 1984 | 
            +
                        }
         | 
| 1985 | 
            +
                      },
         | 
| 1986 | 
            +
                      {
         | 
| 1987 | 
            +
                        params: {
         | 
| 1988 | 
            +
                          'three' => { required: true, desc: 'a token' },
         | 
| 1989 | 
            +
                          'four' => { required: false, desc: 'the limit' }
         | 
| 1990 | 
            +
                        }
         | 
| 1991 | 
            +
                      }
         | 
| 1992 | 
            +
                    ]
         | 
| 1993 | 
            +
                  end
         | 
| 1994 | 
            +
                end
         | 
| 1995 | 
            +
                describe 'api structure with an api without params' do
         | 
| 1996 | 
            +
                  before(:each) do
         | 
| 1997 | 
            +
                    subject.params do
         | 
| 1998 | 
            +
                      requires :one, desc: 'a token'
         | 
| 1999 | 
            +
                      optional :two, desc: 'the limit'
         | 
| 2000 | 
            +
                    end
         | 
| 2001 | 
            +
                    subject.get 'one' do
         | 
| 2002 | 
            +
                    end
         | 
| 2003 | 
            +
             | 
| 2004 | 
            +
                    subject.get 'two' do
         | 
| 2005 | 
            +
                    end
         | 
| 2006 | 
            +
                  end
         | 
| 2007 | 
            +
                  it 'sets route_params' do
         | 
| 2008 | 
            +
                    expect(subject.routes.map { |route|
         | 
| 2009 | 
            +
                      { params: route.route_params }
         | 
| 2010 | 
            +
                    }).to eq [
         | 
| 2011 | 
            +
                      {
         | 
| 2012 | 
            +
                        params: {
         | 
| 2013 | 
            +
                          'one' => { required: true, desc: 'a token' },
         | 
| 2014 | 
            +
                          'two' => { required: false, desc: 'the limit' }
         | 
| 2015 | 
            +
                        }
         | 
| 2016 | 
            +
                      },
         | 
| 2017 | 
            +
                      {
         | 
| 2018 | 
            +
                        params: {}
         | 
| 2019 | 
            +
                      }
         | 
| 2020 | 
            +
                    ]
         | 
| 2021 | 
            +
                  end
         | 
| 2022 | 
            +
                end
         | 
| 2023 | 
            +
                describe 'api with a custom route setting' do
         | 
| 2024 | 
            +
                  before(:each) do
         | 
| 2025 | 
            +
                    subject.route_setting :custom, key: 'value'
         | 
| 2026 | 
            +
                    subject.get 'one'
         | 
| 2027 | 
            +
                  end
         | 
| 2028 | 
            +
                  it 'exposed' do
         | 
| 2029 | 
            +
                    expect(subject.routes.count).to eq 1
         | 
| 2030 | 
            +
                    route = subject.routes.first
         | 
| 2031 | 
            +
                    expect(route.route_settings[:custom]).to eq(key: 'value')
         | 
| 1883 2032 | 
             
                  end
         | 
| 1884 2033 | 
             
                end
         | 
| 1885 2034 | 
             
              end
         | 
| @@ -1889,112 +2038,114 @@ describe Grape::API do | |
| 1889 2038 | 
             
                  expect(subject.routes).to eq([])
         | 
| 1890 2039 | 
             
                end
         | 
| 1891 2040 | 
             
                it 'empty array of routes' do
         | 
| 1892 | 
            -
                  subject.desc  | 
| 2041 | 
            +
                  subject.desc 'grape api'
         | 
| 1893 2042 | 
             
                  expect(subject.routes).to eq([])
         | 
| 1894 2043 | 
             
                end
         | 
| 1895 2044 | 
             
                it 'describes a method' do
         | 
| 1896 | 
            -
                  subject.desc  | 
| 2045 | 
            +
                  subject.desc 'first method'
         | 
| 1897 2046 | 
             
                  subject.get :first do ; end
         | 
| 1898 2047 | 
             
                  expect(subject.routes.length).to eq(1)
         | 
| 1899 2048 | 
             
                  route = subject.routes.first
         | 
| 1900 | 
            -
                  expect(route.route_description).to eq( | 
| 2049 | 
            +
                  expect(route.route_description).to eq('first method')
         | 
| 1901 2050 | 
             
                  expect(route.route_foo).to be_nil
         | 
| 1902 2051 | 
             
                  expect(route.route_params).to eq({})
         | 
| 1903 2052 | 
             
                end
         | 
| 1904 2053 | 
             
                it 'describes methods separately' do
         | 
| 1905 | 
            -
                  subject.desc  | 
| 2054 | 
            +
                  subject.desc 'first method'
         | 
| 1906 2055 | 
             
                  subject.get :first do ; end
         | 
| 1907 | 
            -
                  subject.desc  | 
| 2056 | 
            +
                  subject.desc 'second method'
         | 
| 1908 2057 | 
             
                  subject.get :second do ; end
         | 
| 1909 2058 | 
             
                  expect(subject.routes.count).to eq(2)
         | 
| 1910 2059 | 
             
                  expect(subject.routes.map { |route|
         | 
| 1911 2060 | 
             
                    { description: route.route_description, params: route.route_params }
         | 
| 1912 2061 | 
             
                  }).to eq [
         | 
| 1913 | 
            -
                    { description:  | 
| 1914 | 
            -
                    { description:  | 
| 2062 | 
            +
                    { description: 'first method', params: {} },
         | 
| 2063 | 
            +
                    { description: 'second method', params: {} }
         | 
| 1915 2064 | 
             
                ]
         | 
| 1916 2065 | 
             
                end
         | 
| 1917 2066 | 
             
                it 'resets desc' do
         | 
| 1918 | 
            -
                  subject.desc  | 
| 2067 | 
            +
                  subject.desc 'first method'
         | 
| 1919 2068 | 
             
                  subject.get :first do ; end
         | 
| 1920 2069 | 
             
                  subject.get :second do ; end
         | 
| 1921 2070 | 
             
                  expect(subject.routes.map { |route|
         | 
| 1922 2071 | 
             
                    { description: route.route_description, params: route.route_params }
         | 
| 1923 2072 | 
             
                  }).to eq [
         | 
| 1924 | 
            -
                    { description:  | 
| 2073 | 
            +
                    { description: 'first method', params: {} },
         | 
| 1925 2074 | 
             
                    { description: nil, params: {} }
         | 
| 1926 2075 | 
             
                ]
         | 
| 1927 2076 | 
             
                end
         | 
| 1928 2077 | 
             
                it 'namespaces and describe arbitrary parameters' do
         | 
| 1929 2078 | 
             
                  subject.namespace 'ns' do
         | 
| 1930 | 
            -
                    desc  | 
| 2079 | 
            +
                    desc 'ns second', foo: 'bar'
         | 
| 1931 2080 | 
             
                    get 'second' do ; end
         | 
| 1932 2081 | 
             
                  end
         | 
| 1933 2082 | 
             
                  expect(subject.routes.map { |route|
         | 
| 1934 2083 | 
             
                    { description: route.route_description, foo: route.route_foo, params: route.route_params }
         | 
| 1935 2084 | 
             
                  }).to eq [
         | 
| 1936 | 
            -
                    { description:  | 
| 2085 | 
            +
                    { description: 'ns second', foo: 'bar', params: {} }
         | 
| 1937 2086 | 
             
                ]
         | 
| 1938 2087 | 
             
                end
         | 
| 1939 2088 | 
             
                it 'includes details' do
         | 
| 1940 | 
            -
                  subject.desc  | 
| 2089 | 
            +
                  subject.desc 'method', details: 'method details'
         | 
| 1941 2090 | 
             
                  subject.get 'method' do ; end
         | 
| 1942 2091 | 
             
                  expect(subject.routes.map { |route|
         | 
| 1943 2092 | 
             
                    { description: route.route_description, details: route.route_details, params: route.route_params }
         | 
| 1944 2093 | 
             
                  }).to eq [
         | 
| 1945 | 
            -
                    { description:  | 
| 2094 | 
            +
                    { description: 'method', details: 'method details', params: {} }
         | 
| 1946 2095 | 
             
                ]
         | 
| 1947 2096 | 
             
                end
         | 
| 1948 2097 | 
             
                it 'describes a method with parameters' do
         | 
| 1949 | 
            -
                  subject.desc  | 
| 2098 | 
            +
                  subject.desc 'Reverses a string.', params: { 's' => { desc: 'string to reverse', type: 'string' } }
         | 
| 1950 2099 | 
             
                  subject.get 'reverse' do
         | 
| 1951 2100 | 
             
                    params[:s].reverse
         | 
| 1952 2101 | 
             
                  end
         | 
| 1953 2102 | 
             
                  expect(subject.routes.map { |route|
         | 
| 1954 2103 | 
             
                    { description: route.route_description, params: route.route_params }
         | 
| 1955 2104 | 
             
                  }).to eq [
         | 
| 1956 | 
            -
                    { description:  | 
| 2105 | 
            +
                    { description: 'Reverses a string.', params: { 's' => { desc: 'string to reverse', type: 'string' } } }
         | 
| 1957 2106 | 
             
                ]
         | 
| 1958 2107 | 
             
                end
         | 
| 1959 2108 | 
             
                it 'merges the parameters of the namespace with the parameters of the method' do
         | 
| 1960 | 
            -
                  subject.desc  | 
| 2109 | 
            +
                  subject.desc 'namespace'
         | 
| 1961 2110 | 
             
                  subject.params do
         | 
| 1962 | 
            -
                    requires :ns_param, desc:  | 
| 2111 | 
            +
                    requires :ns_param, desc: 'namespace parameter'
         | 
| 1963 2112 | 
             
                  end
         | 
| 1964 2113 | 
             
                  subject.namespace 'ns' do
         | 
| 1965 | 
            -
                    desc  | 
| 2114 | 
            +
                    desc 'method'
         | 
| 1966 2115 | 
             
                    params do
         | 
| 1967 | 
            -
                      optional :method_param, desc:  | 
| 2116 | 
            +
                      optional :method_param, desc: 'method parameter'
         | 
| 1968 2117 | 
             
                    end
         | 
| 1969 2118 | 
             
                    get 'method' do ; end
         | 
| 1970 2119 | 
             
                  end
         | 
| 1971 | 
            -
             | 
| 2120 | 
            +
             | 
| 2121 | 
            +
                  routes_doc = subject.routes.map { |route|
         | 
| 1972 2122 | 
             
                    { description: route.route_description, params: route.route_params }
         | 
| 1973 | 
            -
                  } | 
| 1974 | 
            -
             | 
| 2123 | 
            +
                  }
         | 
| 2124 | 
            +
                  expect(routes_doc).to eq [
         | 
| 2125 | 
            +
                    { description: 'method',
         | 
| 1975 2126 | 
             
                      params: {
         | 
| 1976 | 
            -
                         | 
| 1977 | 
            -
                         | 
| 2127 | 
            +
                        'ns_param' => { required: true, desc: 'namespace parameter' },
         | 
| 2128 | 
            +
                        'method_param' => { required: false, desc: 'method parameter' }
         | 
| 1978 2129 | 
             
                      }
         | 
| 1979 2130 | 
             
                    }
         | 
| 1980 2131 | 
             
                ]
         | 
| 1981 2132 | 
             
                end
         | 
| 1982 2133 | 
             
                it 'merges the parameters of nested namespaces' do
         | 
| 1983 | 
            -
                  subject.desc  | 
| 2134 | 
            +
                  subject.desc 'ns1'
         | 
| 1984 2135 | 
             
                  subject.params do
         | 
| 1985 | 
            -
                    optional :ns_param, desc:  | 
| 1986 | 
            -
                    requires :ns1_param, desc:  | 
| 2136 | 
            +
                    optional :ns_param, desc: 'ns param 1'
         | 
| 2137 | 
            +
                    requires :ns1_param, desc: 'ns1 param'
         | 
| 1987 2138 | 
             
                  end
         | 
| 1988 2139 | 
             
                  subject.namespace 'ns1' do
         | 
| 1989 | 
            -
                    desc  | 
| 2140 | 
            +
                    desc 'ns2'
         | 
| 1990 2141 | 
             
                    params do
         | 
| 1991 | 
            -
                      requires :ns_param, desc:  | 
| 1992 | 
            -
                      requires :ns2_param, desc:  | 
| 2142 | 
            +
                      requires :ns_param, desc: 'ns param 2'
         | 
| 2143 | 
            +
                      requires :ns2_param, desc: 'ns2 param'
         | 
| 1993 2144 | 
             
                    end
         | 
| 1994 2145 | 
             
                    namespace 'ns2' do
         | 
| 1995 | 
            -
                      desc  | 
| 2146 | 
            +
                      desc 'method'
         | 
| 1996 2147 | 
             
                      params do
         | 
| 1997 | 
            -
                        optional :method_param, desc:  | 
| 2148 | 
            +
                        optional :method_param, desc: 'method param'
         | 
| 1998 2149 | 
             
                      end
         | 
| 1999 2150 | 
             
                      get 'method' do ; end
         | 
| 2000 2151 | 
             
                    end
         | 
| @@ -2002,58 +2153,56 @@ describe Grape::API do | |
| 2002 2153 | 
             
                  expect(subject.routes.map { |route|
         | 
| 2003 2154 | 
             
                    { description: route.route_description, params: route.route_params }
         | 
| 2004 2155 | 
             
                  }).to eq [
         | 
| 2005 | 
            -
                    { description:  | 
| 2156 | 
            +
                    { description: 'method',
         | 
| 2006 2157 | 
             
                      params: {
         | 
| 2007 | 
            -
                         | 
| 2008 | 
            -
                         | 
| 2009 | 
            -
                         | 
| 2010 | 
            -
                         | 
| 2158 | 
            +
                        'ns_param' => { required: true, desc: 'ns param 2' },
         | 
| 2159 | 
            +
                        'ns1_param' => { required: true, desc: 'ns1 param' },
         | 
| 2160 | 
            +
                        'ns2_param' => { required: true, desc: 'ns2 param' },
         | 
| 2161 | 
            +
                        'method_param' => { required: false, desc: 'method param' }
         | 
| 2011 2162 | 
             
                      }
         | 
| 2012 2163 | 
             
                    }
         | 
| 2013 2164 | 
             
                ]
         | 
| 2014 2165 | 
             
                end
         | 
| 2015 | 
            -
                it  | 
| 2016 | 
            -
                  subject.desc  | 
| 2166 | 
            +
                it 'groups nested params and prevents overwriting of params with same name in different groups' do
         | 
| 2167 | 
            +
                  subject.desc 'method'
         | 
| 2017 2168 | 
             
                  subject.params do
         | 
| 2018 2169 | 
             
                    group :group1 do
         | 
| 2019 | 
            -
                      optional :param1, desc:  | 
| 2020 | 
            -
                      requires :param2, desc:  | 
| 2170 | 
            +
                      optional :param1, desc: 'group1 param1 desc'
         | 
| 2171 | 
            +
                      requires :param2, desc: 'group1 param2 desc'
         | 
| 2021 2172 | 
             
                    end
         | 
| 2022 2173 | 
             
                    group :group2 do
         | 
| 2023 | 
            -
                      optional :param1, desc:  | 
| 2024 | 
            -
                      requires :param2, desc:  | 
| 2174 | 
            +
                      optional :param1, desc: 'group2 param1 desc'
         | 
| 2175 | 
            +
                      requires :param2, desc: 'group2 param2 desc'
         | 
| 2025 2176 | 
             
                    end
         | 
| 2026 2177 | 
             
                  end
         | 
| 2027 | 
            -
                  subject.get  | 
| 2178 | 
            +
                  subject.get 'method' do ; end
         | 
| 2028 2179 |  | 
| 2029 | 
            -
                  expect(subject.routes.map { | 
| 2030 | 
            -
                     | 
| 2031 | 
            -
             | 
| 2032 | 
            -
                     | 
| 2033 | 
            -
                     | 
| 2034 | 
            -
                     | 
| 2035 | 
            -
                     | 
| 2036 | 
            -
                    "group2[param1]" => { required: false, desc: "group2 param1 desc" },
         | 
| 2037 | 
            -
                    "group2[param2]" => { required: true, desc: "group2 param2 desc" }
         | 
| 2180 | 
            +
                  expect(subject.routes.map(&:route_params)).to eq [{
         | 
| 2181 | 
            +
                    'group1'         => { required: true, type: 'Array' },
         | 
| 2182 | 
            +
                    'group1[param1]' => { required: false, desc: 'group1 param1 desc' },
         | 
| 2183 | 
            +
                    'group1[param2]' => { required: true, desc: 'group1 param2 desc' },
         | 
| 2184 | 
            +
                    'group2'         => { required: true, type: 'Array' },
         | 
| 2185 | 
            +
                    'group2[param1]' => { required: false, desc: 'group2 param1 desc' },
         | 
| 2186 | 
            +
                    'group2[param2]' => { required: true, desc: 'group2 param2 desc' }
         | 
| 2038 2187 | 
             
                  }]
         | 
| 2039 2188 | 
             
                end
         | 
| 2040 2189 | 
             
                it 'uses full name of parameters in nested groups' do
         | 
| 2041 | 
            -
                  subject.desc  | 
| 2190 | 
            +
                  subject.desc 'nesting'
         | 
| 2042 2191 | 
             
                  subject.params do
         | 
| 2043 | 
            -
                    requires :root_param, desc:  | 
| 2192 | 
            +
                    requires :root_param, desc: 'root param'
         | 
| 2044 2193 | 
             
                    group :nested do
         | 
| 2045 | 
            -
                      requires :nested_param, desc:  | 
| 2194 | 
            +
                      requires :nested_param, desc: 'nested param'
         | 
| 2046 2195 | 
             
                    end
         | 
| 2047 2196 | 
             
                  end
         | 
| 2048 2197 | 
             
                  subject.get 'method' do ; end
         | 
| 2049 2198 | 
             
                  expect(subject.routes.map { |route|
         | 
| 2050 2199 | 
             
                    { description: route.route_description, params: route.route_params }
         | 
| 2051 2200 | 
             
                  }).to eq [
         | 
| 2052 | 
            -
                    { description:  | 
| 2201 | 
            +
                    { description: 'nesting',
         | 
| 2053 2202 | 
             
                      params: {
         | 
| 2054 | 
            -
                         | 
| 2055 | 
            -
                         | 
| 2056 | 
            -
                         | 
| 2203 | 
            +
                        'root_param' => { required: true, desc: 'root param' },
         | 
| 2204 | 
            +
                        'nested' => { required: true, type: 'Array' },
         | 
| 2205 | 
            +
                        'nested[nested_param]' => { required: true, desc: 'nested param' }
         | 
| 2057 2206 | 
             
                      }
         | 
| 2058 2207 | 
             
                    }
         | 
| 2059 2208 | 
             
                ]
         | 
| @@ -2067,30 +2216,30 @@ describe Grape::API do | |
| 2067 2216 | 
             
                end
         | 
| 2068 2217 | 
             
                it 'parses parameters when no description is given' do
         | 
| 2069 2218 | 
             
                  subject.params do
         | 
| 2070 | 
            -
                    requires :one_param, desc:  | 
| 2219 | 
            +
                    requires :one_param, desc: 'one param'
         | 
| 2071 2220 | 
             
                  end
         | 
| 2072 2221 | 
             
                  subject.get 'method' do ; end
         | 
| 2073 2222 | 
             
                  expect(subject.routes.map { |route|
         | 
| 2074 2223 | 
             
                    { description: route.route_description, params: route.route_params }
         | 
| 2075 2224 | 
             
                  }).to eq [
         | 
| 2076 | 
            -
                    { description: nil, params: {  | 
| 2225 | 
            +
                    { description: nil, params: { 'one_param' => { required: true, desc: 'one param' } } }
         | 
| 2077 2226 | 
             
                ]
         | 
| 2078 2227 | 
             
                end
         | 
| 2079 2228 | 
             
                it 'does not symbolize params' do
         | 
| 2080 | 
            -
                  subject.desc  | 
| 2229 | 
            +
                  subject.desc 'Reverses a string.', params: { 's' => { desc: 'string to reverse', type: 'string' } }
         | 
| 2081 2230 | 
             
                  subject.get 'reverse/:s' do
         | 
| 2082 2231 | 
             
                    params[:s].reverse
         | 
| 2083 2232 | 
             
                  end
         | 
| 2084 2233 | 
             
                  expect(subject.routes.map { |route|
         | 
| 2085 2234 | 
             
                    { description: route.route_description, params: route.route_params }
         | 
| 2086 2235 | 
             
                  }).to eq [
         | 
| 2087 | 
            -
                    { description:  | 
| 2236 | 
            +
                    { description: 'Reverses a string.', params: { 's' => { desc: 'string to reverse', type: 'string' } } }
         | 
| 2088 2237 | 
             
                ]
         | 
| 2089 2238 | 
             
                end
         | 
| 2090 2239 | 
             
              end
         | 
| 2091 2240 |  | 
| 2092 2241 | 
             
              describe '.mount' do
         | 
| 2093 | 
            -
                let(:mounted_app) {  | 
| 2242 | 
            +
                let(:mounted_app) { ->(env) { [200, {}, ['MOUNTED']] } }
         | 
| 2094 2243 |  | 
| 2095 2244 | 
             
                context 'with a bare rack app' do
         | 
| 2096 2245 | 
             
                  before do
         | 
| @@ -2111,7 +2260,7 @@ describe Grape::API do | |
| 2111 2260 | 
             
                    subject.mount lambda { |env|
         | 
| 2112 2261 | 
             
                      headers = {}
         | 
| 2113 2262 | 
             
                      headers['X-Cascade'] == 'pass' unless env['PATH_INFO'].include?('boo')
         | 
| 2114 | 
            -
                      [200, headers, [ | 
| 2263 | 
            +
                      [200, headers, ['Farfegnugen']]
         | 
| 2115 2264 | 
             
                    } => '/'
         | 
| 2116 2265 |  | 
| 2117 2266 | 
             
                    get '/boo'
         | 
| @@ -2136,7 +2285,7 @@ describe Grape::API do | |
| 2136 2285 | 
             
                    subject.namespace :cool do
         | 
| 2137 2286 | 
             
                      app = Class.new(Grape::API)
         | 
| 2138 2287 | 
             
                      app.get('/awesome') do
         | 
| 2139 | 
            -
                         | 
| 2288 | 
            +
                        'yo'
         | 
| 2140 2289 | 
             
                      end
         | 
| 2141 2290 |  | 
| 2142 2291 | 
             
                      mount app
         | 
| @@ -2152,7 +2301,7 @@ describe Grape::API do | |
| 2152 2301 | 
             
                    subject.namespace :cool do
         | 
| 2153 2302 | 
             
                      inner_app = Class.new(Grape::API)
         | 
| 2154 2303 | 
             
                      inner_app.get('/awesome') do
         | 
| 2155 | 
            -
                         | 
| 2304 | 
            +
                        'yo'
         | 
| 2156 2305 | 
             
                      end
         | 
| 2157 2306 |  | 
| 2158 2307 | 
             
                      app = Class.new(Grape::API)
         | 
| @@ -2168,12 +2317,15 @@ describe Grape::API do | |
| 2168 2317 | 
             
                    subject.rescue_from :all do |e|
         | 
| 2169 2318 | 
             
                      rack_response("rescued from #{e.message}", 202)
         | 
| 2170 2319 | 
             
                    end
         | 
| 2320 | 
            +
             | 
| 2321 | 
            +
                    app = Class.new(Grape::API)
         | 
| 2322 | 
            +
             | 
| 2171 2323 | 
             
                    subject.namespace :mounted do
         | 
| 2172 | 
            -
                      app = Class.new(Grape::API)
         | 
| 2173 2324 | 
             
                      app.rescue_from ArgumentError
         | 
| 2174 | 
            -
                      app.get('/fail') {  | 
| 2325 | 
            +
                      app.get('/fail') { fail 'doh!' }
         | 
| 2175 2326 | 
             
                      mount app
         | 
| 2176 2327 | 
             
                    end
         | 
| 2328 | 
            +
             | 
| 2177 2329 | 
             
                    get '/mounted/fail'
         | 
| 2178 2330 | 
             
                    expect(last_response.status).to eql 202
         | 
| 2179 2331 | 
             
                    expect(last_response.body).to eq('rescued from doh!')
         | 
| @@ -2195,28 +2347,29 @@ describe Grape::API do | |
| 2195 2347 | 
             
                    subject.namespace :cool do
         | 
| 2196 2348 | 
             
                      app = Class.new(Grape::API)
         | 
| 2197 2349 | 
             
                      app.get '/awesome' do
         | 
| 2198 | 
            -
                         | 
| 2350 | 
            +
                        'sauce'
         | 
| 2199 2351 | 
             
                      end
         | 
| 2200 2352 | 
             
                      mount app => '/mounted'
         | 
| 2201 2353 | 
             
                    end
         | 
| 2202 | 
            -
                    get  | 
| 2354 | 
            +
                    get '/mounted/cool/awesome'
         | 
| 2203 2355 | 
             
                    expect(last_response.status).to eq(200)
         | 
| 2204 | 
            -
                    expect(last_response.body).to eq( | 
| 2356 | 
            +
                    expect(last_response.body).to eq('sauce')
         | 
| 2205 2357 | 
             
                  end
         | 
| 2206 2358 |  | 
| 2207 2359 | 
             
                  it 'mounts on a nested path' do
         | 
| 2208 | 
            -
                     | 
| 2209 | 
            -
                     | 
| 2210 | 
            -
                     | 
| 2211 | 
            -
                       | 
| 2360 | 
            +
                    APP1 = Class.new(Grape::API)
         | 
| 2361 | 
            +
                    APP2 = Class.new(Grape::API)
         | 
| 2362 | 
            +
                    APP2.get '/nice' do
         | 
| 2363 | 
            +
                      'play'
         | 
| 2212 2364 | 
             
                    end
         | 
| 2213 2365 | 
             
                    # note that the reverse won't work, mount from outside-in
         | 
| 2214 | 
            -
                     | 
| 2215 | 
            -
                     | 
| 2216 | 
            -
                     | 
| 2366 | 
            +
                    APP3 = subject
         | 
| 2367 | 
            +
                    APP3.mount APP1 => '/app1'
         | 
| 2368 | 
            +
                    APP1.mount APP2 => '/app2'
         | 
| 2369 | 
            +
                    get '/app1/app2/nice'
         | 
| 2217 2370 | 
             
                    expect(last_response.status).to eq(200)
         | 
| 2218 | 
            -
                    expect(last_response.body).to eq( | 
| 2219 | 
            -
                    options  | 
| 2371 | 
            +
                    expect(last_response.body).to eq('play')
         | 
| 2372 | 
            +
                    options '/app1/app2/nice'
         | 
| 2220 2373 | 
             
                    expect(last_response.status).to eq(204)
         | 
| 2221 2374 | 
             
                  end
         | 
| 2222 2375 |  | 
| @@ -2233,6 +2386,7 @@ describe Grape::API do | |
| 2233 2386 | 
             
                    subject.namespace :apples do
         | 
| 2234 2387 | 
             
                      mount app
         | 
| 2235 2388 | 
             
                    end
         | 
| 2389 | 
            +
             | 
| 2236 2390 | 
             
                    get '/apples/colour'
         | 
| 2237 2391 | 
             
                    expect(last_response.status).to eql 200
         | 
| 2238 2392 | 
             
                    expect(last_response.body).to eq('red')
         | 
| @@ -2250,7 +2404,7 @@ describe Grape::API do | |
| 2250 2404 | 
             
                    subject.namespace :apples do
         | 
| 2251 2405 | 
             
                      app = Class.new(Grape::API)
         | 
| 2252 2406 | 
             
                      app.get('/colour') do
         | 
| 2253 | 
            -
                         | 
| 2407 | 
            +
                        'red'
         | 
| 2254 2408 | 
             
                      end
         | 
| 2255 2409 | 
             
                      mount app
         | 
| 2256 2410 | 
             
                    end
         | 
| @@ -2261,7 +2415,6 @@ describe Grape::API do | |
| 2261 2415 | 
             
                    options '/v1/apples/colour'
         | 
| 2262 2416 | 
             
                    expect(last_response.status).to eql 204
         | 
| 2263 2417 | 
             
                  end
         | 
| 2264 | 
            -
             | 
| 2265 2418 | 
             
                end
         | 
| 2266 2419 | 
             
              end
         | 
| 2267 2420 |  | 
| @@ -2289,7 +2442,7 @@ describe Grape::API do | |
| 2289 2442 | 
             
                end
         | 
| 2290 2443 | 
             
              end
         | 
| 2291 2444 |  | 
| 2292 | 
            -
              describe  | 
| 2445 | 
            +
              describe '.endpoint' do
         | 
| 2293 2446 | 
             
                before(:each) do
         | 
| 2294 2447 | 
             
                  subject.format :json
         | 
| 2295 2448 | 
             
                  subject.get '/endpoint/options' do
         | 
| @@ -2302,9 +2455,9 @@ describe Grape::API do | |
| 2302 2455 | 
             
                it 'path' do
         | 
| 2303 2456 | 
             
                  get '/endpoint/options'
         | 
| 2304 2457 | 
             
                  options = MultiJson.load(last_response.body)
         | 
| 2305 | 
            -
                  expect(options[ | 
| 2306 | 
            -
                  expect(options[ | 
| 2307 | 
            -
                  expect(options[ | 
| 2458 | 
            +
                  expect(options['path']).to eq(['/endpoint/options'])
         | 
| 2459 | 
            +
                  expect(options['source_location'][0]).to include 'api_spec.rb'
         | 
| 2460 | 
            +
                  expect(options['source_location'][1].to_i).to be > 0
         | 
| 2308 2461 | 
             
                end
         | 
| 2309 2462 | 
             
              end
         | 
| 2310 2463 |  | 
| @@ -2320,9 +2473,9 @@ describe Grape::API do | |
| 2320 2473 | 
             
                  end
         | 
| 2321 2474 | 
             
                  it 'provides access to route info' do
         | 
| 2322 2475 | 
             
                    get '/'
         | 
| 2323 | 
            -
                    expect(last_response.body).to eq( | 
| 2476 | 
            +
                    expect(last_response.body).to eq('/(.:format)')
         | 
| 2324 2477 | 
             
                    get '/path'
         | 
| 2325 | 
            -
                    expect(last_response.body).to eq( | 
| 2478 | 
            +
                    expect(last_response.body).to eq('/path(.:format)')
         | 
| 2326 2479 | 
             
                  end
         | 
| 2327 2480 | 
             
                end
         | 
| 2328 2481 | 
             
                context 'with desc' do
         | 
| @@ -2331,18 +2484,18 @@ describe Grape::API do | |
| 2331 2484 | 
             
                    subject.get '/description' do
         | 
| 2332 2485 | 
             
                      route.route_description
         | 
| 2333 2486 | 
             
                    end
         | 
| 2334 | 
            -
                    subject.desc 'returns parameters', params: {  | 
| 2487 | 
            +
                    subject.desc 'returns parameters', params: { 'x' => 'y' }
         | 
| 2335 2488 | 
             
                    subject.get '/params/:id' do
         | 
| 2336 2489 | 
             
                      route.route_params[params[:id]]
         | 
| 2337 2490 | 
             
                    end
         | 
| 2338 2491 | 
             
                  end
         | 
| 2339 2492 | 
             
                  it 'returns route description' do
         | 
| 2340 2493 | 
             
                    get '/description'
         | 
| 2341 | 
            -
                    expect(last_response.body).to eq( | 
| 2494 | 
            +
                    expect(last_response.body).to eq('returns description')
         | 
| 2342 2495 | 
             
                  end
         | 
| 2343 2496 | 
             
                  it 'returns route parameters' do
         | 
| 2344 2497 | 
             
                    get '/params/x'
         | 
| 2345 | 
            -
                    expect(last_response.body).to eq( | 
| 2498 | 
            +
                    expect(last_response.body).to eq('y')
         | 
| 2346 2499 | 
             
                  end
         | 
| 2347 2500 | 
             
                end
         | 
| 2348 2501 | 
             
              end
         | 
| @@ -2350,7 +2503,7 @@ describe Grape::API do | |
| 2350 2503 | 
             
                context ':txt' do
         | 
| 2351 2504 | 
             
                  before(:each) do
         | 
| 2352 2505 | 
             
                    subject.format :txt
         | 
| 2353 | 
            -
                    subject.content_type :json,  | 
| 2506 | 
            +
                    subject.content_type :json, 'application/json'
         | 
| 2354 2507 | 
             
                    subject.get '/meaning_of_life' do
         | 
| 2355 2508 | 
             
                      { meaning_of_life: 42 }
         | 
| 2356 2509 | 
             
                    end
         | 
| @@ -2379,9 +2532,9 @@ describe Grape::API do | |
| 2379 2532 | 
             
                    get '/meaning_of_life'
         | 
| 2380 2533 | 
             
                    expect(last_response.body).to eq({ meaning_of_life: 42 }.to_s)
         | 
| 2381 2534 | 
             
                  end
         | 
| 2382 | 
            -
                  it ' | 
| 2535 | 
            +
                  it 'does not accept any extensions' do
         | 
| 2383 2536 | 
             
                    get '/meaning_of_life.json'
         | 
| 2384 | 
            -
                    expect(last_response. | 
| 2537 | 
            +
                    expect(last_response.status).to eq(404)
         | 
| 2385 2538 | 
             
                  end
         | 
| 2386 2539 | 
             
                  it 'forces txt from a non-accepting header' do
         | 
| 2387 2540 | 
             
                    get '/meaning_of_life', {}, 'HTTP_ACCEPT' => 'application/json'
         | 
| @@ -2391,7 +2544,7 @@ describe Grape::API do | |
| 2391 2544 | 
             
                context ':json' do
         | 
| 2392 2545 | 
             
                  before(:each) do
         | 
| 2393 2546 | 
             
                    subject.format :json
         | 
| 2394 | 
            -
                    subject.content_type :txt,  | 
| 2547 | 
            +
                    subject.content_type :txt, 'text/plain'
         | 
| 2395 2548 | 
             
                    subject.get '/meaning_of_life' do
         | 
| 2396 2549 | 
             
                      { meaning_of_life: 42 }
         | 
| 2397 2550 | 
             
                    end
         | 
| @@ -2410,7 +2563,7 @@ describe Grape::API do | |
| 2410 2563 | 
             
                  end
         | 
| 2411 2564 | 
             
                  it 'can be overwritten with an explicit content type' do
         | 
| 2412 2565 | 
             
                    subject.get '/meaning_of_life_with_content_type' do
         | 
| 2413 | 
            -
                      content_type  | 
| 2566 | 
            +
                      content_type 'text/plain'
         | 
| 2414 2567 | 
             
                      { meaning_of_life: 42 }.to_s
         | 
| 2415 2568 | 
             
                    end
         | 
| 2416 2569 | 
             
                    get '/meaning_of_life_with_content_type'
         | 
| @@ -2419,18 +2572,16 @@ describe Grape::API do | |
| 2419 2572 | 
             
                  it 'raised :error from middleware' do
         | 
| 2420 2573 | 
             
                    middleware = Class.new(Grape::Middleware::Base) do
         | 
| 2421 2574 | 
             
                      def before
         | 
| 2422 | 
            -
                        throw :error, message:  | 
| 2575 | 
            +
                        throw :error, message: 'Unauthorized', status: 42
         | 
| 2423 2576 | 
             
                      end
         | 
| 2424 2577 | 
             
                    end
         | 
| 2425 2578 | 
             
                    subject.use middleware
         | 
| 2426 2579 | 
             
                    subject.get do
         | 
| 2427 | 
            -
             | 
| 2428 2580 | 
             
                    end
         | 
| 2429 | 
            -
                    get  | 
| 2581 | 
            +
                    get '/'
         | 
| 2430 2582 | 
             
                    expect(last_response.status).to eq(42)
         | 
| 2431 | 
            -
                    expect(last_response.body).to eq({ error:  | 
| 2583 | 
            +
                    expect(last_response.body).to eq({ error: 'Unauthorized' }.to_json)
         | 
| 2432 2584 | 
             
                  end
         | 
| 2433 | 
            -
             | 
| 2434 2585 | 
             
                end
         | 
| 2435 2586 | 
             
                context ':serializable_hash' do
         | 
| 2436 2587 | 
             
                  before(:each) do
         | 
| @@ -2450,7 +2601,7 @@ describe Grape::API do | |
| 2450 2601 | 
             
                  end
         | 
| 2451 2602 | 
             
                  it 'root' do
         | 
| 2452 2603 | 
             
                    subject.get '/example' do
         | 
| 2453 | 
            -
                      {  | 
| 2604 | 
            +
                      { 'root' => SerializableHashExample.new }
         | 
| 2454 2605 | 
             
                    end
         | 
| 2455 2606 | 
             
                    get '/example'
         | 
| 2456 2607 | 
             
                    expect(last_response.body).to eq('{"root":{"abc":"def"}}')
         | 
| @@ -2463,13 +2614,13 @@ describe Grape::API do | |
| 2463 2614 | 
             
                    expect(last_response.body).to eq('[{"abc":"def"},{"abc":"def"}]')
         | 
| 2464 2615 | 
             
                  end
         | 
| 2465 2616 | 
             
                end
         | 
| 2466 | 
            -
                context  | 
| 2617 | 
            +
                context ':xml' do
         | 
| 2467 2618 | 
             
                  before(:each) do
         | 
| 2468 2619 | 
             
                    subject.format :xml
         | 
| 2469 2620 | 
             
                  end
         | 
| 2470 2621 | 
             
                  it 'string' do
         | 
| 2471 | 
            -
                    subject.get  | 
| 2472 | 
            -
                       | 
| 2622 | 
            +
                    subject.get '/example' do
         | 
| 2623 | 
            +
                      'example'
         | 
| 2473 2624 | 
             
                    end
         | 
| 2474 2625 | 
             
                    get '/example'
         | 
| 2475 2626 | 
             
                    expect(last_response.status).to eq(500)
         | 
| @@ -2481,10 +2632,10 @@ describe Grape::API do | |
| 2481 2632 | 
             
            XML
         | 
| 2482 2633 | 
             
                  end
         | 
| 2483 2634 | 
             
                  it 'hash' do
         | 
| 2484 | 
            -
                    subject.get  | 
| 2635 | 
            +
                    subject.get '/example' do
         | 
| 2485 2636 | 
             
                      ActiveSupport::OrderedHash[
         | 
| 2486 | 
            -
                        :example1,  | 
| 2487 | 
            -
                        :example2,  | 
| 2637 | 
            +
                        :example1, 'example1',
         | 
| 2638 | 
            +
                        :example2, 'example2'
         | 
| 2488 2639 | 
             
                    ]
         | 
| 2489 2640 | 
             
                    end
         | 
| 2490 2641 | 
             
                    get '/example'
         | 
| @@ -2498,8 +2649,8 @@ XML | |
| 2498 2649 | 
             
            XML
         | 
| 2499 2650 | 
             
                  end
         | 
| 2500 2651 | 
             
                  it 'array' do
         | 
| 2501 | 
            -
                    subject.get  | 
| 2502 | 
            -
                       | 
| 2652 | 
            +
                    subject.get '/example' do
         | 
| 2653 | 
            +
                      %w(example1 example2)
         | 
| 2503 2654 | 
             
                    end
         | 
| 2504 2655 | 
             
                    get '/example'
         | 
| 2505 2656 | 
             
                    expect(last_response.status).to eq(200)
         | 
| @@ -2514,14 +2665,13 @@ XML | |
| 2514 2665 | 
             
                  it 'raised :error from middleware' do
         | 
| 2515 2666 | 
             
                    middleware = Class.new(Grape::Middleware::Base) do
         | 
| 2516 2667 | 
             
                      def before
         | 
| 2517 | 
            -
                        throw :error, message:  | 
| 2668 | 
            +
                        throw :error, message: 'Unauthorized', status: 42
         | 
| 2518 2669 | 
             
                      end
         | 
| 2519 2670 | 
             
                    end
         | 
| 2520 2671 | 
             
                    subject.use middleware
         | 
| 2521 2672 | 
             
                    subject.get do
         | 
| 2522 | 
            -
             | 
| 2523 2673 | 
             
                    end
         | 
| 2524 | 
            -
                    get  | 
| 2674 | 
            +
                    get '/'
         | 
| 2525 2675 | 
             
                    expect(last_response.status).to eq(42)
         | 
| 2526 2676 | 
             
                    expect(last_response.body).to eq <<-XML
         | 
| 2527 2677 | 
             
            <?xml version="1.0" encoding="UTF-8"?>
         | 
| @@ -2533,17 +2683,17 @@ XML | |
| 2533 2683 | 
             
                end
         | 
| 2534 2684 | 
             
              end
         | 
| 2535 2685 |  | 
| 2536 | 
            -
              context  | 
| 2686 | 
            +
              context 'catch-all' do
         | 
| 2537 2687 | 
             
                before do
         | 
| 2538 2688 | 
             
                  api1 = Class.new(Grape::API)
         | 
| 2539 2689 | 
             
                  api1.version 'v1', using: :path
         | 
| 2540 | 
            -
                  api1.get  | 
| 2541 | 
            -
                     | 
| 2690 | 
            +
                  api1.get 'hello' do
         | 
| 2691 | 
            +
                    'v1'
         | 
| 2542 2692 | 
             
                  end
         | 
| 2543 2693 | 
             
                  api2 = Class.new(Grape::API)
         | 
| 2544 2694 | 
             
                  api2.version 'v2', using: :path
         | 
| 2545 | 
            -
                  api2.get  | 
| 2546 | 
            -
                     | 
| 2695 | 
            +
                  api2.get 'hello' do
         | 
| 2696 | 
            +
                    'v2'
         | 
| 2547 2697 | 
             
                  end
         | 
| 2548 2698 | 
             
                  subject.mount api1
         | 
| 2549 2699 | 
             
                  subject.mount api2
         | 
| @@ -2553,53 +2703,53 @@ XML | |
| 2553 2703 | 
             
                    subject.route :any, '*path', anchor: anchor do
         | 
| 2554 2704 | 
             
                      error!("Unrecognized request path: #{params[:path] } - #{env['PATH_INFO'] }#{env['SCRIPT_NAME'] }", 404)
         | 
| 2555 2705 | 
             
                    end
         | 
| 2556 | 
            -
                    get  | 
| 2706 | 
            +
                    get '/v1/hello'
         | 
| 2557 2707 | 
             
                    expect(last_response.status).to eq(200)
         | 
| 2558 | 
            -
                    expect(last_response.body).to eq( | 
| 2559 | 
            -
                    get  | 
| 2708 | 
            +
                    expect(last_response.body).to eq('v1')
         | 
| 2709 | 
            +
                    get '/v2/hello'
         | 
| 2560 2710 | 
             
                    expect(last_response.status).to eq(200)
         | 
| 2561 | 
            -
                    expect(last_response.body).to eq( | 
| 2562 | 
            -
                    get  | 
| 2711 | 
            +
                    expect(last_response.body).to eq('v2')
         | 
| 2712 | 
            +
                    get '/foobar'
         | 
| 2563 2713 | 
             
                    expect(last_response.status).to eq(404)
         | 
| 2564 | 
            -
                    expect(last_response.body).to eq( | 
| 2714 | 
            +
                    expect(last_response.body).to eq('Unrecognized request path: foobar - /foobar')
         | 
| 2565 2715 | 
             
                  end
         | 
| 2566 2716 | 
             
                end
         | 
| 2567 2717 | 
             
              end
         | 
| 2568 2718 |  | 
| 2569 | 
            -
              context  | 
| 2570 | 
            -
                context  | 
| 2571 | 
            -
                  it  | 
| 2719 | 
            +
              context 'cascading' do
         | 
| 2720 | 
            +
                context 'via version' do
         | 
| 2721 | 
            +
                  it 'cascades' do
         | 
| 2572 2722 | 
             
                    subject.version 'v1', using: :path, cascade: true
         | 
| 2573 | 
            -
                    get  | 
| 2723 | 
            +
                    get '/v1/hello'
         | 
| 2574 2724 | 
             
                    expect(last_response.status).to eq(404)
         | 
| 2575 | 
            -
                    expect(last_response.headers[ | 
| 2725 | 
            +
                    expect(last_response.headers['X-Cascade']).to eq('pass')
         | 
| 2576 2726 | 
             
                  end
         | 
| 2577 | 
            -
                  it  | 
| 2727 | 
            +
                  it 'does not cascade' do
         | 
| 2578 2728 | 
             
                    subject.version 'v2', using: :path, cascade: false
         | 
| 2579 | 
            -
                    get  | 
| 2729 | 
            +
                    get '/v2/hello'
         | 
| 2580 2730 | 
             
                    expect(last_response.status).to eq(404)
         | 
| 2581 | 
            -
                    expect(last_response.headers.keys).not_to include  | 
| 2731 | 
            +
                    expect(last_response.headers.keys).not_to include 'X-Cascade'
         | 
| 2582 2732 | 
             
                  end
         | 
| 2583 2733 | 
             
                end
         | 
| 2584 | 
            -
                context  | 
| 2585 | 
            -
                  it  | 
| 2734 | 
            +
                context 'via endpoint' do
         | 
| 2735 | 
            +
                  it 'cascades' do
         | 
| 2586 2736 | 
             
                    subject.cascade true
         | 
| 2587 | 
            -
                    get  | 
| 2737 | 
            +
                    get '/hello'
         | 
| 2588 2738 | 
             
                    expect(last_response.status).to eq(404)
         | 
| 2589 | 
            -
                    expect(last_response.headers[ | 
| 2739 | 
            +
                    expect(last_response.headers['X-Cascade']).to eq('pass')
         | 
| 2590 2740 | 
             
                  end
         | 
| 2591 | 
            -
                  it  | 
| 2741 | 
            +
                  it 'does not cascade' do
         | 
| 2592 2742 | 
             
                    subject.cascade false
         | 
| 2593 | 
            -
                    get  | 
| 2743 | 
            +
                    get '/hello'
         | 
| 2594 2744 | 
             
                    expect(last_response.status).to eq(404)
         | 
| 2595 | 
            -
                    expect(last_response.headers.keys).not_to include  | 
| 2745 | 
            +
                    expect(last_response.headers.keys).not_to include 'X-Cascade'
         | 
| 2596 2746 | 
             
                  end
         | 
| 2597 2747 | 
             
                end
         | 
| 2598 2748 | 
             
              end
         | 
| 2599 2749 |  | 
| 2600 2750 | 
             
              context 'with json default_error_formatter' do
         | 
| 2601 2751 | 
             
                it 'returns json error' do
         | 
| 2602 | 
            -
                  subject.content_type :json,  | 
| 2752 | 
            +
                  subject.content_type :json, 'application/json'
         | 
| 2603 2753 | 
             
                  subject.default_error_formatter :json
         | 
| 2604 2754 | 
             
                  subject.get '/something' do
         | 
| 2605 2755 | 
             
                    'foo'
         | 
| @@ -2609,4 +2759,33 @@ XML | |
| 2609 2759 | 
             
                  expect(last_response.body).to eq("{\"error\":\"The requested format 'txt' is not supported.\"}")
         | 
| 2610 2760 | 
             
                end
         | 
| 2611 2761 | 
             
              end
         | 
| 2762 | 
            +
             | 
| 2763 | 
            +
              context 'body' do
         | 
| 2764 | 
            +
                context 'false' do
         | 
| 2765 | 
            +
                  before do
         | 
| 2766 | 
            +
                    subject.get '/blank' do
         | 
| 2767 | 
            +
                      body false
         | 
| 2768 | 
            +
                    end
         | 
| 2769 | 
            +
                  end
         | 
| 2770 | 
            +
                  it 'returns blank body' do
         | 
| 2771 | 
            +
                    get '/blank'
         | 
| 2772 | 
            +
                    expect(last_response.status).to eq(204)
         | 
| 2773 | 
            +
                    expect(last_response.body).to be_blank
         | 
| 2774 | 
            +
                  end
         | 
| 2775 | 
            +
                end
         | 
| 2776 | 
            +
                context 'plain text' do
         | 
| 2777 | 
            +
                  before do
         | 
| 2778 | 
            +
                    subject.get '/text' do
         | 
| 2779 | 
            +
                      content_type 'text/plain'
         | 
| 2780 | 
            +
                      body 'Hello World'
         | 
| 2781 | 
            +
                      'ignored'
         | 
| 2782 | 
            +
                    end
         | 
| 2783 | 
            +
                  end
         | 
| 2784 | 
            +
                  it 'returns blank body' do
         | 
| 2785 | 
            +
                    get '/text'
         | 
| 2786 | 
            +
                    expect(last_response.status).to eq(200)
         | 
| 2787 | 
            +
                    expect(last_response.body).to eq 'Hello World'
         | 
| 2788 | 
            +
                  end
         | 
| 2789 | 
            +
                end
         | 
| 2790 | 
            +
              end
         | 
| 2612 2791 | 
             
            end
         |