grape 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of grape might be problematic. Click here for more details.

Files changed (144) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -66
  3. data/.rubocop_todo.yml +78 -17
  4. data/.travis.yml +7 -3
  5. data/Appraisals +7 -0
  6. data/CHANGELOG.md +24 -0
  7. data/CONTRIBUTING.md +7 -0
  8. data/Gemfile +1 -7
  9. data/Guardfile +1 -1
  10. data/README.md +560 -94
  11. data/RELEASING.md +1 -1
  12. data/Rakefile +10 -11
  13. data/UPGRADING.md +211 -3
  14. data/gemfiles/rails_3.gemfile +14 -0
  15. data/gemfiles/rails_4.gemfile +14 -0
  16. data/grape.gemspec +10 -9
  17. data/lib/backports/active_support/deep_dup.rb +49 -0
  18. data/lib/backports/active_support/duplicable.rb +88 -0
  19. data/lib/grape.rb +29 -2
  20. data/lib/grape/api.rb +59 -65
  21. data/lib/grape/dsl/api.rb +19 -0
  22. data/lib/grape/dsl/callbacks.rb +6 -4
  23. data/lib/grape/dsl/configuration.rb +49 -5
  24. data/lib/grape/dsl/helpers.rb +7 -8
  25. data/lib/grape/dsl/inside_route.rb +22 -10
  26. data/lib/grape/dsl/middleware.rb +5 -5
  27. data/lib/grape/dsl/parameters.rb +6 -2
  28. data/lib/grape/dsl/request_response.rb +23 -20
  29. data/lib/grape/dsl/routing.rb +52 -49
  30. data/lib/grape/dsl/settings.rb +110 -0
  31. data/lib/grape/dsl/validations.rb +14 -6
  32. data/lib/grape/endpoint.rb +104 -88
  33. data/lib/grape/exceptions/base.rb +2 -2
  34. data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
  35. data/lib/grape/exceptions/invalid_formatter.rb +1 -1
  36. data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
  37. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +1 -1
  38. data/lib/grape/exceptions/missing_mime_type.rb +1 -1
  39. data/lib/grape/exceptions/missing_option.rb +1 -1
  40. data/lib/grape/exceptions/missing_vendor_option.rb +1 -1
  41. data/lib/grape/exceptions/unknown_options.rb +1 -1
  42. data/lib/grape/exceptions/unknown_validator.rb +1 -1
  43. data/lib/grape/exceptions/validation.rb +1 -1
  44. data/lib/grape/exceptions/validation_errors.rb +2 -2
  45. data/lib/grape/formatter/serializable_hash.rb +1 -1
  46. data/lib/grape/formatter/xml.rb +1 -1
  47. data/lib/grape/locale/en.yml +2 -0
  48. data/lib/grape/middleware/auth/dsl.rb +26 -21
  49. data/lib/grape/middleware/auth/strategies.rb +1 -1
  50. data/lib/grape/middleware/auth/strategy_info.rb +0 -2
  51. data/lib/grape/middleware/base.rb +2 -2
  52. data/lib/grape/middleware/error.rb +1 -1
  53. data/lib/grape/middleware/formatter.rb +5 -5
  54. data/lib/grape/middleware/versioner.rb +1 -1
  55. data/lib/grape/middleware/versioner/header.rb +3 -3
  56. data/lib/grape/middleware/versioner/param.rb +2 -2
  57. data/lib/grape/middleware/versioner/path.rb +1 -1
  58. data/lib/grape/namespace.rb +1 -1
  59. data/lib/grape/path.rb +9 -3
  60. data/lib/grape/util/content_types.rb +16 -8
  61. data/lib/grape/util/inheritable_setting.rb +74 -0
  62. data/lib/grape/util/inheritable_values.rb +51 -0
  63. data/lib/grape/util/stackable_values.rb +52 -0
  64. data/lib/grape/util/strict_hash_configuration.rb +106 -0
  65. data/lib/grape/validations.rb +0 -220
  66. data/lib/grape/validations/attributes_iterator.rb +21 -0
  67. data/lib/grape/validations/params_scope.rb +176 -0
  68. data/lib/grape/validations/validators/all_or_none.rb +20 -0
  69. data/lib/grape/validations/validators/allow_blank.rb +30 -0
  70. data/lib/grape/validations/validators/at_least_one_of.rb +20 -0
  71. data/lib/grape/validations/validators/base.rb +37 -0
  72. data/lib/grape/validations/{coerce.rb → validators/coerce.rb} +3 -3
  73. data/lib/grape/validations/{default.rb → validators/default.rb} +1 -1
  74. data/lib/grape/validations/validators/exactly_one_of.rb +20 -0
  75. data/lib/grape/validations/validators/multiple_params_base.rb +26 -0
  76. data/lib/grape/validations/validators/mutual_exclusion.rb +25 -0
  77. data/lib/grape/validations/{presence.rb → validators/presence.rb} +2 -2
  78. data/lib/grape/validations/validators/regexp.rb +12 -0
  79. data/lib/grape/validations/validators/values.rb +26 -0
  80. data/lib/grape/version.rb +1 -1
  81. data/spec/grape/api_spec.rb +522 -343
  82. data/spec/grape/dsl/callbacks_spec.rb +4 -4
  83. data/spec/grape/dsl/configuration_spec.rb +48 -9
  84. data/spec/grape/dsl/helpers_spec.rb +6 -13
  85. data/spec/grape/dsl/inside_route_spec.rb +43 -4
  86. data/spec/grape/dsl/middleware_spec.rb +1 -10
  87. data/spec/grape/dsl/parameters_spec.rb +8 -1
  88. data/spec/grape/dsl/request_response_spec.rb +16 -22
  89. data/spec/grape/dsl/routing_spec.rb +21 -5
  90. data/spec/grape/dsl/settings_spec.rb +219 -0
  91. data/spec/grape/dsl/validations_spec.rb +8 -11
  92. data/spec/grape/endpoint_spec.rb +115 -86
  93. data/spec/grape/entity_spec.rb +33 -33
  94. data/spec/grape/exceptions/invalid_formatter_spec.rb +3 -5
  95. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +4 -6
  96. data/spec/grape/exceptions/missing_mime_type_spec.rb +5 -6
  97. data/spec/grape/exceptions/missing_option_spec.rb +3 -5
  98. data/spec/grape/exceptions/unknown_options_spec.rb +3 -5
  99. data/spec/grape/exceptions/unknown_validator_spec.rb +3 -5
  100. data/spec/grape/exceptions/validation_errors_spec.rb +5 -5
  101. data/spec/grape/loading_spec.rb +44 -0
  102. data/spec/grape/middleware/auth/base_spec.rb +0 -4
  103. data/spec/grape/middleware/auth/dsl_spec.rb +2 -4
  104. data/spec/grape/middleware/auth/strategies_spec.rb +5 -6
  105. data/spec/grape/middleware/exception_spec.rb +8 -10
  106. data/spec/grape/middleware/formatter_spec.rb +13 -15
  107. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +10 -10
  108. data/spec/grape/middleware/versioner/header_spec.rb +25 -25
  109. data/spec/grape/middleware/versioner/param_spec.rb +15 -17
  110. data/spec/grape/middleware/versioner/path_spec.rb +1 -2
  111. data/spec/grape/middleware/versioner_spec.rb +0 -1
  112. data/spec/grape/path_spec.rb +66 -45
  113. data/spec/grape/util/inheritable_setting_spec.rb +217 -0
  114. data/spec/grape/util/inheritable_values_spec.rb +63 -0
  115. data/spec/grape/util/stackable_values_spec.rb +115 -0
  116. data/spec/grape/util/strict_hash_configuration_spec.rb +38 -0
  117. data/spec/grape/validations/attributes_iterator_spec.rb +4 -0
  118. data/spec/grape/validations/params_scope_spec.rb +57 -0
  119. data/spec/grape/validations/validators/all_or_none_spec.rb +60 -0
  120. data/spec/grape/validations/validators/allow_blank_spec.rb +170 -0
  121. data/spec/grape/validations/{at_least_one_of_spec.rb → validators/at_least_one_of_spec.rb} +7 -3
  122. data/spec/grape/validations/{coerce_spec.rb → validators/coerce_spec.rb} +8 -11
  123. data/spec/grape/validations/{default_spec.rb → validators/default_spec.rb} +7 -9
  124. data/spec/grape/validations/{exactly_one_of_spec.rb → validators/exactly_one_of_spec.rb} +15 -11
  125. data/spec/grape/validations/{mutual_exclusion_spec.rb → validators/mutual_exclusion_spec.rb} +11 -9
  126. data/spec/grape/validations/{presence_spec.rb → validators/presence_spec.rb} +30 -30
  127. data/spec/grape/validations/{regexp_spec.rb → validators/regexp_spec.rb} +2 -4
  128. data/spec/grape/validations/{values_spec.rb → validators/values_spec.rb} +95 -23
  129. data/spec/grape/validations/{zh-CN.yml → validators/zh-CN.yml} +0 -0
  130. data/spec/grape/validations_spec.rb +335 -70
  131. data/spec/shared/versioning_examples.rb +7 -8
  132. data/spec/spec_helper.rb +2 -0
  133. data/spec/support/basic_auth_encode_helpers.rb +1 -1
  134. data/spec/support/content_type_helpers.rb +1 -1
  135. data/spec/support/versioned_helpers.rb +3 -3
  136. metadata +80 -33
  137. data/lib/grape/util/deep_merge.rb +0 -23
  138. data/lib/grape/util/hash_stack.rb +0 -120
  139. data/lib/grape/validations/at_least_one_of.rb +0 -25
  140. data/lib/grape/validations/exactly_one_of.rb +0 -26
  141. data/lib/grape/validations/mutual_exclusion.rb +0 -25
  142. data/lib/grape/validations/regexp.rb +0 -12
  143. data/lib/grape/validations/values.rb +0 -23
  144. 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 'grape/util/deep_merge'
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 :HashStack, 'grape/util/hash_stack'
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
- extend Grape::Middleware::Auth::DSL
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 to name the scope to make the code more readable.
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
- nest(block)
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
- settings.key?(:cascade) ? !!settings[:cascade] : true
47
+ inheritable_setting.namespace_inheritable.keys.include?(:cascade) ? !!namespace_inheritable(:cascade) : true
56
48
  else
57
- set(:cascade, value)
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! { |b| b.nil? }
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(other_stack)
110
- settings.prepend other_stack
111
- endpoints.each do |e|
112
- e.settings.prepend(other_stack)
113
- e.options[:app].inherit_settings(other_stack) if e.options[:app].respond_to?(:inherit_settings, true)
114
- end
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.settings[:cascade] if self.class.settings.key?(:cascade)
143
- return !!self.class.settings[:version_options][:cascade] if self.class.settings[:version_options] && self.class.settings[:version_options].key?(:cascade)
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
- without_versioning do
170
- methods_per_path.each do |path, methods|
171
- allowed_methods = methods.dup
172
- unless self.class.settings[:do_not_route_head]
173
- allowed_methods |= ['HEAD'] if allowed_methods.include?('GET')
174
- end
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
- allow_header = (['OPTIONS'] | allowed_methods).join(', ')
177
- unless self.class.settings[:do_not_route_options]
178
- unless allowed_methods.include?('OPTIONS')
179
- self.class.options(path, {}) do
180
- header 'Allow', allow_header
181
- status 204
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
- not_allowed_methods = %w(GET PUT POST DELETE PATCH HEAD) - allowed_methods
188
- not_allowed_methods << 'OPTIONS' if self.class.settings[:do_not_route_options]
189
- self.class.route(not_allowed_methods, path) do
190
- header 'Allow', allow_header
191
- status 405
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.settings.push(version: nil, version_options: nil)
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
- self.class.settings.pop
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
@@ -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
- imbue(:befores, [block])
12
+ namespace_stackable(:befores, block)
11
13
  end
12
14
 
13
15
  def before_validation(&block)
14
- imbue(:before_validations, [block])
16
+ namespace_stackable(:before_validations, block)
15
17
  end
16
18
 
17
19
  def after_validation(&block)
18
- imbue(:after_validations, [block])
20
+ namespace_stackable(:after_validations, block)
19
21
  end
20
22
 
21
23
  def after(&block)
22
- imbue(:afters, [block])
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
- attr_reader :settings
10
+
11
+ include Grape::DSL::Settings
11
12
 
12
13
  def logger(logger = nil)
13
14
  if logger
14
- @logger = logger
15
+ global_setting(:logger, logger)
15
16
  else
16
- @logger ||= Logger.new($stdout)
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
- @last_description = options.merge(description: description)
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
@@ -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 = settings.peek[:helpers] || Module.new
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
- set(:helpers, mod)
40
+
41
+ namespace_stackable(:helpers, mod)
43
42
  else
44
43
  mod = Module.new
45
- settings.stack.each do |s|
46
- mod.send :include, s[:helpers] if s[:helpers]
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.imbue(:named_params, @named_params)
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] ? settings[:declared_params] :
22
- settings.gather(:declared_params)
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
- raise ArgumentError, "Tried to filter for declared parameters but none exist."
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 || settings[:default_error_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 != "GET"
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 "Location", url
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
- representation = (@body || {}).merge(key => representation) if key
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["rack.routing_args"][:route_info]
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 ||= (settings[:representations] || {})[potential]
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)