errapi 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +4 -2
- data/README.md +6 -2
- data/VERSION +1 -1
- data/lib/errapi/condition.rb +71 -0
- data/lib/errapi/configuration.rb +79 -0
- data/lib/errapi/errors.rb +15 -0
- data/lib/errapi/location_builders.rb +17 -0
- data/lib/errapi/locations/dotted.rb +33 -0
- data/lib/errapi/locations/json.rb +33 -0
- data/lib/errapi/locations/none.rb +28 -0
- data/lib/errapi/locations.rb +4 -0
- data/lib/errapi/model.rb +30 -0
- data/lib/errapi/object_validator.rb +230 -0
- data/lib/errapi/plugins/i18n_messages.rb +20 -0
- data/lib/errapi/plugins/location.rb +29 -0
- data/lib/errapi/plugins/reason.rb +22 -0
- data/lib/errapi/plugins.rb +4 -0
- data/lib/errapi/single_validator.rb +19 -0
- data/lib/errapi/utils.rb +12 -0
- data/lib/errapi/validation_context.rb +49 -0
- data/lib/errapi/validation_error.rb +43 -0
- data/lib/errapi/validations/clusivity.rb +45 -0
- data/lib/errapi/validations/exclusion.rb +28 -0
- data/lib/errapi/validations/format.rb +33 -0
- data/lib/errapi/validations/inclusion.rb +28 -0
- data/lib/errapi/validations/length.rb +66 -0
- data/lib/errapi/validations/presence.rb +39 -0
- data/lib/errapi/validations/trim.rb +10 -0
- data/lib/errapi/validations/type.rb +54 -0
- data/lib/errapi/validations.rb +57 -0
- data/lib/errapi/validator_proxy.rb +21 -0
- data/lib/errapi.rb +45 -1
- metadata +63 -7
@@ -0,0 +1,19 @@
|
|
1
|
+
module Errapi
|
2
|
+
|
3
|
+
class SingleValidator
|
4
|
+
|
5
|
+
def self.configure *args, &block
|
6
|
+
|
7
|
+
options = args.last.kind_of?(Hash) ? args.pop : {}
|
8
|
+
config = options[:config] || Errapi.config
|
9
|
+
config = Errapi.config config if config.kind_of? Symbol
|
10
|
+
|
11
|
+
@errapi_validator = ObjectValidator.new config, options, &block
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.validate *args, &block
|
15
|
+
raise "Validator has not yet been configured. You must call #configure before calling #validate." unless @errapi_validator
|
16
|
+
@errapi_validator.validate *args, &block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/errapi/utils.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module Errapi::Utils
|
2
|
+
|
3
|
+
def self.camelize string, uppercase_first_letter = false
|
4
|
+
parts = string.split '_'
|
5
|
+
return string if parts.length < 2
|
6
|
+
parts[0] + parts[1, parts.length - 1].collect(&:capitalize).join
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.underscore string
|
10
|
+
string.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').tr("-", "_").downcase
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
class Errapi::ValidationContext
|
4
|
+
attr_reader :data
|
5
|
+
attr_reader :errors
|
6
|
+
attr_reader :config
|
7
|
+
|
8
|
+
def initialize options = {}
|
9
|
+
@errors = []
|
10
|
+
@data = OpenStruct.new options[:data] || {}
|
11
|
+
@config = options[:config]
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_error options = {}, &block
|
15
|
+
|
16
|
+
error = options.kind_of?(Errapi::ValidationError) ? options : @config.new_error(options)
|
17
|
+
yield error if block_given?
|
18
|
+
@config.build_error error, self
|
19
|
+
|
20
|
+
@errors << error
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def errors? criteria = {}, &block
|
25
|
+
return !@errors.empty? if criteria.empty? && !block
|
26
|
+
block ? @errors.any?{ |err| err.matches?(criteria) && block.call(err) } : @errors.any?{ |err| err.matches?(criteria) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def valid?
|
30
|
+
!errors?
|
31
|
+
end
|
32
|
+
|
33
|
+
def clear
|
34
|
+
@errors.clear
|
35
|
+
@data = OpenStruct.new
|
36
|
+
end
|
37
|
+
|
38
|
+
# TODO: add custom serialization options
|
39
|
+
def serialize
|
40
|
+
# TODO: add hook for plugins to serialize context
|
41
|
+
{ errors: [] }.tap do |h|
|
42
|
+
@errors.each do |error|
|
43
|
+
serialized = {}
|
44
|
+
@config.serialize_error error, serialized
|
45
|
+
h[:errors] << serialized
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
class Errapi::ValidationError
|
4
|
+
attr_accessor :reason
|
5
|
+
attr_accessor :check_value
|
6
|
+
attr_accessor :checked_value
|
7
|
+
attr_accessor :validation
|
8
|
+
attr_accessor :constraints
|
9
|
+
attr_accessor :location
|
10
|
+
|
11
|
+
def initialize options = {}
|
12
|
+
ATTRIBUTES.each do |attr|
|
13
|
+
instance_variable_set "@#{attr}", options[attr] if options.key? attr
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def matches? criteria = {}
|
18
|
+
unknown_criteria = criteria.keys - ATTRIBUTES
|
19
|
+
raise "Unknown error attributes: #{unknown_criteria.join(', ')}." if unknown_criteria.any?
|
20
|
+
ATTRIBUTES.all?{ |attr| criterion_matches? criteria, attr }
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
ATTRIBUTES = %i(reason location check_value checked_value validation)
|
26
|
+
|
27
|
+
def criterion_matches? criteria, attr
|
28
|
+
return true unless criteria.key? attr
|
29
|
+
|
30
|
+
value = send attr
|
31
|
+
criterion = criteria[attr]
|
32
|
+
|
33
|
+
if criterion.kind_of? Regexp
|
34
|
+
!!criterion.match(value.to_s)
|
35
|
+
elsif criterion.kind_of? String
|
36
|
+
criterion == value.to_s
|
37
|
+
elsif criterion.respond_to? :===
|
38
|
+
criterion === value
|
39
|
+
else
|
40
|
+
criterion == value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Errapi::Validations
|
2
|
+
module Clusivity
|
3
|
+
private
|
4
|
+
|
5
|
+
DELIMITER_METHOD_CHECKS = %i(include? call to_sym).freeze
|
6
|
+
|
7
|
+
def check_delimiter! option_desc
|
8
|
+
unless @delimiter.respond_to?(:include?) || callable_option_value?(@delimiter)
|
9
|
+
raise callable_option_type_error option_desc, "an object with the #include? method", @delimiter
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def members option_desc, options = {}
|
14
|
+
enumerable = actual_option_value @delimiter, options
|
15
|
+
|
16
|
+
unless enumerable.respond_to? :include?
|
17
|
+
raise callable_option_value_error option_desc, "an object with the #include? method", @delimiter
|
18
|
+
end
|
19
|
+
|
20
|
+
enumerable
|
21
|
+
end
|
22
|
+
|
23
|
+
def include? members, value
|
24
|
+
members.send inclusion_method(members), value
|
25
|
+
end
|
26
|
+
|
27
|
+
# From rails/activemodel/lib/active_model/validations/clusivity.rb:
|
28
|
+
# In Ruby 1.9 <tt>Range#include?</tt> on non-number-or-time-ish ranges checks all
|
29
|
+
# possible values in the range for equality, which is slower but more accurate.
|
30
|
+
# <tt>Range#cover?</tt> uses the previous logic of comparing a value with the range
|
31
|
+
# endpoints, which is fast but is only accurate on Numeric, Time, or DateTime ranges.
|
32
|
+
def inclusion_method enumerable
|
33
|
+
if enumerable.is_a? Range
|
34
|
+
case enumerable.first
|
35
|
+
when Numeric, Time, DateTime
|
36
|
+
:cover?
|
37
|
+
else
|
38
|
+
:include?
|
39
|
+
end
|
40
|
+
else
|
41
|
+
:include?
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'clusivity.rb')
|
2
|
+
|
3
|
+
module Errapi::Validations
|
4
|
+
class Exclusion < Base
|
5
|
+
include Clusivity
|
6
|
+
|
7
|
+
def initialize options = {}
|
8
|
+
unless key = exactly_one_option?(OPTIONS, options)
|
9
|
+
raise ArgumentError, "Either :from or :in or :within must be supplied (but only one of them)."
|
10
|
+
end
|
11
|
+
|
12
|
+
@delimiter = options[key]
|
13
|
+
check_delimiter! OPTIONS_DESCRIPTION
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate value, context, options = {}
|
17
|
+
excluded_values = members OPTIONS_DESCRIPTION, options
|
18
|
+
if include? excluded_values, value
|
19
|
+
context.add_error reason: :excluded, check_value: excluded_values
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
OPTIONS = %i(from in within)
|
26
|
+
OPTIONS_DESCRIPTION = ":from (or :in or :within)"
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Errapi::Validations
|
2
|
+
class Format < Base
|
3
|
+
|
4
|
+
def initialize options = {}
|
5
|
+
unless key = exactly_one_option?(OPTIONS, options)
|
6
|
+
raise ArgumentError, "Either :with or :without must be supplied (but not both)."
|
7
|
+
end
|
8
|
+
|
9
|
+
@format = options[key]
|
10
|
+
@should_match = key == :with
|
11
|
+
|
12
|
+
unless @format.kind_of?(Regexp) or callable_option_value?(@format)
|
13
|
+
raise callable_option_type_error ":with (or :without)", "a regular expression", @format
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate value, context, options = {}
|
18
|
+
|
19
|
+
regexp = actual_option_value @format, options
|
20
|
+
unless regexp.kind_of? Regexp
|
21
|
+
raise callable_option_value_error ":with (or :without)", "a regular expression", regexp
|
22
|
+
end
|
23
|
+
|
24
|
+
if !regexp.match(value.to_s) == @should_match
|
25
|
+
context.add_error reason: :invalid_format, check_value: regexp
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
OPTIONS = %i(with without)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'clusivity.rb')
|
2
|
+
|
3
|
+
module Errapi::Validations
|
4
|
+
class Inclusion < Base
|
5
|
+
include Clusivity
|
6
|
+
|
7
|
+
def initialize options = {}
|
8
|
+
unless key = exactly_one_option?(OPTIONS, options)
|
9
|
+
raise ArgumentError, "Either :in or :within must be supplied (but not both)."
|
10
|
+
end
|
11
|
+
|
12
|
+
@delimiter = options[key]
|
13
|
+
check_delimiter! OPTIONS_DESCRIPTION
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate value, context, options = {}
|
17
|
+
allowed_values = members OPTIONS_DESCRIPTION, options
|
18
|
+
unless include? allowed_values, value
|
19
|
+
context.add_error reason: :not_included, check_value: allowed_values
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
OPTIONS = %i(in within)
|
26
|
+
OPTIONS_DESCRIPTION = ":in (or :within)"
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Errapi::Validations
|
2
|
+
class Length < Base
|
3
|
+
CHECKS = { is: :==, minimum: :>=, maximum: :<= }.freeze
|
4
|
+
REASONS = { is: :wrong_length, minimum: :too_short, maximum: :too_long }.freeze
|
5
|
+
|
6
|
+
def initialize options = {}
|
7
|
+
|
8
|
+
constraints = options.select{ |k,v| OPTIONS.include? k }
|
9
|
+
if constraints.empty?
|
10
|
+
raise ArgumentError, "The :is, :minimum/:maximum or :within options must be supplied (but only :minimum and :maximum can be used together)."
|
11
|
+
elsif options.key?(:is) && constraints.length != 1
|
12
|
+
raise ArgumentError, "The :is option cannot be combined with :minimum, :maximum or :within."
|
13
|
+
elsif options.key?(:is)
|
14
|
+
check_numeric! options[:is]
|
15
|
+
elsif options.key?(:within)
|
16
|
+
if options.key?(:minimum) || options.key?(:maximum)
|
17
|
+
raise ArgumentError, "The :within option cannot be combined with :minimum or :maximum."
|
18
|
+
else
|
19
|
+
check_range! options[:within]
|
20
|
+
end
|
21
|
+
else
|
22
|
+
check_numeric! options[:minimum] if options.key? :minimum
|
23
|
+
check_numeric! options[:maximum] if options.key? :maximum
|
24
|
+
end
|
25
|
+
|
26
|
+
@constraints = actual_constraints constraints
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate value, context, options = {}
|
30
|
+
return unless value.respond_to? :length
|
31
|
+
actual_length = value.length
|
32
|
+
|
33
|
+
CHECKS.each_pair do |key,check|
|
34
|
+
next unless check_value = @constraints[key]
|
35
|
+
next if actual_length.send check, check_value
|
36
|
+
context.add_error reason: REASONS[key], check_value: check_value, checked_value: actual_length, constraints: @constraints
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
OPTIONS = %i(is minimum maximum within)
|
43
|
+
|
44
|
+
def actual_constraints options = {}
|
45
|
+
if range = options[:within]
|
46
|
+
{ minimum: range.min, maximum: range.max }
|
47
|
+
else
|
48
|
+
options
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def check_numeric! bound
|
53
|
+
unless bound.kind_of? Numeric
|
54
|
+
raise ArgumentError, "The :is, :minimum or :maximum option must be a numeric value, but a #{bound.class.name} was given."
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def check_range! range
|
59
|
+
if !range.kind_of?(Range)
|
60
|
+
raise ArgumentError, "The :within option must be a numeric range, but a #{range.class.name} was given."
|
61
|
+
elsif !(t = range.first).kind_of?(Numeric)
|
62
|
+
raise ArgumentError, "The :within option must be a numeric range, but a #{t.class.name} range was given."
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Errapi::Validations
|
2
|
+
class Presence < Factory
|
3
|
+
class Implementation < Base
|
4
|
+
|
5
|
+
def validate value, context, options = {}
|
6
|
+
if reason = check(value, options.fetch(:value_set, true))
|
7
|
+
context.add_error reason: reason
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
BLANK_REGEXP = /\A[[:space:]]*\z/
|
14
|
+
|
15
|
+
def check value, value_set
|
16
|
+
# TODO: allow customization (e.g. values that are not required, booleans, etc)
|
17
|
+
if !value_set
|
18
|
+
:missing
|
19
|
+
elsif value.nil?
|
20
|
+
:null
|
21
|
+
elsif value.respond_to?(:empty?) && value.empty?
|
22
|
+
:empty
|
23
|
+
elsif value_blank? value
|
24
|
+
:blank
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def value_blank? value
|
29
|
+
if value.respond_to? :blank?
|
30
|
+
value.blank?
|
31
|
+
elsif value.kind_of? String
|
32
|
+
BLANK_REGEXP === value
|
33
|
+
else
|
34
|
+
false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Errapi::Validations
|
2
|
+
class Type < Base
|
3
|
+
|
4
|
+
def initialize options = {}
|
5
|
+
unless key = exactly_one_option?(OPTIONS, options)
|
6
|
+
raise ArgumentError, "One option among :instance_of, :kind_of, :is_a or :is_an must be supplied (but only one)."
|
7
|
+
end
|
8
|
+
|
9
|
+
if key == :instance_of
|
10
|
+
@instance_of = check_types! options[key]
|
11
|
+
raise ArgumentError, "Type aliases cannot be used with the :instance_of option. Use :kind_of, :is_a or :is_an." if options[key].kind_of? Symbol
|
12
|
+
else
|
13
|
+
@kind_of = check_types! options[key]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def validate value, context, options = {}
|
18
|
+
if @instance_of && @instance_of.none?{ |type| value.instance_of? type }
|
19
|
+
context.add_error reason: :wrong_type, check_value: @instance_of, checked_value: value.class
|
20
|
+
elsif @kind_of && @kind_of.none?{ |type| value.kind_of? type }
|
21
|
+
context.add_error reason: :wrong_type, check_value: @kind_of, checked_value: value.class
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def check_types! types
|
28
|
+
if !types.kind_of?(Array)
|
29
|
+
types = [ types ]
|
30
|
+
elsif types.empty?
|
31
|
+
raise ArgumentError, "At least one class or module is required, but an empty array was given."
|
32
|
+
end
|
33
|
+
|
34
|
+
types.each do |type|
|
35
|
+
unless TYPE_ALIASES.key?(type) || type.class == Class || type.class == Module
|
36
|
+
raise ArgumentError, "A class or module (or an array of classes or modules, or a type alias) is required, but a #{type.class} was given."
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
types.collect{ |type| TYPE_ALIASES[type] || type }.flatten.uniq
|
41
|
+
end
|
42
|
+
|
43
|
+
OPTIONS = %i(instance_of kind_of is_a is_an)
|
44
|
+
TYPE_ALIASES = {
|
45
|
+
string: [ String ],
|
46
|
+
number: [ Numeric ],
|
47
|
+
integer: [ Integer ],
|
48
|
+
boolean: [ TrueClass, FalseClass ],
|
49
|
+
object: [ Hash ],
|
50
|
+
array: [ Array ],
|
51
|
+
null: [ NilClass ]
|
52
|
+
}
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Errapi::Validations
|
2
|
+
|
3
|
+
class Base
|
4
|
+
|
5
|
+
def initialize options = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def actual_option_value supplied_value, options
|
9
|
+
if supplied_value.respond_to? :call
|
10
|
+
supplied_value.call options[:source]
|
11
|
+
elsif supplied_value.respond_to? :to_sym
|
12
|
+
unless options[:source].respond_to? supplied_value
|
13
|
+
raise ArgumentError, "The validation source (#{options[:source].class.name}) does not respond to :#{supplied_value}."
|
14
|
+
else
|
15
|
+
options[:source].send supplied_value
|
16
|
+
end
|
17
|
+
else
|
18
|
+
supplied_value
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def callable_option_value? supplied_value
|
23
|
+
supplied_value.respond_to?(:call) || supplied_value.respond_to?(:to_sym)
|
24
|
+
end
|
25
|
+
|
26
|
+
def exactly_one_option? keys, options
|
27
|
+
found_keys = options.keys.select{ |k| keys.include? k }
|
28
|
+
found_keys.length == 1 ? found_keys.first : false
|
29
|
+
end
|
30
|
+
|
31
|
+
def callable_option_type_error key_desc, value_desc, supplied_value
|
32
|
+
ArgumentError.new "The #{key_desc} option must be #{value_desc}, a proc, a lambda or a symbol, but a #{supplied_value.class.name} was given."
|
33
|
+
end
|
34
|
+
|
35
|
+
def callable_option_value_error key_desc, type_desc, supplied_value
|
36
|
+
ArgumentError.new "The call supplied to #{key_desc} must return #{type_desc}, but a #{supplied_value.class.name} was returned."
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Factory
|
41
|
+
|
42
|
+
def config= config
|
43
|
+
raise "A configuration has already been set for this factory." if @config
|
44
|
+
@config = config
|
45
|
+
end
|
46
|
+
|
47
|
+
def validation options = {}
|
48
|
+
self.class.const_get('Implementation').new options
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
Errapi::Utils.underscore self.class.name.sub(/.*::/, '')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Dir[File.join File.dirname(__FILE__), File.basename(__FILE__, '.*'), '*.rb'].each{ |lib| require lib }
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Errapi
|
2
|
+
|
3
|
+
class ValidatorProxy
|
4
|
+
instance_methods.each{ |m| undef_method m unless m =~ /(^__|^send$|^object_id$)/ }
|
5
|
+
|
6
|
+
def initialize object, validator
|
7
|
+
@object = object
|
8
|
+
@validator = validator
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate context, options = {}
|
12
|
+
@validator.validate @object, context, options
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def method_missing name, *args, &block
|
18
|
+
@validator.send name, *args, &block
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/errapi.rb
CHANGED
@@ -1,3 +1,47 @@
|
|
1
1
|
module Errapi
|
2
|
-
VERSION = '0.1.
|
2
|
+
VERSION = '0.1.2'
|
3
|
+
end
|
4
|
+
|
5
|
+
Dir[File.join File.dirname(__FILE__), File.basename(__FILE__, '.*'), '*.rb'].each{ |lib| require lib }
|
6
|
+
|
7
|
+
module Errapi
|
8
|
+
|
9
|
+
def self.configure name = nil, &block
|
10
|
+
|
11
|
+
init_configs
|
12
|
+
name ||= :default
|
13
|
+
|
14
|
+
if @configs[name]
|
15
|
+
@configs[name].configure &block
|
16
|
+
else
|
17
|
+
@configs[name] = Configuration.new &block
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.config name = nil
|
22
|
+
init_configs[name || :default]
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def self.init_configs
|
28
|
+
@configs ? @configs : @configs = { default: default_config }
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.default_config
|
32
|
+
Configuration.new.tap do |config|
|
33
|
+
config.plugin Errapi::Plugins::I18nMessages
|
34
|
+
config.plugin Errapi::Plugins::Reason
|
35
|
+
config.plugin Errapi::Plugins::Location
|
36
|
+
config.validation_factory Errapi::Validations::Exclusion
|
37
|
+
config.validation_factory Errapi::Validations::Format
|
38
|
+
config.validation_factory Errapi::Validations::Inclusion
|
39
|
+
config.validation_factory Errapi::Validations::Length
|
40
|
+
config.validation_factory Errapi::Validations::Presence.new
|
41
|
+
config.validation_factory Errapi::Validations::Trim
|
42
|
+
config.validation_factory Errapi::Validations::Type
|
43
|
+
config.register_condition Errapi::Condition::SimpleCheck
|
44
|
+
config.register_condition Errapi::Condition::ErrorCheck
|
45
|
+
end
|
46
|
+
end
|
3
47
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: errapi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Simon Oulevay
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: i18n
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.7.0
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.7.0
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rake
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +52,20 @@ dependencies:
|
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '3.1'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec-collection_matchers
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.1'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: jeweler
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -72,28 +100,28 @@ dependencies:
|
|
72
100
|
requirements:
|
73
101
|
- - "~>"
|
74
102
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
103
|
+
version: 0.9.1
|
76
104
|
type: :development
|
77
105
|
prerelease: false
|
78
106
|
version_requirements: !ruby/object:Gem::Requirement
|
79
107
|
requirements:
|
80
108
|
- - "~>"
|
81
109
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
110
|
+
version: 0.9.1
|
83
111
|
- !ruby/object:Gem::Dependency
|
84
112
|
name: coveralls
|
85
113
|
requirement: !ruby/object:Gem::Requirement
|
86
114
|
requirements:
|
87
115
|
- - "~>"
|
88
116
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
117
|
+
version: 0.7.3
|
90
118
|
type: :development
|
91
119
|
prerelease: false
|
92
120
|
version_requirements: !ruby/object:Gem::Requirement
|
93
121
|
requirements:
|
94
122
|
- - "~>"
|
95
123
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
124
|
+
version: 0.7.3
|
97
125
|
description: Utilities to validate data and serialize errors.
|
98
126
|
email: git@alphahydrae.com
|
99
127
|
executables: []
|
@@ -107,6 +135,34 @@ files:
|
|
107
135
|
- README.md
|
108
136
|
- VERSION
|
109
137
|
- lib/errapi.rb
|
138
|
+
- lib/errapi/condition.rb
|
139
|
+
- lib/errapi/configuration.rb
|
140
|
+
- lib/errapi/errors.rb
|
141
|
+
- lib/errapi/location_builders.rb
|
142
|
+
- lib/errapi/locations.rb
|
143
|
+
- lib/errapi/locations/dotted.rb
|
144
|
+
- lib/errapi/locations/json.rb
|
145
|
+
- lib/errapi/locations/none.rb
|
146
|
+
- lib/errapi/model.rb
|
147
|
+
- lib/errapi/object_validator.rb
|
148
|
+
- lib/errapi/plugins.rb
|
149
|
+
- lib/errapi/plugins/i18n_messages.rb
|
150
|
+
- lib/errapi/plugins/location.rb
|
151
|
+
- lib/errapi/plugins/reason.rb
|
152
|
+
- lib/errapi/single_validator.rb
|
153
|
+
- lib/errapi/utils.rb
|
154
|
+
- lib/errapi/validation_context.rb
|
155
|
+
- lib/errapi/validation_error.rb
|
156
|
+
- lib/errapi/validations.rb
|
157
|
+
- lib/errapi/validations/clusivity.rb
|
158
|
+
- lib/errapi/validations/exclusion.rb
|
159
|
+
- lib/errapi/validations/format.rb
|
160
|
+
- lib/errapi/validations/inclusion.rb
|
161
|
+
- lib/errapi/validations/length.rb
|
162
|
+
- lib/errapi/validations/presence.rb
|
163
|
+
- lib/errapi/validations/trim.rb
|
164
|
+
- lib/errapi/validations/type.rb
|
165
|
+
- lib/errapi/validator_proxy.rb
|
110
166
|
homepage: http://github.com/AlphaHydrae/errapi
|
111
167
|
licenses:
|
112
168
|
- MIT
|
@@ -127,7 +183,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
183
|
version: '0'
|
128
184
|
requirements: []
|
129
185
|
rubyforge_project:
|
130
|
-
rubygems_version: 2.
|
186
|
+
rubygems_version: 2.4.3
|
131
187
|
signing_key:
|
132
188
|
specification_version: 4
|
133
189
|
summary: An extensible API-oriented validation library.
|