validation_kit 1.0.5 → 2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ff3e9944d7507b5b68ac90c343eb6e95ee9c8219b9f210dcdf843352c72ac39d
4
- data.tar.gz: 57c6162bd4b136b247c7c15857fcde816e65a592a5dfcff2f793bb8719fb060a
3
+ metadata.gz: 48f6bae26b123232914da0c154b955798b82233cf152c9c0c823f0f223289956
4
+ data.tar.gz: 55a3a8f8458f886adbcfb3e2dceb84d7900f206bc0c491d18203dc193ae755e3
5
5
  SHA512:
6
- metadata.gz: 686fc83cb5b88630d36ff2ceccc260e889f6800100700d8420b6a49d2702ffe5887892016fe219126ada9b656b2d671ca00f6fb991c5c5ba2dad0be84bba3016
7
- data.tar.gz: 831b93a7ec64043a9aaf43e2b050d4a93c0f050cda66dd378764857aad36bb09ffeba0fc59086dd19e2581e2227a9cd02c62c5f46f6bedd55dcbbe952d45accd
6
+ metadata.gz: 81cb679e9504f56963681edf741dd33c93c370664dc9e33c376923c934487a78f8d1e189f0506124889070fa62f3447c05978d8abffc2f5abf71094c4e53eafb
7
+ data.tar.gz: b8baa82c5421ae9388f1b36f12be7214613ad7948b8ac2bf5c1e8074a8e768a43a7ec1fa15466c3e06758bdbe58a7428d30a305559468f36be7eb0ac480596ff
data/CHANGELOG.md ADDED
@@ -0,0 +1,80 @@
1
+ # Changelog
2
+
3
+ ## 2.0.0 (2026-10-01)
4
+
5
+ ### Breaking changes
6
+
7
+ - **Ruby 3.4+ and activemodel 7.2+ are required.** The gem now declares its
8
+ activemodel dependency and loads without Rails.
9
+ - **Errors are added by type instead of as translated strings.** All four
10
+ validators call `errors.add(attribute, :invalid)` (mixed case:
11
+ `:all_caps` / `:all_lowercase`), so `errors.added?(:email, :invalid)` and
12
+ `errors.details` work, and ActiveModel does the message lookup.
13
+ - Existing `activerecord.errors.models.<model>.attributes.<attribute>.<type>`
14
+ translations keep working.
15
+ - Non-ActiveRecord models now look under `activemodel.*` instead of
16
+ `activerecord.*`, and fall back to Rails' "is invalid".
17
+ - A `message:` (or `all_caps:` / `all_lowercase:`) option now takes
18
+ precedence over translations, as it does for Rails' own validators.
19
+ - The bundled mixed case messages moved from `activerecord.errors.messages`
20
+ to `errors.messages`.
21
+ - **`ActiveModel::Validations::EmailValidator` (and `PhoneValidator`,
22
+ `PostalCodeValidator`, `MixedCaseValidator`) no longer exist.** Use
23
+ `ValidationKit::EmailValidator` and so on. `validates :email, email: true`
24
+ is unchanged, and an app's own validator with the same name now takes
25
+ precedence over the gem's.
26
+ - **`MixedCaseValidator::ALL_CAPS` / `ALL_LOWERCASE`** are now the symbols
27
+ `:all_caps` / `:all_lowercase` instead of `1` / `-1`.
28
+ - **Validation is stricter**, so some values that used to pass are now
29
+ invalid:
30
+ - postal codes of the wrong length (e.g. a 7-digit US ZIP code)
31
+ - email addresses containing a newline
32
+ - phone and postal input that's blank once cleaned up (e.g. `"n/a"`), even
33
+ with `allow_blank`
34
+ - **`format_as_phone` returns `nil`** for numbers it can't format, instead of
35
+ the raw digits.
36
+
37
+ ### Fixed
38
+
39
+ - The email regex no longer backtracks catastrophically: crafted input that
40
+ took over a minute to reject now fails in under a millisecond.
41
+ - Postal codes of the wrong length were accepted and then replaced with `nil`
42
+ by `set:`.
43
+ - With `allow_blank`, junk phone and postal input was accepted and replaced
44
+ with `""` or `nil`.
45
+ - US/CA numbers with a leading 1 (`1-212-555-1234`) were stored with a
46
+ trailing space.
47
+ - Phone extensions could be taken from the wrong part of the input when the
48
+ last four digits appeared earlier in it.
49
+ - Country codes in lowercase or as symbols (`"us"`, `:US`) silently skipped
50
+ validation.
51
+ - Integer values (e.g. a ZIP code from an integer column) raised instead of
52
+ validating.
53
+ - Mixed case errors were missing the attribute name and ignored the
54
+ `attribute_name:` option, and the bundled English and French messages were
55
+ never loaded.
56
+ - Values with no letters (`"123"`) or in scripts without case failed as "all
57
+ caps", and short accented names skipped the check.
58
+ - A stray `|` in the AU phone regex character classes.
59
+
60
+ ### Added
61
+
62
+ - UK postcode validation and formatting (`UK` or `GB`).
63
+ - `source_code_uri`, `bug_tracker_uri`, and `changelog_uri` gemspec metadata,
64
+ and a declared MIT license.
65
+
66
+ ### Documentation
67
+
68
+ - One `README.md` replaces the per-validator READMEs, with current usage,
69
+ options, and a translation key reference. Added `LICENSE` and this
70
+ changelog.
71
+
72
+ ### Internal
73
+
74
+ - Minitest suite, CI on Ruby 3.4/4.0 against activemodel 7.2/8.0/8.1,
75
+ rubocop, Dependabot, and a trusted publishing release workflow. The gem now
76
+ packages only `lib/`, `README.md`, `LICENSE`, and `CHANGELOG.md`.
77
+
78
+ ## 1.0.5
79
+
80
+ Last release before 2.0.0.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2008-2026 The validation_kit contributors (see README.md)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,173 @@
1
+ # validation_kit
2
+
3
+ ActiveModel validators for email addresses, phone numbers, postal codes, and
4
+ mixed-case text.
5
+
6
+ ## Installation
7
+
8
+ Add the gem to your Gemfile:
9
+
10
+ ```ruby
11
+ gem "validation_kit"
12
+ ```
13
+
14
+ The validators are available in any class that includes
15
+ `ActiveModel::Validations`, including ActiveRecord models. If your app defines
16
+ its own validator with the same name (e.g. `app/validators/email_validator.rb`),
17
+ yours is used instead.
18
+
19
+ ## Email
20
+
21
+ Validates that an attribute is an email address.
22
+
23
+ ```ruby
24
+ class Person < ActiveRecord::Base
25
+ validates :email, email: true
26
+ end
27
+
28
+ Person.new(email: "Bob").valid? # => false
29
+ Person.new(email: "joe@foobar.com").valid? # => true
30
+ ```
31
+
32
+ ## Mixed case
33
+
34
+ Validates that a string isn't all capitals or all lowercase. Values with fewer
35
+ than three letters that have a case are skipped, so initials, digits, and
36
+ scripts without case (e.g. Chinese) never fail.
37
+
38
+ ```ruby
39
+ class Person < ActiveRecord::Base
40
+ validates :first_name, mixed_case: true
41
+ end
42
+
43
+ Person.new(first_name: "BOB").valid? # => false, "First name cannot be in all caps"
44
+ Person.new(first_name: "bob").valid? # => false, "First name cannot be in all lowercase"
45
+ Person.new(first_name: "Bob").valid? # => true
46
+ ```
47
+
48
+ | Option | Description |
49
+ | ----------------- | ---------------------------------------------------------------------------------------------- |
50
+ | `attribute_name:` | Name to use in the message. Defaults to the translated attribute name, then the humanized one. |
51
+ | `all_caps:` | Custom message for all-caps values. |
52
+ | `all_lowercase:` | Custom message for all-lowercase values. |
53
+
54
+ ## Phone
55
+
56
+ Strict validation for phone numbers in the United States (`US`), Canada
57
+ (`CA`), and Australia (`AU`).
58
+
59
+ ```ruby
60
+ class Person < ActiveRecord::Base
61
+ validates :phone, phone: { country: "US", set: true }, allow_blank: true
62
+ end
63
+ ```
64
+
65
+ | Option | Description |
66
+ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------- |
67
+ | `country:` | See [Specifying the country](#specifying-the-country). |
68
+ | `set:` | Reformat the stored value: `"1-212-555-1234 x5"` becomes `"(212) 555-1234 x5"`, `"0298765432"` becomes `"(02) 9876 5432"`. |
69
+ | `area_key:` | For Australian landlines entered without an area code, the state whose area code to add (`"VIC"`, `"QLD"`, …; default NSW/ACT, `02`). |
70
+
71
+ ## Postal code
72
+
73
+ Strict validation for postal and ZIP codes in the United States (`US`), Canada
74
+ (`CA`), the United Kingdom (`UK` or `GB`), Australia (`AU`), and New Zealand
75
+ (`NZ`).
76
+
77
+ ```ruby
78
+ class Person < ActiveRecord::Base
79
+ validates :postal_code, postal_code: { country: "CA", set: true }, allow_blank: true
80
+ end
81
+ ```
82
+
83
+ | Option | Description |
84
+ | ---------- | ----------------------------------------------------------------------------------------------------------------------- |
85
+ | `country:` | See [Specifying the country](#specifying-the-country). |
86
+ | `set:` | Reformat the stored value: Canadian and UK codes get a space (`K1A 0B1`, `SW1A 1AA`), US ZIP+4 a hyphen (`10001-1234`). |
87
+
88
+ ## Specifying the country
89
+
90
+ The phone and postal code validators need a country. Country codes are
91
+ case-insensitive (`"CA"`, `"ca"`, or `:CA`), and validation is skipped when the
92
+ country isn't supported.
93
+
94
+ ```ruby
95
+ # A fixed country code
96
+ validates :phone, phone: { country: "CA" }
97
+
98
+ # The name of a method on your model that returns the country code
99
+ validates :phone, phone: { country: :billing_country }
100
+
101
+ # Neither: the validator calls your model's country method
102
+ validates :phone, phone: true
103
+ ```
104
+
105
+ ## Error messages
106
+
107
+ Errors are added with standard types, so the usual ActiveModel tools work:
108
+
109
+ ```ruby
110
+ person.errors.added?(:email, :invalid) # email, phone, postal code
111
+ person.errors.added?(:first_name, :all_caps) # mixed case (also :all_lowercase)
112
+ ```
113
+
114
+ Pass `message:` (or `all_caps:` / `all_lowercase:` for mixed case) for a custom
115
+ message, or translate it like any other Rails validation error:
116
+
117
+ ```yaml
118
+ en:
119
+ activerecord:
120
+ errors:
121
+ models:
122
+ person:
123
+ attributes:
124
+ email:
125
+ invalid: "Enter your email address"
126
+ first_name:
127
+ all_caps: "Your first name cannot be in all caps"
128
+ ```
129
+
130
+ Use `activemodel` instead of `activerecord` for classes that aren't
131
+ ActiveRecord models. The gem includes English and French messages for the
132
+ mixed case errors.
133
+
134
+ ## Translation keys
135
+
136
+ Each validator adds an error of the type below. Rails looks up its message in
137
+ this order, using the first key it finds. These are the keys for an
138
+ ActiveRecord model `Person`; use `activemodel` instead of `activerecord` for
139
+ other ActiveModel classes:
140
+
141
+ 1. `activerecord.errors.models.person.attributes.<attribute>.<type>`
142
+ 2. `activerecord.errors.models.person.<type>`
143
+ 3. `activerecord.errors.messages.<type>`
144
+ 4. `errors.attributes.<attribute>.<type>`
145
+ 5. `errors.messages.<type>`
146
+
147
+ A `message:` option (or `all_caps:` / `all_lowercase:`) skips the lookup.
148
+
149
+ | Validator | Error type | Default message (en) | Default message (fr) |
150
+ | ------------- | ---------------- | ------------------------------------ | ------------------------------------------ |
151
+ | `email` | `:invalid` | "is invalid" (from Rails) | from Rails' locale files (e.g. rails-i18n) |
152
+ | `phone` | `:invalid` | "is invalid" (from Rails) | from Rails' locale files (e.g. rails-i18n) |
153
+ | `postal_code` | `:invalid` | "is invalid" (from Rails) | from Rails' locale files (e.g. rails-i18n) |
154
+ | `mixed_case` | `:all_caps` | "%{item} cannot be in all caps" | "%{item} ne peut pas être en majuscules" |
155
+ | `mixed_case` | `:all_lowercase` | "%{item} cannot be in all lowercase" | "%{item} ne peut pas être en minuscules" |
156
+
157
+ For mixed case, `%{item}` is the attribute's name: its translation at
158
+ `activerecord.attributes.person.<attribute>`, then the `attribute_name:`
159
+ option, then the humanized attribute name.
160
+
161
+ ## Credits
162
+
163
+ - **Email, mixed case, and postal code validators:** [Paul Schreiber](https://paulschreiber.com/), 2010–2011.
164
+ - **Phone validator:** written by Kristina Lim, copyright © 2008 Syndeo
165
+ Media. Paul Schreiber added US
166
+ and Canada support (September 2010) and extension support (November 2010).
167
+ It is named after, and was originally built on, Jerrod Blavos's
168
+ [validates_as_phone](https://code.google.com/archive/p/validates-as-phone/) plugin.
169
+ - **Gem:** co-authored by Wes Morgan.
170
+
171
+ ## License
172
+
173
+ Released under the MIT License. See [LICENSE](LICENSE).
@@ -1,21 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ValidationKit
2
4
  class EmailValidator < ActiveModel::EachValidator
3
- # This hangs ruby if you have more than one validates_as_email rule in the same object
4
- # Commenting it out for now
5
- # Using the one found at <http://fightingforalostcause.net/misc/2006/compare-email-regex.php>
6
- # EMAIL_ADDRESS_RE = /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i
7
-
8
- EMAIL_ADDRESS_RE = /^(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){255,})(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){65,}@)(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22))(?:\.(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-[a-z0-9]+)*\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-[a-z0-9]+)*)|(?:\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\]))$/i
5
+ EMAIL_ADDRESS_RE = /\A(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){255,})(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){65,}@)(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22))(?:\.(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:xn--)?[a-z0-9]+(?:-[a-z0-9]+)*\.){1,126}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-[a-z0-9]+)*)|(?:\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\]))\z/i
9
6
 
10
7
  def validate_each(record, attribute, value)
11
- unless EMAIL_ADDRESS_RE.match(value)
12
- model_name = record.class.to_s
13
- message = I18n.t("activerecord.errors.models.#{model_name.underscore}.attributes.#{attribute}.invalid",
14
- :default => [:"activerecord.errors.models.#{model_name.underscore}.invalid",
15
- options[:message],
16
- :'activerecord.errors.messages.invalid'])
17
- record.errors.add(attribute, message)
18
- end
8
+ return if EMAIL_ADDRESS_RE.match?(value.to_s)
9
+
10
+ record.errors.add(attribute, :invalid, message: options[:message])
19
11
  end
20
12
  end
21
13
  end
@@ -1,6 +1,5 @@
1
1
  en:
2
- activerecord:
3
- errors:
4
- messages:
5
- all_caps: "%{item} cannot be in all caps"
6
- all_lowercase: "%{item} cannot be in all lowercase"
2
+ errors:
3
+ messages:
4
+ all_caps: "%{item} cannot be in all caps"
5
+ all_lowercase: "%{item} cannot be in all lowercase"
@@ -1,6 +1,5 @@
1
1
  fr:
2
- activerecord:
3
- errors:
4
- messages:
5
- all_caps: "%{item} ne peut pas être en majuscules"
6
- all_lowercase: "%{item} ne peut pas être en minuscules"
2
+ errors:
3
+ messages:
4
+ all_caps: "%{item} ne peut pas être en majuscules"
5
+ all_lowercase: "%{item} ne peut pas être en minuscules"
@@ -1,42 +1,40 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ValidationKit
2
4
  class MixedCaseValidator < ActiveModel::EachValidator
3
- ALL_CAPS = 1
4
- ALL_LOWERCASE = -1
5
+ # Error types, also used as the I18n keys and option names for custom messages.
6
+ ALL_CAPS = :all_caps
7
+ ALL_LOWERCASE = :all_lowercase
5
8
 
6
9
  def validate_each(record, attribute, value)
7
10
  return if value.nil?
8
- return if value.gsub(/\W/, "").size < 3 # skip very short words
9
- error = nil
10
-
11
- if (value.upcase == value)
12
- error = ALL_CAPS
13
- elsif (value.downcase == value)
14
- error = ALL_LOWERCASE
15
- end
16
11
 
17
- return if error.nil?
12
+ # Only letters that have a case count, so digits, punctuation, and
13
+ # scripts without case (e.g. Chinese) never trigger an error.
14
+ upper = value.to_s.scan(/\p{Lu}/).size
15
+ lower = value.to_s.scan(/\p{Ll}/).size
16
+ return if upper + lower < 3 # skip very short words
18
17
 
19
- model_name = record.class.to_s
18
+ error = if lower.zero?
19
+ ALL_CAPS
20
+ elsif upper.zero?
21
+ ALL_LOWERCASE
22
+ end
20
23
 
21
- item_name = I18n.t("activerecord.attributes.#{model_name.underscore}.#{attribute}",
22
- :default => nil) or options[:attribute_name] or attribute
24
+ return if error.nil?
23
25
 
24
- if error == ALL_CAPS
25
- message = I18n.t("activerecord.errors.models.#{model_name.underscore}.attributes.#{attribute}.all_caps",
26
- :item => item_name,
27
- :default => [:"activerecord.errors.models.#{model_name.underscore}.all_caps",
28
- options[:all_caps],
29
- :'activerecord.errors.messages.all_caps'])
30
- elsif error == ALL_LOWERCASE
31
- message = I18n.t("activerecord.errors.models.#{model_name.underscore}.attributes.#{attribute}.all_lowercase",
32
- :item => item_name,
33
- :default => [:"activerecord.errors.models.#{model_name.underscore}.all_lowercase",
34
- options[:all_lowercase],
35
- :'activerecord.errors.messages.all_lowercase'])
36
- end
26
+ record.errors.add(attribute, error, item: item_name(record, attribute), message: options[error])
27
+ end
37
28
 
38
- record.errors.add(attribute, message)
29
+ private
39
30
 
31
+ # A translated attribute name wins, then the :attribute_name option, then
32
+ # the humanized attribute name.
33
+ def item_name(record, attribute)
34
+ scope = [record.class.i18n_scope, :attributes, record.class.model_name.i18n_key]
35
+ I18n.t(attribute, scope:, default: nil) ||
36
+ options[:attribute_name] ||
37
+ record.class.human_attribute_name(attribute)
40
38
  end
41
39
  end
42
40
  end
@@ -1,123 +1,116 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ValidationKit
2
4
  class PhoneValidator < ActiveModel::EachValidator
3
5
  def regex_for_country(country_code)
6
+ country_code = country_code.to_s.strip.upcase
7
+
4
8
  if country_code.blank?
5
9
  nil
6
- elsif ["AU"].include?(country_code)
7
- /(^(1300|1800|1900|1902)\d{6}$)|(^([0]?[1|2|3|7|8])?[1-9][0-9]{7}$)|(^13\d{4}$)|(^[0]?4\d{8}$)/
8
- elsif ["US", "CA"].include?(country_code)
9
- /^1?[2-9]\d{2}[2-9]\d{2}\d{4}/
10
- else
11
- nil
10
+ elsif country_code == "AU"
11
+ /\A(?:(?:1300|1800|1900|1902)\d{6}|(?:0?[12378])?[1-9][0-9]{7}|13\d{4}|0?4\d{8})\z/
12
+ elsif %w[US CA].include?(country_code)
13
+ /\A1?[2-9]\d{2}[2-9]\d{2}\d{4}/
12
14
  end
13
15
  end
14
16
 
15
17
  def validate_each(record, attribute, value)
16
- if options[:country].is_a?(String)
17
- country = options[:country]
18
- elsif options[:country].is_a?(Symbol) && record.respond_to?(options[:country])
19
- country = record.send(options[:country])
20
- elsif record.respond_to?(:country)
21
- country = record.send(:country)
22
- else
23
- country = false
24
- end
18
+ country = if options[:country].is_a?(String)
19
+ options[:country]
20
+ elsif options[:country].is_a?(Symbol) && record.respond_to?(options[:country])
21
+ record.public_send(options[:country])
22
+ elsif record.respond_to?(:country)
23
+ record.country
24
+ else
25
+ false
26
+ end
25
27
 
26
28
  return unless country
27
- current_regex = regex_for_country(country)
28
- return unless current_regex
29
29
 
30
- new_value = value.to_s.gsub(/[^0-9]/, '')
31
- new_value ||= ''
30
+ # accept "us", :US, " US " as well as "US"
31
+ country = country.to_s.strip.upcase
32
+ return if country.empty?
32
33
 
33
- model_name = record.class.to_s
34
+ current_regex = regex_for_country(country)
35
+ return unless current_regex
34
36
 
35
- message = I18n.t("activerecord.errors.models.#{model_name.underscore}.attributes.#{attribute}.invalid",
36
- :default => [:"activerecord.errors.models.#{model_name.underscore}.invalid",
37
- options[:message], :'activerecord.errors.messages.invalid'])
37
+ new_value = value.to_s.gsub(/[^0-9]/, "")
38
38
 
39
- unless (options[:allow_blank] && new_value.blank?) || new_value =~ current_regex
40
- record.errors.add(attribute, message)
41
- else
39
+ # allow_blank/allow_nil are handled by ActiveModel on the original value,
40
+ # so input that only becomes blank once cleaned up (e.g. "n/a") is invalid.
41
+ if current_regex.match?(new_value)
42
42
  if options[:set]
43
43
  formatted_phone = format_as_phone(value, country, options[:area_key])
44
44
  if formatted_phone.nil?
45
- record.errors.add(attribute, message)
45
+ record.errors.add(attribute, :invalid, message: options[:message])
46
46
  else
47
- record.send(attribute.to_s + '=', formatted_phone)
47
+ record.public_send("#{attribute}=", formatted_phone)
48
48
  end
49
- end # options
50
- end # unless
49
+ end
50
+ else
51
+ record.errors.add(attribute, :invalid, message: options[:message])
52
+ end
51
53
  end
52
54
 
53
55
  def format_as_phone(arg, country_code = nil, area_key = nil)
54
- return nil if (arg.blank? or country_code.blank? or !regex_for_country(country_code))
56
+ country_code = country_code.to_s.strip.upcase
57
+ return nil if arg.blank? || country_code.blank? || !regex_for_country(country_code)
55
58
 
56
- number = arg.gsub(/[^0-9]/, '')
59
+ arg = arg.to_s
60
+ number = arg.gsub(/[^0-9]/, "")
57
61
 
58
62
  if country_code == "AU"
59
- if number =~ /^(1300|1800|1900|1902)\d{6}$/
60
- number.insert(4, ' ').insert(8, ' ')
61
- elsif number =~ /^([0]?[1|2|3|7|8])?[1-9][0-9]{7}$/
62
- if number =~ /^[1-9][0-9]{7}$/
63
- number = number.insert(0, area_code_for_key(area_key))
64
- end
65
- number = number.insert(0, '0') if number =~ /^[1|2|3|7|8][1-9][0-9]{7}$/
66
-
67
- number.insert(0, '(').insert(3, ') ').insert(9, ' ')
68
- elsif number =~ /^13\d{4}$/
69
- number.insert(2, ' ').insert(5, ' ')
70
- elsif number =~ /^[0]?4\d{8}$/
71
- number = number.insert(0, '0') if number =~ /^4\d{8}$/
72
-
73
- number.insert(4, ' ').insert(8, ' ')
74
- else
75
- number
63
+ case number
64
+ when /\A(?:1300|1800|1900|1902)\d{6}\z/
65
+ number.insert(4, " ").insert(8, " ")
66
+ when /\A(?:0?[12378])?[1-9][0-9]{7}\z/
67
+ number.insert(0, area_code_for_key(area_key)) if /\A[1-9][0-9]{7}\z/.match?(number)
68
+ number.insert(0, "0") if /\A[12378][1-9][0-9]{7}\z/.match?(number)
69
+
70
+ number.insert(0, "(").insert(3, ") ").insert(9, " ")
71
+ when /\A13\d{4}\z/
72
+ number.insert(2, " ").insert(5, " ")
73
+ when /\A0?4\d{8}\z/
74
+ number.insert(0, "0") if /\A4\d{8}\z/.match?(number)
75
+
76
+ number.insert(4, " ").insert(8, " ")
76
77
  end
77
- elsif ["CA", "US"].include?(country_code)
78
- digit_count = number.length
78
+ elsif %w[CA US].include?(country_code)
79
79
  # if it's too short
80
- if digit_count < 10
81
- return number
82
- end
80
+ return nil if number.length < 10
83
81
 
84
- # strip off any leading ones
85
- if number[0..0] == "1"
86
- number = number[1..10]
87
- end
82
+ # strip off the leading 1 (country code); any digits beyond ten are an extension
83
+ leading_one = number.length > 10 && number.start_with?("1")
84
+ number = number[1..] if leading_one
88
85
 
89
86
  area_code = number[0..2]
90
87
  exchange = number[3..5]
91
88
  sln = number[6..9]
92
89
 
93
- if digit_count == 10
90
+ if number.length == 10
94
91
  extension = nil
95
92
  else
96
- # save everything after the SLN as extension
97
- sln_index = arg.index(sln)
98
- # if something went wrong, return nil so we can error out
99
- # i.e. 519 444 000 ext 123 would cause sln to be 0001, which is not found
100
- # in the original string
101
- return nil if sln_index.nil?
102
- extension = " %s" % arg[(sln_index+4)..-1].strip
93
+ # save everything after the last digit of the number as the extension
94
+ national = arg[/\A(?:\D*\d){#{leading_one ? 11 : 10}}/]
95
+ # if letters appear among those digits, the extension's digits were
96
+ # counted as part of the number (e.g. 519 444 000 ext 123), so return
97
+ # nil to error out
98
+ return nil if national.sub(/\A\D*/, "").match?(/[[:alpha:]]/)
99
+
100
+ extension = " #{arg[national.length..].strip}"
103
101
  end
104
102
 
105
- "(%s) %s-%s%s" % [area_code, exchange, sln, extension]
103
+ "(#{area_code}) #{exchange}-#{sln}#{extension}"
106
104
  end
107
105
  end
108
106
 
109
107
  def area_code_for_key(key)
110
108
  case key
111
- when 'NSW' then '02'
112
- when 'ACT' then '02'
113
- when 'VIC' then '03'
114
- when 'TAS' then '03'
115
- when 'QLD' then '07'
116
- when 'SA' then '08'
117
- when 'NT' then '08'
118
- when 'WA' then '08'
109
+ when "VIC", "TAS" then "03"
110
+ when "QLD" then "07"
111
+ when "SA", "NT", "WA" then "08"
119
112
  else
120
- '02'
113
+ "02" # NSW, ACT, and the default
121
114
  end
122
115
  end
123
116
  end
@@ -1,88 +1,94 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ValidationKit
2
4
  class PostalCodeValidator < ActiveModel::EachValidator
3
5
  def postal_code_regex_for_country(country_code)
6
+ country_code = country_code.to_s.strip.upcase
7
+
4
8
  if country_code.blank?
5
9
  nil
6
- elsif ["AU", "NZ"].include?(country_code)
7
- /\d{4}/
8
- elsif ["US"].include?(country_code)
9
- /\d{5}(-\d{4})?/
10
- elsif ["CA"].include?(country_code)
11
- /[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTWVXYZ]\d[ABCEGHJKLMNPRSTWVXYZ]\d/
12
- else
13
- nil
10
+ elsif %w[AU NZ].include?(country_code)
11
+ /\A\d{4}\z/
12
+ elsif country_code == "US"
13
+ /\A\d{5}(?:-?\d{4})?\z/
14
+ elsif country_code == "CA"
15
+ /\A[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTWVXYZ] ?\d[ABCEGHJKLMNPRSTWVXYZ]\d\z/
16
+ elsif %w[UK GB].include?(country_code)
17
+ /\A(?:[A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}|GIR ?0AA)\z/
14
18
  end
15
19
  end
16
20
 
17
21
  def disallowed_characters_for_country(country_code)
22
+ country_code = country_code.to_s.strip.upcase
23
+
18
24
  if country_code.blank?
19
25
  nil
20
- elsif ["US", "AU", "NZ"].include?(country_code)
26
+ elsif %w[US AU NZ].include?(country_code)
21
27
  /[^0-9]/
22
- elsif ["CA", "UK"].include?(country_code)
28
+ elsif %w[CA UK GB].include?(country_code)
23
29
  /[^0-9A-Z]/
24
- else
25
- nil
26
30
  end
27
31
  end
28
32
 
29
33
  def validate_each(record, attribute, value)
30
- if options[:country].is_a?(String)
31
- country = options[:country]
32
- elsif options[:country].is_a?(Symbol) and record.respond_to?(options[:country])
33
- country = record.send(options[:country])
34
- elsif record.respond_to?(:country)
35
- country = record.send(:country)
36
- else
37
- country = false
38
- end
34
+ country = if options[:country].is_a?(String)
35
+ options[:country]
36
+ elsif options[:country].is_a?(Symbol) && record.respond_to?(options[:country])
37
+ record.public_send(options[:country])
38
+ elsif record.respond_to?(:country)
39
+ record.country
40
+ else
41
+ false
42
+ end
39
43
 
40
44
  return unless country
45
+
46
+ # accept "us", :US, " US " as well as "US"
47
+ country = country.to_s.strip.upcase
48
+ return if country.empty?
49
+
41
50
  current_regex = postal_code_regex_for_country(country)
42
51
  return unless current_regex
43
- disallowed_characters = disallowed_characters_for_country(country)
44
52
 
45
- new_value = value.nil? ? "" : value.upcase.gsub(disallowed_characters, '')
53
+ disallowed_characters = disallowed_characters_for_country(country)
46
54
 
47
- model_name = record.class.to_s
55
+ new_value = value.to_s.upcase.gsub(disallowed_characters, "")
48
56
 
49
- unless (options[:allow_blank] && new_value.blank?) || new_value =~ current_regex
50
- message = I18n.t("activerecord.errors.models.#{model_name.underscore}.attributes.#{attribute}.invalid",
51
- :default => [:"activerecord.errors.models.#{model_name.underscore}.invalid",
52
- options[:message],
53
- :'activerecord.errors.messages.invalid'])
54
- record.errors.add(attribute, message)
57
+ # allow_blank/allow_nil are handled by ActiveModel on the original value,
58
+ # so input that only becomes blank once cleaned up (e.g. "n/a") is invalid.
59
+ if current_regex.match?(new_value)
60
+ if options[:set]
61
+ record.public_send("#{attribute}=", format_as_postal_code(new_value, country, disallowed_characters))
62
+ end
55
63
  else
56
- record.send(attribute.to_s + '=',
57
- format_as_postal_code(new_value, country, disallowed_characters)
58
- ) if options[:set]
64
+ record.errors.add(attribute, :invalid, message: options[:message])
59
65
  end
60
66
  end
61
67
 
62
68
  def format_as_postal_code(arg, country_code, disallowed_characters)
63
- return nil if (arg.blank? or country_code.blank? or !postal_code_regex_for_country(country_code))
69
+ country_code = country_code.to_s.strip.upcase
70
+ return nil if arg.blank? || country_code.blank? || !postal_code_regex_for_country(country_code)
64
71
 
65
- postal_code = arg.gsub(disallowed_characters, '')
72
+ postal_code = arg.to_s.gsub(disallowed_characters, "")
66
73
 
67
- if ["US"].include?(country_code)
74
+ if country_code == "US"
68
75
  digit_count = postal_code.length
69
76
  if digit_count == 5
70
- return postal_code
77
+ postal_code
71
78
  elsif digit_count == 9
72
- return "%s-%s" % [postal_code[0..4], postal_code[5..8]]
73
- else
74
- return nil
79
+ "#{postal_code[0..4]}-#{postal_code[5..8]}"
75
80
  end
76
81
 
77
- elsif ["AU", "NZ"].include?(country_code)
82
+ elsif %w[AU NZ].include?(country_code)
78
83
  postal_code
79
84
 
80
- elsif ["CA"].include?(country_code)
81
- fsa = postal_code[0..2]
82
- lda = postal_code[3..5]
85
+ elsif country_code == "CA"
86
+ # forward sortation area, then local delivery unit
87
+ "#{postal_code[0..2]} #{postal_code[3..5]}"
83
88
 
84
- postal_code = "%s %s" % [fsa, lda]
85
- postal_code.upcase
89
+ elsif %w[UK GB].include?(country_code)
90
+ # the inward code is always the last three characters
91
+ "#{postal_code[0...-3]} #{postal_code[-3..]}"
86
92
  end
87
93
  end
88
94
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ValidationKit
2
- VERSION = "1.0.5"
4
+ VERSION = "2.0.0"
3
5
  end
@@ -1,10 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model"
4
+ require "active_support/core_ext/string/inflections"
1
5
  require "validation_kit/version"
2
6
 
7
+ module ValidationKit
8
+ VALIDATORS = {} # rubocop:disable Style/MutableConstant -- filled below, then frozen
9
+
10
+ # Lets `validates :email, email: true` (and phone:, postal_code:,
11
+ # mixed_case:) find this gem's validators. Rails resolves those keys with
12
+ # const_get on the model, and Ruby only calls const_missing once normal
13
+ # lookup -- including autoloading an app's own app/validators/*.rb -- has
14
+ # failed, so an app's validator of the same name always wins.
15
+ module ValidatorLookup
16
+ def const_missing(name)
17
+ VALIDATORS.fetch(name) { super }
18
+ end
19
+ end
20
+ end
21
+
3
22
  lib_path = File.dirname(__FILE__)
4
- validators = Dir[File.join(lib_path, '**', '*_validator.rb')]
5
- validators.each do |v|
6
- require v
7
- validator_class = File.basename(v, '.rb').camelize
8
- validator = "ValidationKit::#{validator_class}".constantize
9
- ActiveModel::Validations.const_set(validator_class, validator)
23
+ Dir[File.join(lib_path, "**", "*_validator.rb")].each do |path|
24
+ require path
25
+ name = File.basename(path, ".rb").camelize
26
+ ValidationKit::VALIDATORS[name.to_sym] = ValidationKit.const_get(name)
10
27
  end
28
+ ValidationKit::VALIDATORS.freeze
29
+
30
+ ActiveModel::Validations::ClassMethods.include(ValidationKit::ValidatorLookup)
31
+
32
+ # Put the bundled translations first in the load path so an app's own
33
+ # locale files (which Rails appends later) can override them.
34
+ I18n.load_path.unshift(*Dir[File.join(lib_path, "validation_kit", "**", "locales", "*.yml")])
metadata CHANGED
@@ -1,16 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: validation_kit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.5
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wes Morgan
8
8
  - Paul Schreiber
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2018-02-19 00:00:00.000000000 Z
13
- dependencies: []
11
+ date: 1980-01-02 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: '7.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '7.2'
14
27
  description: A collection of various validators for Rails forms
15
28
  email:
16
29
  - wes@turbovote.org
@@ -19,26 +32,25 @@ executables: []
19
32
  extensions: []
20
33
  extra_rdoc_files: []
21
34
  files:
22
- - ".gitignore"
23
- - Gemfile
24
- - Rakefile
35
+ - CHANGELOG.md
36
+ - LICENSE
37
+ - README.md
25
38
  - lib/validation_kit.rb
26
- - lib/validation_kit/email_validator/README
27
39
  - lib/validation_kit/email_validator/email_validator.rb
28
- - lib/validation_kit/mixed_case_validator/README
29
40
  - lib/validation_kit/mixed_case_validator/config/locales/en.yml
30
41
  - lib/validation_kit/mixed_case_validator/config/locales/fr.yml
31
42
  - lib/validation_kit/mixed_case_validator/mixed_case_validator.rb
32
- - lib/validation_kit/phone_validator/README
33
43
  - lib/validation_kit/phone_validator/phone_validator.rb
34
- - lib/validation_kit/postal_code_validator/README
35
44
  - lib/validation_kit/postal_code_validator/postal_code_validator.rb
36
45
  - lib/validation_kit/version.rb
37
- - validation_kit.gemspec
38
- homepage: https://github.com/turbovote/validation_kit
39
- licenses: []
40
- metadata: {}
41
- post_install_message:
46
+ homepage: https://github.com/paulschreiber/validation_kit
47
+ licenses:
48
+ - MIT
49
+ metadata:
50
+ rubygems_mfa_required: 'true'
51
+ source_code_uri: https://github.com/paulschreiber/validation_kit
52
+ bug_tracker_uri: https://github.com/paulschreiber/validation_kit/issues
53
+ changelog_uri: https://github.com/paulschreiber/validation_kit/blob/main/CHANGELOG.md
42
54
  rdoc_options: []
43
55
  require_paths:
44
56
  - lib
@@ -46,16 +58,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
46
58
  requirements:
47
59
  - - ">="
48
60
  - !ruby/object:Gem::Version
49
- version: '0'
61
+ version: '3.4'
50
62
  required_rubygems_version: !ruby/object:Gem::Requirement
51
63
  requirements:
52
64
  - - ">="
53
65
  - !ruby/object:Gem::Version
54
66
  version: '0'
55
67
  requirements: []
56
- rubyforge_project: validation_kit
57
- rubygems_version: 2.7.3
58
- signing_key:
68
+ rubygems_version: 4.0.20
59
69
  specification_version: 4
60
70
  summary: Handy validations for Rails forms
61
71
  test_files: []
data/.gitignore DELETED
@@ -1,4 +0,0 @@
1
- *.gem
2
- .bundle
3
- Gemfile.lock
4
- pkg/*
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- # Specify your gem's dependencies in validation_kit.gemspec
4
- gemspec
data/Rakefile DELETED
@@ -1 +0,0 @@
1
- require "bundler/gem_tasks"
@@ -1,32 +0,0 @@
1
- validates_as_email
2
- ==================
3
-
4
- Validation module for email addresses.
5
-
6
- Installation
7
- ============
8
-
9
- You can install the plugin the traditional way. Go to your application root
10
- and do:
11
-
12
- script/plugin install git://github.com/paulschreiber/validates_as_email.git
13
-
14
- Example
15
- =======
16
-
17
- class Person < ActiveRecord::Base
18
- validates_as_email :email
19
- end
20
-
21
- p = Person.new(:email => "Bob")
22
- p.valid? # false
23
-
24
- p = Person.new(:email => "joe@foobar.com")
25
- p.valid? # true
26
-
27
- Just like with built-in ActiveRecord validations, you can optionally supply a :message parameter with a custom error. Or, you can use Rails' built-in localization system and
28
-
29
-
30
- = License
31
-
32
- Copyright (c) 2010 Paul Schreiber, released under the MIT license
@@ -1,59 +0,0 @@
1
- Validates Mixed Case Of
2
- =======================
3
-
4
- When validating a string item, ensure it is not all in capital or lowercase letters.
5
-
6
- Example
7
- =======
8
-
9
- class Person < ActiveRecord::Base
10
- validates_mixed_case_of :firstname
11
- end
12
-
13
- p = Person.new(:firstname => "BOB")
14
- p.valid? # false
15
- p = Person.new(:firstname => "Bob")
16
- p.valid? # true
17
-
18
- Attribute Names
19
- ===============
20
- Attribute names are looked up using Rails' I18n system. Create a hierarchy like so:
21
-
22
- en:
23
- activerecord:
24
- models:
25
- attributes:
26
- person:
27
- firstname: "first name"
28
-
29
- Alternately, pass in the :attribute_name option:
30
-
31
- class Person < ActiveRecord::Base
32
- validates_mixed_case_of :firstname, :attribute_name => "first name"
33
- end
34
-
35
-
36
- Error Messages
37
- ==============
38
- Error messages follow the standard ActiveRecord lookup method.
39
-
40
- You'll likely error messages can be customized like so:
41
-
42
- en:
43
- activerecord:
44
- errors:
45
- models:
46
- attributes:
47
- person:
48
- firstname:
49
- all_caps: "first name should not be in all caps"
50
-
51
- Alternatively, pass in tje :all_caps option:
52
-
53
- class Person < ActiveRecord::Base
54
- validates_mixed_case_of :firstname, :all_caps => "don't shout at me, bro"
55
- end
56
-
57
-
58
-
59
- Copyright 2011 Paul Schreiber, released under the MIT license
@@ -1,69 +0,0 @@
1
- validates_as_phone
2
- ==================
3
-
4
-
5
- Strict validation module for phone numbers that supports classifications and
6
- areas.
7
-
8
- = General usage
9
-
10
- == Installation
11
-
12
- You can install the plugin the traditional way. Go to your application root
13
- and do:
14
-
15
- script/plugin install git://github.com/paulschreiber/validates_as_phone.git
16
-
17
- == Validate your model attributes
18
-
19
- Example:
20
-
21
- There are three ways to specify the country:
22
- (1) Pass the country name in as a string parameter (:country => "CA")
23
- class Person < ActiveRecord::Base
24
- validates_as_phone :phone, :country => "CA", :allow_blank => true, :set => true
25
- end
26
-
27
- (2) Create an attribute (country field) named foo in your object, and pass in a reference to foo:
28
-
29
- class Person < ActiveRecord::Base
30
- validates_as_phone :phone, :country => :foo
31
- end
32
-
33
- (3) Create an attribute named country it in your object, i.e. Person#country
34
- i.e. country is the default name for your country field, and the validator tries that automatically
35
-
36
- class Person < ActiveRecord::Base
37
- validates_as_phone :phone
38
- end
39
-
40
- The :set parameter tells the validator to reformat the phone number (change punctuation and spacing) in to a standard format.
41
-
42
-
43
- Supported countries are Canada (CA), the United States (US) and Australia (AU).
44
-
45
-
46
- = License
47
-
48
- Written by Kristina Lim (http://i-think.com.ph/kristina/)
49
-
50
- Copyright (c) 2008 Syndeo Media
51
- http://syndeomedia.com
52
-
53
- US and Canada support added by Paul Schreiber (http://paulschreiber.com/)
54
- Last modified 07 September 2010
55
- Extension support added 17 November 2010
56
-
57
- = Contributing
58
-
59
- If you wish to contribute to the project, you may contact the author through:
60
-
61
- 'kristinasyndeomediacom'.insert(8, '@').insert(20, '.')
62
-
63
- = Acknowledgements
64
-
65
- This plugin is named after the validates_as_phone plugin of Jerrod Blavos
66
- (http://code.google.com/p/validates-as-phone/). Admittedly, this plugin was
67
- built over the latter, but as the purposes of this plugin is more complex than
68
- that of the minimal one, practically all of the code has been written over by
69
- now.
@@ -1,44 +0,0 @@
1
- validates_as_postal_code
2
- =====================
3
-
4
- Strict validation module for postal and zip codes.
5
-
6
- = General usage
7
-
8
- == Installation
9
-
10
- You can install the plugin the traditional way. Go to your application root
11
- and do:
12
-
13
- script/plugin install git://github.com/paulschreiber/validates_as_postal_code.git
14
-
15
- == Validate your model attributes
16
-
17
- Example:
18
-
19
- There are three ways to specify the country:
20
- (1) Pass the country name in as a string parameter (:country => "CA")
21
- class Person < ActiveRecord::Base
22
- validates_as_postal_code :postal_code, :country => "CA", :allow_blank => true
23
- end
24
-
25
- (2) Create an attribute (country field) named foo in your object, and pass in a reference to foo:
26
- class Person < ActiveRecord::Base
27
- validates_as_postal_code :postal_code, :country => :foo
28
- end
29
-
30
- (3) Create an attribute named country it in your object, i.e. Person#country
31
- i.e. country is the default name for your country field, and the validator tries that automatically
32
-
33
- class Person < ActiveRecord::Base
34
- validates_as_postal_code :postal_code
35
- end
36
-
37
- The :set parameter tells the validator to reformat the postal_code number (change punctuation and spacing) in to a standard format.
38
-
39
- Supported countries are Canada (CA), the United States (US), Australia (AU), New Zealand (NZ). :set only works for Canada and the US; it's ignored for other countries.
40
-
41
-
42
- = License
43
-
44
- Copyright (c) 2010 Paul Schreiber, released under the MIT license
@@ -1,21 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "validation_kit/version"
4
-
5
- Gem::Specification.new do |s|
6
- s.name = "validation_kit"
7
- s.version = ValidationKit::VERSION
8
- s.authors = ["Wes Morgan", "Paul Schreiber"]
9
- s.email = ["wes@turbovote.org", "paulschreiber@gmail.com"]
10
- s.homepage = "https://github.com/turbovote/validation_kit"
11
- s.summary = %q{Handy validations for Rails forms}
12
- s.description = %q{A collection of various validators for Rails forms}
13
-
14
- s.rubyforge_project = "validation_kit"
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
- end