Repository URL to install this package:
Version:
4.0.0.pre.1 ▾
|
# frozen_string_literal: true
require 'sinatra/flash'
require 'sinatra/param'
# Top-level module documentation comment goes here...
module Sinatra
# Shared helpers for validating parameters and forms
module Validator
# Helpers for Sinatra
module Helpers
def filter_params
# Filter params, replace empty strings/arrays with nil
params.each do |(param, value)|
params[param] = nil if value == ''
params[param] = [nil] if value == ['']
end
rescue StandardError => e
raise "Filter params failed: #{e}"
end
def validate(validator, args)
validator.context = self
validator.run(*args)
validator.handle_failure unless validator.success?
end
end
# A validator for a form. Essentially holds a list of methods to call and their arguments for parameter validation.
class Validator
VALID_METHODS = %i[block param one_of any_of].freeze
attr_writer :context
def initialize(definition)
@definition = definition
clear
end
def method_missing(name, *args, &block)
super unless VALID_METHODS.include? name
@methods.push({ name: name, args: args, block: block })
end
def respond_to_missing?(method, *)
VALID_METHODS.include?(method) || super
end
def run(*args)
clear
save_params_copy
run_definition(*args)
@methods.each do |method|
run_method method
rescue Sinatra::Param::InvalidParameterError => e
save_method_error method, e
end
end
def success?
@errors.empty?
end
def handle_failure
raise 'Validation Failed'
end
private
def clear
@methods = []
@errors = {}
end
# Run the validator definition block in the route context
# Pass in this validator object and any arguments
def run_definition(*args)
@context.instance_exec self, *args, &@definition
end
# Run a defined method in the route context
def run_method(method)
# :block is a placeholder to just run the given block, not a specific validation method
@context.instance_exec(*method[:args], &@context.method(method[:name])) unless method[:name] == :block
@context.instance_eval(&method[:block]) if method[:block]
end
def save_method_error(method, error)
key = method[:name] == :param ? method[:args][0] : :global_errors
@errors[key] ||= []
@errors[key].push error.options&.key?(:message) ? error.options[:message].dup : error.to_s.dup
end
def save_params_copy
@params = @context.params.dup
end
end
# Holds a validator method identifier and any arguments to pass to the validator
class ValidatorIdentifier
attr_reader :identifier, :args
def initialize(identifier, *args)
@identifier = identifier
@args = args
end
end
def self.registered(app)
app.helpers Helpers
app.helpers Sinatra::Param
app.enable :raise_sinatra_param_exceptions
end
end
register Sinatra::Validator
end