Skip to content

Commit

Permalink
Merge pull request #2200 from ericproulx/validators_module
Browse files Browse the repository at this point in the history
Add validators module to all validators
  • Loading branch information
dblock authored Dec 5, 2021
2 parents 05768df + 7a64729 commit e9d605f
Show file tree
Hide file tree
Showing 45 changed files with 1,148 additions and 1,091 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

* [#2193](https://github.com/ruby-grape/grape/pull/2193): Fixed the broken ruby-head NoMethodError spec - [@Jack12816](https://github.com/Jack12816).
* [#2192](https://github.com/ruby-grape/grape/pull/2192): Memoize the result of Grape::Middleware::Base#response - [@Jack12816](https://github.com/Jack12816).
* [#2200](https://github.com/ruby-grape/grape/pull/2200): Add validators module to all validators - [@ericproulx](https://github.com/ericproulx).
* Your contribution here.

### 1.6.0 (2021/10/04)
Expand Down
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ group :test do
gem 'rack-test', '~> 1.1.0'
gem 'rspec', '~> 3.0'
gem 'ruby-grape-danger', '~> 0.2.0', require: false
gem 'test-prof', require: false
end

platforms :jruby do
Expand Down
1 change: 1 addition & 0 deletions gemfiles/multi_json.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ group :test do
gem 'rack-test', '~> 1.1.0'
gem 'rspec', '~> 3.0'
gem 'ruby-grape-danger', '~> 0.2.0', require: false
gem 'test-prof', require: false
end

gemspec path: '../'
1 change: 1 addition & 0 deletions gemfiles/multi_xml.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ group :test do
gem 'rack-test', '~> 1.1.0'
gem 'rspec', '~> 3.0'
gem 'ruby-grape-danger', '~> 0.2.0', require: false
gem 'test-prof', require: false
end

gemspec path: '../'
1 change: 1 addition & 0 deletions gemfiles/rack1.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ group :test do
gem 'rack-test', '~> 1.1.0'
gem 'rspec', '~> 3.0'
gem 'ruby-grape-danger', '~> 0.2.0', require: false
gem 'test-prof', require: false
end

gemspec path: '../'
1 change: 1 addition & 0 deletions gemfiles/rack2.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ group :test do
gem 'rack-test', '~> 1.1.0'
gem 'rspec', '~> 3.0'
gem 'ruby-grape-danger', '~> 0.2.0', require: false
gem 'test-prof', require: false
end

gemspec path: '../'
1 change: 1 addition & 0 deletions gemfiles/rack2_2.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ group :test do
gem 'rack-test', '~> 1.1.0'
gem 'rspec', '~> 3.0'
gem 'ruby-grape-danger', '~> 0.2.0', require: false
gem 'test-prof', require: false
end

gemspec path: '../'
1 change: 1 addition & 0 deletions gemfiles/rack_edge.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ group :test do
gem 'rack-test', '~> 1.1.0'
gem 'rspec', '~> 3.0'
gem 'ruby-grape-danger', '~> 0.2.0', require: false
gem 'test-prof', require: false
end

gemspec path: '../'
1 change: 1 addition & 0 deletions gemfiles/rails_5.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ group :test do
gem 'rack-test', '~> 1.1.0'
gem 'rspec', '~> 3.0'
gem 'ruby-grape-danger', '~> 0.2.0', require: false
gem 'test-prof', require: false
end

gemspec path: '../'
1 change: 1 addition & 0 deletions gemfiles/rails_6.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ group :test do
gem 'rack-test', '~> 1.1.0'
gem 'rspec', '~> 3.0'
gem 'ruby-grape-danger', '~> 0.2.0', require: false
gem 'test-prof', require: false
end

gemspec path: '../'
1 change: 1 addition & 0 deletions gemfiles/rails_6_1.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ group :test do
gem 'rack-test', '~> 1.1.0'
gem 'rspec', '~> 3.0'
gem 'ruby-grape-danger', '~> 0.2.0', require: false
gem 'test-prof', require: false
end

gemspec path: '../'
1 change: 1 addition & 0 deletions gemfiles/rails_edge.gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ group :test do
gem 'rack-test', '~> 1.1.0'
gem 'rspec', '~> 3.0'
gem 'ruby-grape-danger', '~> 0.2.0', require: false
gem 'test-prof', require: false
end

gemspec path: '../'
12 changes: 12 additions & 0 deletions lib/grape/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ class API
# Class methods that we want to call on the API rather than on the API object
NON_OVERRIDABLE = (Class.new.methods + %i[call call! configuration compile! inherited]).freeze

class Boolean
def self.build(val)
return nil if val != true && val != false

new
end
end

class Instance
Boolean = Grape::API::Boolean
end

class << self
attr_accessor :base_instance, :instances

Expand Down
6 changes: 6 additions & 0 deletions lib/grape/validations.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# frozen_string_literal: true

require 'grape/validations/attributes_iterator'
require 'grape/validations/single_attribute_iterator'
require 'grape/validations/multiple_attributes_iterator'
require 'grape/validations/params_scope'
require 'grape/validations/types'

module Grape
# Registry to store and locate known Validators.
module Validations
Expand Down
12 changes: 7 additions & 5 deletions lib/grape/validations/validators/all_or_none.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@

module Grape
module Validations
class AllOrNoneOfValidator < MultipleParamsBase
def validate_params!(params)
keys = keys_in_common(params)
return if keys.empty? || keys.length == all_keys.length
module Validators
class AllOrNoneOfValidator < MultipleParamsBase
def validate_params!(params)
keys = keys_in_common(params)
return if keys.empty? || keys.length == all_keys.length

raise Grape::Exceptions::Validation.new(params: all_keys, message: message(:all_or_none))
raise Grape::Exceptions::Validation.new(params: all_keys, message: message(:all_or_none))
end
end
end
end
Expand Down
16 changes: 9 additions & 7 deletions lib/grape/validations/validators/allow_blank.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@

module Grape
module Validations
class AllowBlankValidator < Base
def validate_param!(attr_name, params)
return if (options_key?(:value) ? @option[:value] : @option) || !params.is_a?(Hash)
module Validators
class AllowBlankValidator < Base
def validate_param!(attr_name, params)
return if (options_key?(:value) ? @option[:value] : @option) || !params.is_a?(Hash)

value = params[attr_name]
value = value.strip if value.respond_to?(:strip)
value = params[attr_name]
value = value.strip if value.respond_to?(:strip)

return if value == false || value.present?
return if value == false || value.present?

raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:blank))
raise Grape::Exceptions::Validation.new(params: [@scope.full_name(attr_name)], message: message(:blank))
end
end
end
end
Expand Down
12 changes: 7 additions & 5 deletions lib/grape/validations/validators/as.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

module Grape
module Validations
class AsValidator < Base
# We use a validator for renaming parameters. This is just a marker for
# the parameter scope to handle the renaming. No actual validation
# happens here.
def validate_param!(*); end
module Validators
class AsValidator < Base
# We use a validator for renaming parameters. This is just a marker for
# the parameter scope to handle the renaming. No actual validation
# happens here.
def validate_param!(*); end
end
end
end
end
10 changes: 6 additions & 4 deletions lib/grape/validations/validators/at_least_one_of.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@

module Grape
module Validations
class AtLeastOneOfValidator < MultipleParamsBase
def validate_params!(params)
return unless keys_in_common(params).empty?
module Validators
class AtLeastOneOfValidator < MultipleParamsBase
def validate_params!(params)
return unless keys_in_common(params).empty?

raise Grape::Exceptions::Validation.new(params: all_keys, message: message(:at_least_one))
raise Grape::Exceptions::Validation.new(params: all_keys, message: message(:at_least_one))
end
end
end
end
Expand Down
144 changes: 73 additions & 71 deletions lib/grape/validations/validators/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,91 +2,93 @@

module Grape
module Validations
class Base
attr_reader :attrs
module Validators
class Base
attr_reader :attrs

# Creates a new Validator from options specified
# by a +requires+ or +optional+ directive during
# parameter definition.
# @param attrs [Array] names of attributes to which the Validator applies
# @param options [Object] implementation-dependent Validator options
# @param required [Boolean] attribute(s) are required or optional
# @param scope [ParamsScope] parent scope for this Validator
# @param opts [Array] additional validation options
def initialize(attrs, options, required, scope, *opts)
@attrs = Array(attrs)
@option = options
@required = required
@scope = scope
opts = opts.any? ? opts.shift : {}
@fail_fast = opts.fetch(:fail_fast, false)
@allow_blank = opts.fetch(:allow_blank, false)
end
# Creates a new Validator from options specified
# by a +requires+ or +optional+ directive during
# parameter definition.
# @param attrs [Array] names of attributes to which the Validator applies
# @param options [Object] implementation-dependent Validator options
# @param required [Boolean] attribute(s) are required or optional
# @param scope [ParamsScope] parent scope for this Validator
# @param opts [Array] additional validation options
def initialize(attrs, options, required, scope, *opts)
@attrs = Array(attrs)
@option = options
@required = required
@scope = scope
opts = opts.any? ? opts.shift : {}
@fail_fast = opts.fetch(:fail_fast, false)
@allow_blank = opts.fetch(:allow_blank, false)
end

# Validates a given request.
# @note Override #validate! unless you need to access the entire request.
# @param request [Grape::Request] the request currently being handled
# @raise [Grape::Exceptions::Validation] if validation failed
# @return [void]
def validate(request)
return unless @scope.should_validate?(request.params)
# Validates a given request.
# @note Override #validate! unless you need to access the entire request.
# @param request [Grape::Request] the request currently being handled
# @raise [Grape::Exceptions::Validation] if validation failed
# @return [void]
def validate(request)
return unless @scope.should_validate?(request.params)

validate!(request.params)
end
validate!(request.params)
end

# Validates a given parameter hash.
# @note Override #validate if you need to access the entire request.
# @param params [Hash] parameters to validate
# @raise [Grape::Exceptions::Validation] if validation failed
# @return [void]
def validate!(params)
attributes = SingleAttributeIterator.new(self, @scope, params)
# we collect errors inside array because
# there may be more than one error per field
array_errors = []
# Validates a given parameter hash.
# @note Override #validate if you need to access the entire request.
# @param params [Hash] parameters to validate
# @raise [Grape::Exceptions::Validation] if validation failed
# @return [void]
def validate!(params)
attributes = SingleAttributeIterator.new(self, @scope, params)
# we collect errors inside array because
# there may be more than one error per field
array_errors = []

attributes.each do |val, attr_name, empty_val, skip_value|
next if skip_value
next if !@scope.required? && empty_val
next unless @scope.meets_dependency?(val, params)
attributes.each do |val, attr_name, empty_val, skip_value|
next if skip_value
next if !@scope.required? && empty_val
next unless @scope.meets_dependency?(val, params)

begin
validate_param!(attr_name, val) if @required || (val.respond_to?(:key?) && val.key?(attr_name))
rescue Grape::Exceptions::Validation => e
array_errors << e
begin
validate_param!(attr_name, val) if @required || (val.respond_to?(:key?) && val.key?(attr_name))
rescue Grape::Exceptions::Validation => e
array_errors << e
end
end
end

raise Grape::Exceptions::ValidationArrayErrors.new(array_errors) if array_errors.any?
end
raise Grape::Exceptions::ValidationArrayErrors.new(array_errors) if array_errors.any?
end

def self.convert_to_short_name(klass)
ret = klass.name.gsub(/::/, '/')
ret.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
ret.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
ret.tr!('-', '_')
ret.downcase!
File.basename(ret, '_validator')
end
def self.convert_to_short_name(klass)
ret = klass.name.gsub(/::/, '/')
ret.gsub!(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
ret.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
ret.tr!('-', '_')
ret.downcase!
File.basename(ret, '_validator')
end

def self.inherited(klass)
return unless klass.name.present?
def self.inherited(klass)
return unless klass.name.present?

Validations.register_validator(convert_to_short_name(klass), klass)
end
Validations.register_validator(convert_to_short_name(klass), klass)
end

def message(default_key = nil)
options = instance_variable_get(:@option)
options_key?(:message) ? options[:message] : default_key
end
def message(default_key = nil)
options = instance_variable_get(:@option)
options_key?(:message) ? options[:message] : default_key
end

def options_key?(key, options = nil)
options = instance_variable_get(:@option) if options.nil?
options.respond_to?(:key?) && options.key?(key) && !options[key].nil?
end
def options_key?(key, options = nil)
options = instance_variable_get(:@option) if options.nil?
options.respond_to?(:key?) && options.key?(key) && !options[key].nil?
end

def fail_fast?
@fail_fast
def fail_fast?
@fail_fast
end
end
end
end
Expand Down
Loading

0 comments on commit e9d605f

Please sign in to comment.