This could be useful for those who wants to do a simple parameter validation in Sinatra.
Syntax is simple:
validation_configuration do
rule_for :posts, :edit do
param :id, :number, :required
param :language, :string, :optional, [ 'sk', 'en' ]
end
end
Now lets create some action in sinatra:
post "/posts/edit" do
unless valid_params(:posts, :edit, params).empty?
return "Bad parameters"
end
end
Implementation in Ruby is little bit tricky ;-)
require 'singleton'
module Sinatra
module Validation; end;
end;
class Sinatra::Validation::Suite
include Singleton
attr_accessor :rules
def initialize
self.rules = {}
@current_action = nil
end
def rule_for(model, action, ¶ms)
@current_action = "#{model}:#{action}"
rules[@current_action] ||= {}
params.call
@current_action = nil
end
def param(*args)
rules[@current_action].merge!({ args.first => {
:type => args[2],
:class => args[1] || :string,
:options => args[3] || []
}})
end
def validate(model, action, params)
@errors = []
action_rules = rules["#{model}:#{action}"]
validated_params = action_rules.collect { |name| name.first }
validated_params.each do |param|
check(param, action_rules[param], params[param])
end
return @errors
end
private
def check(name, rule, param)
# Check if parameter is required
if param.nil? and rule[:type].eql?(:required)
@errors << Sinatra::Validation::Error.new(:required, name, nil, rule[:options])
return false
end
# Check if paramer need some specific value
if not rule[:options].empty? and not rule[:options].include?(param)
@errors << Sinatra::Validation::Error.new(:invalid_value, name, param, rule[:options])
return false
end
# Check parameter class (number, string...)
case rule[:class]
when :number
unless param.to_s =~ /^([0-9]+)$/
@errors << Sinatra::Validation::Error.new(:type_error, name, param, [rule[:class]])
end
end
end
end
class Sinatra::Validation::Error
attr_accessor :kind
attr_accessor :parameter
attr_accessor :given_value
attr_accessor :valid_values
def initialize(kind, parameter, given_value, valid_values=[])
self.kind, self.parameter = kind, parameter
self.given_value, self.valid_values = given_value, valid_values
end
def to_s
case kind
when :required
"Required parameter #{parameter} not specified"
when :invalid_value
"Invalid value #{given_value} for parameter #{parameter}. Valid values: #{valid_values.join(',')}"
when :type_error
"Invalid type for parameter #{parameter}. Required type: #{valid_values.first.to_s.capitalize}"
end
end
end
def validation_configuration(&block)
Sinatra::Validation::Suite.instance.instance_eval(&block)
end
def valid_params(model, action, params = {})
Sinatra::Validation::Suite.instance.validate(model, action, params)
end










