activemodel-validators 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +11 -0
  5. data/Rakefile +24 -0
  6. data/Readme.md +132 -0
  7. data/activemodel-validators.gemspec +25 -0
  8. data/config/locales/en.yml +12 -0
  9. data/lib/activemodel-validators.rb +26 -0
  10. data/lib/activemodel-validators/address_state_validator.rb +12 -0
  11. data/lib/activemodel-validators/all.rb +3 -0
  12. data/lib/activemodel-validators/at_least_one_present_validator.rb +13 -0
  13. data/lib/activemodel-validators/at_least_validator.rb +16 -0
  14. data/lib/activemodel-validators/blank_validator.rb +11 -0
  15. data/lib/activemodel-validators/boolean_presence_validator.rb +17 -0
  16. data/lib/activemodel-validators/date_validator.rb +22 -0
  17. data/lib/activemodel-validators/greater_than_validator.rb +16 -0
  18. data/lib/activemodel-validators/less_or_greater_than_validator.rb +74 -0
  19. data/lib/activemodel-validators/less_than_validator.rb +16 -0
  20. data/lib/activemodel-validators/multiple_of_validator.rb +18 -0
  21. data/lib/activemodel-validators/phone_validator.rb +8 -0
  22. data/lib/activemodel-validators/postal_code_validator.rb +8 -0
  23. data/lib/activemodel-validators/rails.rb +4 -0
  24. data/lib/activemodel-validators/restrict_to_validator.rb +51 -0
  25. data/lib/activemodel-validators/sum_of_validator.rb +23 -0
  26. data/lib/activemodel-validators/version.rb +5 -0
  27. data/lib/activemodel-validators/year_validator.rb +8 -0
  28. data/spec/less_or_greater_than_validator_spec.rb +13 -0
  29. data/spec/spec_helper.rb +39 -0
  30. data/spec/support/models/response.rb +8 -0
  31. data/spec/support/models/user.rb +3 -0
  32. metadata +89 -0
@@ -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
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --no-drb
2
+ --color
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in activemodel-validators.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem 'rspec'
8
+ gem 'shoulda-matchers'
9
+ gem 'debugger', platform: :ruby_19
10
+ gem 'railties'
11
+ end
@@ -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
@@ -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,3 @@
1
+ require 'pathname'
2
+ __DIR__ = Pathname.new(__FILE__).dirname
3
+ Dir[__DIR__ + "**/*.rb"].each {|f| require f}
@@ -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,11 @@
1
+ module ActiveModel
2
+ module Validations
3
+ class BlankValidator < ActiveModel::EachValidator
4
+ def validate_each(record, attribute, value)
5
+ unless value.blank?
6
+ record.errors.add attribute, options[:message] || :must_be_blank
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -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,8 @@
1
+ class PhoneValidator < ActiveModel::EachValidator
2
+ def validate_each(record, attribute, value)
3
+ return if value.blank?
4
+ unless value.to_s.gsub(/[\s-]+/, '').length >= 10
5
+ record.errors[attribute] << "must have at least 10 digits"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ class PostalCodeValidator < ActiveModel::EachValidator
2
+ def validate_each(record, attribute, value)
3
+ return if value.blank?
4
+ if value.to_s.length < 5
5
+ record.errors.add attribute, :postal_code_too_short
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ module ActiveModelValidators
2
+ class Railtie < ::Rails::Engine
3
+ end
4
+ end if defined?(Rails)
@@ -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,5 @@
1
+ module Activemodel
2
+ module Validators
3
+ Version = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ class YearValidator < ActiveModel::EachValidator
2
+ def validate_each(record, attribute, value)
3
+ return if value.blank?
4
+ unless ((min=1700) .. (max=2200)).include? value
5
+ record.errors.add attribute, :year_invalid, min: min, max: max
6
+ end
7
+ end
8
+ 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
@@ -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
@@ -0,0 +1,3 @@
1
+ class User < Struct.new(:name, :age)
2
+ include ActiveModel::Validations
3
+ 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: