standalone_validator 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/standalone_validator/named_validations/validates_numericality_of.rb +78 -0
- data/lib/standalone_validator/named_validations/validates_presence_of.rb +4 -0
- data/lib/standalone_validator/validation_result.rb +24 -3
- data/lib/standalone_validator/validation_result_builder.rb +3 -2
- data/lib/standalone_validator/version.rb +1 -1
- data/lib/standalone_validator/violation.rb +2 -1
- data/lib/standalone_validator.rb +27 -3
- data/spec/named_validations/validates_numericality_of_spec.rb +166 -0
- data/spec/named_validations/validates_presence_of_spec.rb +6 -0
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43bfee850787c7744539eb0695223feae9bce1d5
|
4
|
+
data.tar.gz: dbf0df8cce8600097a85a8aefef28633febc0fae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6e66ab4b98ec778fd1e8f8aaaecb30446ac6c2582ee3f5fdc92418cda5ba147733c6814a094c0460430b142d30539f73452be950068ccb046563ed9b070976a
|
7
|
+
data.tar.gz: 3abd3dd8ed13f2b94b3e91d639c23525c025203b239e679b315b98a9851df4de931d92674cd35df4bfd0d9f74928b22322a285d3ff6ca2c2de88cb3050cab743
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'standalone_validator'
|
2
|
+
require_relative 'common_rails_options'
|
3
|
+
|
4
|
+
class StandaloneValidator
|
5
|
+
module NamedValidations
|
6
|
+
class ValidatesNumericalityOf < StandaloneValidator
|
7
|
+
register_as :validates_numericality_of
|
8
|
+
|
9
|
+
include CommonRailsOptions
|
10
|
+
|
11
|
+
# Stolen from ActiveSupport
|
12
|
+
INTEGER_REGEX = /\A[+-]?\d+\Z/.freeze
|
13
|
+
|
14
|
+
COMPARISON_OPTIONS = {
|
15
|
+
:greater_than => lambda { |base, x| x > base },
|
16
|
+
:greater_than_or_equal_to => lambda { |base, x| x >= base },
|
17
|
+
:equal_to => lambda { |base, x| x == base },
|
18
|
+
:less_than => lambda { |base, x| x < base },
|
19
|
+
:less_than_or_equal_to => lambda { |base, x| x <= base },
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
include_validation do |object, result|
|
23
|
+
each_validated_attribute_on(object) do |attribute_name, value|
|
24
|
+
next if ignore_value?(value)
|
25
|
+
|
26
|
+
begin
|
27
|
+
coerced_value = coerce_to_number(value)
|
28
|
+
|
29
|
+
each_comparison_violation_of(coerced_value) do |violation, base|
|
30
|
+
result.add_violation(attribute_name, violation, :count => base)
|
31
|
+
end
|
32
|
+
rescue TypeError, ArgumentError
|
33
|
+
result.add_violation(attribute_name, :not_a_number)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def ignore_value?(value)
|
41
|
+
if options[:allow_nil]
|
42
|
+
value.nil?
|
43
|
+
elsif options[:allow_blank]
|
44
|
+
value.blank?
|
45
|
+
else
|
46
|
+
false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def each_comparison_violation_of(value)
|
51
|
+
selected_comparisons.each do |option, (base, check)|
|
52
|
+
yield(option, base) unless check.call(base, value)
|
53
|
+
end
|
54
|
+
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def selected_comparisons
|
59
|
+
return @selected_comparisons if defined?(@selected_comparisons)
|
60
|
+
|
61
|
+
passed = COMPARISON_OPTIONS.keys & options.keys
|
62
|
+
@selected_comparisons = passed.each_with_object({}) do |option, result|
|
63
|
+
result[option] = [options[option], COMPARISON_OPTIONS[option]]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def coerce_to_number(value)
|
68
|
+
if options[:only_integer]
|
69
|
+
raise ArgumentError unless value.to_s =~ INTEGER_REGEX
|
70
|
+
Kernel.Integer(value)
|
71
|
+
else
|
72
|
+
Kernel.Float(value)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -25,6 +25,8 @@ class StandaloneValidator
|
|
25
25
|
@violations = violations.to_list
|
26
26
|
end
|
27
27
|
|
28
|
+
OK = new({})
|
29
|
+
|
28
30
|
def add_errors_to(errors_object)
|
29
31
|
violations.each do |violation|
|
30
32
|
violation.add_to(errors_object)
|
@@ -33,15 +35,13 @@ class StandaloneValidator
|
|
33
35
|
self
|
34
36
|
end
|
35
37
|
|
36
|
-
OK = new({})
|
37
|
-
|
38
38
|
include Enumerable
|
39
39
|
|
40
40
|
def each(&block)
|
41
41
|
violations.each(&block)
|
42
42
|
end
|
43
43
|
|
44
|
-
def empty
|
44
|
+
def empty?
|
45
45
|
violations.empty?
|
46
46
|
end
|
47
47
|
|
@@ -50,5 +50,26 @@ class StandaloneValidator
|
|
50
50
|
end
|
51
51
|
|
52
52
|
alias_method :valid?, :ok?
|
53
|
+
|
54
|
+
def [](attribute)
|
55
|
+
violations.select do |violation|
|
56
|
+
violation.attribute == attribute
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def of_type(type)
|
61
|
+
subset { |violation| violation.type == type }
|
62
|
+
end
|
63
|
+
|
64
|
+
def on_attribute(attribute)
|
65
|
+
subset { |violation| violation.attribute == attribute }
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def subset(&block)
|
71
|
+
self.class.new(:violations => violations.select(&block),
|
72
|
+
:validated_object => validated_object)
|
73
|
+
end
|
53
74
|
end
|
54
75
|
end
|
@@ -10,10 +10,11 @@ class StandaloneValidator
|
|
10
10
|
self
|
11
11
|
end
|
12
12
|
|
13
|
-
def add_violation(attribute_name, violation_type_or_message)
|
13
|
+
def add_violation(attribute_name, violation_type_or_message, options = {})
|
14
14
|
creation_attributes = {
|
15
15
|
:attribute => attribute_name.to_sym,
|
16
|
-
:source_object => validated_object
|
16
|
+
:source_object => validated_object,
|
17
|
+
:options => options,
|
17
18
|
}
|
18
19
|
|
19
20
|
if violation_type_or_message.kind_of?(Symbol)
|
@@ -8,9 +8,10 @@ class StandaloneValidator
|
|
8
8
|
attribute :attribute, Symbol, :default => :base
|
9
9
|
attribute :type, Symbol, :default => :invalid
|
10
10
|
attribute :message, String, :default => nil
|
11
|
+
attribute :options, Hash, :default => {}
|
11
12
|
|
12
13
|
def add_to(errors_object)
|
13
|
-
errors_object.add(attribute, message || type)
|
14
|
+
errors_object.add(attribute, message || type, options)
|
14
15
|
self
|
15
16
|
end
|
16
17
|
end
|
data/lib/standalone_validator.rb
CHANGED
@@ -32,21 +32,35 @@ class StandaloneValidator
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
def required_fields
|
36
|
+
return @required_fields if defined?(@required_fields)
|
37
|
+
|
38
|
+
if superclass.kind_of?(StandaloneValidator)
|
39
|
+
@required_fields = superclass.required_fields
|
40
|
+
else
|
41
|
+
@required_fields = Hamster.set
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
35
45
|
private
|
36
46
|
|
37
47
|
def include_validation(*args, &block)
|
38
48
|
validation = Definitions.coerce_to_validation(*args, &block)
|
39
49
|
@validations = validations.add(validation)
|
40
50
|
end
|
51
|
+
|
52
|
+
def requires_field(name)
|
53
|
+
@required_fields = required_fields.add(name.to_sym)
|
54
|
+
end
|
41
55
|
end
|
42
56
|
|
43
57
|
require 'standalone_validator/named_validations'
|
44
58
|
|
45
|
-
def violations_of(object)
|
46
|
-
builder = ValidationResultBuilder.new
|
59
|
+
def violations_of(object, appliable_validations = validations)
|
60
|
+
builder = StandaloneValidator::ValidationResultBuilder.new
|
47
61
|
builder.validated_object = object
|
48
62
|
|
49
|
-
|
63
|
+
appliable_validations.each do |validation|
|
50
64
|
if validation.respond_to?(:to_proc)
|
51
65
|
result = instance_exec(object, &validation)
|
52
66
|
else
|
@@ -67,6 +81,16 @@ class StandaloneValidator
|
|
67
81
|
validation_result
|
68
82
|
end
|
69
83
|
|
84
|
+
def requires_field?(field)
|
85
|
+
return true if self.class.required_fields.include?(field.to_sym)
|
86
|
+
|
87
|
+
validations.any? do |validation|
|
88
|
+
if validation.respond_to?(:requires_field?)
|
89
|
+
validation.requires_field?(field)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
70
94
|
private
|
71
95
|
|
72
96
|
def validations
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "ostruct"
|
3
|
+
require "standalone_validator"
|
4
|
+
|
5
|
+
module StandaloneValidator::NamedValidations
|
6
|
+
describe "validates_numericality_of" do
|
7
|
+
let(:object) { OpenStruct.new }
|
8
|
+
let(:validator) { ValidatesNumericalityOf.new(:foo) }
|
9
|
+
|
10
|
+
it "adds a 'not_a_number' violation if the attribute isn't a number" do
|
11
|
+
object.foo = "not a number"
|
12
|
+
violations = validator.violations_of(object).on_attribute(:foo)
|
13
|
+
expect(violations.of_type(:not_a_number)).to_not be_empty
|
14
|
+
end
|
15
|
+
|
16
|
+
it "doesn't add the violation if the attribute is a number" do
|
17
|
+
object.foo = 10
|
18
|
+
violations = validator.violations_of(object).on_attribute(:foo)
|
19
|
+
expect(violations.of_type(:not_a_number)).to be_empty
|
20
|
+
end
|
21
|
+
|
22
|
+
it "accepts strings that represent integer numbers" do
|
23
|
+
object.foo = "10"
|
24
|
+
violations = validator.violations_of(object).on_attribute(:foo)
|
25
|
+
expect(violations.of_type(:not_a_number)).to be_empty
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "the :only_integer option" do
|
29
|
+
context "when the :only_integer option is set to true" do
|
30
|
+
let(:validator) { ValidatesNumericalityOf.new(:foo, :only_integer => true) }
|
31
|
+
|
32
|
+
it "does not accept floats" do
|
33
|
+
object.foo = 10.5
|
34
|
+
violations = validator.violations_of(object).on_attribute(:foo)
|
35
|
+
expect(violations.of_type(:not_a_number)).to_not be_empty
|
36
|
+
end
|
37
|
+
|
38
|
+
it "does not accept strings that represent floating numbers" do
|
39
|
+
object.foo = "10.5"
|
40
|
+
violations = validator.violations_of(object).on_attribute(:foo)
|
41
|
+
expect(violations.of_type(:not_a_number)).to_not be_empty
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when the :only_integer is not set" do
|
46
|
+
let(:validator) { ValidatesNumericalityOf.new(:foo) }
|
47
|
+
|
48
|
+
it "accepts floats" do
|
49
|
+
object.foo = 10.5
|
50
|
+
violations = validator.violations_of(object).on_attribute(:foo)
|
51
|
+
expect(violations.of_type(:not_a_number)).to be_empty
|
52
|
+
end
|
53
|
+
|
54
|
+
it "accepts strings that represent floating numbers" do
|
55
|
+
object.foo = "10.5"
|
56
|
+
violations = validator.violations_of(object).on_attribute(:foo)
|
57
|
+
expect(violations.of_type(:not_a_number)).to be_empty
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "the :allow_blank option" do
|
63
|
+
context "when the :allow_blank option is set" do
|
64
|
+
let(:validator) { ValidatesNumericalityOf.new(:foo, :allow_blank => true) }
|
65
|
+
|
66
|
+
it "ignores 'blank' values" do
|
67
|
+
object.foo = stub(:blank? => true, :to_f => 0)
|
68
|
+
violations = validator.violations_of(object).on_attribute(:foo)
|
69
|
+
expect(violations).to be_empty
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context "when the :allow_blank option is not set" do
|
74
|
+
let(:validator) { ValidatesNumericalityOf.new(:foo) }
|
75
|
+
|
76
|
+
it "does not ignore 'blank' values" do
|
77
|
+
object.foo = stub(:blank? => true, :to_f => 0)
|
78
|
+
violations = validator.violations_of(object).on_attribute(:foo)
|
79
|
+
expect(violations.of_type(:not_a_number)).to_not be_empty
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "the :allow_nil option" do
|
85
|
+
context "when the :allow_nil option is set" do
|
86
|
+
let(:validator) { ValidatesNumericalityOf.new(:foo, :allow_nil => true) }
|
87
|
+
|
88
|
+
it "ignores nil values" do
|
89
|
+
object.foo = nil
|
90
|
+
violations = validator.violations_of(object).on_attribute(:foo)
|
91
|
+
expect(violations).to be_empty
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "when the :allow_blank option is not set" do
|
96
|
+
let(:validator) { ValidatesNumericalityOf.new(:foo) }
|
97
|
+
|
98
|
+
it "does not ignore 'nil' values" do
|
99
|
+
object.foo = nil
|
100
|
+
violations = validator.violations_of(object).on_attribute(:foo)
|
101
|
+
expect(violations.of_type(:not_a_number)).to_not be_empty
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
compared_value = v = 1
|
107
|
+
|
108
|
+
comparison_options = {
|
109
|
+
:greater_than => {:ok => v + 1, :not_ok => [v, v - 1] },
|
110
|
+
:greater_than_or_equal_to => {:ok => [v, v + 1], :not_ok => v - 1 },
|
111
|
+
:equal_to => {:ok => v, :not_ok => [v - 1, v + 1]},
|
112
|
+
:less_than => {:ok => v - 1, :not_ok => [v, v + 1] },
|
113
|
+
:less_than_or_equal_to => {:ok => [v, v - 1], :not_ok => v + 1 },
|
114
|
+
}.freeze
|
115
|
+
|
116
|
+
comparison_options.each do |option_name, comparisons|
|
117
|
+
describe "when '#{compared_value}' is given on :#{option_name}" do
|
118
|
+
let(:validator) do
|
119
|
+
ValidatesNumericalityOf.new(:foo, option_name => compared_value)
|
120
|
+
end
|
121
|
+
|
122
|
+
Array(comparisons[:ok]).each do |ok_value|
|
123
|
+
it "accepts the value '#{ok_value}'" do
|
124
|
+
object.foo = ok_value
|
125
|
+
violations = validator.violations_of(object).on_attribute(:foo)
|
126
|
+
expect(violations.of_type(option_name)).to be_empty
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
Array(comparisons[:not_ok]).each do |not_ok_value|
|
131
|
+
it "rejects the value '#{not_ok_value}'" do
|
132
|
+
object.foo = not_ok_value
|
133
|
+
violations = validator.violations_of(object).on_attribute(:foo)
|
134
|
+
expect(violations.of_type(option_name)).to_not be_empty
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
it "accepts an :if condition that can block the validation" do
|
141
|
+
validator = ValidatesNumericalityOf.new :foo, :if => :bar
|
142
|
+
|
143
|
+
triggers = stub(:foo => "not a number", :bar => true)
|
144
|
+
doesnt_trigger = stub(:foo => "not a number", :bar => false)
|
145
|
+
|
146
|
+
result = validator.violations_of(triggers)
|
147
|
+
expect(result).to_not be_ok
|
148
|
+
|
149
|
+
result = validator.violations_of(doesnt_trigger)
|
150
|
+
expect(result).to be_ok
|
151
|
+
end
|
152
|
+
|
153
|
+
it "accepts an :unless condition that can block the validation" do
|
154
|
+
validator = ValidatesNumericalityOf.new :foo, :unless => :bar
|
155
|
+
|
156
|
+
triggers = stub(:foo => "not a number", :bar => false)
|
157
|
+
doesnt_trigger = stub(:foo => "not a number", :bar => true)
|
158
|
+
|
159
|
+
result = validator.violations_of(triggers)
|
160
|
+
expect(result).to_not be_ok
|
161
|
+
|
162
|
+
result = validator.violations_of(doesnt_trigger)
|
163
|
+
expect(result).to be_ok
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -43,5 +43,11 @@ module StandaloneValidator::NamedValidations
|
|
43
43
|
result = validator.violations_of(doesnt_trigger)
|
44
44
|
expect(result).to be_ok
|
45
45
|
end
|
46
|
+
|
47
|
+
it "requires the attributes it was given on construction" do
|
48
|
+
validator = ValidatesPresenceOf.new :foo
|
49
|
+
expect(validator.requires_field?(:foo)).to be_true
|
50
|
+
expect(validator.requires_field?(:bar)).to be_false
|
51
|
+
end
|
46
52
|
end
|
47
53
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: standalone_validator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Renato Zannon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-05-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: backports
|
@@ -114,12 +114,14 @@ files:
|
|
114
114
|
- lib/standalone_validator/definitions.rb
|
115
115
|
- lib/standalone_validator/named_validations.rb
|
116
116
|
- lib/standalone_validator/named_validations/common_rails_options.rb
|
117
|
+
- lib/standalone_validator/named_validations/validates_numericality_of.rb
|
117
118
|
- lib/standalone_validator/named_validations/validates_presence_of.rb
|
118
119
|
- lib/standalone_validator/validation_result.rb
|
119
120
|
- lib/standalone_validator/validation_result_builder.rb
|
120
121
|
- lib/standalone_validator/version.rb
|
121
122
|
- lib/standalone_validator/violation.rb
|
122
123
|
- spec/integration_spec.rb
|
124
|
+
- spec/named_validations/validates_numericality_of_spec.rb
|
123
125
|
- spec/named_validations/validates_presence_of_spec.rb
|
124
126
|
- spec/spec_helper.rb
|
125
127
|
- standalone_validator.gemspec
|
@@ -143,12 +145,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
143
145
|
version: '0'
|
144
146
|
requirements: []
|
145
147
|
rubyforge_project:
|
146
|
-
rubygems_version: 2.0.
|
148
|
+
rubygems_version: 2.0.3
|
147
149
|
signing_key:
|
148
150
|
specification_version: 4
|
149
151
|
summary: PORO standalone validators compatible with ActiveRecord
|
150
152
|
test_files:
|
151
153
|
- spec/integration_spec.rb
|
154
|
+
- spec/named_validations/validates_numericality_of_spec.rb
|
152
155
|
- spec/named_validations/validates_presence_of_spec.rb
|
153
156
|
- spec/spec_helper.rb
|
154
157
|
has_rdoc:
|