grape 1.2.4 → 1.2.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -4
  3. data/README.md +144 -4
  4. data/grape.gemspec +3 -1
  5. data/lib/grape.rb +94 -66
  6. data/lib/grape/api.rb +46 -4
  7. data/lib/grape/api/instance.rb +23 -12
  8. data/lib/grape/dsl/desc.rb +11 -2
  9. data/lib/grape/dsl/validations.rb +4 -3
  10. data/lib/grape/eager_load.rb +18 -0
  11. data/lib/grape/endpoint.rb +3 -3
  12. data/lib/grape/error_formatter.rb +1 -1
  13. data/lib/grape/exceptions/validation_errors.rb +4 -2
  14. data/lib/grape/formatter.rb +1 -1
  15. data/lib/grape/middleware/auth/base.rb +2 -4
  16. data/lib/grape/middleware/base.rb +2 -0
  17. data/lib/grape/middleware/helpers.rb +10 -0
  18. data/lib/grape/parser.rb +1 -1
  19. data/lib/grape/util/base_inheritable.rb +34 -0
  20. data/lib/grape/util/inheritable_values.rb +5 -25
  21. data/lib/grape/util/lazy_block.rb +25 -0
  22. data/lib/grape/util/lazy_value.rb +5 -0
  23. data/lib/grape/util/reverse_stackable_values.rb +7 -36
  24. data/lib/grape/util/stackable_values.rb +19 -22
  25. data/lib/grape/validations/attributes_iterator.rb +5 -3
  26. data/lib/grape/validations/multiple_attributes_iterator.rb +11 -0
  27. data/lib/grape/validations/params_scope.rb +12 -12
  28. data/lib/grape/validations/single_attribute_iterator.rb +13 -0
  29. data/lib/grape/validations/validator_factory.rb +6 -11
  30. data/lib/grape/validations/validators/all_or_none.rb +6 -13
  31. data/lib/grape/validations/validators/at_least_one_of.rb +5 -13
  32. data/lib/grape/validations/validators/base.rb +11 -10
  33. data/lib/grape/validations/validators/coerce.rb +4 -0
  34. data/lib/grape/validations/validators/default.rb +1 -1
  35. data/lib/grape/validations/validators/exactly_one_of.rb +6 -23
  36. data/lib/grape/validations/validators/multiple_params_base.rb +14 -10
  37. data/lib/grape/validations/validators/mutual_exclusion.rb +6 -18
  38. data/lib/grape/version.rb +1 -1
  39. data/spec/grape/api/defines_boolean_in_params_spec.rb +37 -0
  40. data/spec/grape/api_remount_spec.rb +158 -0
  41. data/spec/grape/api_spec.rb +72 -0
  42. data/spec/grape/endpoint_spec.rb +1 -1
  43. data/spec/grape/exceptions/base_spec.rb +4 -0
  44. data/spec/grape/exceptions/validation_errors_spec.rb +6 -4
  45. data/spec/grape/integration/rack_spec.rb +22 -6
  46. data/spec/grape/middleware/base_spec.rb +8 -0
  47. data/spec/grape/middleware/formatter_spec.rb +11 -1
  48. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +29 -0
  49. data/spec/grape/validations/params_scope_spec.rb +13 -0
  50. data/spec/grape/validations/single_attribute_iterator_spec.rb +33 -0
  51. data/spec/grape/validations/validators/all_or_none_spec.rb +138 -30
  52. data/spec/grape/validations/validators/at_least_one_of_spec.rb +173 -29
  53. data/spec/grape/validations/validators/coerce_spec.rb +6 -2
  54. data/spec/grape/validations/validators/exactly_one_of_spec.rb +202 -38
  55. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +184 -27
  56. data/spec/grape/validations_spec.rb +32 -20
  57. metadata +103 -115
  58. data/Appraisals +0 -28
  59. data/Dangerfile +0 -2
  60. data/Gemfile +0 -33
  61. data/Gemfile.lock +0 -231
  62. data/Guardfile +0 -10
  63. data/RELEASING.md +0 -111
  64. data/Rakefile +0 -25
  65. data/benchmark/simple.rb +0 -27
  66. data/benchmark/simple_with_type_coercer.rb +0 -22
  67. data/gemfiles/multi_json.gemfile +0 -35
  68. data/gemfiles/multi_xml.gemfile +0 -35
  69. data/gemfiles/rack_1.5.2.gemfile.lock +0 -232
  70. data/gemfiles/rack_edge.gemfile +0 -35
  71. data/gemfiles/rails_3.gemfile +0 -36
  72. data/gemfiles/rails_3.gemfile.lock +0 -288
  73. data/gemfiles/rails_4.gemfile +0 -35
  74. data/gemfiles/rails_4.gemfile.lock +0 -280
  75. data/gemfiles/rails_5.gemfile +0 -35
  76. data/gemfiles/rails_5.gemfile.lock +0 -312
  77. data/gemfiles/rails_edge.gemfile +0 -35
  78. data/pkg/grape-1.2.0.gem +0 -0
  79. data/pkg/grape-1.2.1.gem +0 -0
  80. data/pkg/grape-1.2.3.gem +0 -0
@@ -7,6 +7,11 @@ module Grape
7
7
  @access_keys = access_keys
8
8
  end
9
9
 
10
+ def evaluate_from(configuration)
11
+ matching_lazy_value = configuration.fetch(@access_keys)
12
+ matching_lazy_value.evaluate
13
+ end
14
+
10
15
  def evaluate
11
16
  @value
12
17
  end
@@ -1,45 +1,16 @@
1
+ require_relative 'stackable_values'
2
+
1
3
  module Grape
2
4
  module Util
3
- class ReverseStackableValues
4
- attr_accessor :inherited_values
5
- attr_accessor :new_values
6
-
7
- def initialize(inherited_values = {})
8
- @inherited_values = inherited_values
9
- @new_values = {}
10
- end
5
+ class ReverseStackableValues < StackableValues
6
+ protected
11
7
 
12
- def [](name)
8
+ def concat_values(inherited_value, new_value)
13
9
  [].tap do |value|
14
- value.concat(@new_values[name] || [])
15
- value.concat(@inherited_values[name] || [])
16
- end
17
- end
18
-
19
- def []=(name, value)
20
- @new_values[name] ||= []
21
- @new_values[name].push value
22
- end
23
-
24
- def delete(key)
25
- new_values.delete key
26
- end
27
-
28
- def keys
29
- (@new_values.keys + @inherited_values.keys).sort.uniq
30
- end
31
-
32
- def to_hash
33
- keys.each_with_object({}) do |key, result|
34
- result[key] = self[key]
10
+ value.concat(new_value)
11
+ value.concat(inherited_value)
35
12
  end
36
13
  end
37
-
38
- def initialize_copy(other)
39
- super
40
- self.inherited_values = other.inherited_values
41
- self.new_values = other.new_values.dup
42
- end
43
14
  end
44
15
  end
45
16
  end
@@ -1,23 +1,25 @@
1
+ require_relative 'base_inheritable'
2
+
1
3
  module Grape
2
4
  module Util
3
- class StackableValues
4
- attr_accessor :inherited_values
5
- attr_accessor :new_values
5
+ class StackableValues < BaseInheritable
6
6
  attr_reader :frozen_values
7
7
 
8
- def initialize(inherited_values = {})
9
- @inherited_values = inherited_values
10
- @new_values = {}
8
+ def initialize(*_args)
9
+ super
10
+
11
11
  @frozen_values = {}
12
12
  end
13
13
 
14
14
  def [](name)
15
15
  return @frozen_values[name] if @frozen_values.key? name
16
16
 
17
- value = []
18
- value.concat(@inherited_values[name] || [])
19
- value.concat(@new_values[name] || [])
20
- value
17
+ inherited_value = @inherited_values[name]
18
+ new_value = @new_values[name] || []
19
+
20
+ return new_value unless inherited_value
21
+
22
+ concat_values(inherited_value, new_value)
21
23
  end
22
24
 
23
25
  def []=(name, value)
@@ -26,14 +28,6 @@ module Grape
26
28
  @new_values[name].push value
27
29
  end
28
30
 
29
- def delete(key)
30
- new_values.delete key
31
- end
32
-
33
- def keys
34
- (@new_values.keys + @inherited_values.keys).sort.uniq
35
- end
36
-
37
31
  def to_hash
38
32
  keys.each_with_object({}) do |key, result|
39
33
  result[key] = self[key]
@@ -44,10 +38,13 @@ module Grape
44
38
  @frozen_values[key] = self[key].freeze
45
39
  end
46
40
 
47
- def initialize_copy(other)
48
- super
49
- self.inherited_values = other.inherited_values
50
- self.new_values = other.new_values.dup
41
+ protected
42
+
43
+ def concat_values(inherited_value, new_value)
44
+ [].tap do |value|
45
+ value.concat(inherited_value)
46
+ value.concat(new_value)
47
+ end
51
48
  end
52
49
  end
53
50
  end
@@ -41,11 +41,13 @@ module Grape
41
41
  @scope.index = index
42
42
  end
43
43
 
44
- @attrs.each do |attr_name|
45
- yield resource_params, attr_name, inside_array
46
- end
44
+ yield_attributes(resource_params, @attrs, &block)
47
45
  end
48
46
  end
47
+
48
+ def yield_attributes(_resource_params, _attrs)
49
+ raise NotImplementedError
50
+ end
49
51
  end
50
52
  end
51
53
  end
@@ -0,0 +1,11 @@
1
+ module Grape
2
+ module Validations
3
+ class MultipleAttributesIterator < AttributesIterator
4
+ private
5
+
6
+ def yield_attributes(resource_params, _attrs)
7
+ yield resource_params
8
+ end
9
+ end
10
+ end
11
+ end
@@ -76,7 +76,7 @@ module Grape
76
76
  def full_name(name, index: nil)
77
77
  if nested?
78
78
  # Find our containing element's name, and append ours.
79
- [@parent.full_name(@element), [@index || index, name].map(&method(:brackets))].compact.join
79
+ "#{@parent.full_name(@element)}#{brackets(@index || index)}#{brackets(name)}"
80
80
  elsif lateral?
81
81
  # Find the name of the element as if it was at the same nesting level
82
82
  # as our parent. We need to forward our index upward to achieve this.
@@ -184,14 +184,12 @@ module Grape
184
184
  raise Grape::Exceptions::UnsupportedGroupTypeError.new unless Grape::Validations::Types.group?(type)
185
185
  end
186
186
 
187
- opts = attrs[1] || { type: Array }
188
-
189
187
  self.class.new(
190
188
  api: @api,
191
- element: attrs.first,
189
+ element: attrs[1][:as] || attrs.first,
192
190
  parent: self,
193
191
  optional: optional,
194
- type: opts[:type],
192
+ type: type || Array,
195
193
  &block
196
194
  )
197
195
  end
@@ -412,13 +410,15 @@ module Grape
412
410
 
413
411
  raise Grape::Exceptions::UnknownValidator.new(type) unless validator_class
414
412
 
415
- factory = Grape::Validations::ValidatorFactory.new(attributes: attrs,
416
- options: options,
417
- required: doc_attrs[:required],
418
- params_scope: self,
419
- opts: opts,
420
- validator_class: validator_class)
421
- @api.namespace_stackable(:validations, factory)
413
+ validator_options = {
414
+ attributes: attrs,
415
+ options: options,
416
+ required: doc_attrs[:required],
417
+ params_scope: self,
418
+ opts: opts,
419
+ validator_class: validator_class
420
+ }
421
+ @api.namespace_stackable(:validations, validator_options)
422
422
  end
423
423
 
424
424
  def validate_value_coercion(coerce_type, *values_list)
@@ -0,0 +1,13 @@
1
+ module Grape
2
+ module Validations
3
+ class SingleAttributeIterator < AttributesIterator
4
+ private
5
+
6
+ def yield_attributes(resource_params, attrs)
7
+ attrs.each do |attr_name|
8
+ yield resource_params, attr_name
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,17 +1,12 @@
1
1
  module Grape
2
2
  module Validations
3
3
  class ValidatorFactory
4
- def initialize(**options)
5
- @validator_class = options.delete(:validator_class)
6
- @options = options
7
- end
8
-
9
- def create_validator
10
- @validator_class.new(@options[:attributes],
11
- @options[:options],
12
- @options[:required],
13
- @options[:params_scope],
14
- @options[:opts])
4
+ def self.create_validator(**options)
5
+ options[:validator_class].new(options[:attributes],
6
+ options[:options],
7
+ options[:required],
8
+ options[:params_scope],
9
+ options[:opts])
15
10
  end
16
11
  end
17
12
  end
@@ -1,19 +1,12 @@
1
+ require 'grape/validations/validators/multiple_params_base'
2
+
1
3
  module Grape
2
4
  module Validations
3
- require 'grape/validations/validators/multiple_params_base'
4
5
  class AllOrNoneOfValidator < MultipleParamsBase
5
- def validate!(params)
6
- super
7
- if scope_requires_params && only_subset_present
8
- raise Grape::Exceptions::Validation, params: all_keys, message: message(: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).empty? && keys_in_common(resource_params).length < attrs.length }
6
+ def validate_params!(params)
7
+ keys = keys_in_common(params)
8
+ return if keys.empty? || keys.length == all_keys.length
9
+ raise Grape::Exceptions::Validation, params: all_keys, message: message(:all_or_none)
17
10
  end
18
11
  end
19
12
  end
@@ -1,19 +1,11 @@
1
+ require 'grape/validations/validators/multiple_params_base'
2
+
1
3
  module Grape
2
4
  module Validations
3
- require 'grape/validations/validators/multiple_params_base'
4
5
  class AtLeastOneOfValidator < MultipleParamsBase
5
- def validate!(params)
6
- super
7
- if scope_requires_params && no_exclusive_params_are_present
8
- raise Grape::Exceptions::Validation, params: all_keys, message: message(: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? }
6
+ def validate_params!(params)
7
+ return unless keys_in_common(params).empty?
8
+ raise Grape::Exceptions::Validation, params: all_keys, message: message(:at_least_one)
17
9
  end
18
10
  end
19
11
  end
@@ -35,18 +35,19 @@ module Grape
35
35
  # @raise [Grape::Exceptions::Validation] if validation failed
36
36
  # @return [void]
37
37
  def validate!(params)
38
- attributes = AttributesIterator.new(self, @scope, params)
38
+ attributes = SingleAttributeIterator.new(self, @scope, params)
39
+ # we collect errors inside array because
40
+ # there may be more than one error per field
39
41
  array_errors = []
42
+
40
43
  attributes.each do |resource_params, attr_name|
41
44
  next if !@scope.required? && resource_params.empty?
42
- next unless @required || (resource_params.respond_to?(:key?) && resource_params.key?(attr_name))
43
45
  next unless @scope.meets_dependency?(resource_params, params)
44
-
45
46
  begin
46
- validate_param!(attr_name, resource_params)
47
+ if @required || resource_params.respond_to?(:key?) && resource_params.key?(attr_name)
48
+ validate_param!(attr_name, resource_params)
49
+ end
47
50
  rescue Grape::Exceptions::Validation => e
48
- # we collect errors inside array because
49
- # there may be more than one error per field
50
51
  array_errors << e
51
52
  end
52
53
  end
@@ -56,10 +57,10 @@ module Grape
56
57
 
57
58
  def self.convert_to_short_name(klass)
58
59
  ret = klass.name.gsub(/::/, '/')
59
- .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
60
- .gsub(/([a-z\d])([A-Z])/, '\1_\2')
61
- .tr('-', '_')
62
- .downcase
60
+ ret.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
61
+ ret.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
62
+ ret.tr!('-', '_')
63
+ ret.downcase!
63
64
  File.basename(ret, '_validator')
64
65
  end
65
66
 
@@ -1,6 +1,10 @@
1
1
  module Grape
2
2
  class API
3
3
  Boolean = Virtus::Attribute::Boolean
4
+
5
+ class Instance
6
+ Boolean = Virtus::Attribute::Boolean
7
+ end
4
8
  end
5
9
 
6
10
  module Validations
@@ -18,7 +18,7 @@ module Grape
18
18
  end
19
19
 
20
20
  def validate!(params)
21
- attrs = AttributesIterator.new(self, @scope, params)
21
+ attrs = SingleAttributeIterator.new(self, @scope, params)
22
22
  attrs.each do |resource_params, attr_name|
23
23
  if resource_params.is_a?(Hash) && resource_params[attr_name].nil?
24
24
  validate_param!(attr_name, resource_params)
@@ -1,28 +1,11 @@
1
+ require 'grape/validations/validators/multiple_params_base'
2
+
1
3
  module Grape
2
4
  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
- raise Grape::Exceptions::Validation, params: all_keys, message: message(:exactly_one)
9
- end
10
- params
11
- end
12
-
13
- def message(default_key = nil)
14
- options = instance_variable_get(:@option)
15
- if options_key?(:message)
16
- (options_key?(default_key, options[:message]) ? options[:message][default_key] : options[:message])
17
- else
18
- default_key
19
- end
20
- end
21
-
22
- private
23
-
24
- def none_of_restricted_params_is_present
25
- scoped_params.any? { |resource_params| keys_in_common(resource_params).empty? }
5
+ class ExactlyOneOfValidator < MultipleParamsBase
6
+ def validate_params!(params)
7
+ return if keys_in_common(params).length == 1
8
+ raise Grape::Exceptions::Validation, params: all_keys, message: message(:exactly_one)
26
9
  end
27
10
  end
28
11
  end
@@ -1,26 +1,30 @@
1
1
  module Grape
2
2
  module Validations
3
3
  class MultipleParamsBase < Base
4
- attr_reader :scoped_params
5
-
6
4
  def validate!(params)
7
- @scoped_params = [@scope.params(params)].flatten
8
- params
9
- end
5
+ attributes = MultipleAttributesIterator.new(self, @scope, params)
6
+ array_errors = []
10
7
 
11
- private
8
+ attributes.each do |resource_params|
9
+ begin
10
+ validate_params!(resource_params)
11
+ rescue Grape::Exceptions::Validation => e
12
+ array_errors << e
13
+ end
14
+ end
12
15
 
13
- def scope_requires_params
14
- @scope.required? || scoped_params.any? { |param| param.respond_to?(:any?) && param.any? }
16
+ raise Grape::Exceptions::ValidationArrayErrors, array_errors if array_errors.any?
15
17
  end
16
18
 
19
+ private
20
+
17
21
  def keys_in_common(resource_params)
18
22
  return [] unless resource_params.is_a?(Hash)
19
- (all_keys & resource_params.stringify_keys.keys).map(&:to_s)
23
+ all_keys & resource_params.keys.map! { |attr| @scope.full_name(attr) }
20
24
  end
21
25
 
22
26
  def all_keys
23
- attrs.map(&:to_s)
27
+ attrs.map { |attr| @scope.full_name(attr) }
24
28
  end
25
29
  end
26
30
  end
@@ -1,24 +1,12 @@
1
+ require 'grape/validations/validators/multiple_params_base'
2
+
1
3
  module Grape
2
4
  module Validations
3
- require 'grape/validations/validators/multiple_params_base'
4
5
  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
- raise Grape::Exceptions::Validation, params: processing_keys_in_common, message: message(: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
6
+ def validate_params!(params)
7
+ keys = keys_in_common(params)
8
+ return if keys.length <= 1
9
+ raise Grape::Exceptions::Validation, params: keys, message: message(:mutual_exclusion)
22
10
  end
23
11
  end
24
12
  end