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 +4 -4
- data/CHANGELOG.md +80 -0
- data/LICENSE +21 -0
- data/README.md +173 -0
- data/lib/validation_kit/email_validator/email_validator.rb +6 -14
- data/lib/validation_kit/mixed_case_validator/config/locales/en.yml +4 -5
- data/lib/validation_kit/mixed_case_validator/config/locales/fr.yml +4 -5
- data/lib/validation_kit/mixed_case_validator/mixed_case_validator.rb +26 -28
- data/lib/validation_kit/phone_validator/phone_validator.rb +69 -76
- data/lib/validation_kit/postal_code_validator/postal_code_validator.rb +52 -46
- data/lib/validation_kit/version.rb +3 -1
- data/lib/validation_kit.rb +30 -6
- metadata +30 -20
- data/.gitignore +0 -4
- data/Gemfile +0 -4
- data/Rakefile +0 -1
- data/lib/validation_kit/email_validator/README +0 -32
- data/lib/validation_kit/mixed_case_validator/README +0 -59
- data/lib/validation_kit/phone_validator/README +0 -69
- data/lib/validation_kit/postal_code_validator/README +0 -44
- data/validation_kit.gemspec +0 -21
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 48f6bae26b123232914da0c154b955798b82233cf152c9c0c823f0f223289956
|
|
4
|
+
data.tar.gz: 55a3a8f8458f886adbcfb3e2dceb84d7900f206bc0c491d18203dc193ae755e3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
|
|
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
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|
fr:
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
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
|
-
|
|
4
|
-
|
|
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
|
-
|
|
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
|
-
|
|
18
|
+
error = if lower.zero?
|
|
19
|
+
ALL_CAPS
|
|
20
|
+
elsif upper.zero?
|
|
21
|
+
ALL_LOWERCASE
|
|
22
|
+
end
|
|
20
23
|
|
|
21
|
-
|
|
22
|
-
:default => nil) or options[:attribute_name] or attribute
|
|
24
|
+
return if error.nil?
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
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
|
|
7
|
-
|
|
8
|
-
elsif [
|
|
9
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
31
|
-
|
|
30
|
+
# accept "us", :US, " US " as well as "US"
|
|
31
|
+
country = country.to_s.strip.upcase
|
|
32
|
+
return if country.empty?
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
current_regex = regex_for_country(country)
|
|
35
|
+
return unless current_regex
|
|
34
36
|
|
|
35
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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.
|
|
47
|
+
record.public_send("#{attribute}=", formatted_phone)
|
|
48
48
|
end
|
|
49
|
-
end
|
|
50
|
-
|
|
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
|
-
|
|
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
|
-
|
|
59
|
+
arg = arg.to_s
|
|
60
|
+
number = arg.gsub(/[^0-9]/, "")
|
|
57
61
|
|
|
58
62
|
if country_code == "AU"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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 [
|
|
78
|
-
digit_count = number.length
|
|
78
|
+
elsif %w[CA US].include?(country_code)
|
|
79
79
|
# if it's too short
|
|
80
|
-
if
|
|
81
|
-
return number
|
|
82
|
-
end
|
|
80
|
+
return nil if number.length < 10
|
|
83
81
|
|
|
84
|
-
# strip off
|
|
85
|
-
|
|
86
|
-
|
|
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
|
|
90
|
+
if number.length == 10
|
|
94
91
|
extension = nil
|
|
95
92
|
else
|
|
96
|
-
# save everything after the
|
|
97
|
-
|
|
98
|
-
# if
|
|
99
|
-
#
|
|
100
|
-
#
|
|
101
|
-
return nil if
|
|
102
|
-
|
|
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
|
-
"(
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
-
|
|
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 [
|
|
7
|
-
/\d{4}/
|
|
8
|
-
elsif
|
|
9
|
-
/\d{5}(
|
|
10
|
-
elsif
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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 [
|
|
26
|
+
elsif %w[US AU NZ].include?(country_code)
|
|
21
27
|
/[^0-9]/
|
|
22
|
-
elsif [
|
|
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
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
53
|
+
disallowed_characters = disallowed_characters_for_country(country)
|
|
46
54
|
|
|
47
|
-
|
|
55
|
+
new_value = value.to_s.upcase.gsub(disallowed_characters, "")
|
|
48
56
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
74
|
+
if country_code == "US"
|
|
68
75
|
digit_count = postal_code.length
|
|
69
76
|
if digit_count == 5
|
|
70
|
-
|
|
77
|
+
postal_code
|
|
71
78
|
elsif digit_count == 9
|
|
72
|
-
|
|
73
|
-
else
|
|
74
|
-
return nil
|
|
79
|
+
"#{postal_code[0..4]}-#{postal_code[5..8]}"
|
|
75
80
|
end
|
|
76
81
|
|
|
77
|
-
elsif [
|
|
82
|
+
elsif %w[AU NZ].include?(country_code)
|
|
78
83
|
postal_code
|
|
79
84
|
|
|
80
|
-
elsif
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
85
|
-
|
|
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
|
data/lib/validation_kit.rb
CHANGED
|
@@ -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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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:
|
|
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:
|
|
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
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
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
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
metadata:
|
|
41
|
-
|
|
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: '
|
|
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
|
-
|
|
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
data/Gemfile
DELETED
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
|
data/validation_kit.gemspec
DELETED
|
@@ -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
|