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.
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: