real_world_email_validator 0.1.5

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b3546d066fdd7ad2ee33ccec9682444dab55bda2848600506f8267b4f9c6e6f3
4
+ data.tar.gz: 880760435fa006089d41ceaaf928f6c80f148d7ad794375959443eac3a118870
5
+ SHA512:
6
+ metadata.gz: 11e5f65ed6fb1a6ba65ba6a3f6ce962f6a38b9f1338e5d499ad5ab7508b4de90b48c174df36043500ba2fd281edc66fd513b42dc3e328f6122f3c5c6be394f31
7
+ data.tar.gz: 0b4dce49ed2c08bd71f6aefed3620ae5aaf54ead153520766288d295c0d8b93d2cd39ac19911b7ee2686c311ee9f8115519b93715c585a096d6df8687266f3ab
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_model/validator'
4
+
5
+ # Email address validator based on RFC 5322, plus own flavors that real world needs
6
+ # ref: https://tools.ietf.org/html/rfc5322#section-3.4.1
7
+ class RealWorldEmailValidator < ActiveModel::EachValidator
8
+ module StringExt
9
+ refine String do
10
+ def start_and_end_with?(chars)
11
+ self.start_with?(chars) && self.end_with?(chars)
12
+ end
13
+
14
+ def start_or_end_with?(chars)
15
+ self.start_with?(chars) || self.end_with?(chars)
16
+ end
17
+ end
18
+ end
19
+
20
+ using RealWorldEmailValidator::StringExt
21
+
22
+ def validate_each(record, attribute, value)
23
+ if value.blank?
24
+ record.errors.add attribute, :invalid
25
+ return
26
+ end
27
+
28
+ username, domain = value.split('@')
29
+
30
+ unless domain.present? && username_valid?(username) && domain_valid?(domain)
31
+ record.errors.add attribute, :invalid
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ # Local-part A.K.A username format definition based on RFC 5322.
38
+ # Any of following characters are allowed basically:
39
+ # - Uppercase and lowercase alphabetical letters
40
+ # - Digits 0 to 9
41
+ # - Printable characters other than letters and digits !#$%&'*+-/=?^_`{|}~
42
+ # - .(dot)
43
+ # However, a .(dot) MUST be surrounded by other allowed characters unless whole username is quoted.
44
+ # e.g.
45
+ # John.Doe@example.com => OK
46
+ # John..Doe@example.com => NG
47
+ # "John..Doe"@example.com => OK
48
+ #
49
+ # And we add following validations as own flavor:
50
+ # - Whitespace is not allowed
51
+ # - Backslash is not allowed
52
+ # - Comment, allowed characters surrounded by '(' and ')' is not allowed
53
+ def username_valid?(username)
54
+ regex = %r{\A"?([a-zA-Z]|[0-9]|[!#$%&'*+-/=?^_`{|}~]|[.])+"?\z}
55
+ result = username.match?(regex)
56
+
57
+ return result if username.start_and_end_with?('"')
58
+ return false if username.start_or_end_with?('.') || username.include?('..')
59
+ result
60
+ end
61
+
62
+ # Domain format definition based on RFC 5322.
63
+ # It must match the requirements for a hostname, which you can imagine of DNS.
64
+ # It is limited to a length of 63 characters.
65
+ # Any of following characters are allowed:
66
+ # - Uppercase and lowercase alphabetical letters
67
+ # - Digits 0 to 9, however, top-level domain MUST NOT all-numeric
68
+ # - Hyphen(-), however, it MUST not be the first or last character of the each domain
69
+ # And we add following validation as own flavor:
70
+ # - Comment, allowed characters surrounded by '(' and ')' is not allowed
71
+ # - It MUST contain domains other than top-level
72
+ def domain_valid?(domain_str)
73
+ return false if domain_str.length > 63
74
+
75
+ domains = domain_str.split('.')
76
+ top_level = domains[-1]
77
+ subdomains = domains - [top_level]
78
+
79
+ top_level_domain_valid?(top_level) && subdomains_valid?(subdomains)
80
+ end
81
+
82
+ def top_level_domain_valid?(top_level_domain)
83
+ return false if top_level_domain.start_or_end_with?('-')
84
+ return false if top_level_domain.match?(/\A([0-9])+\z/)
85
+
86
+ top_level_domain.match?(/\A([a-zA-Z]|[0-9]|[-])+\z/)
87
+ end
88
+
89
+ def subdomains_valid?(subdomains)
90
+ return false if subdomains.empty?
91
+
92
+ subdomains.all? do |subdomain|
93
+ !subdomain.start_or_end_with?('-') && subdomain.match?(/\A([a-zA-Z]|[0-9]|[-])+\z/)
94
+ end
95
+ end
96
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: real_world_email_validator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.5
5
+ platform: ruby
6
+ authors:
7
+ - bary822
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-05-22 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: '4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: Basically based on RFC 5322, with some additional validations so it works
42
+ on almost all variety of systems.
43
+ email: hiroto.fukui822@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - lib/real_world_email_validator.rb
49
+ homepage: https://github.com/bary822/real_world_email_validator
50
+ licenses:
51
+ - MIT
52
+ metadata: {}
53
+ post_install_message:
54
+ rdoc_options: []
55
+ require_paths:
56
+ - lib
57
+ required_ruby_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ requirements: []
68
+ rubygems_version: 3.0.3
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: Email address validator that real world needs, for ActiveModel 4+.
72
+ test_files: []