standalone_validator 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bca879be6bf42bd2a02eae2221a168206782348c
4
- data.tar.gz: a82ee314d96bf3d10b3dbc16538de68d6311fbbe
3
+ metadata.gz: 43bfee850787c7744539eb0695223feae9bce1d5
4
+ data.tar.gz: dbf0df8cce8600097a85a8aefef28633febc0fae
5
5
  SHA512:
6
- metadata.gz: 1eb6e22ab8bd654da4d87a0917b52d1ffa25a4ae81bf9e6ab30dc9c07460bd8a7de3022f4dc7a74ecee7c3259b69e75284009fe27c3cdfec07e45a88f57ba9cf
7
- data.tar.gz: 97822fabfa6deb523853f135df9ce830b2b05b3f785a524e6f0f3fc02a1dce48df91353037d38711d5e94bf2519b321fe8b0991cdcb7015b182ec6a73e75c6c6
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
@@ -15,6 +15,10 @@ class StandaloneValidator
15
15
  end
16
16
  end
17
17
  end
18
+
19
+ def requires_field?(field)
20
+ attributes.include?(field.to_sym)
21
+ end
18
22
  end
19
23
  end
20
24
  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)
@@ -1,3 +1,3 @@
1
1
  class StandaloneValidator
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -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
@@ -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
- validations.each do |validation|
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.1
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-03-07 00:00:00.000000000 Z
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.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: