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
    
        data/lib/grape.rb
    CHANGED
    
    | @@ -7,11 +7,19 @@ require 'rack/auth/basic' | |
| 7 7 | 
             
            require 'rack/auth/digest/md5'
         | 
| 8 8 | 
             
            require 'hashie'
         | 
| 9 9 | 
             
            require 'set'
         | 
| 10 | 
            +
            require 'active_support/version'
         | 
| 10 11 | 
             
            require 'active_support/core_ext/hash/indifferent_access'
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            if ActiveSupport::VERSION::MAJOR >= 4
         | 
| 14 | 
            +
              require 'active_support/core_ext/object/deep_dup'
         | 
| 15 | 
            +
            else
         | 
| 16 | 
            +
              require_relative 'backports/active_support/deep_dup'
         | 
| 17 | 
            +
            end
         | 
| 18 | 
            +
             | 
| 11 19 | 
             
            require 'active_support/ordered_hash'
         | 
| 12 20 | 
             
            require 'active_support/core_ext/object/conversions'
         | 
| 13 21 | 
             
            require 'active_support/core_ext/array/extract_options'
         | 
| 14 | 
            -
            require ' | 
| 22 | 
            +
            require 'active_support/core_ext/hash/deep_merge'
         | 
| 15 23 | 
             
            require 'grape/util/content_types'
         | 
| 16 24 | 
             
            require 'multi_json'
         | 
| 17 25 | 
             
            require 'multi_xml'
         | 
| @@ -92,11 +100,16 @@ module Grape | |
| 92 100 | 
             
              end
         | 
| 93 101 |  | 
| 94 102 | 
             
              module Util
         | 
| 95 | 
            -
                autoload : | 
| 103 | 
            +
                autoload :InheritableValues, 'grape/util/inheritable_values'
         | 
| 104 | 
            +
                autoload :StackableValues,   'grape/util/stackable_values'
         | 
| 105 | 
            +
                autoload :InheritableSetting, 'grape/util/inheritable_setting'
         | 
| 106 | 
            +
                autoload :StrictHashConfiguration, 'grape/util/strict_hash_configuration'
         | 
| 96 107 | 
             
              end
         | 
| 97 108 |  | 
| 98 109 | 
             
              module DSL
         | 
| 110 | 
            +
                autoload :API,               'grape/dsl/api'
         | 
| 99 111 | 
             
                autoload :Callbacks,         'grape/dsl/callbacks'
         | 
| 112 | 
            +
                autoload :Settings,          'grape/dsl/settings'
         | 
| 100 113 | 
             
                autoload :Configuration,     'grape/dsl/configuration'
         | 
| 101 114 | 
             
                autoload :InsideRoute,       'grape/dsl/inside_route'
         | 
| 102 115 | 
             
                autoload :Helpers,           'grape/dsl/helpers'
         | 
| @@ -112,4 +125,18 @@ module Grape | |
| 112 125 | 
             
              end
         | 
| 113 126 | 
             
            end
         | 
| 114 127 |  | 
| 128 | 
            +
            require 'grape/validations/validators/base'
         | 
| 129 | 
            +
            require 'grape/validations/attributes_iterator'
         | 
| 130 | 
            +
            require 'grape/validations/validators/allow_blank'
         | 
| 131 | 
            +
            require 'grape/validations/validators/at_least_one_of'
         | 
| 132 | 
            +
            require 'grape/validations/validators/coerce'
         | 
| 133 | 
            +
            require 'grape/validations/validators/default'
         | 
| 134 | 
            +
            require 'grape/validations/validators/exactly_one_of'
         | 
| 135 | 
            +
            require 'grape/validations/validators/mutual_exclusion'
         | 
| 136 | 
            +
            require 'grape/validations/validators/presence'
         | 
| 137 | 
            +
            require 'grape/validations/validators/regexp'
         | 
| 138 | 
            +
            require 'grape/validations/validators/values'
         | 
| 139 | 
            +
            require 'grape/validations/params_scope'
         | 
| 140 | 
            +
            require 'grape/validations/validators/all_or_none'
         | 
| 141 | 
            +
             | 
| 115 142 | 
             
            require 'grape/version'
         | 
    
        data/lib/grape/api.rb
    CHANGED
    
    | @@ -3,23 +3,13 @@ module Grape | |
| 3 3 | 
             
              # creating Grape APIs.Users should subclass this
         | 
| 4 4 | 
             
              # class in order to build an API.
         | 
| 5 5 | 
             
              class API
         | 
| 6 | 
            -
                 | 
| 7 | 
            -
             | 
| 8 | 
            -
                include Grape::DSL::Validations
         | 
| 9 | 
            -
                include Grape::DSL::Callbacks
         | 
| 10 | 
            -
                include Grape::DSL::Configuration
         | 
| 11 | 
            -
                include Grape::DSL::Helpers
         | 
| 12 | 
            -
                include Grape::DSL::Middleware
         | 
| 13 | 
            -
                include Grape::DSL::RequestResponse
         | 
| 14 | 
            -
                include Grape::DSL::Routing
         | 
| 6 | 
            +
                include Grape::DSL::API
         | 
| 15 7 |  | 
| 16 8 | 
             
                class << self
         | 
| 17 9 | 
             
                  attr_reader :instance
         | 
| 18 | 
            -
             | 
| 19 10 | 
             
                  LOCK = Mutex.new
         | 
| 20 11 |  | 
| 21 12 | 
             
                  def reset!
         | 
| 22 | 
            -
                    @settings  = Grape::Util::HashStack.new
         | 
| 23 13 | 
             
                    @route_set = Rack::Mount::RouteSet.new
         | 
| 24 14 | 
             
                    @endpoints = []
         | 
| 25 15 | 
             
                    @routes = nil
         | 
| @@ -45,36 +35,21 @@ module Grape | |
| 45 35 |  | 
| 46 36 | 
             
                  # Create a scope without affecting the URL.
         | 
| 47 37 | 
             
                  #
         | 
| 48 | 
            -
                  # @param name [Symbol] Purely placebo, just allows to  | 
| 38 | 
            +
                  # @param name [Symbol] Purely placebo, just allows to name the scope to make the code more readable.
         | 
| 49 39 | 
             
                  def scope(name = nil, &block)
         | 
| 50 | 
            -
                     | 
| 40 | 
            +
                    within_namespace do
         | 
| 41 | 
            +
                      nest(block)
         | 
| 42 | 
            +
                    end
         | 
| 51 43 | 
             
                  end
         | 
| 52 44 |  | 
| 53 45 | 
             
                  def cascade(value = nil)
         | 
| 54 46 | 
             
                    if value.nil?
         | 
| 55 | 
            -
                       | 
| 47 | 
            +
                      inheritable_setting.namespace_inheritable.keys.include?(:cascade) ? !!namespace_inheritable(:cascade) : true
         | 
| 56 48 | 
             
                    else
         | 
| 57 | 
            -
                       | 
| 49 | 
            +
                      namespace_inheritable(:cascade, value)
         | 
| 58 50 | 
             
                    end
         | 
| 59 51 | 
             
                  end
         | 
| 60 52 |  | 
| 61 | 
            -
                  # Set a configuration value for this namespace.
         | 
| 62 | 
            -
                  #
         | 
| 63 | 
            -
                  # @param key [Symbol] The key of the configuration variable.
         | 
| 64 | 
            -
                  # @param value [Object] The value to which to set the configuration variable.
         | 
| 65 | 
            -
                  def set(key, value)
         | 
| 66 | 
            -
                    settings[key.to_sym] = value
         | 
| 67 | 
            -
                  end
         | 
| 68 | 
            -
             | 
| 69 | 
            -
                  # Add to a configuration value for this
         | 
| 70 | 
            -
                  # namespace.
         | 
| 71 | 
            -
                  #
         | 
| 72 | 
            -
                  # @param key [Symbol] The key of the configuration variable.
         | 
| 73 | 
            -
                  # @param value [Object] The value to which to set the configuration variable.
         | 
| 74 | 
            -
                  def imbue(key, value)
         | 
| 75 | 
            -
                    settings.imbue(key, value)
         | 
| 76 | 
            -
                  end
         | 
| 77 | 
            -
             | 
| 78 53 | 
             
                  protected
         | 
| 79 54 |  | 
| 80 55 | 
             
                  def prepare_routes
         | 
| @@ -89,12 +64,10 @@ module Grape | |
| 89 64 | 
             
                  # block passed in. Allows for simple 'before' setups
         | 
| 90 65 | 
             
                  # of settings stack pushes.
         | 
| 91 66 | 
             
                  def nest(*blocks, &block)
         | 
| 92 | 
            -
                    blocks.reject! | 
| 67 | 
            +
                    blocks.reject!(&:nil?)
         | 
| 93 68 | 
             
                    if blocks.any?
         | 
| 94 | 
            -
                      settings.push  # create a new context to eval the follow
         | 
| 95 69 | 
             
                      instance_eval(&block) if block_given?
         | 
| 96 70 | 
             
                      blocks.each { |b| instance_eval(&b) }
         | 
| 97 | 
            -
                      settings.pop # when finished, we pop the context
         | 
| 98 71 | 
             
                      reset_validations!
         | 
| 99 72 | 
             
                    else
         | 
| 100 73 | 
             
                      instance_eval(&block)
         | 
| @@ -106,12 +79,12 @@ module Grape | |
| 106 79 | 
             
                    subclass.logger = logger.clone
         | 
| 107 80 | 
             
                  end
         | 
| 108 81 |  | 
| 109 | 
            -
                  def inherit_settings( | 
| 110 | 
            -
                     | 
| 111 | 
            -
             | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 114 | 
            -
                     | 
| 82 | 
            +
                  def inherit_settings(other_settings)
         | 
| 83 | 
            +
                    top_level_setting.inherit_from other_settings.point_in_time_copy
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                    endpoints.each(&:reset_routes!)
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                    @routes = nil
         | 
| 115 88 | 
             
                  end
         | 
| 116 89 | 
             
                end
         | 
| 117 90 |  | 
| @@ -121,6 +94,7 @@ module Grape | |
| 121 94 | 
             
                  self.class.endpoints.each do |endpoint|
         | 
| 122 95 | 
             
                    endpoint.mount_in(@route_set)
         | 
| 123 96 | 
             
                  end
         | 
| 97 | 
            +
             | 
| 124 98 | 
             
                  @route_set.freeze
         | 
| 125 99 | 
             
                end
         | 
| 126 100 |  | 
| @@ -139,8 +113,8 @@ module Grape | |
| 139 113 | 
             
                # errors from reaching upstream. This is effectivelly done by unsetting
         | 
| 140 114 | 
             
                # X-Cascade. Default :cascade is true.
         | 
| 141 115 | 
             
                def cascade?
         | 
| 142 | 
            -
                  return !!self.class. | 
| 143 | 
            -
                  return !!self.class. | 
| 116 | 
            +
                  return !!self.class.namespace_inheritable(:cascade) if self.class.inheritable_setting.namespace_inheritable.keys.include?(:cascade)
         | 
| 117 | 
            +
                  return !!self.class.namespace_inheritable(:version_options)[:cascade] if self.class.namespace_inheritable(:version_options) && self.class.namespace_inheritable(:version_options).key?(:cascade)
         | 
| 144 118 | 
             
                  true
         | 
| 145 119 | 
             
                end
         | 
| 146 120 |  | 
| @@ -154,6 +128,7 @@ module Grape | |
| 154 128 | 
             
                # cannot handle.
         | 
| 155 129 | 
             
                def add_head_not_allowed_methods_and_options_methods
         | 
| 156 130 | 
             
                  methods_per_path = {}
         | 
| 131 | 
            +
             | 
| 157 132 | 
             
                  self.class.endpoints.each do |endpoint|
         | 
| 158 133 | 
             
                    routes = endpoint.routes
         | 
| 159 134 | 
             
                    routes.each do |route|
         | 
| @@ -166,39 +141,58 @@ module Grape | |
| 166 141 | 
             
                  # contain already versioning information when using path versioning.
         | 
| 167 142 | 
             
                  # Disable versioning so adding a route won't prepend versioning
         | 
| 168 143 | 
             
                  # informations again.
         | 
| 169 | 
            -
                   | 
| 170 | 
            -
                     | 
| 171 | 
            -
                       | 
| 172 | 
            -
             | 
| 173 | 
            -
                         | 
| 174 | 
            -
             | 
| 144 | 
            +
                  without_root_prefix do
         | 
| 145 | 
            +
                    without_versioning do
         | 
| 146 | 
            +
                      methods_per_path.each do |path, methods|
         | 
| 147 | 
            +
                        allowed_methods = methods.dup
         | 
| 148 | 
            +
                        unless self.class.namespace_inheritable(:do_not_route_head)
         | 
| 149 | 
            +
                          allowed_methods |= ['HEAD'] if allowed_methods.include?('GET')
         | 
| 150 | 
            +
                        end
         | 
| 175 151 |  | 
| 176 | 
            -
             | 
| 177 | 
            -
             | 
| 178 | 
            -
             | 
| 179 | 
            -
             | 
| 180 | 
            -
             | 
| 181 | 
            -
             | 
| 182 | 
            -
             | 
| 152 | 
            +
                        allow_header = (['OPTIONS'] | allowed_methods).join(', ')
         | 
| 153 | 
            +
                        unless self.class.namespace_inheritable(:do_not_route_options)
         | 
| 154 | 
            +
                          unless allowed_methods.include?('OPTIONS')
         | 
| 155 | 
            +
                            self.class.options(path, {}) do
         | 
| 156 | 
            +
                              header 'Allow', allow_header
         | 
| 157 | 
            +
                              status 204
         | 
| 158 | 
            +
                              ''
         | 
| 159 | 
            +
                            end
         | 
| 183 160 | 
             
                          end
         | 
| 184 161 | 
             
                        end
         | 
| 185 | 
            -
                      end
         | 
| 186 162 |  | 
| 187 | 
            -
             | 
| 188 | 
            -
             | 
| 189 | 
            -
             | 
| 190 | 
            -
             | 
| 191 | 
            -
             | 
| 192 | 
            -
             | 
| 163 | 
            +
                        not_allowed_methods = %w(GET PUT POST DELETE PATCH HEAD) - allowed_methods
         | 
| 164 | 
            +
                        not_allowed_methods << 'OPTIONS' if self.class.namespace_inheritable(:do_not_route_options)
         | 
| 165 | 
            +
                        self.class.route(not_allowed_methods, path) do
         | 
| 166 | 
            +
                          header 'Allow', allow_header
         | 
| 167 | 
            +
                          status 405
         | 
| 168 | 
            +
                          ''
         | 
| 169 | 
            +
                        end
         | 
| 193 170 | 
             
                      end
         | 
| 194 171 | 
             
                    end
         | 
| 195 172 | 
             
                  end
         | 
| 196 173 | 
             
                end
         | 
| 197 174 |  | 
| 198 175 | 
             
                def without_versioning(&block)
         | 
| 199 | 
            -
                  self.class. | 
| 176 | 
            +
                  old_version = self.class.namespace_inheritable(:version)
         | 
| 177 | 
            +
                  old_version_options = self.class.namespace_inheritable(:version_options)
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                  self.class.namespace_inheritable_to_nil(:version)
         | 
| 180 | 
            +
                  self.class.namespace_inheritable_to_nil(:version_options)
         | 
| 181 | 
            +
             | 
| 200 182 | 
             
                  yield
         | 
| 201 | 
            -
             | 
| 183 | 
            +
             | 
| 184 | 
            +
                  self.class.namespace_inheritable(:version, old_version)
         | 
| 185 | 
            +
                  self.class.namespace_inheritable(:version_options, old_version_options)
         | 
| 186 | 
            +
                end
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                def without_root_prefix(&block)
         | 
| 189 | 
            +
                  old_prefix = self.class.namespace_inheritable(:root_prefix)
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                  self.class.namespace_inheritable_to_nil(:root_prefix)
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                  yield
         | 
| 194 | 
            +
             | 
| 195 | 
            +
                  self.class.namespace_inheritable(:root_prefix, old_prefix)
         | 
| 202 196 | 
             
                end
         | 
| 203 197 | 
             
              end
         | 
| 204 198 | 
             
            end
         | 
| @@ -0,0 +1,19 @@ | |
| 1 | 
            +
            require 'active_support/concern'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Grape
         | 
| 4 | 
            +
              module DSL
         | 
| 5 | 
            +
                module API
         | 
| 6 | 
            +
                  extend ActiveSupport::Concern
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  include Grape::Middleware::Auth::DSL
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                  include Grape::DSL::Validations
         | 
| 11 | 
            +
                  include Grape::DSL::Callbacks
         | 
| 12 | 
            +
                  include Grape::DSL::Configuration
         | 
| 13 | 
            +
                  include Grape::DSL::Helpers
         | 
| 14 | 
            +
                  include Grape::DSL::Middleware
         | 
| 15 | 
            +
                  include Grape::DSL::RequestResponse
         | 
| 16 | 
            +
                  include Grape::DSL::Routing
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
            end
         | 
    
        data/lib/grape/dsl/callbacks.rb
    CHANGED
    
    | @@ -5,21 +5,23 @@ module Grape | |
| 5 5 | 
             
                module Callbacks
         | 
| 6 6 | 
             
                  extend ActiveSupport::Concern
         | 
| 7 7 |  | 
| 8 | 
            +
                  include Grape::DSL::Configuration
         | 
| 9 | 
            +
             | 
| 8 10 | 
             
                  module ClassMethods
         | 
| 9 11 | 
             
                    def before(&block)
         | 
| 10 | 
            -
                       | 
| 12 | 
            +
                      namespace_stackable(:befores, block)
         | 
| 11 13 | 
             
                    end
         | 
| 12 14 |  | 
| 13 15 | 
             
                    def before_validation(&block)
         | 
| 14 | 
            -
                       | 
| 16 | 
            +
                      namespace_stackable(:before_validations, block)
         | 
| 15 17 | 
             
                    end
         | 
| 16 18 |  | 
| 17 19 | 
             
                    def after_validation(&block)
         | 
| 18 | 
            -
                       | 
| 20 | 
            +
                      namespace_stackable(:after_validations, block)
         | 
| 19 21 | 
             
                    end
         | 
| 20 22 |  | 
| 21 23 | 
             
                    def after(&block)
         | 
| 22 | 
            -
                       | 
| 24 | 
            +
                      namespace_stackable(:afters, block)
         | 
| 23 25 | 
             
                    end
         | 
| 24 26 | 
             
                  end
         | 
| 25 27 | 
             
                end
         | 
| @@ -7,19 +7,63 @@ module Grape | |
| 7 7 |  | 
| 8 8 | 
             
                  module ClassMethods
         | 
| 9 9 | 
             
                    attr_writer :logger
         | 
| 10 | 
            -
             | 
| 10 | 
            +
             | 
| 11 | 
            +
                    include Grape::DSL::Settings
         | 
| 11 12 |  | 
| 12 13 | 
             
                    def logger(logger = nil)
         | 
| 13 14 | 
             
                      if logger
         | 
| 14 | 
            -
                         | 
| 15 | 
            +
                        global_setting(:logger, logger)
         | 
| 15 16 | 
             
                      else
         | 
| 16 | 
            -
                         | 
| 17 | 
            +
                        global_setting(:logger) || global_setting(:logger, Logger.new($stdout))
         | 
| 17 18 | 
             
                      end
         | 
| 18 19 | 
             
                    end
         | 
| 19 20 |  | 
| 20 21 | 
             
                    # Add a description to the next namespace or function.
         | 
| 21 | 
            -
                    def desc(description, options = {})
         | 
| 22 | 
            -
                       | 
| 22 | 
            +
                    def desc(description, options = {}, &config_block)
         | 
| 23 | 
            +
                      if block_given?
         | 
| 24 | 
            +
                        config_class = Grape::DSL::Configuration.desc_container
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                        config_class.configure do
         | 
| 27 | 
            +
                          description description
         | 
| 28 | 
            +
                        end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                        config_class.configure(&config_block)
         | 
| 31 | 
            +
                        options = config_class.settings
         | 
| 32 | 
            +
                      else
         | 
| 33 | 
            +
                        options = options.merge(description: description)
         | 
| 34 | 
            +
                      end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                      namespace_setting :description, options
         | 
| 37 | 
            +
                      route_setting :description, options
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                  module_function
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  def stacked_hash_to_hash(settings)
         | 
| 44 | 
            +
                    return nil if settings.nil? || settings.blank?
         | 
| 45 | 
            +
                    settings.each_with_object(ActiveSupport::OrderedHash.new) { |value, result| result.deep_merge!(value) }
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  def desc_container
         | 
| 49 | 
            +
                    Module.new do
         | 
| 50 | 
            +
                      include Grape::Util::StrictHashConfiguration.module(
         | 
| 51 | 
            +
                                  :description,
         | 
| 52 | 
            +
                                  :detail,
         | 
| 53 | 
            +
                                  :params,
         | 
| 54 | 
            +
                                  :entity,
         | 
| 55 | 
            +
                                  :http_codes,
         | 
| 56 | 
            +
                                  :named,
         | 
| 57 | 
            +
                                  :headers
         | 
| 58 | 
            +
                      )
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                      def config_context.success(*args)
         | 
| 61 | 
            +
                        entity(*args)
         | 
| 62 | 
            +
                      end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                      def config_context.failure(*args)
         | 
| 65 | 
            +
                        http_codes(*args)
         | 
| 66 | 
            +
                      end
         | 
| 23 67 | 
             
                    end
         | 
| 24 68 | 
             
                  end
         | 
| 25 69 | 
             
                end
         | 
    
        data/lib/grape/dsl/helpers.rb
    CHANGED
    
    | @@ -4,6 +4,7 @@ module Grape | |
| 4 4 | 
             
              module DSL
         | 
| 5 5 | 
             
                module Helpers
         | 
| 6 6 | 
             
                  extend ActiveSupport::Concern
         | 
| 7 | 
            +
                  include Grape::DSL::Configuration
         | 
| 7 8 |  | 
| 8 9 | 
             
                  module ClassMethods
         | 
| 9 10 | 
             
                    # Add helper methods that will be accessible from any
         | 
| @@ -27,23 +28,21 @@ module Grape | |
| 27 28 | 
             
                    #
         | 
| 28 29 | 
             
                    def helpers(new_mod = nil, &block)
         | 
| 29 30 | 
             
                      if block_given? || new_mod
         | 
| 30 | 
            -
                        mod =  | 
| 31 | 
            +
                        mod = new_mod || Module.new
         | 
| 31 32 | 
             
                        if new_mod
         | 
| 32 33 | 
             
                          inject_api_helpers_to_mod(new_mod) if new_mod.is_a?(BaseHelper)
         | 
| 33 | 
            -
                          mod.class_eval do
         | 
| 34 | 
            -
                            include new_mod
         | 
| 35 | 
            -
                          end
         | 
| 36 34 | 
             
                        end
         | 
| 37 35 | 
             
                        if block_given?
         | 
| 38 36 | 
             
                          inject_api_helpers_to_mod(mod) do
         | 
| 39 37 | 
             
                            mod.class_eval(&block)
         | 
| 40 38 | 
             
                          end
         | 
| 41 39 | 
             
                        end
         | 
| 42 | 
            -
             | 
| 40 | 
            +
             | 
| 41 | 
            +
                        namespace_stackable(:helpers, mod)
         | 
| 43 42 | 
             
                      else
         | 
| 44 43 | 
             
                        mod = Module.new
         | 
| 45 | 
            -
                         | 
| 46 | 
            -
                          mod.send :include,  | 
| 44 | 
            +
                        namespace_stackable(:helpers).each do |mod_to_include|
         | 
| 45 | 
            +
                          mod.send :include, mod_to_include
         | 
| 47 46 | 
             
                        end
         | 
| 48 47 | 
             
                        change!
         | 
| 49 48 | 
             
                        mod
         | 
| @@ -77,7 +76,7 @@ module Grape | |
| 77 76 |  | 
| 78 77 | 
             
                    def process_named_params
         | 
| 79 78 | 
             
                      if @named_params && @named_params.any?
         | 
| 80 | 
            -
                        api. | 
| 79 | 
            +
                        api.namespace_stackable(:named_params, @named_params)
         | 
| 81 80 | 
             
                      end
         | 
| 82 81 | 
             
                    end
         | 
| 83 82 | 
             
                  end
         | 
| @@ -4,6 +4,7 @@ module Grape | |
| 4 4 | 
             
              module DSL
         | 
| 5 5 | 
             
                module InsideRoute
         | 
| 6 6 | 
             
                  extend ActiveSupport::Concern
         | 
| 7 | 
            +
                  include Grape::DSL::Settings
         | 
| 7 8 |  | 
| 8 9 | 
             
                  # A filtering method that will return a hash
         | 
| 9 10 | 
             
                  # consisting only of keys that have been declared by a
         | 
| @@ -18,12 +19,12 @@ module Grape | |
| 18 19 | 
             
                    options[:include_missing] = true unless options.key?(:include_missing)
         | 
| 19 20 | 
             
                    options[:include_parent_namespaces] = true unless options.key?(:include_parent_namespaces)
         | 
| 20 21 | 
             
                    if declared_params.nil?
         | 
| 21 | 
            -
                      declared_params = !options[:include_parent_namespaces] ?  | 
| 22 | 
            -
                           | 
| 22 | 
            +
                      declared_params = (!options[:include_parent_namespaces] ? route_setting(:declared_params) :
         | 
| 23 | 
            +
                          (route_setting(:saved_declared_params) || [])).flatten(1) || []
         | 
| 23 24 | 
             
                    end
         | 
| 24 25 |  | 
| 25 26 | 
             
                    unless declared_params
         | 
| 26 | 
            -
                       | 
| 27 | 
            +
                      fail ArgumentError, 'Tried to filter for declared parameters but none exist.'
         | 
| 27 28 | 
             
                    end
         | 
| 28 29 |  | 
| 29 30 | 
             
                    if params.is_a? Array
         | 
| @@ -36,6 +37,9 @@ module Grape | |
| 36 37 |  | 
| 37 38 | 
             
                        key.each_pair do |parent, children|
         | 
| 38 39 | 
             
                          output_key = options[:stringify] ? parent.to_s : parent.to_sym
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                          next unless options[:include_missing] || children || params[parent]
         | 
| 42 | 
            +
             | 
| 39 43 | 
             
                          if params.key?(parent) || options[:include_missing]
         | 
| 40 44 | 
             
                            hash[output_key] = if children
         | 
| 41 45 | 
             
                                                 declared(params[parent] || {}, options, Array(children))
         | 
| @@ -61,7 +65,7 @@ module Grape | |
| 61 65 | 
             
                  # @param message [String] The message to display.
         | 
| 62 66 | 
             
                  # @param status [Integer] the HTTP Status Code. Defaults to default_error_status, 500 if not set.
         | 
| 63 67 | 
             
                  def error!(message, status = nil, headers = nil)
         | 
| 64 | 
            -
                    self.status(status ||  | 
| 68 | 
            +
                    self.status(status || namespace_inheritable(:default_error_status))
         | 
| 65 69 | 
             
                    throw :error, message: message, status: self.status, headers: headers
         | 
| 66 70 | 
             
                  end
         | 
| 67 71 |  | 
| @@ -75,14 +79,14 @@ module Grape | |
| 75 79 | 
             
                    if merged_options[:permanent]
         | 
| 76 80 | 
             
                      status 301
         | 
| 77 81 | 
             
                    else
         | 
| 78 | 
            -
                      if env['HTTP_VERSION'] == 'HTTP/1.1' && request.request_method.to_s.upcase !=  | 
| 82 | 
            +
                      if env['HTTP_VERSION'] == 'HTTP/1.1' && request.request_method.to_s.upcase != 'GET'
         | 
| 79 83 | 
             
                        status 303
         | 
| 80 84 | 
             
                      else
         | 
| 81 85 | 
             
                        status 302
         | 
| 82 86 | 
             
                      end
         | 
| 83 87 | 
             
                    end
         | 
| 84 | 
            -
                    header  | 
| 85 | 
            -
                    body  | 
| 88 | 
            +
                    header 'Location', url
         | 
| 89 | 
            +
                    body ''
         | 
| 86 90 | 
             
                  end
         | 
| 87 91 |  | 
| 88 92 | 
             
                  # Set or retrieve the HTTP status code.
         | 
| @@ -146,6 +150,9 @@ module Grape | |
| 146 150 | 
             
                  def body(value = nil)
         | 
| 147 151 | 
             
                    if value
         | 
| 148 152 | 
             
                      @body = value
         | 
| 153 | 
            +
                    elsif value == false
         | 
| 154 | 
            +
                      @body = ''
         | 
| 155 | 
            +
                      status 204
         | 
| 149 156 | 
             
                    else
         | 
| 150 157 | 
             
                      @body
         | 
| 151 158 | 
             
                    end
         | 
| @@ -186,7 +193,12 @@ module Grape | |
| 186 193 | 
             
                                     end
         | 
| 187 194 |  | 
| 188 195 | 
             
                    representation = { root => representation } if root
         | 
| 189 | 
            -
                     | 
| 196 | 
            +
                    if key
         | 
| 197 | 
            +
                      representation = (@body || {}).merge(key => representation)
         | 
| 198 | 
            +
                    elsif entity_class.present? && representation.respond_to?('merge')
         | 
| 199 | 
            +
                      representation = (@body || {}).merge(representation)
         | 
| 200 | 
            +
                    end
         | 
| 201 | 
            +
             | 
| 190 202 | 
             
                    body representation
         | 
| 191 203 | 
             
                  end
         | 
| 192 204 |  | 
| @@ -199,7 +211,7 @@ module Grape | |
| 199 211 | 
             
                  #     route.route_description
         | 
| 200 212 | 
             
                  #   end
         | 
| 201 213 | 
             
                  def route
         | 
| 202 | 
            -
                    env[ | 
| 214 | 
            +
                    env['rack.routing_args'][:route_info]
         | 
| 203 215 | 
             
                  end
         | 
| 204 216 |  | 
| 205 217 | 
             
                  def entity_class_for_obj(object, options)
         | 
| @@ -214,7 +226,7 @@ module Grape | |
| 214 226 | 
             
                                     end
         | 
| 215 227 |  | 
| 216 228 | 
             
                      object_class.ancestors.each do |potential|
         | 
| 217 | 
            -
                        entity_class ||= ( | 
| 229 | 
            +
                        entity_class ||= (Grape::DSL::Configuration.stacked_hash_to_hash(namespace_stackable(:representations)) || {})[potential]
         | 
| 218 230 | 
             
                      end
         | 
| 219 231 |  | 
| 220 232 | 
             
                      entity_class ||= object_class.const_get(:Entity) if object_class.const_defined?(:Entity) && object_class.const_get(:Entity).respond_to?(:represent)
         |