grape 0.12.0 → 0.14.0

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

Potentially problematic release.


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

Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/Appraisals +9 -4
  3. data/CHANGELOG.md +265 -215
  4. data/CONTRIBUTING.md +4 -4
  5. data/Gemfile +0 -1
  6. data/Gemfile.lock +166 -0
  7. data/README.md +426 -161
  8. data/RELEASING.md +14 -6
  9. data/Rakefile +30 -33
  10. data/UPGRADING.md +54 -23
  11. data/benchmark/simple.rb +27 -0
  12. data/gemfiles/rack_1.5.2.gemfile +13 -0
  13. data/gemfiles/rails_3.gemfile +2 -2
  14. data/gemfiles/rails_4.gemfile +1 -2
  15. data/grape.gemspec +6 -7
  16. data/lib/grape/api.rb +24 -4
  17. data/lib/grape/dsl/callbacks.rb +20 -0
  18. data/lib/grape/dsl/configuration.rb +59 -2
  19. data/lib/grape/dsl/helpers.rb +8 -3
  20. data/lib/grape/dsl/inside_route.rb +100 -45
  21. data/lib/grape/dsl/parameters.rb +96 -7
  22. data/lib/grape/dsl/request_response.rb +1 -1
  23. data/lib/grape/dsl/routing.rb +17 -4
  24. data/lib/grape/dsl/settings.rb +36 -1
  25. data/lib/grape/dsl/validations.rb +7 -5
  26. data/lib/grape/endpoint.rb +102 -57
  27. data/lib/grape/error_formatter/base.rb +6 -6
  28. data/lib/grape/exceptions/base.rb +5 -5
  29. data/lib/grape/exceptions/invalid_version_header.rb +10 -0
  30. data/lib/grape/exceptions/unknown_parameter.rb +10 -0
  31. data/lib/grape/exceptions/validation_errors.rb +4 -3
  32. data/lib/grape/formatter/serializable_hash.rb +3 -2
  33. data/lib/grape/http/headers.rb +0 -1
  34. data/lib/grape/locale/en.yml +5 -1
  35. data/lib/grape/middleware/auth/base.rb +2 -2
  36. data/lib/grape/middleware/auth/dsl.rb +1 -1
  37. data/lib/grape/middleware/auth/strategies.rb +1 -1
  38. data/lib/grape/middleware/base.rb +8 -4
  39. data/lib/grape/middleware/error.rb +3 -2
  40. data/lib/grape/middleware/filter.rb +1 -1
  41. data/lib/grape/middleware/formatter.rb +64 -45
  42. data/lib/grape/middleware/globals.rb +3 -3
  43. data/lib/grape/middleware/versioner/accept_version_header.rb +5 -7
  44. data/lib/grape/middleware/versioner/header.rb +113 -50
  45. data/lib/grape/middleware/versioner/param.rb +5 -8
  46. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +20 -0
  47. data/lib/grape/middleware/versioner/path.rb +3 -6
  48. data/lib/grape/namespace.rb +13 -2
  49. data/lib/grape/path.rb +4 -3
  50. data/lib/grape/request.rb +40 -0
  51. data/lib/grape/route.rb +5 -0
  52. data/lib/grape/util/content_types.rb +9 -9
  53. data/lib/grape/util/env.rb +22 -0
  54. data/lib/grape/util/file_response.rb +21 -0
  55. data/lib/grape/util/inheritable_setting.rb +23 -2
  56. data/lib/grape/util/inheritable_values.rb +1 -1
  57. data/lib/grape/util/stackable_values.rb +5 -2
  58. data/lib/grape/util/strict_hash_configuration.rb +2 -1
  59. data/lib/grape/validations/attributes_iterator.rb +8 -3
  60. data/lib/grape/validations/params_scope.rb +164 -22
  61. data/lib/grape/validations/types/build_coercer.rb +53 -0
  62. data/lib/grape/validations/types/custom_type_coercer.rb +183 -0
  63. data/lib/grape/validations/types/file.rb +28 -0
  64. data/lib/grape/validations/types/json.rb +65 -0
  65. data/lib/grape/validations/types/multiple_type_coercer.rb +76 -0
  66. data/lib/grape/validations/types/variant_collection_coercer.rb +59 -0
  67. data/lib/grape/validations/types/virtus_collection_patch.rb +16 -0
  68. data/lib/grape/validations/types.rb +144 -0
  69. data/lib/grape/validations/validators/all_or_none.rb +1 -1
  70. data/lib/grape/validations/validators/allow_blank.rb +3 -3
  71. data/lib/grape/validations/validators/base.rb +7 -0
  72. data/lib/grape/validations/validators/coerce.rb +32 -34
  73. data/lib/grape/validations/validators/presence.rb +2 -3
  74. data/lib/grape/validations/validators/regexp.rb +2 -4
  75. data/lib/grape/validations/validators/values.rb +3 -3
  76. data/lib/grape/validations.rb +5 -0
  77. data/lib/grape/version.rb +2 -1
  78. data/lib/grape.rb +15 -12
  79. data/pkg/grape-0.13.0.gem +0 -0
  80. data/spec/grape/api/custom_validations_spec.rb +5 -4
  81. data/spec/grape/api/deeply_included_options_spec.rb +7 -7
  82. data/spec/grape/api/nested_helpers_spec.rb +4 -2
  83. data/spec/grape/api/shared_helpers_spec.rb +8 -8
  84. data/spec/grape/api_spec.rb +151 -54
  85. data/spec/grape/dsl/configuration_spec.rb +13 -0
  86. data/spec/grape/dsl/helpers_spec.rb +16 -2
  87. data/spec/grape/dsl/inside_route_spec.rb +40 -4
  88. data/spec/grape/dsl/parameters_spec.rb +0 -6
  89. data/spec/grape/dsl/routing_spec.rb +1 -1
  90. data/spec/grape/dsl/validations_spec.rb +18 -0
  91. data/spec/grape/endpoint_spec.rb +130 -6
  92. data/spec/grape/entity_spec.rb +10 -8
  93. data/spec/grape/exceptions/invalid_accept_header_spec.rb +1 -15
  94. data/spec/grape/exceptions/validation_errors_spec.rb +28 -0
  95. data/spec/grape/integration/rack_spec.rb +3 -2
  96. data/spec/grape/middleware/base_spec.rb +40 -16
  97. data/spec/grape/middleware/error_spec.rb +16 -15
  98. data/spec/grape/middleware/exception_spec.rb +45 -43
  99. data/spec/grape/middleware/formatter_spec.rb +34 -5
  100. data/spec/grape/middleware/versioner/header_spec.rb +79 -47
  101. data/spec/grape/path_spec.rb +10 -10
  102. data/spec/grape/presenters/presenter_spec.rb +2 -2
  103. data/spec/grape/request_spec.rb +100 -0
  104. data/spec/grape/util/inheritable_values_spec.rb +14 -0
  105. data/spec/grape/util/stackable_values_spec.rb +10 -0
  106. data/spec/grape/validations/params_scope_spec.rb +86 -0
  107. data/spec/grape/validations/types_spec.rb +95 -0
  108. data/spec/grape/validations/validators/coerce_spec.rb +364 -10
  109. data/spec/grape/validations/validators/values_spec.rb +27 -15
  110. data/spec/grape/validations_spec.rb +53 -24
  111. data/spec/shared/versioning_examples.rb +2 -2
  112. data/spec/spec_helper.rb +0 -1
  113. data/spec/support/versioned_helpers.rb +2 -2
  114. metadata +55 -14
  115. data/.gitignore +0 -46
  116. data/.rspec +0 -2
  117. data/.rubocop.yml +0 -7
  118. data/.rubocop_todo.yml +0 -84
  119. data/.travis.yml +0 -20
  120. data/.yardopts +0 -2
  121. data/lib/backports/active_support/deep_dup.rb +0 -49
  122. data/lib/backports/active_support/duplicable.rb +0 -88
  123. data/lib/grape/http/request.rb +0 -27
@@ -1,13 +1,13 @@
1
1
  module Grape
2
2
  class API
3
- Boolean = Virtus::Attribute::Boolean # rubocop:disable ConstantName
3
+ Boolean = Virtus::Attribute::Boolean
4
4
  end
5
5
 
6
6
  module Validations
7
7
  class CoerceValidator < Base
8
8
  def validate_param!(attr_name, params)
9
9
  fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :coerce unless params.is_a? Hash
10
- new_value = coerce_value(@option, params[attr_name])
10
+ new_value = coerce_value(params[attr_name])
11
11
  if valid_type?(new_value)
12
12
  params[attr_name] = new_value
13
13
  else
@@ -15,52 +15,50 @@ module Grape
15
15
  end
16
16
  end
17
17
 
18
- class InvalidValue; end
19
-
20
18
  private
21
19
 
22
- def _valid_array_type?(type, values)
23
- values.all? do |val|
24
- _valid_single_type?(type, val)
25
- end
26
- end
20
+ def valid_type?(val)
21
+ # Special value to denote coercion failure
22
+ return false if val.instance_of?(Types::InvalidValue)
27
23
 
28
- def _valid_single_type?(klass, val)
29
- # allow nil, to ignore when a parameter is absent
24
+ # Allow nil, to ignore when a parameter is absent
30
25
  return true if val.nil?
31
- if klass == Virtus::Attribute::Boolean
32
- val.is_a?(TrueClass) || val.is_a?(FalseClass) || (val.is_a?(String) && val.empty?)
33
- elsif klass == Rack::Multipart::UploadedFile
34
- val.is_a?(Hashie::Mash) && val.key?(:tempfile)
35
- elsif [DateTime, Date, Numeric].any? { |vclass| vclass >= klass }
36
- return true if val.is_a?(String) && val.empty?
37
- val.is_a?(klass)
38
- else
39
- val.is_a?(klass)
40
- end
41
- end
42
26
 
43
- def valid_type?(val)
44
- if @option.is_a?(Array) || @option.is_a?(Set)
45
- _valid_array_type?(@option.first, val)
46
- else
47
- _valid_single_type?(@option, val)
48
- end
27
+ converter.value_coerced? val
49
28
  end
50
29
 
51
- def coerce_value(type, val)
30
+ def coerce_value(val)
52
31
  # Don't coerce things other than nil to Arrays or Hashes
53
- return val || [] if type == Array
54
- return val || Set.new if type == Set
55
- return val || {} if type == Hash
32
+ unless (@option[:method] && !val.nil?) || type.is_a?(Virtus::Attribute)
33
+ return val || [] if type == Array
34
+ return val || Set.new if type == Set
35
+ return val || {} if type == Hash
36
+ end
56
37
 
57
- converter = Virtus::Attribute.build(type)
58
38
  converter.coerce(val)
59
39
 
60
40
  # not the prettiest but some invalid coercion can currently trigger
61
41
  # errors in Virtus (see coerce_spec.rb:75)
62
42
  rescue
63
- InvalidValue.new
43
+ Types::InvalidValue.new
44
+ end
45
+
46
+ # Type to which the parameter will be coerced.
47
+ #
48
+ # @return [Class]
49
+ def type
50
+ @option[:type]
51
+ end
52
+
53
+ # Create and cache the attribute object
54
+ # that will be used for parameter coercion
55
+ # and type checking.
56
+ #
57
+ # See {Types.build_coercer}
58
+ #
59
+ # @return [Virtus::Attribute]
60
+ def converter
61
+ @converter ||= Types.build_coercer(type, @option[:method])
64
62
  end
65
63
  end
66
64
  end
@@ -7,9 +7,8 @@ module Grape
7
7
  end
8
8
 
9
9
  def validate_param!(attr_name, params)
10
- unless params.respond_to?(:key?) && params.key?(attr_name)
11
- fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :presence
12
- end
10
+ return if params.respond_to?(:key?) && params.key?(attr_name)
11
+ fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :presence
13
12
  end
14
13
  end
15
14
  end
@@ -2,10 +2,8 @@ module Grape
2
2
  module Validations
3
3
  class RegexpValidator < Base
4
4
  def validate_param!(attr_name, params)
5
- if params.key?(attr_name) &&
6
- !params[attr_name].nil? && !(params[attr_name].to_s =~ @option)
7
- fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :regexp
8
- end
5
+ return unless params.key?(attr_name) && !params[attr_name].nil? && !(params[attr_name].to_s =~ @option)
6
+ fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :regexp
9
7
  end
10
8
  end
11
9
  end
@@ -7,13 +7,13 @@ module Grape
7
7
  end
8
8
 
9
9
  def validate_param!(attr_name, params)
10
+ return unless params.is_a?(Hash)
10
11
  return unless params[attr_name] || required_for_root_scope?
11
12
 
12
13
  values = @values.is_a?(Proc) ? @values.call : @values
13
14
  param_array = params[attr_name].nil? ? [nil] : Array.wrap(params[attr_name])
14
- unless param_array.all? { |param| values.include?(param) }
15
- fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :values
16
- end
15
+ return if param_array.all? { |param| values.include?(param) }
16
+ fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message_key: :values
17
17
  end
18
18
 
19
19
  private
@@ -1,4 +1,5 @@
1
1
  module Grape
2
+ # Registry to store and locate known Validators.
2
3
  module Validations
3
4
  class << self
4
5
  attr_accessor :validators
@@ -6,6 +7,10 @@ module Grape
6
7
 
7
8
  self.validators = {}
8
9
 
10
+ # Register a new validator, so it can be used to validate parameters.
11
+ # @param short_name [String] all lower-case, no spaces
12
+ # @param klass [Class] the validator class. Should inherit from
13
+ # Validations::Base.
9
14
  def self.register_validator(short_name, klass)
10
15
  validators[short_name] = klass
11
16
  end
data/lib/grape/version.rb CHANGED
@@ -1,3 +1,4 @@
1
1
  module Grape
2
- VERSION = '0.12.0'
2
+ # The current version of Grape.
3
+ VERSION = '0.14.0'
3
4
  end
data/lib/grape.rb CHANGED
@@ -9,25 +9,21 @@ require 'hashie'
9
9
  require 'set'
10
10
  require 'active_support/version'
11
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
-
19
- require 'active_support/ordered_hash'
20
- require 'active_support/core_ext/object/conversions'
12
+ require 'active_support/core_ext/object/blank'
21
13
  require 'active_support/core_ext/array/extract_options'
14
+ require 'active_support/core_ext/array/wrap'
22
15
  require 'active_support/core_ext/hash/deep_merge'
16
+ require 'active_support/core_ext/hash/reverse_merge'
17
+ require 'active_support/core_ext/hash/except'
23
18
  require 'active_support/dependencies/autoload'
24
- require 'grape/util/content_types'
19
+ require 'active_support/notifications'
25
20
  require 'multi_json'
26
21
  require 'multi_xml'
27
- require 'virtus'
28
22
  require 'i18n'
29
23
  require 'thread'
30
24
 
25
+ require 'virtus'
26
+
31
27
  I18n.load_path << File.expand_path('../grape/locale/en.yml', __FILE__)
32
28
 
33
29
  module Grape
@@ -44,7 +40,8 @@ module Grape
44
40
 
45
41
  autoload :Cookies
46
42
  autoload :Validations
47
- autoload :Request, 'grape/http/request'
43
+ autoload :Request
44
+ autoload :Env, 'grape/util/env'
48
45
  end
49
46
 
50
47
  module Http
@@ -66,12 +63,14 @@ module Grape
66
63
  autoload :InvalidVersionerOption
67
64
  autoload :UnknownValidator
68
65
  autoload :UnknownOptions
66
+ autoload :UnknownParameter
69
67
  autoload :InvalidWithOptionForRepresent
70
68
  autoload :IncompatibleOptionValues
71
69
  autoload :MissingGroupTypeError, 'grape/exceptions/missing_group_type'
72
70
  autoload :UnsupportedGroupTypeError, 'grape/exceptions/unsupported_group_type'
73
71
  autoload :InvalidMessageBody
74
72
  autoload :InvalidAcceptHeader
73
+ autoload :InvalidVersionHeader
75
74
  end
76
75
 
77
76
  module ErrorFormatter
@@ -129,6 +128,7 @@ module Grape
129
128
  autoload :StackableValues
130
129
  autoload :InheritableSetting
131
130
  autoload :StrictHashConfiguration
131
+ autoload :FileResponse
132
132
  end
133
133
 
134
134
  module DSL
@@ -159,6 +159,8 @@ module Grape
159
159
  end
160
160
  end
161
161
 
162
+ require 'grape/util/content_types'
163
+
162
164
  require 'grape/validations/validators/base'
163
165
  require 'grape/validations/attributes_iterator'
164
166
  require 'grape/validations/validators/allow_blank'
@@ -172,5 +174,6 @@ require 'grape/validations/validators/regexp'
172
174
  require 'grape/validations/validators/values'
173
175
  require 'grape/validations/params_scope'
174
176
  require 'grape/validations/validators/all_or_none'
177
+ require 'grape/validations/types'
175
178
 
176
179
  require 'grape/version'
Binary file
@@ -2,10 +2,11 @@ require 'spec_helper'
2
2
 
3
3
  describe Grape::Validations do
4
4
  before do
5
- class DefaultLength < Grape::Validations::Base
6
- def validate_param!(attr_name, params)
7
- @option = params[:max].to_i if params.key?(:max)
8
- unless params[attr_name].length <= @option
5
+ module CustomValidationsSpec
6
+ class DefaultLength < Grape::Validations::Base
7
+ def validate_param!(attr_name, params)
8
+ @option = params[:max].to_i if params.key?(:max)
9
+ return if params[attr_name].length <= @option
9
10
  fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: "must be at the most #{@option} characters long"
10
11
  end
11
12
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- module API
3
+ module DeeplyIncludedOptionsSpec
4
4
  module Defaults
5
5
  extend ActiveSupport::Concern
6
6
  included do
@@ -11,11 +11,11 @@ module API
11
11
  module Admin
12
12
  module Defaults
13
13
  extend ActiveSupport::Concern
14
- include API::Defaults
14
+ include DeeplyIncludedOptionsSpec::Defaults
15
15
  end
16
16
 
17
17
  class Users < Grape::API
18
- include API::Admin::Defaults
18
+ include DeeplyIncludedOptionsSpec::Admin::Defaults
19
19
 
20
20
  resource :users do
21
21
  get do
@@ -24,14 +24,14 @@ module API
24
24
  end
25
25
  end
26
26
  end
27
- end
28
27
 
29
- class Main < Grape::API
30
- mount API::Admin::Users
28
+ class Main < Grape::API
29
+ mount DeeplyIncludedOptionsSpec::Admin::Users
30
+ end
31
31
  end
32
32
 
33
33
  describe Grape::API do
34
- subject { Main }
34
+ subject { DeeplyIncludedOptionsSpec::Main }
35
35
 
36
36
  def app
37
37
  subject
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Grape::API::Helpers do
4
- subject do
4
+ module NestedHelpersSpec
5
5
  module HelperMethods
6
6
  extend Grape::API::Helpers
7
7
  def current_user
@@ -28,8 +28,10 @@ describe Grape::API::Helpers do
28
28
  class Main < Grape::API
29
29
  mount Nested
30
30
  end
31
+ end
31
32
 
32
- Main
33
+ subject do
34
+ NestedHelpersSpec::Main
33
35
  end
34
36
 
35
37
  def app
@@ -1,18 +1,18 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Grape::API::Helpers do
4
- module SharedParams
5
- extend Grape::API::Helpers
4
+ subject do
5
+ shared_params = Module.new do
6
+ extend Grape::API::Helpers
6
7
 
7
- params :pagination do
8
- optional :page, type: Integer
9
- optional :size, type: Integer
8
+ params :pagination do
9
+ optional :page, type: Integer
10
+ optional :size, type: Integer
11
+ end
10
12
  end
11
- end
12
13
 
13
- subject do
14
14
  Class.new(Grape::API) do
15
- helpers SharedParams
15
+ helpers shared_params
16
16
  format :json
17
17
 
18
18
  params do