activemodel-validators 1.0.0
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 +7 -0
- data/.gitignore +4 -0
- data/.rspec +2 -0
- data/Gemfile +11 -0
- data/Rakefile +24 -0
- data/Readme.md +132 -0
- data/activemodel-validators.gemspec +25 -0
- data/config/locales/en.yml +12 -0
- data/lib/activemodel-validators.rb +26 -0
- data/lib/activemodel-validators/address_state_validator.rb +12 -0
- data/lib/activemodel-validators/all.rb +3 -0
- data/lib/activemodel-validators/at_least_one_present_validator.rb +13 -0
- data/lib/activemodel-validators/at_least_validator.rb +16 -0
- data/lib/activemodel-validators/blank_validator.rb +11 -0
- data/lib/activemodel-validators/boolean_presence_validator.rb +17 -0
- data/lib/activemodel-validators/date_validator.rb +22 -0
- data/lib/activemodel-validators/greater_than_validator.rb +16 -0
- data/lib/activemodel-validators/less_or_greater_than_validator.rb +74 -0
- data/lib/activemodel-validators/less_than_validator.rb +16 -0
- data/lib/activemodel-validators/multiple_of_validator.rb +18 -0
- data/lib/activemodel-validators/phone_validator.rb +8 -0
- data/lib/activemodel-validators/postal_code_validator.rb +8 -0
- data/lib/activemodel-validators/rails.rb +4 -0
- data/lib/activemodel-validators/restrict_to_validator.rb +51 -0
- data/lib/activemodel-validators/sum_of_validator.rb +23 -0
- data/lib/activemodel-validators/version.rb +5 -0
- data/lib/activemodel-validators/year_validator.rb +8 -0
- data/spec/less_or_greater_than_validator_spec.rb +13 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/support/models/response.rb +8 -0
- data/spec/support/models/user.rb +3 -0
- metadata +89 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 795554ae591fe014e540d898361f2a4aaa2a588a
|
4
|
+
data.tar.gz: c33cdc6d6417a0dfddec20ed28b0f3c43032b3eb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b3e2e2d049271ea0b24acfce842c5db974f11ff81203faed628c688823ec30d8b5113b8f973b288482a29a82fa271aee6011406d884fe462592c5b2606cbd794
|
7
|
+
data.tar.gz: e307cc4d0699d8d541bbb0c7a8b021f765c005023c5840222ad9e8b98d7c1679ca400d238c4c87f5109b13624883d4e948d9e9fa87cc0e3e4d3a702474017d85
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
|
3
|
+
#require 'bundler'
|
4
|
+
#begin
|
5
|
+
# Bundler.setup(:default, :development)
|
6
|
+
#rescue Bundler::BundlerError => e
|
7
|
+
# $stderr.puts e.message
|
8
|
+
# $stderr.puts "Run `bundle install` to install missing gems"
|
9
|
+
# exit e.status_code
|
10
|
+
#end
|
11
|
+
|
12
|
+
#---------------------------------------------------------------------------------------------------
|
13
|
+
require 'rspec/core'
|
14
|
+
require 'rspec/core/rake_task'
|
15
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
16
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
20
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
21
|
+
spec.rcov = true
|
22
|
+
end
|
23
|
+
|
24
|
+
task :default => :spec
|
data/Readme.md
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
ActiveModel Validators
|
2
|
+
=======================
|
3
|
+
|
4
|
+
A collection of Rails 3 ActiveModel Validators
|
5
|
+
|
6
|
+
Example Usage
|
7
|
+
-------------
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
class Thing < ActiveRecord::Base
|
11
|
+
validates :birthdate, greater_than: { value: Date.new(1900), message: 'must be later than 1900' }
|
12
|
+
validates :birthdate, less_than: { value: Time.zone.now.years_ago(1).to_date+1, message: 'must be at least 1 year ago' }
|
13
|
+
validates :end_date, greater_than: {attr: :begin_date, operator_text: 'later than'}
|
14
|
+
|
15
|
+
# shortcut for greater_than: { value: 1, operator: :>=, operator_text: 'at least' }
|
16
|
+
validates :how_many_pies, at_least: { value: 1 }
|
17
|
+
|
18
|
+
# Because presence: true doesn't work for boolean attributes!
|
19
|
+
validates :is_18_or_older, boolean_presence: true
|
20
|
+
|
21
|
+
validates :model, restrict_to: {allowed_options: ['Model A', 'Model B']}, allow_blank: true
|
22
|
+
|
23
|
+
validates_with AtLeastOnePresentValidator, at_least_one_of: [:parent_1_home_phone, :parent_1_work_phone, :parent_1_mobile_phone], message: :at_least_one_phone_parent_1
|
24
|
+
|
25
|
+
validates :option_b, blank: {message: :must_be_blank_if_option_a}, if: :option_a?
|
26
|
+
|
27
|
+
validates :rating, multiple_of: {of: '0.5'}
|
28
|
+
|
29
|
+
validates :total_profit, sum_of: { attr_names: (1..4).map {|quarter| :"total_profit_q#{quarter}" } }
|
30
|
+
|
31
|
+
validates :end_date, date: {required: true}
|
32
|
+
validates :graduation_year, year: true
|
33
|
+
|
34
|
+
validates :phone, phone: true
|
35
|
+
validates :address_postal_code, postal_code: true
|
36
|
+
validates :address_state, address_state: true
|
37
|
+
end
|
38
|
+
```
|
39
|
+
|
40
|
+
Documentation
|
41
|
+
-------------
|
42
|
+
|
43
|
+
* [GreaterThanValidator](activemodel-validators/blob/master/lib/activemodel-validators/greater_than_validator.rb)
|
44
|
+
* [LessOrGreaterThanValidator](activemodel-validators/blob/master/lib/activemodel-validators/less_or_greater_than_validator.rb)
|
45
|
+
* [LessThanValidator](activemodel-validators/blob/master/lib/activemodel-validators/less_than_validator.rb)
|
46
|
+
* [AtLeastValidator](activemodel-validators/blob/master/lib/activemodel-validators/at_least_validator.rb)
|
47
|
+
|
48
|
+
* [BooleanPresenceValidator](activemodel-validators/blob/master/lib/activemodel-validators/boolean_presence_validator.rb)
|
49
|
+
* [RestrictToValidator](activemodel-validators/blob/master/lib/activemodel-validators/restrict_to_validator.rb)
|
50
|
+
* [AtLeastOnePresentValidator](activemodel-validators/blob/master/lib/activemodel-validators/at_least_one_present_validator.rb)
|
51
|
+
* [BlankValidator](activemodel-validators/blob/master/lib/activemodel-validators/blank_validator.rb)
|
52
|
+
* [MultipleOfValidator](activemodel-validators/blob/master/lib/activemodel-validators/multiple_of_validator.rb)
|
53
|
+
* [SumOfValidator](activemodel-validators/blob/master/lib/activemodel-validators/sum_of_validator.rb)
|
54
|
+
|
55
|
+
* [DateValidator](activemodel-validators/blob/master/lib/activemodel-validators/date_validator.rb)
|
56
|
+
* [YearValidator](activemodel-validators/blob/master/lib/activemodel-validators/year_validator.rb)
|
57
|
+
|
58
|
+
* [PhoneValidator](activemodel-validators/blob/master/lib/activemodel-validators/phone_validator.rb)
|
59
|
+
* [PostalCodeValidator](activemodel-validators/blob/master/lib/activemodel-validators/postal_code_validator.rb)
|
60
|
+
* [AddressStateValidator](activemodel-validators/blob/master/lib/activemodel-validators/address_state_validator.rb)
|
61
|
+
|
62
|
+
Installation
|
63
|
+
============
|
64
|
+
|
65
|
+
Add to your Gemfile :
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
gem 'activemodel-validators'
|
69
|
+
```
|
70
|
+
|
71
|
+
|
72
|
+
Comparison to other validation gems/collections
|
73
|
+
===============================================
|
74
|
+
|
75
|
+
I like this idea from https://github.com/fnando/validators:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
class Server < ActiveRecord::Base
|
79
|
+
validates_datetime :starts_at
|
80
|
+
validates_datetime :ends_at, :after => :starts_at, :if => :starts_at?
|
81
|
+
validates_datetime :ends_at, :after => :now
|
82
|
+
validates_datetime :ends_at, :before => :today
|
83
|
+
|
84
|
+
validates :starts_at, :datetime => true
|
85
|
+
end
|
86
|
+
```
|
87
|
+
|
88
|
+
Other collections worth taking a look at:
|
89
|
+
-----------------------------------------------
|
90
|
+
|
91
|
+
* https://github.com/e-travel/evelpidon_validators
|
92
|
+
* Different
|
93
|
+
* Less
|
94
|
+
* More
|
95
|
+
* Associated
|
96
|
+
* Credit Card
|
97
|
+
* https://github.com/cesario/activevalidators
|
98
|
+
* :postal_code => { :country => :us }
|
99
|
+
* :phone => true
|
100
|
+
* :password => { :strength => :medium }
|
101
|
+
* https://github.com/fnando/validators
|
102
|
+
* https://github.com/jeremiahishere/format_validators
|
103
|
+
* :phone_format => true
|
104
|
+
* Days of the Week
|
105
|
+
|
106
|
+
Other collections not worth taking a look at:
|
107
|
+
-----------------------------------------------
|
108
|
+
|
109
|
+
* https://github.com/willian/rails_validators
|
110
|
+
* https://github.com/infosimples/more_validators
|
111
|
+
* https://github.com/aurels/extra_validators
|
112
|
+
|
113
|
+
Specialized validators that stand on their own:
|
114
|
+
-----------------------------------------------
|
115
|
+
|
116
|
+
* https://github.com/balexand/email_validator
|
117
|
+
|
118
|
+
|
119
|
+
To do
|
120
|
+
=====
|
121
|
+
|
122
|
+
* Write actual documentation
|
123
|
+
* Add tests
|
124
|
+
* Merge into/with an other existing gem
|
125
|
+
|
126
|
+
|
127
|
+
License
|
128
|
+
=======
|
129
|
+
|
130
|
+
Copyright 2012, Tyler Rick
|
131
|
+
|
132
|
+
This is free software, distributed under the terms of the MIT License.
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "activemodel-validators/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "activemodel-validators"
|
7
|
+
s.version = Activemodel::Validators::Version
|
8
|
+
s.authors = ["Tyler Rick"]
|
9
|
+
s.email = ["tyler@k3integrations.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Some reusable ActiveModel validations}
|
12
|
+
s.description = %q{Some reusable ActiveModel validations, including greater_than, boolean_presence, and at_least_one_present }
|
13
|
+
|
14
|
+
s.rubyforge_project = "activemodel-validators"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_runtime_dependency "activemodel"
|
22
|
+
|
23
|
+
# For config/locales
|
24
|
+
#s.add_runtime_dependency "railties"
|
25
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
en:
|
2
|
+
errors:
|
3
|
+
messages:
|
4
|
+
restrict_to: "is not one of the allowed options (%{allowed_options})"
|
5
|
+
|
6
|
+
less_or_greater_than: "must be %{operator_text} %{other_value}"
|
7
|
+
less_or_greater_than_attr: "must be %{operator_text} %{attr_name} (%{other_value})"
|
8
|
+
|
9
|
+
sum_of: "must be the sum of %{attr_names} (%{sum}) but was %{value}"
|
10
|
+
sum_of_with_addends: "must be the sum of %{attr_names} (%{addends} = %{sum}) but was %{value}"
|
11
|
+
|
12
|
+
must_be_blank: "must be blank"
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "active_model"
|
2
|
+
require "activemodel-validators/version"
|
3
|
+
require "activemodel-validators/rails"
|
4
|
+
require "activemodel-validators/all"
|
5
|
+
|
6
|
+
#module ActiveModel
|
7
|
+
# module Validations
|
8
|
+
# autoload :LessOrGreaterThanValidator , 'activemodel-validators/less_or_greater_than_validator'
|
9
|
+
# autoload :GreaterThanValidator , 'activemodel-validators/greater_than_validator'
|
10
|
+
# autoload :LessThanValidator , 'activemodel-validators/less_than_validator'
|
11
|
+
#
|
12
|
+
# autoload :BooleanPresenceValidator , 'activemodel-validators/boolean_presence_validator'
|
13
|
+
# autoload :RestrictToValidator , 'activemodel-validators/restrict_to_validator'
|
14
|
+
# autoload :AtLeastOnePresentValidator , 'activemodel-validators/at_least_one_present_validator'
|
15
|
+
# autoload :BlankValidator , 'activemodel-validators/blank_validator'
|
16
|
+
# autoload :MultipleOfValidator , 'activemodel-validators/multiple_of_validator'
|
17
|
+
# autoload :SumOfValidator , 'activemodel-validators/sum_of_validator'
|
18
|
+
#
|
19
|
+
# autoload :DateValidator , 'activemodel-validators/date_validator'
|
20
|
+
# autoload :YearValidator , 'activemodel-validators/year_validator'
|
21
|
+
#
|
22
|
+
# autoload :PhoneValidator , 'activemodel-validators/phone_validator'
|
23
|
+
# autoload :PostalCodeValidator , 'activemodel-validators/postal_code_validator'
|
24
|
+
# autoload :AddressStateValidator , 'activemodel-validators/address_state_validator'
|
25
|
+
# end
|
26
|
+
#end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
class AddressStateValidator < ActiveModel::EachValidator
|
4
|
+
def validate_each(record, attribute, value)
|
5
|
+
return if value.blank?
|
6
|
+
unless value.match /\A^[A-Z ]{2,}\z/i
|
7
|
+
record.errors.add attribute, :state_invalid
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
class AtLeastOnePresentValidator < ActiveModel::Validator
|
4
|
+
def validate(record)
|
5
|
+
attr_names = options[:at_least_one_of]
|
6
|
+
#puts %(attr_names=#{attr_names.inspect})
|
7
|
+
unless attr_names.map {|attr_name| record[attr_name]}.any?(&:present?)
|
8
|
+
record.errors.add :base, options[:message] || "at least 1 of these fields must be present: #{attr_names.to_sentence(last_word_connector: ', or ')}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'activemodel-validators/greater_than_validator'
|
2
|
+
|
3
|
+
module ActiveModel
|
4
|
+
module Validations
|
5
|
+
class AtLeastValidator < GreaterThanValidator
|
6
|
+
protected
|
7
|
+
def default_operator
|
8
|
+
:>=
|
9
|
+
end
|
10
|
+
def operator_text
|
11
|
+
options[:operator_text] || 'at least' || super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
class BooleanPresenceValidator < ActiveModel::EachValidator
|
4
|
+
# You can't use validates :presence for boolean attributes!
|
5
|
+
# You could do this instead:
|
6
|
+
# validates_inclusion_of :attr, :in => [true, false]
|
7
|
+
# but the main reason to use this validator instead of is that the error message is better ("not
|
8
|
+
# in list? what list?") and the meaning is clearer when reading the code (we're validating the
|
9
|
+
# presence of a boolean attribute -- true or false).
|
10
|
+
def validate_each(record, attribute, value)
|
11
|
+
unless [true, false].include? value
|
12
|
+
record.errors.add attribute, :blank
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
class DateValidator < ActiveModel::EachValidator
|
4
|
+
def validate_each(record, attr_name, value)
|
5
|
+
before_type_cast = "#{attr_name}_before_type_cast"
|
6
|
+
raw_value = record.send(before_type_cast) if record.respond_to?(before_type_cast.to_sym)
|
7
|
+
#puts "raw_value=#{raw_value.inspect} (#{raw_value.class}), value=#{value.inspect} (#{value.class})"
|
8
|
+
raw_value ||= value
|
9
|
+
|
10
|
+
if raw_value.present? and !value.is_a?(Date)
|
11
|
+
record.errors.add attr_name, :date_invalid
|
12
|
+
return # don't want it to show *both* errors (:date_invalid and :blank)
|
13
|
+
end
|
14
|
+
|
15
|
+
if options[:required] && value.blank?
|
16
|
+
message = (options[:required] == true ? :blank : options[:required])
|
17
|
+
record.errors.add attr_name, message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'activemodel-validators/less_or_greater_than_validator'
|
2
|
+
|
3
|
+
module ActiveModel
|
4
|
+
module Validations
|
5
|
+
class GreaterThanValidator < LessOrGreaterThanValidator
|
6
|
+
protected
|
7
|
+
def default_operator
|
8
|
+
:>
|
9
|
+
end
|
10
|
+
|
11
|
+
def allowed_operators
|
12
|
+
[:>, :>=]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
module Validations
|
3
|
+
class LessOrGreaterThanValidator < ActiveModel::EachValidator
|
4
|
+
def check_validity!
|
5
|
+
unless options[:attr] or options[:value]
|
6
|
+
# TODO: If options[:attr], check that it is an actual column or virtual attribute
|
7
|
+
raise ArgumentError, "must supply :attr or :value option"
|
8
|
+
end
|
9
|
+
unless allowed_operators.include?(operator)
|
10
|
+
# TODO: If options[:attr], check that it is an actual column or virtual attribute
|
11
|
+
raise ArgumentError, ":operator must be one of #{allowed_operators.join(', ')} but was #{operator}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
def default_operator
|
17
|
+
raise NotImplementedError, 'must be defined in subclass'
|
18
|
+
end
|
19
|
+
|
20
|
+
def operator
|
21
|
+
options[:operator] || default_operator
|
22
|
+
end
|
23
|
+
|
24
|
+
# Defaults to the standard mathematical name for these operators, but you're free to override with
|
25
|
+
# something that makes more sense ('later than' might make more sense for dates, for example)
|
26
|
+
def operator_text
|
27
|
+
options[:operator_text] ||
|
28
|
+
{
|
29
|
+
:< => 'less than',
|
30
|
+
:<= => 'less than or equal to',
|
31
|
+
:> => 'greater than',
|
32
|
+
:>= => 'greater than or equal to',
|
33
|
+
:== => 'equal to',
|
34
|
+
}[operator]
|
35
|
+
end
|
36
|
+
|
37
|
+
# The value we're comparing against.
|
38
|
+
# If we're comparing to another attribute, options[:attr] must be a symbol.
|
39
|
+
# Otherwise, options[:value] may be any comparable value (number, date).
|
40
|
+
def other_value
|
41
|
+
if comparing_to_attr?
|
42
|
+
@record.send options[:attr]
|
43
|
+
else
|
44
|
+
options[:value]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def comparing_to_attr?
|
49
|
+
!!options[:attr]
|
50
|
+
end
|
51
|
+
|
52
|
+
def message_key
|
53
|
+
comparing_to_attr? ? :less_or_greater_than_attr : :less_or_greater_than
|
54
|
+
end
|
55
|
+
public
|
56
|
+
|
57
|
+
def validate_each(record, attribute, value)
|
58
|
+
@record = record
|
59
|
+
return if value.blank? or other_value.blank?
|
60
|
+
unless value.send(operator, other_value)
|
61
|
+
record.errors.add(attribute, message_key,
|
62
|
+
options.merge(
|
63
|
+
value: value,
|
64
|
+
operator: operator,
|
65
|
+
operator_text: operator_text,
|
66
|
+
attr_name: options[:attr],
|
67
|
+
other_value: other_value,
|
68
|
+
)
|
69
|
+
)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'activemodel-validators/less_or_greater_than_validator'
|
2
|
+
|
3
|
+
module ActiveModel
|
4
|
+
module Validations
|
5
|
+
class LessThanValidator < LessOrGreaterThanValidator
|
6
|
+
protected
|
7
|
+
def default_operator
|
8
|
+
:<
|
9
|
+
end
|
10
|
+
|
11
|
+
def allowed_operators
|
12
|
+
[:<, :<=]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class MultipleOfValidator < ActiveModel::EachValidator
|
2
|
+
def validate_each(record, attribute, value)
|
3
|
+
return if value.blank?
|
4
|
+
#tolerance = options[:tolerance] || 0.00001
|
5
|
+
#puts %(#{value} % #{options[:of]}=#{(value % options[:of]).inspect})
|
6
|
+
|
7
|
+
#unless BigDecimal.new(value) % BigDecimal.new(options[:of]) <= tolerance
|
8
|
+
begin
|
9
|
+
unless BigDecimal.new(value.to_s) % BigDecimal.new(options[:of].to_s) == BigDecimal.new('0.0')
|
10
|
+
record.errors.add attribute, :not_multiple_of, of: options[:of]
|
11
|
+
end
|
12
|
+
rescue
|
13
|
+
puts "#{$!} for either #{value.inspect} or #{options[:of].inspect}"
|
14
|
+
return
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class RestrictToValidator < ActiveModel::EachValidator
|
2
|
+
ErrorMessage = "An object with the method #include? or a proc or lambda is required, " <<
|
3
|
+
"and must be supplied as the :allowed_options option of the configuration hash"
|
4
|
+
|
5
|
+
def initialize(*args)
|
6
|
+
super
|
7
|
+
@allowed_options = options[:allowed_options]
|
8
|
+
end
|
9
|
+
|
10
|
+
def check_validity!
|
11
|
+
unless [:include?, :call].any?{ |method| options[:allowed_options].respond_to?(method) }
|
12
|
+
raise ArgumentError, ErrorMessage
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def allowed_options(record)
|
17
|
+
@allowed_options.respond_to?(:call) ? @allowed_options.call(record) : @allowed_options
|
18
|
+
end
|
19
|
+
def allowed_options_string(record)
|
20
|
+
allowed_options = allowed_options(record)
|
21
|
+
if allowed_options.is_a?(Range)
|
22
|
+
"#{allowed_options}"
|
23
|
+
else
|
24
|
+
allowed_options.to_sentence(last_word_connector: ', or ')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate_each(record, attribute, value)
|
29
|
+
allowed_options = allowed_options(record)
|
30
|
+
inclusion_method = inclusion_method(allowed_options)
|
31
|
+
unless allowed_options.send(inclusion_method, value)
|
32
|
+
record.errors.add(attribute, :restrict_to,
|
33
|
+
options.except(:in).merge!(
|
34
|
+
value: value,
|
35
|
+
allowed_options: allowed_options_string(record)
|
36
|
+
)
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
# In Ruby 1.9 <tt>Range#include?</tt> on non-numeric ranges checks all possible values in the
|
45
|
+
# range for equality, so it may be slow for large ranges. The new <tt>Range#cover?</tt>
|
46
|
+
# uses the previous logic of comparing a value with the range endpoints.
|
47
|
+
def inclusion_method(enumerable)
|
48
|
+
enumerable.is_a?(Range) ? :cover? : :include?
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class SumOfValidator < ActiveModel::EachValidator
|
2
|
+
def check_validity!
|
3
|
+
unless options[:attr_names]
|
4
|
+
raise ArgumentError, "must supply :attr_names option"
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
def validate_each(record, attribute, value)
|
9
|
+
addends = options[:attr_names].map {|_| record[_] }
|
10
|
+
return if value.blank? || addends.any?(&:blank?)
|
11
|
+
sum = addends.sum
|
12
|
+
unless value == sum
|
13
|
+
record.errors.add(attribute, options[:message] || :sum_of,
|
14
|
+
options.merge(
|
15
|
+
attr_names: options[:attr_names].to_sentence,
|
16
|
+
addends: addends.join(' + '),
|
17
|
+
sum: sum,
|
18
|
+
value: value,
|
19
|
+
)
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'test that config/locales/en.yml is being loaded' do
|
4
|
+
it { I18n.t(:'errors.messages.must_be_blank').should == 'must be blank' }
|
5
|
+
end
|
6
|
+
|
7
|
+
describe Response do
|
8
|
+
it { should_not allow_value(0).for(:how_many_people).with_message('must be greater than or equal to 1') }
|
9
|
+
it { should allow_value(1).for(:how_many_people) }
|
10
|
+
|
11
|
+
it { should_not allow_value(0).for(:how_many_pies). with_message('must be at least 1') }
|
12
|
+
it { should allow_value(1).for(:how_many_pies) }
|
13
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'pp'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
__DIR__ = Pathname.new(__FILE__).dirname
|
5
|
+
$LOAD_PATH.unshift __DIR__
|
6
|
+
$LOAD_PATH.unshift __DIR__ + '../lib'
|
7
|
+
|
8
|
+
#---------------------------------------------------------------------------------------------------
|
9
|
+
# ActiveRecord
|
10
|
+
|
11
|
+
#require 'active_record'
|
12
|
+
#driver = ENV["DB"] || 'sqlite3'
|
13
|
+
##require driver
|
14
|
+
#database_config = YAML::load(File.open(__DIR__ + "support/database.#{driver}.yml"))
|
15
|
+
#ActiveRecord::Base.establish_connection(database_config)
|
16
|
+
|
17
|
+
#---------------------------------------------------------------------------------------------------
|
18
|
+
# RSpec
|
19
|
+
|
20
|
+
# TODO: Why does this seem to have no effect? Why don't I see gems like railties listed in $LOADED_FEATURES?
|
21
|
+
Bundler.setup(:default, :development)
|
22
|
+
#pp $LOADED_FEATURES
|
23
|
+
|
24
|
+
require 'rails/engine'
|
25
|
+
require 'rspec'
|
26
|
+
module ActiveRecord; end # Trick lib/shoulda/matchers/integrations/rspec.rb into including the ActiveModel matchers
|
27
|
+
require 'shoulda/matchers'
|
28
|
+
|
29
|
+
require 'activemodel-validators'
|
30
|
+
|
31
|
+
# Requires supporting ruby files in spec/support/
|
32
|
+
Dir[__DIR__ + 'support/**/*.rb'].each do |f|
|
33
|
+
require f
|
34
|
+
end
|
35
|
+
|
36
|
+
# TODO: Why is this necessary? http://api.rubyonrails.org/classes/Rails/Engine.html says that the
|
37
|
+
# Engine will "load locales at config/locales/*"? Maybe that only applies when you have a
|
38
|
+
# Rails::Application?
|
39
|
+
I18n.load_path << __DIR__ + '../config/locales/en.yml'
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class Response < Struct.new(:how_many_people, :how_many_pies)
|
2
|
+
#extend ActiveModel::Naming
|
3
|
+
#include ActiveModel::Conversion
|
4
|
+
include ActiveModel::Validations
|
5
|
+
|
6
|
+
validates :how_many_people, greater_than: { value: 1, operator: :>= }, allow_blank: true
|
7
|
+
validates :how_many_pies, at_least: { value: 1 }, allow_blank: true
|
8
|
+
end
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: activemodel-validators
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tyler Rick
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-06-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activemodel
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: 'Some reusable ActiveModel validations, including greater_than, boolean_presence,
|
28
|
+
and at_least_one_present '
|
29
|
+
email:
|
30
|
+
- tyler@k3integrations.com
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- .gitignore
|
36
|
+
- .rspec
|
37
|
+
- Gemfile
|
38
|
+
- Rakefile
|
39
|
+
- Readme.md
|
40
|
+
- activemodel-validators.gemspec
|
41
|
+
- config/locales/en.yml
|
42
|
+
- lib/activemodel-validators.rb
|
43
|
+
- lib/activemodel-validators/address_state_validator.rb
|
44
|
+
- lib/activemodel-validators/all.rb
|
45
|
+
- lib/activemodel-validators/at_least_one_present_validator.rb
|
46
|
+
- lib/activemodel-validators/at_least_validator.rb
|
47
|
+
- lib/activemodel-validators/blank_validator.rb
|
48
|
+
- lib/activemodel-validators/boolean_presence_validator.rb
|
49
|
+
- lib/activemodel-validators/date_validator.rb
|
50
|
+
- lib/activemodel-validators/greater_than_validator.rb
|
51
|
+
- lib/activemodel-validators/less_or_greater_than_validator.rb
|
52
|
+
- lib/activemodel-validators/less_than_validator.rb
|
53
|
+
- lib/activemodel-validators/multiple_of_validator.rb
|
54
|
+
- lib/activemodel-validators/phone_validator.rb
|
55
|
+
- lib/activemodel-validators/postal_code_validator.rb
|
56
|
+
- lib/activemodel-validators/rails.rb
|
57
|
+
- lib/activemodel-validators/restrict_to_validator.rb
|
58
|
+
- lib/activemodel-validators/sum_of_validator.rb
|
59
|
+
- lib/activemodel-validators/version.rb
|
60
|
+
- lib/activemodel-validators/year_validator.rb
|
61
|
+
- spec/less_or_greater_than_validator_spec.rb
|
62
|
+
- spec/spec_helper.rb
|
63
|
+
- spec/support/models/response.rb
|
64
|
+
- spec/support/models/user.rb
|
65
|
+
homepage: ''
|
66
|
+
licenses: []
|
67
|
+
metadata: {}
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
requirements: []
|
83
|
+
rubyforge_project: activemodel-validators
|
84
|
+
rubygems_version: 2.0.3
|
85
|
+
signing_key:
|
86
|
+
specification_version: 4
|
87
|
+
summary: Some reusable ActiveModel validations
|
88
|
+
test_files: []
|
89
|
+
has_rdoc:
|