email_validator 2.2.2 → 2.2.3

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: 9f5010b8d56592e8febeda1e96b6fa35a27e2dae75dab6277fbade5f35b74b18
4
- data.tar.gz: 50bbb4a9c6abea2db5c2e887ba67a88739afccdb445c56be74c063b10993cef3
3
+ metadata.gz: 46bd723714c6aa3a844e584e986e5989920b6d3f212a44d800183d118c561cb7
4
+ data.tar.gz: bb58e5bf862c4be796e3ce59727dcf3fd2e28267e7c6077014f01d25dc841580
5
5
  SHA512:
6
- metadata.gz: b520404b2777c72ac87eaccaaacb073b340ebca043d104d531d8d78c74fd413d2f0e1c5ef6b7d08529a23d2aad913c7e1d15ab16989ea5777b5f41d37539365b
7
- data.tar.gz: 100eb11eaff2bd530d7a6c554655d93649a45aa6a5e5718a31cfa0c994f8e5341b57964d01c7f256ce4e8e927c3ba8e5610694cd293dda2d3241a2f2c187e1b9
6
+ metadata.gz: 2ece91a44bd82bd79c5484a17729996731787148b6813af0c4e41804715242a9cbfb4c0d661b08e0c904753dd59f23560d11aed7bf9044986802445e36f69438
7
+ data.tar.gz: 1b91bf21ce112f86f9b97138573d20fe14b67f075935136c3b19a620f155d50c5d5cf5ff9566e4c101429b8d7ce80ccb80709a2a15eeb07f4caeaac34f2b86b0
data/CHANGELOG.md CHANGED
@@ -5,6 +5,16 @@ This file is used to list changes made in `email_validator`.
5
5
  All notable changes to this project will be documented in this file.
6
6
  This project adheres to [Semantic Versioning](http://semver.org/).
7
7
 
8
+ ## 2.2.3 (2021-04-05)
9
+
10
+ * [karlwilbur] - Fix regexp for numeric domains (fixes [#72](https://github.com/K-and-R/email_validator/issues/72))
11
+ - [delphaber] - Add checks for numeric-only domains in tests (should be considered valid)
12
+ - [karlwilbur] - Fix specs for numeric-only domains labels (should be considered valid)
13
+ - [karlwilbur] - Add checks for numeric-only TLDs in tests (should be considered invalid)
14
+ - [karlwilbur] - Add tests to ensure that `regexp` returns expected value
15
+ - [karlwilbur] - Add checks for double dash in domain (should be considered invalid)
16
+ - [karlwilbur] - Add `EmailValidator::Error` class, raise `EmailValidator::Error` when invalid `mode`
17
+
8
18
  ## 2.2.2 (2020-12-10)
9
19
 
10
20
  * [karlwilbur] - Fix includes for `:rfc` and `:strict` modes from `Gemfile`
data/README.md CHANGED
@@ -54,9 +54,9 @@ by setting `require_fqdn: true` or by enabling `:strict` checking:
54
54
  validates :my_email_attribute, email: {mode: :strict, require_fqdn: true}
55
55
  ```
56
56
 
57
- You can also limit to a single domain (e.g: this might help if, for example, you
58
- have separate `User` and `AdminUser` models and want to ensure that `AdminUser`
59
- emails are on a specific domain):
57
+ You can also limit to a single domain (e.g: you have separate `User` and
58
+ `AdminUser` models and want to ensure that `AdminUser` emails are on a specific
59
+ domain):
60
60
 
61
61
  ```ruby
62
62
  validates :my_email_attribute, email: {domain: 'example.com'}
@@ -166,6 +166,10 @@ EmailValidator.valid?('narf@somehost') # boolean false
166
166
  EmailValidator.invalid?('narf@somehost', require_fqdn: false) # boolean true
167
167
  ```
168
168
 
169
+ _NB: Enabling strict mode (`mode: :strict`) enables `require_fqdn`
170
+ (`require_fqdn: true`), overridding any `require_fqdn: false` while
171
+ `mode: :strict` is set._
172
+
169
173
  ### Requiring a specific domain
170
174
 
171
175
  ```ruby
@@ -1,4 +1,6 @@
1
1
  # Based on work from http://thelucid.com/2010/01/08/sexy-validation-in-edge-rails-rails-3/
2
+
3
+ # EmailValidator class
2
4
  class EmailValidator < ActiveModel::EachValidator
3
5
  # rubocop:disable Style/ClassVars
4
6
  @@default_options = {
@@ -9,6 +11,13 @@ class EmailValidator < ActiveModel::EachValidator
9
11
  }
10
12
  # rubocop:enable Style/ClassVars
11
13
 
14
+ # EmailValidator::Error class
15
+ class Error < StandardError
16
+ def initialize(msg = 'EmailValidator error')
17
+ super
18
+ end
19
+ end
20
+
12
21
  class << self
13
22
  def default_options
14
23
  @@default_options
@@ -35,8 +44,11 @@ class EmailValidator < ActiveModel::EachValidator
35
44
  loose_regexp(options)
36
45
  when :rfc
37
46
  rfc_regexp(options)
38
- else
47
+ when :strict
48
+ options[:require_fqdn] = true
39
49
  strict_regexp(options)
50
+ else
51
+ fail EmailValidator::Error, "Validation mode '#{options[:mode]}' is not supported by EmailValidator"
40
52
  end
41
53
  end
42
54
 
@@ -81,31 +93,38 @@ class EmailValidator < ActiveModel::EachValidator
81
93
  end
82
94
 
83
95
  def host_label_pattern
96
+ "#{label_is_correct_length}" \
97
+ "#{label_contains_no_more_than_one_consecutive_hyphen}" \
84
98
  "#{alnum}(?:#{alnumhy}{,61}#{alnum})?"
85
99
  end
86
100
 
87
101
  # splitting this up into separate regex pattern for performance; let's not
88
102
  # try the "contains" pattern unless we have to
89
103
  def domain_label_pattern
90
- '(?=[^.]{1,63}(?:\.|$))' \
91
- '(?:' \
92
- "#{alpha}" \
93
- "|#{domain_label_starts_with_a_letter_pattern}" \
94
- "|#{domain_label_ends_with_a_letter_pattern}" \
95
- "|#{domain_label_contains_a_letter_pattern}" \
96
- ')'
104
+ "#{host_label_pattern}\\.#{tld_label_pattern}"
105
+ end
106
+
107
+ # While, techincally, TLDs can be numeric-only, this is not allowed by ICANN
108
+ # Ref: ICANN Application Guidebook for new TLDs (June 2012)
109
+ # says the following starting at page 64:
110
+ #
111
+ # > The ASCII label must consist entirely of letters (alphabetic characters a-z)
112
+ #
113
+ # -- https://newgtlds.icann.org/en/applicants/agb/guidebook-full-04jun12-en.pdf
114
+ def tld_label_pattern
115
+ "#{alpha}{1,64}"
97
116
  end
98
117
 
99
- def domain_label_starts_with_a_letter_pattern
100
- "#{alpha}#{alnumhy}{,61}#{alnum}"
118
+ def label_is_correct_length
119
+ '(?=[^.]{1,63}(?:\.|$))'
101
120
  end
102
121
 
103
- def domain_label_ends_with_a_letter_pattern
104
- "#{alnum}#{alnumhy}{,61}#{alpha}"
122
+ def domain_part_is_correct_length
123
+ '(?=.{1,255}$)'
105
124
  end
106
125
 
107
- def domain_label_contains_a_letter_pattern
108
- "(?:[[:digit:]])(?:[[:digit:]]|-)*#{alpha}#{alnumhy}*#{alnum}"
126
+ def label_contains_no_more_than_one_consecutive_hyphen
127
+ '(?!.*?--.*$)'
109
128
  end
110
129
 
111
130
  def atom_char
@@ -122,11 +141,11 @@ class EmailValidator < ActiveModel::EachValidator
122
141
  def domain_part_pattern(options)
123
142
  return options[:domain].sub(/\./, '\.') if options[:domain].present?
124
143
  return fqdn_pattern if options[:require_fqdn]
125
- "(?=.{1,255}$)(?:#{address_literal}|(?:#{host_label_pattern}\\.)*#{domain_label_pattern})"
144
+ "#{domain_part_is_correct_length}(?:#{address_literal}|(?:#{host_label_pattern}\\.)*#{tld_label_pattern})"
126
145
  end
127
146
 
128
147
  def fqdn_pattern
129
- "(?=.{1,255}$)(?:#{host_label_pattern}\\.)*#{domain_label_pattern}\\.#{domain_label_pattern}"
148
+ "(?=.{1,255}$)(?:#{host_label_pattern}\\.)*#{domain_label_pattern}"
130
149
  end
131
150
 
132
151
  private
@@ -146,7 +146,8 @@ RSpec.describe EmailValidator do
146
146
  'john.doe@a2.com',
147
147
  'john.doe@2020.a-z.com',
148
148
  'john.doe@2020.a2z.com',
149
- 'john.doe@2020.12345a6789.com'
149
+ 'john.doe@2020.12345a6789.com',
150
+ 'jonh.doe@163.com'
150
151
  ]).flatten.each do |email|
151
152
  context 'when using defaults' do
152
153
  it "'#{email}' should be valid" do
@@ -289,20 +290,20 @@ RSpec.describe EmailValidator do
289
290
  end
290
291
 
291
292
  context 'when in `:strict` mode' do
292
- it "'#{email}' should not be valid" do
293
- expect(StrictUser.new(:email => email)).not_to be_valid
293
+ it "'#{email}' should be valid" do
294
+ expect(StrictUser.new(:email => email)).to be_valid
294
295
  end
295
296
 
296
- it "'#{email}' should not be valid using EmailValidator.valid?" do
297
- expect(described_class).not_to be_valid(email, :mode => :strict)
297
+ it "'#{email}' should be valid using EmailValidator.valid?" do
298
+ expect(described_class).to be_valid(email, :mode => :strict)
298
299
  end
299
300
 
300
- it "'#{email}' should be invalid using EmailValidator.invalid?" do
301
- expect(described_class).to be_invalid(email, :mode => :strict)
301
+ it "'#{email}' should be not invalid using EmailValidator.invalid?" do
302
+ expect(described_class).not_to be_invalid(email, :mode => :strict)
302
303
  end
303
304
 
304
- it "'#{email}' should not match the regexp" do
305
- expect(!!(email.strip =~ described_class.regexp(:mode => :strict))).to be(false)
305
+ it "'#{email}' should match the regexp" do
306
+ expect(!!(email.strip =~ described_class.regexp(:mode => :strict))).to be(true)
306
307
  end
307
308
  end
308
309
 
@@ -476,6 +477,7 @@ RSpec.describe EmailValidator do
476
477
  'host-beginning-with-dot@.example.com',
477
478
  'domain-beginning-with-dash@-example.com',
478
479
  'domain-ending-with-dash@example-.com',
480
+ 'domain-contains-double-dash@foo--example.com',
479
481
  'the-local-part-is-invalid-if-it-is-longer-than-sixty-four-characters@sld.dev',
480
482
  "domain-too-long@t#{".#{'o' * 63}" * 5}.long",
481
483
  "user@example.com<script>alert('hello')</script>"
@@ -703,7 +705,8 @@ RSpec.describe EmailValidator do
703
705
  ]}).concat([
704
706
  'user..-with-double-dots@example.com',
705
707
  '.user-beginning-with-dot@example.com',
706
- 'user-ending-with-dot.@example.com'
708
+ 'user-ending-with-dot.@example.com',
709
+ 'fully-numeric-tld@example.123'
707
710
  ]).flatten.each do |email|
708
711
  context 'when using defaults' do
709
712
  it "#{email.strip} in a model should be valid" do
@@ -781,23 +784,24 @@ RSpec.describe EmailValidator do
781
784
  end
782
785
  end
783
786
 
787
+ # Strict mode enables `require_fqdn` anyway
784
788
  context 'when in `:strict` mode' do
785
789
  let(:opts) { { :require_fqdn => false, :mode => :strict } }
786
790
 
787
- it 'is valid' do
788
- expect(NonFqdnStrictUser.new(:email => email)).to be_valid
791
+ it 'is not valid' do
792
+ expect(NonFqdnStrictUser.new(:email => email)).not_to be_valid
789
793
  end
790
794
 
791
- it 'is valid using EmailValidator.valid?' do
792
- expect(described_class).to be_valid(email, opts)
795
+ it 'is not valid using EmailValidator.valid?' do
796
+ expect(described_class).not_to be_valid(email, opts)
793
797
  end
794
798
 
795
- it 'is not invalid using EmailValidator.invalid?' do
796
- expect(described_class).not_to be_invalid(email, opts)
799
+ it 'is invalid using EmailValidator.invalid?' do
800
+ expect(described_class).to be_invalid(email, opts)
797
801
  end
798
802
 
799
803
  it 'matches the regexp' do
800
- expect(!!(email =~ described_class.regexp(opts))).to be(true)
804
+ expect(!!(email =~ described_class.regexp(opts))).to be(false)
801
805
  end
802
806
  end
803
807
 
@@ -1012,4 +1016,36 @@ RSpec.describe EmailValidator do
1012
1016
  end
1013
1017
  end
1014
1018
  end
1019
+
1020
+ context 'with regexp' do
1021
+ it 'returns a regexp when asked' do
1022
+ expect(described_class.regexp).to be_a(Regexp)
1023
+ end
1024
+
1025
+ it 'returns a strict regexp when asked' do
1026
+ expect(described_class.regexp(:mode => :strict)).to be_a(Regexp)
1027
+ end
1028
+
1029
+ it 'returns a RFC regexp when asked' do
1030
+ expect(described_class.regexp(:mode => :rfc)).to be_a(Regexp)
1031
+ end
1032
+
1033
+ it 'has different regexp for strict and loose' do
1034
+ expect(described_class.regexp(:mode => :strict)).not_to eq(described_class.regexp(:mode => :loose))
1035
+ end
1036
+
1037
+ it 'has different regexp for RFC and loose' do
1038
+ expect(described_class.regexp(:mode => :rfc)).not_to eq(described_class.regexp(:mode => :loose))
1039
+ end
1040
+
1041
+ it 'has different regexp for RFC and strict' do
1042
+ expect(described_class.regexp(:mode => :rfc)).not_to eq(described_class.regexp(:mode => :strict))
1043
+ end
1044
+ end
1045
+
1046
+ context 'with invalid `:mode`' do
1047
+ it 'raises an error' do
1048
+ expect { described_class.regexp(:mode => :invalid) }.to raise_error(EmailValidator::Error)
1049
+ end
1050
+ end
1015
1051
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: email_validator
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.2
4
+ version: 2.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Alexander
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-12-11 00:00:00.000000000 Z
12
+ date: 2021-04-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activemodel