valid_email 0.1.3 → 0.2.1

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: 066fc2f842dfd3d3afc0df730f7e44951a6692aa035b378036e2587731073dd1
4
- data.tar.gz: a21522fd9b8453ff36fc960fdbcd916843fe3232a4a87f2528611f1d8f9f693c
3
+ metadata.gz: 7e0da2f8d6e1b69a777c0d9a6bb14632fa577ecfa55acb7128d436e1543a6842
4
+ data.tar.gz: c8a125e2971de31cd1e43a49827af99cb1a44130082c555b448083aa1fc6bbaf
5
5
  SHA512:
6
- metadata.gz: f6dbf19e9942dacf1d749d3027d1d20e130a64c1418c7cae5e43165d0ddf304d46f02a530658760626af4cbe6cb686fcb30964bfd8512967e74c7599712c06cf
7
- data.tar.gz: cd549c34b78c76ef33ed9e60b3d683706a6fde6bcf2e5dcf7223dbf26f46a7556bbcb3325e8a862f1708b80072fce0f5c4b2e8bef479178d9633ffabd8224ddd
6
+ metadata.gz: 736072b973d66828d1f2cd78b6248599a5ecc3d054d0cbbd1354a4735447a97024575649c7bbe110edb576f18cedd647d378ceb12a9d8344639179c3c8d8ade0
7
+ data.tar.gz: 52fa87c50d4bf5570779706a39dea8c803b894256d7a92563b0b02009f92b262b6439565d4efd5345b65974f41dbd899085c6349f7c1cb4a5e9c82abcf21efe1
@@ -0,0 +1,44 @@
1
+ name: CI
2
+ on:
3
+ workflow_dispatch:
4
+ push:
5
+
6
+ permissions:
7
+ checks: write
8
+ contents: read
9
+ pull-requests: write
10
+
11
+ jobs:
12
+ rspec:
13
+ name: RSpec (ruby ${{ matrix.ruby-version }})
14
+ runs-on: ubuntu-20.04
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ ruby-version:
19
+ - '1.9.3'
20
+ - '2.0'
21
+ - '2.1'
22
+ - '2.2'
23
+ - '2.3'
24
+ - '2.4'
25
+ - '2.5'
26
+ - '2.6'
27
+ - '2.7'
28
+ - '3.0'
29
+ - '3.1'
30
+ - '3.2'
31
+ - 'jruby-head'
32
+ - 'truffleruby-head'
33
+ env:
34
+ CI: true
35
+ steps:
36
+ - name: Checkout
37
+ uses: actions/checkout@v3
38
+ - name: Setup ruby
39
+ uses: ruby/setup-ruby@v1
40
+ with:
41
+ ruby-version: ${{ matrix.ruby-version }}
42
+ bundler-cache: true
43
+ - name: Run tests
44
+ run: bundle exec rake
data/.rspec ADDED
File without changes
data/README.md CHANGED
@@ -1,98 +1,141 @@
1
- # Purpose
1
+ # Valid Email
2
2
 
3
- It validates email for application use (registering a new account for example)
3
+ ## Purpose
4
4
 
5
- # Usage
5
+ It validates email for application use (registering a new account for example).
6
6
 
7
- In your Gemfile :
8
-
9
- gem 'valid_email'
7
+ ## Usage
10
8
 
9
+ In your `Gemfile`:
10
+ ```ruby
11
+ gem 'valid_email'
12
+ ```
11
13
 
12
- In your code :
14
+ In your code:
15
+ ```ruby
16
+ require 'valid_email'
13
17
 
14
- require 'valid_email'
15
- class Person
16
- include ActiveModel::Validations
17
- attr_accessor :name, :email
18
+ class Person
19
+ include ActiveModel::Validations
20
+ attr_accessor :name, :email
18
21
 
19
- validates :name, :presence => true, :length => { :maximum => 100 }
20
- validates :email, :presence => true, :email => true
21
- end
22
+ validates :name, presence: true, length: { maximum: 100 }
23
+ validates :email, presence: true, email: true
24
+ end
22
25
 
23
26
 
24
- p = Person.new
25
- p.name = "hallelujah"
26
- p.email = "john@doe.com"
27
- p.valid? # => true
27
+ person = Person.new
28
+ person.name = 'hallelujah'
29
+ person.email = 'john@doe.com'
30
+ person.valid? # => true
28
31
 
29
- p.email = "john@doe"
30
- p.valid? # => false
32
+ person.email = 'john@doe'
33
+ person.valid? # => false
31
34
 
32
- p.email = "John Does <john@doe.com>"
33
- p.valid? # => false
35
+ person.email = 'John Does <john@doe.com>'
36
+ person.valid? # => false
37
+ ```
34
38
 
35
39
  You can check if email domain has MX record:
36
-
37
- validates :email, :email => {:mx => true, :message => I18n.t('validations.errors.models.user.invalid_email')}
40
+ ```ruby
41
+ validates :email,
42
+ email: {
43
+ mx: true,
44
+ message: I18n.t('validations.errors.models.user.invalid_email')
45
+ }
46
+ ```
38
47
 
39
48
  Or
40
49
 
41
- validates :email, :email => {:message => I18n.t('validations.errors.models.user.invalid_email')}, :mx => {:message => I18n.t('validations.errors.models.user.invalid_mx')}
50
+ ```ruby
51
+ validates :email,
52
+ email: {
53
+ message: I18n.t('validations.errors.models.user.invalid_email')
54
+ },
55
+ mx: {
56
+ message: I18n.t('validations.errors.models.user.invalid_mx')
57
+ }
58
+ ```
42
59
 
43
60
  By default, the email domain is validated using a regular expression, which does not require an external service and improves performance.
44
61
  Alternatively, you can check if an email domain has a MX or A record by using `:mx_with_fallback` instead of `:mx`.
45
62
 
46
- validates :email, :email => {:mx_with_fallback => true}
63
+ ```ruby
64
+ validates :email, email: { mx_with_fallback: true }
65
+ ```
47
66
 
48
67
  You can detect disposable accounts
49
68
 
50
- validates :email, :email => {:ban_disposable_email => true, :message => I18n.t('validations.errors.models.user.invalid_email')}
69
+ ```ruby
70
+ validates :email,
71
+ email: {
72
+ ban_disposable_email: true,
73
+ message: I18n.t('validations.errors.models.user.invalid_email')
74
+ }
75
+ ```
51
76
 
52
- If you don't want the MX validator stuff, just require the right file
77
+ You can also detect a partial match on disposable accounts, good for services that use subdomains.
53
78
 
54
- require 'valid_email/email_validator'
79
+ ```ruby
80
+ validates :email,
81
+ email: {
82
+ message: I18n.t('validations.errors.models.user.invalid_email')
83
+ ban_disposable_email: true,
84
+ partial: true
85
+ }
86
+ ```
87
+
88
+ If you don't want the MX validator stuff, just require the right file
55
89
 
56
- Or in your Gemfile
90
+ ```ruby
91
+ require 'valid_email/email_validator'
92
+ ```
57
93
 
58
- gem 'valid_email', :require => 'valid_email/email_validator'
94
+ Or in your `Gemfile`
59
95
 
96
+ ```ruby
97
+ gem 'valid_email', require: 'valid_email/email_validator'
98
+ ```
60
99
 
61
100
  ### Usage outside of model validation
62
- There is a chance that you want to use e-mail validator outside of model validation.
101
+
102
+ There is a chance that you want to use e-mail validator outside of model validation.
63
103
  If that's the case, you can use the following methods:
64
104
 
65
105
  ```ruby
66
- ValidateEmail.valid?('email@randommail.com') # You can optionally pass a hash of options, same as validator
106
+ options = {} # You can optionally pass a hash of options, same as validator
107
+ ValidateEmail.valid?('email@randommail.com', options)
67
108
  ValidateEmail.mx_valid?('email@randommail.com')
68
109
  ValidateEmail.mx_valid_with_fallback?('email@randommail.com')
69
110
  ValidateEmail.valid?('email@randommail.com')
70
111
  ```
71
112
 
72
- Load it (and not the rails extensions) with
73
-
74
- gem 'valid_email', require: 'valid_email/validate_email'
113
+ Load it (and not the Rails extensions) with
75
114
 
115
+ ```ruby
116
+ gem 'valid_email', require: 'valid_email/validate_email'
117
+ ```
76
118
 
77
119
  ### String and Nil object extensions
78
120
 
79
- There is also a String and Nil class extension, if you require the gem in this way in Gemfile:
121
+ There is also a String and Nil class extension, if you require the gem in this way in `Gemfile`:
80
122
 
81
123
  ```ruby
82
- gem 'valid_email', require: ['valid_email/all_with_extensions']
124
+ gem 'valid_email', require: 'valid_email/all_with_extensions'
83
125
  ```
84
126
 
85
127
  You will be able to use the following methods:
86
128
  ```ruby
87
129
  nil.email? # => false
88
- "john@gmail.com".email? # => May return true if it exists. It accepts a hash of options like ValidateEmail.valid?
130
+ 'john@gmail.com'.email? # => May return true if it exists.
131
+ # It accepts a hash of options like ValidateEmail.valid?
89
132
  ```
90
133
 
91
134
  ## Code Status
92
135
 
93
- * [![Build Status](https://travis-ci.org/hallelujah/valid_email.svg?branch=master)](https://travis-ci.org/hallelujah/valid_email)
136
+ [![Build Status](https://github.com/hallelujah/valid_email/actions/workflows/ci.yaml/badge.svg)](https://github.com/hallelujah/valid_email/actions/workflows/ci.yaml)
94
137
 
95
- # Credits
138
+ ## Credits
96
139
 
97
140
  * Ramihajamalala Hery hery[at]rails-royce.org
98
141
  * Fire-Dragon-DoL francesco.belladonna[at]gmail.com
@@ -109,18 +152,14 @@ nil.email? # => false
109
152
  * Jean Boussier jean.boussier[at]gmail.com
110
153
  * Masaki Hara - @qnighy
111
154
 
112
- # Note on Patches/Pull Requests
113
-
114
- * Fork the project.
115
-
116
- * Make your feature addition or bug fix.
117
-
118
- * Add tests for it. This is important so I don’t break it in a future version unintentionally.
119
-
120
- * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
155
+ ## Pull Requests
121
156
 
122
- * Send me a pull request. Bonus points for topic branches.
157
+ 1. Fork the project.
158
+ 2. Make your feature addition or bug fix.
159
+ 3. Add tests for it. This is important so I don’t break it in a future version unintentionally.
160
+ 4. Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
161
+ 5. Send me a pull request. Bonus points for topic branches.
123
162
 
124
- # Copyright
163
+ ## Copyright
125
164
 
126
165
  Copyright &copy; 2011 Ramihajamalala Hery. See LICENSE for details
@@ -0,0 +1,5 @@
1
+ cs:
2
+ valid_email:
3
+ validations:
4
+ email:
5
+ invalid: je neplatný
@@ -0,0 +1,5 @@
1
+ es:
2
+ valid_email:
3
+ validations:
4
+ email:
5
+ invalid: "no es válido"
@@ -347,7 +347,6 @@ disposable_email_services:
347
347
  - prtnx.com
348
348
  - punkass.com
349
349
  - putthisinyourspamdatabase.com
350
- - qq.com
351
350
  - quickinbox.com
352
351
  - rcpt.at
353
352
  - recode.me
@@ -15,9 +15,19 @@ class BanDisposableEmailValidator < ActiveModel::EachValidator
15
15
  end
16
16
 
17
17
  def validate_each(record, attribute, value)
18
- r = ValidateEmail.ban_disposable_email?(value)
19
- record.errors.add attribute, (options[:message] || I18n.t(:invalid, :scope => "valid_email.validations.email")) unless r
18
+ # Check if part of domain is in disposable_email_services yml list
19
+ if options[:partial]
20
+ r = ValidateEmail.ban_partial_disposable_email?(value)
21
+ record.errors.add attribute, (options[:message] ||
22
+ I18n.t(:invalid, :scope => "valid_email.validations.email")) unless r
20
23
 
21
- r
24
+ r
25
+ else
26
+ r = ValidateEmail.ban_disposable_email?(value)
27
+ record.errors.add attribute, (options[:message] ||
28
+ I18n.t(:invalid, :scope => "valid_email.validations.email")) unless r
29
+
30
+ r
31
+ end
22
32
  end
23
33
  end
@@ -18,11 +18,11 @@ class EmailValidator < ActiveModel::EachValidator
18
18
  # Check if domain is disposable
19
19
  if r && options[:ban_disposable_email]
20
20
  require 'valid_email/ban_disposable_email_validator'
21
- r = BanDisposableEmailValidator.new(:attributes => attributes, message: options[:message]).validate(record)
21
+ r = BanDisposableEmailValidator.new(:attributes => attributes, message: options[:message], partial: options[:partial]).validate(record)
22
22
  end
23
23
  unless r
24
24
  msg = (options[:message] || I18n.t(:invalid, :scope => "valid_email.validations.email"))
25
- record.errors.add attribute, (msg % {value: value})
25
+ record.errors.add attribute, message: I18n.interpolate(msg, value: value)
26
26
  end
27
27
  end
28
28
  end
@@ -1,4 +1,5 @@
1
1
  require 'mail'
2
+ require 'simpleidn'
2
3
 
3
4
  class ValidateEmail
4
5
  class << self
@@ -27,7 +28,7 @@ class ValidateEmail
27
28
  return false unless m.domain.match(/^\S+$/)
28
29
 
29
30
  domain_dot_elements = m.domain.split(/\./)
30
- return false unless domain_dot_elements.size > 1 && !domain_dot_elements.any?(&:empty?)
31
+ return false unless domain_dot_elements.size > 1 && domain_dot_elements.none?(&:empty?)
31
32
 
32
33
  # Ensure that the local segment adheres to adheres to RFC-5322
33
34
  return false unless valid_local?(m.local)
@@ -90,11 +91,17 @@ class ValidateEmail
90
91
  m = Mail::Address.new(value)
91
92
  return false unless m.domain
92
93
 
94
+ if m.domain.ascii_only?
95
+ ascii_domain = m.domain
96
+ else
97
+ ascii_domain = SimpleIDN.to_ascii(m.domain)
98
+ end
99
+
93
100
  Resolv::DNS.open do |dns|
94
101
  dns.timeouts = MxValidator.config[:timeouts] unless MxValidator.config[:timeouts].empty?
95
102
 
96
- return dns.getresources(m.domain, Resolv::DNS::Resource::IN::MX).size > 0 || (
97
- fallback && dns.getresources(m.domain, Resolv::DNS::Resource::IN::A).size > 0
103
+ return dns.getresources(ascii_domain, Resolv::DNS::Resource::IN::MX).size > 0 || (
104
+ fallback && dns.getresources(ascii_domain, Resolv::DNS::Resource::IN::A).size > 0
98
105
  )
99
106
  end
100
107
  rescue Mail::Field::ParseError
@@ -121,5 +128,15 @@ class ValidateEmail
121
128
  rescue Mail::Field::ParseError
122
129
  false
123
130
  end
131
+
132
+ def ban_partial_disposable_email?(value)
133
+ m = Mail::Address.new(value)
134
+ m.domain && !BanDisposableEmailValidator.config.any? do |bde|
135
+ next if bde == nil
136
+ m.domain.end_with?(bde)
137
+ end
138
+ rescue Mail::Field::ParseError
139
+ false
140
+ end
124
141
  end
125
142
  end
@@ -1 +1 @@
1
- ValidEmailVersion = "0.1.3"
1
+ ValidEmailVersion = "0.2.1"
@@ -1,63 +1,73 @@
1
1
  require 'spec_helper'
2
2
 
3
+ RSpec::Matchers.define :have_error_messages do |field, expected|
4
+ match do |model|
5
+ errors = model.errors[field]
6
+
7
+ messages = errors.map do |error|
8
+ case error
9
+ when String then error
10
+ when Hash then error[:message]
11
+ else fail ArgumentError, "Unknown model error type #{error.class}"
12
+ end
13
+ end
14
+
15
+ expect(messages).to eq expected
16
+ end
17
+ end
18
+
3
19
  describe EmailValidator do
4
- person_class = Class.new do
20
+ email_class = Class.new do
5
21
  include ActiveModel::Validations
22
+
6
23
  attr_accessor :email
24
+
25
+ def self.model_name
26
+ ActiveModel::Name.new(self, nil, "TestModel")
27
+ end
28
+ end
29
+
30
+ person_class = Class.new(email_class) do
7
31
  validates :email, :email => true
8
32
  end
9
33
 
10
- person_class_mx = Class.new do
11
- include ActiveModel::Validations
12
- attr_accessor :email
34
+ person_class_mx = Class.new(email_class) do
13
35
  validates :email, :email => {:mx => true}
14
36
  end
15
37
 
16
- person_class_mx_with_fallback = Class.new do
17
- include ActiveModel::Validations
18
- attr_accessor :email
38
+ person_class_mx_with_fallback = Class.new(email_class) do
19
39
  validates :email, :email => {:mx_with_fallback => true}
20
40
  end
21
41
 
22
- person_class_disposable_email = Class.new do
23
- include ActiveModel::Validations
24
- attr_accessor :email
42
+ person_class_disposable_email = Class.new(email_class) do
25
43
  validates :email, :email => {:ban_disposable_email => true}
26
44
  end
27
45
 
28
- person_class_nil_allowed = Class.new do
29
- include ActiveModel::Validations
30
- attr_accessor :email
46
+ person_class_partial_disposable_email = Class.new(email_class) do
47
+ validates :email, :email => {:ban_disposable_email => true, :partial => true}
48
+ end
49
+
50
+ person_class_nil_allowed = Class.new(email_class) do
31
51
  validates :email, :email => {:allow_nil => true}
32
52
  end
33
53
 
34
- person_class_blank_allowed = Class.new do
35
- include ActiveModel::Validations
36
- attr_accessor :email
54
+ person_class_blank_allowed = Class.new(email_class) do
37
55
  validates :email, :email => {:allow_blank => true}
38
56
  end
39
57
 
40
- person_class_mx_separated = Class.new do
41
- include ActiveModel::Validations
42
- attr_accessor :email
58
+ person_class_mx_separated = Class.new(email_class) do
43
59
  validates :email, :mx => true
44
60
  end
45
61
 
46
- person_class_mx_with_fallback_separated = Class.new do
47
- include ActiveModel::Validations
48
- attr_accessor :email
62
+ person_class_mx_with_fallback_separated = Class.new(email_class) do
49
63
  validates :email, :mx_with_fallback => true
50
64
  end
51
65
 
52
- person_class_domain = Class.new do
53
- include ActiveModel::Validations
54
- attr_accessor :email
66
+ person_class_domain = Class.new(email_class) do
55
67
  validates :email, :domain => true
56
68
  end
57
69
 
58
- person_message_specified = Class.new do
59
- include ActiveModel::Validations
60
- attr_accessor :email
70
+ person_message_specified = Class.new(email_class) do
61
71
  validates :email, :email => { :message => 'custom message', :ban_disposable_email => true }
62
72
  end
63
73
 
@@ -79,43 +89,43 @@ describe EmailValidator do
79
89
 
80
90
  it "fails when email empty" do
81
91
  expect(subject.valid?).to be_falsey
82
- expect(subject.errors[:email]).to eq errors
92
+ expect(subject).to have_error_messages(:email, errors)
83
93
  end
84
94
 
85
95
  it "fails when email is not valid" do
86
96
  subject.email = 'joh@doe'
87
97
  expect(subject.valid?).to be_falsey
88
- expect(subject.errors[:email]).to eq errors
98
+ expect(subject).to have_error_messages(:email, errors)
89
99
  end
90
100
 
91
101
  it "fails when email domain is prefixed with dot" do
92
102
  subject.email = 'john@.doe'
93
103
  expect(subject.valid?).to be_falsey
94
- expect(subject.errors[:email]).to eq errors
104
+ expect(subject).to have_error_messages(:email, errors)
95
105
  end
96
106
 
97
107
  it "fails when email domain contains two consecutive dots" do
98
108
  subject.email = 'john@doe-two..com'
99
109
  expect(subject.valid?).to be_falsey
100
- expect(subject.errors[:email]).to eq errors
110
+ expect(subject).to have_error_messages(:email, errors)
101
111
  end
102
112
 
103
113
  it "fails when email ends with a period" do
104
114
  subject.email = 'john@doe.com.'
105
115
  expect(subject.valid?).to be_falsey
106
- expect(subject.errors[:email]).to eq errors
116
+ expect(subject).to have_error_messages(:email, errors)
107
117
  end
108
118
 
109
119
  it "fails when email ends with special characters" do
110
120
  subject.email = 'john@doe.com&'
111
121
  expect(subject.valid?).to be_falsey
112
- expect(subject.errors[:email]).to eq errors
122
+ expect(subject).to have_error_messages(:email, errors)
113
123
  end
114
124
 
115
125
  it "fails when email is valid with information" do
116
126
  subject.email = '"John Doe" <john@doe.com>'
117
127
  expect(subject.valid?).to be_falsey
118
- expect(subject.errors[:email]).to eq errors
128
+ expect(subject).to have_error_messages(:email, errors)
119
129
  end
120
130
 
121
131
  it "passes when email is simple email address" do
@@ -127,42 +137,51 @@ describe EmailValidator do
127
137
  it "fails when email is simple email address not stripped" do
128
138
  subject.email = 'john@doe.com '
129
139
  expect(subject.valid?).to be_falsey
130
- expect(subject.errors[:email]).to eq errors
140
+ expect(subject).to have_error_messages(:email, errors)
131
141
  end
132
142
 
133
143
  it "fails when domain contains a space" do
134
144
  subject.email = 'john@doe .com'
135
145
  expect(subject.valid?).to be_falsey
136
- expect(subject.errors[:email]).to eq errors
146
+ expect(subject).to have_error_messages(:email, errors)
137
147
  end
138
148
 
139
149
  it "fails when passing multiple simple email addresses" do
140
150
  subject.email = 'john@doe.com, maria@doe.com'
141
151
  expect(subject.valid?).to be_falsey
142
- expect(subject.errors[:email]).to eq errors
152
+ expect(subject).to have_error_messages(:email, errors)
143
153
  end
144
-
145
154
  end
146
155
 
147
156
  describe "validating email with MX and fallback to A" do
157
+ let(:dns) { instance_double('Resolv::DNS', :dns) }
158
+
148
159
  subject { person_class_mx_with_fallback.new }
149
160
 
161
+ before do
162
+ allow(Resolv::DNS).to receive(:open).and_yield(dns)
163
+ end
164
+
150
165
  it "passes when email domain has MX record" do
151
- subject.email = 'john@gmail.com'
166
+ allow(dns).to receive(:getresources).with('has-mx-record.org', Resolv::DNS::Resource::IN::MX).and_return(['1.2.3.4'])
167
+ subject.email = 'john@has-mx-record.org'
152
168
  expect(subject.valid?).to be_truthy
153
169
  expect(subject.errors[:email]).to be_empty
154
170
  end
155
171
 
156
172
  it "passes when email domain has no MX record but has an A record" do
157
- subject.email = 'john@subdomain.rubyonrails.org'
173
+ allow(dns).to receive(:getresources).with('has-a-record.org', Resolv::DNS::Resource::IN::MX).and_return([])
174
+ allow(dns).to receive(:getresources).with('has-a-record.org', Resolv::DNS::Resource::IN::A).and_return(['1.2.3.4'])
175
+ subject.email = 'john@has-a-record.org'
158
176
  expect(subject.valid?).to be_truthy
159
177
  expect(subject.errors[:email]).to be_empty
160
178
  end
161
179
 
162
180
  it "fails when domain does not exists" do
163
- subject.email = 'john@nonexistentdomain.abc'
181
+ allow(dns).to receive(:getresources).with('does-not-exist.org', anything).and_return([])
182
+ subject.email = 'john@does-not-exist.org'
164
183
  expect(subject.valid?).to be_falsey
165
- expect(subject.errors[:email]).to eq errors
184
+ expect(subject).to have_error_messages(:email, errors)
166
185
  end
167
186
  end
168
187
 
@@ -178,13 +197,13 @@ describe EmailValidator do
178
197
  it "fails when email domain has no MX record" do
179
198
  subject.email = 'john@subdomain.rubyonrails.org'
180
199
  expect(subject.valid?).to be_falsey
181
- expect(subject.errors[:email]).to eq errors
200
+ expect(subject).to have_error_messages(:email, errors)
182
201
  end
183
202
 
184
203
  it "fails when domain does not exists" do
185
204
  subject.email = 'john@nonexistentdomain.abc'
186
205
  expect(subject.valid?).to be_falsey
187
- expect(subject.errors[:email]).to eq errors
206
+ expect(subject).to have_error_messages(:email, errors)
188
207
  end
189
208
  end
190
209
 
@@ -228,6 +247,22 @@ describe EmailValidator do
228
247
  it "fails when email from disposable email services" do
229
248
  subject.email = 'john@grr.la'
230
249
  expect(subject.valid?).to be_falsey
250
+ expect(subject).to have_error_messages(:email, errors)
251
+ end
252
+ end
253
+
254
+ describe "validating email against partial disposable service match" do
255
+ subject { person_class_partial_disposable_email.new }
256
+
257
+ it "passes when email from trusted email services" do
258
+ subject.email = 'john@test.mail.ru'
259
+ expect(subject.valid?).to be_truthy
260
+ expect(subject.errors[:email]).to be_empty
261
+ end
262
+
263
+ it "fails when disposable email services partially matches email domain" do
264
+ subject.email = 'john@sub.grr.la'
265
+ expect(subject.valid?).to be_falsey
231
266
  expect(subject.errors[:email]).to eq errors
232
267
  end
233
268
  end
@@ -238,7 +273,7 @@ describe EmailValidator do
238
273
  it "does not pass with an invalid domain" do
239
274
  subject.email = "test@example.org$\'"
240
275
  expect(subject.valid?).to be_falsey
241
- expect(subject.errors[:email]).to eq errors
276
+ expect(subject).to have_error_messages(:email, errors)
242
277
  end
243
278
 
244
279
  it "passes with valid domain" do
@@ -290,4 +325,19 @@ describe EmailValidator do
290
325
  let!(:errors) { [ "est invalide" ] }
291
326
  it_behaves_like "Validating emails"
292
327
  end
328
+
329
+ describe 'Translating in czech' do
330
+ let!(:locale){ :cs }
331
+ let!(:errors) do
332
+ [
333
+ I18n.t(
334
+ :invalid,
335
+ locale: locale,
336
+ scope: [:valid_email, :validations, :email]
337
+ )
338
+ ]
339
+ end
340
+
341
+ it_behaves_like 'Validating emails'
342
+ end
293
343
  end
data/spec/spec_helper.rb CHANGED
@@ -2,5 +2,11 @@ $:.unshift File.expand_path('../../lib',__FILE__)
2
2
  require 'valid_email'
3
3
 
4
4
  RSpec.configure do |config|
5
+ config.order = :random
5
6
  config.raise_errors_for_deprecations!
7
+ Kernel.srand config.seed
8
+
9
+ if ENV['CI']
10
+ config.warnings = true
11
+ end
6
12
  end
@@ -15,13 +15,27 @@ describe ValidateEmail do
15
15
  end
16
16
 
17
17
  context 'when mx: true option passed' do
18
+ let(:dns) { Resolv::DNS.new }
19
+
20
+ def mock_dns_mx
21
+ allow(dns).to receive(:getresources).and_return([])
22
+ allow(Resolv::DNS).to receive(:new).and_return(dns)
23
+ end
24
+
18
25
  it 'returns true when mx record exist' do
19
26
  expect(ValidateEmail.valid?('user@gmail.com', mx: true)).to be_truthy
20
27
  end
21
28
 
22
29
  it "returns false when mx record doesn't exist" do
30
+ mock_dns_mx
23
31
  expect(ValidateEmail.valid?('user@example.com', mx: true)).to be_falsey
24
32
  end
33
+
34
+ it "IDN-encodes the domain name if it contains multibyte characters" do
35
+ mock_dns_mx
36
+ ValidateEmail.valid?("user@\u{1F600}.com", mx: true)
37
+ expect(dns).to have_received(:getresources).with('xn--e28h.com', anything)
38
+ end
25
39
  end
26
40
 
27
41
  context 'when domain: true option passed' do
data/valid_email.gemspec CHANGED
@@ -12,21 +12,20 @@ Gem::Specification.new do |s|
12
12
  s.description = %q{ActiveModel Validation for email}
13
13
  s.license = 'MIT'
14
14
 
15
- s.rubyforge_project = "valid_email"
16
-
17
15
  s.files = `git ls-files`.split("\n")
18
16
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
18
  s.require_paths = ["lib"]
21
19
 
22
20
  # specify any dependencies here; for example:
23
- s.add_development_dependency "rspec", "~> 2.99"
24
- s.add_development_dependency "rake", '< 11.0'
21
+ s.add_development_dependency "rspec", "~> 3.10"
22
+ s.add_development_dependency "rake"
25
23
  s.add_runtime_dependency "mail", ">= 2.6.1"
26
- if Gem::Version.new(RUBY_VERSION) <= Gem::Version.new('2.0')
24
+ s.add_runtime_dependency "simpleidn"
25
+ if Gem::Version.new(RUBY_VERSION.dup) <= Gem::Version.new('2.0')
27
26
  s.add_runtime_dependency 'mime-types', '<= 2.6.2'
28
27
  end
29
- if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2.2')
28
+ if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.2.2')
30
29
  s.add_runtime_dependency "activemodel", '< 5.0.0'
31
30
  else
32
31
  s.add_runtime_dependency "activemodel"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: valid_email
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ramihajamalala Hery
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-24 00:00:00.000000000 Z
11
+ date: 2024-03-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -16,28 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.99'
19
+ version: '3.10'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.99'
26
+ version: '3.10'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "<"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '11.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "<"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '11.0'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: mail
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: 2.6.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: simpleidn
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: activemodel
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -73,15 +87,18 @@ executables: []
73
87
  extensions: []
74
88
  extra_rdoc_files: []
75
89
  files:
90
+ - ".github/workflows/ci.yaml"
76
91
  - ".gitignore"
77
- - ".travis.yml"
92
+ - ".rspec"
78
93
  - Gemfile
79
94
  - History.md
80
95
  - LICENSE
81
96
  - README.md
82
97
  - Rakefile
98
+ - config/locales/cs.yml
83
99
  - config/locales/de.yml
84
100
  - config/locales/en.yml
101
+ - config/locales/es.yml
85
102
  - config/locales/fi.yml
86
103
  - config/locales/fr.yml
87
104
  - config/locales/hu.yml
@@ -113,7 +130,7 @@ homepage: https://github.com/hallelujah/valid_email
113
130
  licenses:
114
131
  - MIT
115
132
  metadata: {}
116
- post_install_message:
133
+ post_install_message:
117
134
  rdoc_options: []
118
135
  require_paths:
119
136
  - lib
@@ -128,9 +145,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
128
145
  - !ruby/object:Gem::Version
129
146
  version: '0'
130
147
  requirements: []
131
- rubyforge_project: valid_email
132
- rubygems_version: 2.7.6
133
- signing_key:
148
+ rubygems_version: 3.5.6
149
+ signing_key:
134
150
  specification_version: 4
135
151
  summary: ActiveModel Validation for email
136
152
  test_files:
data/.travis.yml DELETED
@@ -1,15 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- cache: bundler
4
- rvm:
5
- - 1.9.3
6
- - 2.0.0
7
- - 2.1
8
- - 2.2.1
9
- - 2.2.2
10
- - 2.3.3
11
- - 2.4.0
12
- - jruby-19mode
13
- - jruby-20mode
14
- before_install:
15
- - gem install bundler:1.17.3