normailize 0.0.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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +104 -0
- data/Rakefile +1 -0
- data/lib/normailize.rb +11 -0
- data/lib/normailize/email_address.rb +99 -0
- data/lib/normailize/provider.rb +105 -0
- data/lib/normailize/provider/generic.rb +9 -0
- data/lib/normailize/provider/gmail.rb +16 -0
- data/lib/normailize/provider/hotmail.rb +15 -0
- data/lib/normailize/provider/live.rb +15 -0
- data/lib/normailize/version.rb +3 -0
- data/normailize.gemspec +24 -0
- data/spec/lib/normailize/email_address_spec.rb +116 -0
- data/spec/lib/normailize/provider/generic_spec.rb +49 -0
- data/spec/lib/normailize/provider/gmail_spec.rb +61 -0
- data/spec/lib/normailize/provider/hotmail_spec.rb +57 -0
- data/spec/lib/normailize/provider/live_spec.rb +57 -0
- data/spec/lib/normailize/provider_spec.rb +35 -0
- data/spec/spec_helper.rb +15 -0
- metadata +128 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2013 Michael Henriksen
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Normailize
|
|
2
|
+
|
|
3
|
+
Normailize is a gem to normalize email addresses from something like `Jo.Hn+sneaky@gmail.com` to `john@gmail.com`. This can be used in applications to prevent
|
|
4
|
+
spammers and other shady types from signing up multiple times with variations of the same email address by adding dots, mixing the case or adding a plus sign
|
|
5
|
+
followed by an arbitrary string.
|
|
6
|
+
|
|
7
|
+
Normailize currently supports normalizations for the following providers:
|
|
8
|
+
|
|
9
|
+
- gmail.com (including googlemail.com)
|
|
10
|
+
- live.com
|
|
11
|
+
- hotmail.com
|
|
12
|
+
|
|
13
|
+
If an email is given that is not from any of the known providers, it will not do any normalization and only make a simple comparison between two addresses.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
Add this line to your application's Gemfile:
|
|
18
|
+
|
|
19
|
+
gem 'normailize'
|
|
20
|
+
|
|
21
|
+
And then execute:
|
|
22
|
+
|
|
23
|
+
$ bundle
|
|
24
|
+
|
|
25
|
+
Or install it yourself as:
|
|
26
|
+
|
|
27
|
+
$ gem install normailize
|
|
28
|
+
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
### Comparing two email addresses
|
|
32
|
+
|
|
33
|
+
The core of the gem is the `Normailize::EmailAddress#same_as?` which can compare two email addresses and returns true if they normalize into the same address:
|
|
34
|
+
|
|
35
|
+
# Lets compare two Gmail addresses:
|
|
36
|
+
|
|
37
|
+
address1 = Normailize::EmailAddress.new('Jo.Hn+sneaky@gmail.com')
|
|
38
|
+
address2 = Normailize::EmailAddress.new('j.o.h.n+again@googlemail.com')
|
|
39
|
+
|
|
40
|
+
address1.same_as?(address2) # => True, they both normalize to john and gmail.com and googlemail.com are domains for the same provider
|
|
41
|
+
|
|
42
|
+
# Now we compare two live.com addresses:
|
|
43
|
+
|
|
44
|
+
address1 = Normailize::EmailAddress.new('john@live.com')
|
|
45
|
+
address2 = Normailize::EmailAddress.new('john+sneaky@live.com')
|
|
46
|
+
|
|
47
|
+
address1.same_as?(address2) # => True, they both normalize to john@live.com
|
|
48
|
+
|
|
49
|
+
# These are not the same addresses:
|
|
50
|
+
|
|
51
|
+
address1 = Normailize::EmailAddress.new('john@somewhere.com')
|
|
52
|
+
address2 = Normailize::EmailAddress.new('john@somewhereelse.com')
|
|
53
|
+
|
|
54
|
+
address1.same_as?(address2) # => False, they are not the same addresses
|
|
55
|
+
|
|
56
|
+
### Getting the normalized email address
|
|
57
|
+
|
|
58
|
+
If you want to get the normalized email address, you can call the `Normailize::EmailAddress#normalized_address` method:
|
|
59
|
+
|
|
60
|
+
address = Normailize::EmailAddress.new('J.oh.N+sNeaky@gmail.com')
|
|
61
|
+
address.normalized_address # => john@gmail.com
|
|
62
|
+
|
|
63
|
+
### Adding a new provider
|
|
64
|
+
|
|
65
|
+
If you want to normalize addresses from providers that are not already covered, it's fairly easy to add a new one:
|
|
66
|
+
|
|
67
|
+
#### Adding a new provider class
|
|
68
|
+
|
|
69
|
+
The following is a basic provider for somewhere.com:
|
|
70
|
+
|
|
71
|
+
module Normailize
|
|
72
|
+
module Provider
|
|
73
|
+
class Somewhere
|
|
74
|
+
include Normailize::Provider
|
|
75
|
+
|
|
76
|
+
# Specify one or more domains for somewhere.com
|
|
77
|
+
set_domains 'somewhere.com'
|
|
78
|
+
|
|
79
|
+
# Specify modificiations to be done on the username part of the email.
|
|
80
|
+
# The following modificiations are currently supported:
|
|
81
|
+
# - :lowercase Lowercases the username
|
|
82
|
+
# - :remove_dots Removes all dots
|
|
83
|
+
# - :remove_plus_part Removes everything after the first occurrence of a plus sign
|
|
84
|
+
set_modifications :lowercase, :remove_plus_part
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
Adapt the Somewhere provider to fit the new provider and save it in the `lib/normailize/providers` directory
|
|
90
|
+
|
|
91
|
+
#### Registering the new provider
|
|
92
|
+
|
|
93
|
+
Open `lib/normailize/provider.rb` and add a switch case in the `Normailize::Provider#factory` method
|
|
94
|
+
|
|
95
|
+
This is not perfect and will probably change in the future.
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
## Contributing
|
|
99
|
+
|
|
100
|
+
1. Fork it
|
|
101
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
102
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
103
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
104
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/normailize.rb
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
require "normailize/version"
|
|
2
|
+
require "normailize/email_address"
|
|
3
|
+
require "normailize/provider"
|
|
4
|
+
require "normailize/provider/generic"
|
|
5
|
+
require "normailize/provider/gmail"
|
|
6
|
+
require "normailize/provider/live"
|
|
7
|
+
require "normailize/provider/hotmail"
|
|
8
|
+
|
|
9
|
+
module Normailize
|
|
10
|
+
# Your code goes here...
|
|
11
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
module Normailize
|
|
2
|
+
|
|
3
|
+
# Public: Class to represent an email address.
|
|
4
|
+
#
|
|
5
|
+
# Normalizes email addresses according to the rules given by the provider.
|
|
6
|
+
#
|
|
7
|
+
# Examples
|
|
8
|
+
#
|
|
9
|
+
# # Compare two Gmail accounts
|
|
10
|
+
# address1 = Normailize::EmailAddress.new('Jo.Hn+sneaky@gmail.com')
|
|
11
|
+
# address2 = Normailize::EmailAddress.new('j.o.h.n@googlemail.com')
|
|
12
|
+
# address1.same_as?(address2) # => true
|
|
13
|
+
#
|
|
14
|
+
# # Get normalized email address
|
|
15
|
+
# address = Normailize::EmailAddress.new('Jo.Hn+sneaky@gmail.com')
|
|
16
|
+
# address.normalized_address # => john@gmail.com
|
|
17
|
+
class EmailAddress
|
|
18
|
+
attr_reader :address, :username, :domain
|
|
19
|
+
|
|
20
|
+
# Private: Simple regex to validate format of an email address
|
|
21
|
+
#
|
|
22
|
+
# We're deliberately ignoring a whole range of special and restricted chars
|
|
23
|
+
# for the sake of simplicity. This should match 99.99% of all the email
|
|
24
|
+
# addresses out there. If you allow comments (parentheses enclosed) in the
|
|
25
|
+
# local or domain part of your email addresses, make sure to strip them for
|
|
26
|
+
# normalization purposes. For '@' in the local part to be allowed, split
|
|
27
|
+
# local and domain part at the _last_ occurrence of the @-symbol.
|
|
28
|
+
EMAIL_ADDRESS_REGEX = /\A([a-z0-9_\-][a-z0-9_\-\+\.]{,62})?[a-z0-9_\-]@(([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\.)+[a-z]{2,}\z/i
|
|
29
|
+
|
|
30
|
+
# Public: Class initializer
|
|
31
|
+
#
|
|
32
|
+
# address - An email address
|
|
33
|
+
#
|
|
34
|
+
# Raises ArgumentError if email address does not have correct format
|
|
35
|
+
def initialize(address)
|
|
36
|
+
raise ArgumentError.new("Does not look like a valid email address") unless address =~ EMAIL_ADDRESS_REGEX
|
|
37
|
+
@address = address
|
|
38
|
+
@username, @domain = @address.split('@', 2)
|
|
39
|
+
normalize!
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Internal: Remove all dots from username parts
|
|
43
|
+
#
|
|
44
|
+
# Returns nothing
|
|
45
|
+
def remove_dots
|
|
46
|
+
@username.gsub!('.', '')
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Internal: Removes everything after the first occurrence of a plus sign in the username parts
|
|
50
|
+
#
|
|
51
|
+
# Returns nothing
|
|
52
|
+
def remove_plus_part
|
|
53
|
+
@username = @username.split('+', 2).first
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Internal: Lowercase characthers in username part
|
|
57
|
+
#
|
|
58
|
+
# Returns nothing
|
|
59
|
+
def lowercase
|
|
60
|
+
@username.downcase!
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Internal: Get provider instance for email address
|
|
64
|
+
#
|
|
65
|
+
# If provider is known, it returns a specific provider instance,
|
|
66
|
+
# otherwise a generic provider instance is returned
|
|
67
|
+
#
|
|
68
|
+
# Returns Normailize::Provider
|
|
69
|
+
def provider
|
|
70
|
+
Provider.factory(@domain)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Public: Get normalized email address
|
|
74
|
+
#
|
|
75
|
+
# Returns normalized address according to the rules specified by the provider.
|
|
76
|
+
def normalized_address
|
|
77
|
+
"#{@username}@#{@domain}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Public: Determine if two email addresses are the same
|
|
81
|
+
#
|
|
82
|
+
# Performs a comparison of the normalized username and provider
|
|
83
|
+
#
|
|
84
|
+
# Returns true if same or false if not
|
|
85
|
+
def same_as?(address)
|
|
86
|
+
(@username == address.username) && self.provider.same_as?(address.provider)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
# Internal: Normalize email address according to rules specified by the provider
|
|
92
|
+
#
|
|
93
|
+
# Returns nothing
|
|
94
|
+
def normalize!
|
|
95
|
+
@domain.downcase!
|
|
96
|
+
provider.modifications.each { |m| self.send(m) if self.respond_to?(m) }
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
module Normailize
|
|
2
|
+
|
|
3
|
+
# Public: Module to give email provider classes default functionality
|
|
4
|
+
module Provider
|
|
5
|
+
|
|
6
|
+
# Internal: Create a provider instance from a domain
|
|
7
|
+
#
|
|
8
|
+
# domain - A domain for an email provider, like gmail.com
|
|
9
|
+
#
|
|
10
|
+
# Returns an instance of a provider that recognizes the domain or a
|
|
11
|
+
# generic provider
|
|
12
|
+
def self.factory(domain)
|
|
13
|
+
case domain
|
|
14
|
+
when *Gmail.domains then Gmail.new(domain)
|
|
15
|
+
when *Live.domains then Live.new(domain)
|
|
16
|
+
when *Hotmail.domains then Hotmail.new(domain)
|
|
17
|
+
else Generic.new(domain)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.included(base)
|
|
22
|
+
class << base; attr_accessor :domains, :modifications end
|
|
23
|
+
base.extend(ClassMethods)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
module ClassMethods
|
|
27
|
+
|
|
28
|
+
# Public: Set on or more domains for a provider
|
|
29
|
+
#
|
|
30
|
+
# *domains - one or more domains
|
|
31
|
+
#
|
|
32
|
+
# Returns nothing
|
|
33
|
+
def set_domains(*domains)
|
|
34
|
+
@domains = domains
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Public: Set one or more modifications to be performed on email address
|
|
38
|
+
# belonging to the provider
|
|
39
|
+
#
|
|
40
|
+
# *modifications - One or more modification symbols
|
|
41
|
+
#
|
|
42
|
+
# Currently, the following modifications are supported:
|
|
43
|
+
#
|
|
44
|
+
# - :lowercase Lowercase characthers in username part
|
|
45
|
+
# - :remove_dots Removes all dots in username part
|
|
46
|
+
# - :remove_plus_part Removes everything after the first occurrence of a plus sign
|
|
47
|
+
#
|
|
48
|
+
# Returns nothing
|
|
49
|
+
def set_modifications(*modifications)
|
|
50
|
+
self.modifications = modifications.map(&:to_sym)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Internal: Get domains that are associated with the provider
|
|
54
|
+
#
|
|
55
|
+
# Returns an array of domains
|
|
56
|
+
def domains
|
|
57
|
+
@domains || []
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Public: Class initializer
|
|
62
|
+
#
|
|
63
|
+
# domain - A domain like gmail.com
|
|
64
|
+
#
|
|
65
|
+
# Returns nothing
|
|
66
|
+
def initialize(domain)
|
|
67
|
+
@domain = domain
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Internal: Get all modification rules for the provider
|
|
71
|
+
#
|
|
72
|
+
# Returns symbols that tell the email class how to normalize an address
|
|
73
|
+
# for the provider
|
|
74
|
+
def modifications
|
|
75
|
+
self.class.modifications || []
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Internal: Get the domain that the provider was instantiated with
|
|
79
|
+
#
|
|
80
|
+
# Returns domain
|
|
81
|
+
def domain
|
|
82
|
+
@domain
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Internal: Determine if a provider is generic or not
|
|
86
|
+
#
|
|
87
|
+
# Returns true if generic or false if not
|
|
88
|
+
def generic?
|
|
89
|
+
self.is_a?(Normailize::Provider::Generic)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Internal: Determine if two providers are the same or not
|
|
93
|
+
#
|
|
94
|
+
# provider - An instance of another provider class
|
|
95
|
+
#
|
|
96
|
+
# Returns true if providers are the same or false if not
|
|
97
|
+
def same_as?(provider)
|
|
98
|
+
if self.generic? || provider.generic?
|
|
99
|
+
@domain == provider.domain
|
|
100
|
+
else
|
|
101
|
+
self.class == provider.class
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Normailize
|
|
2
|
+
module Provider
|
|
3
|
+
|
|
4
|
+
# Internal: A provider to represent Gmail and Googlemail
|
|
5
|
+
class Gmail
|
|
6
|
+
include Normailize::Provider
|
|
7
|
+
|
|
8
|
+
# Gmail addresses work on both gmail.com and googlemail.com
|
|
9
|
+
set_domains 'gmail.com', 'googlemail.com'
|
|
10
|
+
|
|
11
|
+
# A normalized Gmail address is lowercased, dots and everything after a
|
|
12
|
+
# plus sign is removed from the username part
|
|
13
|
+
set_modifications :lowercase, :remove_dots, :remove_plus_part
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Normailize
|
|
2
|
+
module Provider
|
|
3
|
+
|
|
4
|
+
# Internal: A provider to represent Hotmail
|
|
5
|
+
class Hotmail
|
|
6
|
+
include Normailize::Provider
|
|
7
|
+
|
|
8
|
+
# A hotmail account only works on the hotmail.com domain
|
|
9
|
+
set_domains 'hotmail.com'
|
|
10
|
+
|
|
11
|
+
# A normalized hotmail address is lowercased and everything after a plus sign is removed
|
|
12
|
+
set_modifications :lowercase, :remove_plus_part
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module Normailize
|
|
2
|
+
module Provider
|
|
3
|
+
|
|
4
|
+
# Internal: A provider to represent Live
|
|
5
|
+
class Live
|
|
6
|
+
include Normailize::Provider
|
|
7
|
+
|
|
8
|
+
# A Live account only works on the live.com domain
|
|
9
|
+
set_domains 'live.com'
|
|
10
|
+
|
|
11
|
+
# A mormalized Live address is lowercased and everything after a plus sign is removed
|
|
12
|
+
set_modifications :lowercase, :remove_plus_part
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
data/normailize.gemspec
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'normailize/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "normailize"
|
|
8
|
+
spec.version = Normailize::VERSION
|
|
9
|
+
spec.authors = ["Michael Henriksen"]
|
|
10
|
+
spec.email = ["michenriksen87@gmail.com"]
|
|
11
|
+
spec.description = %q{Normalize emails like J.oh.n+sneaky@gmail.com into john@gmail.com}
|
|
12
|
+
spec.summary = %q{Normalize emails like J.oh.n+sneaky@gmail.com into john@gmail.com}
|
|
13
|
+
spec.homepage = "https://github.com/soundcloud/normailize"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files`.split($/)
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
+
spec.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
|
22
|
+
spec.add_development_dependency "rake"
|
|
23
|
+
spec.add_development_dependency "rspec"
|
|
24
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Normailize::EmailAddress do
|
|
4
|
+
let(:address) { Normailize::EmailAddress.new('sneaky.dude+lol@gmail.com') }
|
|
5
|
+
|
|
6
|
+
describe '#initialize' do
|
|
7
|
+
it 'accepts an email address as argument' do
|
|
8
|
+
expect do
|
|
9
|
+
Normailize::EmailAddress.new('john@doe.com')
|
|
10
|
+
end.to_not raise_error
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
context 'when email address is not valid' do
|
|
14
|
+
it 'raises an exception' do
|
|
15
|
+
expect do
|
|
16
|
+
Normailize::EmailAddress.new('not an @email address. sorry!')
|
|
17
|
+
end.to raise_error(ArgumentError)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context 'when email address is technically valid, but we do not accept it' do
|
|
22
|
+
it 'raises an exception' do
|
|
23
|
+
expect do
|
|
24
|
+
Normailize::EmailAddress.new('" fairly.@.unusual.example.com"(&a_comment_making_it_extralong!)@[IPv6:2001:db8:23:::42]')
|
|
25
|
+
end.to raise_error(ArgumentError)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe '#normalized_address' do
|
|
31
|
+
it 'returns expected normalized address' do
|
|
32
|
+
emails = {
|
|
33
|
+
'rahenadibirfx+seicascoumsip@gmail.com' => 'rahenadibirfx@gmail.com',
|
|
34
|
+
'ScrapeBoxAutoa.pp.r.ovelist+427727@googlemail.com' => 'scrapeboxautoapprovelist@googlemail.com',
|
|
35
|
+
'scrapeboxautoa.pp.r..ovelist+427727@gmail.com' => 'scrapeboxautoapprovelist@gmail.com',
|
|
36
|
+
'o.b.r.a.c.h.t.p.r.d.z.y.n.s.k.i+22@gmail.com' => 'obrachtprdzynski@gmail.com',
|
|
37
|
+
'z+o.e+j+ayl.e+em+a+r.t+i.n+d3u76n@gmail.com' => 'z@gmail.com',
|
|
38
|
+
'sneakydude+lol@live.com' => 'sneakydude@live.com'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
emails.each_pair do |sneaky, expected_normalization|
|
|
42
|
+
Normailize::EmailAddress.new(sneaky).normalized_address.should == expected_normalization
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe '#provider' do
|
|
48
|
+
context 'when address is a @gmail.com' do
|
|
49
|
+
it 'returns instance of Gmail provider' do
|
|
50
|
+
Normailize::EmailAddress.new('john@gmail.com').provider.should be_a(Normailize::Provider::Gmail)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
context 'when address is a @googlemail.com' do
|
|
55
|
+
it 'returns instance of Gmail provider' do
|
|
56
|
+
Normailize::EmailAddress.new('john@googlemail.com').provider.should be_a(Normailize::Provider::Gmail)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context 'when address is a @live.com' do
|
|
61
|
+
it 'returns instance of Live provider' do
|
|
62
|
+
Normailize::EmailAddress.new('john@live.com').provider.should be_a(Normailize::Provider::Live)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
context 'when address is a @hotmail.com' do
|
|
67
|
+
it 'returns instance of Hotmail provider' do
|
|
68
|
+
Normailize::EmailAddress.new('john@hotmail.com').provider.should be_a(Normailize::Provider::Hotmail)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
context 'when address is an unknown provider' do
|
|
73
|
+
it 'returns instance of Generic provider' do
|
|
74
|
+
Normailize::EmailAddress.new('john@somewhere.com').provider.should be_a(Normailize::Provider::Generic)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
describe '#same_as?' do
|
|
80
|
+
context 'when emails are the same' do
|
|
81
|
+
it 'returns true' do
|
|
82
|
+
emails = {
|
|
83
|
+
'john@gmail.com' => 'john@gmail.com',
|
|
84
|
+
'john+lol@gmail.com' => 'john+wtf@gmail.com',
|
|
85
|
+
'JoHn@gmail.com' => 'jOhN@gmail.com',
|
|
86
|
+
'jo.hn@gmail.com' => 'j.oh.n@gmail.com',
|
|
87
|
+
'Jo.h.n+lol+wtf@gmail.com' => 'jO.h.n+lol@googlemail.com',
|
|
88
|
+
'john@live.com' => 'john@live.com',
|
|
89
|
+
'JoHn@live.com' => 'jOhN@live.com',
|
|
90
|
+
'john+lol@live.com' => 'john+wtf@live.com',
|
|
91
|
+
'John+lol+wtf@live.com' => 'jOhn+lol@live.com',
|
|
92
|
+
'john@hotmail.com' => 'john@hotmail.com'
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
emails.each_pair do |e1, e2|
|
|
96
|
+
Normailize::EmailAddress.new(e1).same_as?(Normailize::EmailAddress.new(e2)).should be_true
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
context 'when emails are not the same' do
|
|
102
|
+
it 'returns false' do
|
|
103
|
+
emails = {
|
|
104
|
+
'john@gmail.com' => 'john@live.com',
|
|
105
|
+
'johnny@gmail.com' => 'john@gmail.com',
|
|
106
|
+
'john@googlemail.com' => 'john@hotmail.com',
|
|
107
|
+
'john+lol@gmail.com' => 'john+lol@live.com',
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
emails.each_pair do |e1, e2|
|
|
111
|
+
Normailize::EmailAddress.new(e1).same_as?(Normailize::EmailAddress.new(e2)).should be_false
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Normailize::Provider::Generic do
|
|
4
|
+
subject { Normailize::Provider::Generic.new('somewhere.com') }
|
|
5
|
+
|
|
6
|
+
it 'includes the Provider module' do
|
|
7
|
+
subject.should be_a(Normailize::Provider)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'is a generic provider' do
|
|
11
|
+
subject.should be_generic
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe '.domains' do
|
|
15
|
+
subject { Normailize::Provider::Generic.domains }
|
|
16
|
+
|
|
17
|
+
it 'does not include any domains' do
|
|
18
|
+
subject.should be_nil
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe '#modifications' do
|
|
23
|
+
subject { Normailize::Provider::Generic.new('somewhere.com').modifications }
|
|
24
|
+
|
|
25
|
+
it 'does not contain any modifications' do
|
|
26
|
+
subject.should be_empty
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe '#same_as?' do
|
|
31
|
+
context 'when comparing a provider of the same type' do
|
|
32
|
+
it 'returns true' do
|
|
33
|
+
subject.same_as?(Normailize::Provider::Generic.new('somewhere.com')).should be_true
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
context 'when comparing a generic provider with a different domain' do
|
|
38
|
+
it 'returns false' do
|
|
39
|
+
subject.same_as?(Normailize::Provider::Generic.new('somewhereelse.com')).should be_false
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context 'when comparing a Gmail provider' do
|
|
44
|
+
it 'returns false' do
|
|
45
|
+
subject.same_as?(Normailize::Provider::Gmail.new('gmail.com')).should be_false
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Normailize::Provider::Gmail do
|
|
4
|
+
subject { Normailize::Provider::Gmail.new('gmail.com') }
|
|
5
|
+
|
|
6
|
+
it 'includes the Provider module' do
|
|
7
|
+
subject.should be_a(Normailize::Provider)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'is not a generic provider' do
|
|
11
|
+
subject.should_not be_generic
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe '.domains' do
|
|
15
|
+
subject { Normailize::Provider::Gmail.domains }
|
|
16
|
+
|
|
17
|
+
it 'includes gmail.com' do
|
|
18
|
+
subject.should include('gmail.com')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'includes googlemail.com' do
|
|
22
|
+
subject.should include('googlemail.com')
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe '#modifications' do
|
|
27
|
+
subject { Normailize::Provider::Gmail.new('gmail.com').modifications }
|
|
28
|
+
|
|
29
|
+
it 'lowercases emails' do
|
|
30
|
+
subject.should include(:lowercase)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'removes dots' do
|
|
34
|
+
subject.should include(:remove_dots)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'removes plus parts' do
|
|
38
|
+
subject.should include(:remove_plus_part)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe '#same_as?' do
|
|
43
|
+
context 'when comparing a provider of the same type' do
|
|
44
|
+
it 'returns true' do
|
|
45
|
+
subject.same_as?(Normailize::Provider::Gmail.new('gmail.com')).should be_true
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context 'when comparing a generic provider' do
|
|
50
|
+
it 'returns false' do
|
|
51
|
+
subject.same_as?(Normailize::Provider::Generic.new('somewhere.com')).should be_false
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context 'when comparing a Hotmail provider' do
|
|
56
|
+
it 'returns false' do
|
|
57
|
+
subject.same_as?(Normailize::Provider::Hotmail.new('hotmail.com')).should be_false
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Normailize::Provider::Hotmail do
|
|
4
|
+
subject { Normailize::Provider::Hotmail.new('hotmail.com') }
|
|
5
|
+
|
|
6
|
+
it 'includes the Provider module' do
|
|
7
|
+
subject.should be_a(Normailize::Provider)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'is not a generic provider' do
|
|
11
|
+
subject.should_not be_generic
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe '.domains' do
|
|
15
|
+
subject { Normailize::Provider::Hotmail.domains }
|
|
16
|
+
|
|
17
|
+
it 'includes hotmail.com' do
|
|
18
|
+
subject.should include('hotmail.com')
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe '#modifications' do
|
|
23
|
+
subject { Normailize::Provider::Hotmail.new('hotmail.com').modifications }
|
|
24
|
+
|
|
25
|
+
it 'lowercases emails' do
|
|
26
|
+
subject.should include(:lowercase)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'does not remove dots' do
|
|
30
|
+
subject.should_not include(:remove_dots)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'removes plus parts' do
|
|
34
|
+
subject.should include(:remove_plus_part)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe '#same_as?' do
|
|
39
|
+
context 'when comparing a provider of the same type' do
|
|
40
|
+
it 'returns true' do
|
|
41
|
+
subject.same_as?(Normailize::Provider::Hotmail.new('hotmail.com')).should be_true
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
context 'when comparing a generic provider' do
|
|
46
|
+
it 'returns false' do
|
|
47
|
+
subject.same_as?(Normailize::Provider::Generic.new('somewhere.com')).should be_false
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context 'when comparing a Gmail provider' do
|
|
52
|
+
it 'returns false' do
|
|
53
|
+
subject.same_as?(Normailize::Provider::Gmail.new('gmail.com')).should be_false
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Normailize::Provider::Live do
|
|
4
|
+
subject { Normailize::Provider::Live.new('live.com') }
|
|
5
|
+
|
|
6
|
+
it 'includes the Provider module' do
|
|
7
|
+
subject.should be_a(Normailize::Provider)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'is not a generic provider' do
|
|
11
|
+
subject.should_not be_generic
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe '.domains' do
|
|
15
|
+
subject { Normailize::Provider::Live.domains }
|
|
16
|
+
|
|
17
|
+
it 'includes live.com' do
|
|
18
|
+
subject.should include('live.com')
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe '#modifications' do
|
|
23
|
+
subject { Normailize::Provider::Live.new('live.com').modifications }
|
|
24
|
+
|
|
25
|
+
it 'lowercases emails' do
|
|
26
|
+
subject.should include(:lowercase)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'does not remove dots' do
|
|
30
|
+
subject.should_not include(:remove_dots)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'removes plus parts' do
|
|
34
|
+
subject.should include(:remove_plus_part)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe '#same_as?' do
|
|
39
|
+
context 'when comparing a provider of the same type' do
|
|
40
|
+
it 'returns true' do
|
|
41
|
+
subject.same_as?(Normailize::Provider::Live.new('live.com')).should be_true
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
context 'when comparing a generic provider' do
|
|
46
|
+
it 'returns false' do
|
|
47
|
+
subject.same_as?(Normailize::Provider::Generic.new('somewhere.com')).should be_false
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context 'when comparing a Hotmail provider' do
|
|
52
|
+
it 'returns false' do
|
|
53
|
+
subject.same_as?(Normailize::Provider::Hotmail.new('hotmail.com')).should be_false
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Normailize::Provider do
|
|
4
|
+
describe '.factory' do
|
|
5
|
+
context 'when given gmail.com as domain' do
|
|
6
|
+
it 'returns the Gmail provider' do
|
|
7
|
+
Normailize::Provider.factory('gmail.com').should be_a(Normailize::Provider::Gmail)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
context 'when given googlemail.com as domain' do
|
|
12
|
+
it 'returns the Gmail provider' do
|
|
13
|
+
Normailize::Provider.factory('googlemail.com').should be_a(Normailize::Provider::Gmail)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
context 'when given live.com as domain' do
|
|
18
|
+
it 'returns the Live provider' do
|
|
19
|
+
Normailize::Provider.factory('live.com').should be_a(Normailize::Provider::Live)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
context 'when given hotmail.com as domain' do
|
|
24
|
+
it 'returns the Hotmail provider' do
|
|
25
|
+
Normailize::Provider.factory('hotmail.com').should be_a(Normailize::Provider::Hotmail)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context 'when given an unknown domain' do
|
|
30
|
+
it 'returns instance of Generic provider' do
|
|
31
|
+
Normailize::Provider.factory('somewhere.com').should be_a(Normailize::Provider::Generic)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'bundler'
|
|
2
|
+
begin
|
|
3
|
+
Bundler.setup(:default, :development)
|
|
4
|
+
rescue Bundler::BundlerError => e
|
|
5
|
+
$stderr.puts e.message
|
|
6
|
+
$stderr.puts 'Run `bundle install` to install missing gems'
|
|
7
|
+
exit e.status_code
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
require 'normailize'
|
|
11
|
+
|
|
12
|
+
RSpec.configure do |config|
|
|
13
|
+
config.filter_run :focus => true
|
|
14
|
+
config.run_all_when_everything_filtered = true
|
|
15
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: normailize
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Michael Henriksen
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-03-12 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: bundler
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ~>
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '1.3'
|
|
22
|
+
type: :development
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ~>
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '1.3'
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: rake
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
none: false
|
|
34
|
+
requirements:
|
|
35
|
+
- - ! '>='
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: '0'
|
|
38
|
+
type: :development
|
|
39
|
+
prerelease: false
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ! '>='
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '0'
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: rspec
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
none: false
|
|
50
|
+
requirements:
|
|
51
|
+
- - ! '>='
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
type: :development
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
none: false
|
|
58
|
+
requirements:
|
|
59
|
+
- - ! '>='
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
description: Normalize emails like J.oh.n+sneaky@gmail.com into john@gmail.com
|
|
63
|
+
email:
|
|
64
|
+
- michenriksen87@gmail.com
|
|
65
|
+
executables: []
|
|
66
|
+
extensions: []
|
|
67
|
+
extra_rdoc_files: []
|
|
68
|
+
files:
|
|
69
|
+
- .gitignore
|
|
70
|
+
- Gemfile
|
|
71
|
+
- LICENSE.txt
|
|
72
|
+
- README.md
|
|
73
|
+
- Rakefile
|
|
74
|
+
- lib/normailize.rb
|
|
75
|
+
- lib/normailize/email_address.rb
|
|
76
|
+
- lib/normailize/provider.rb
|
|
77
|
+
- lib/normailize/provider/generic.rb
|
|
78
|
+
- lib/normailize/provider/gmail.rb
|
|
79
|
+
- lib/normailize/provider/hotmail.rb
|
|
80
|
+
- lib/normailize/provider/live.rb
|
|
81
|
+
- lib/normailize/version.rb
|
|
82
|
+
- normailize.gemspec
|
|
83
|
+
- spec/lib/normailize/email_address_spec.rb
|
|
84
|
+
- spec/lib/normailize/provider/generic_spec.rb
|
|
85
|
+
- spec/lib/normailize/provider/gmail_spec.rb
|
|
86
|
+
- spec/lib/normailize/provider/hotmail_spec.rb
|
|
87
|
+
- spec/lib/normailize/provider/live_spec.rb
|
|
88
|
+
- spec/lib/normailize/provider_spec.rb
|
|
89
|
+
- spec/spec_helper.rb
|
|
90
|
+
homepage: https://github.com/soundcloud/normailize
|
|
91
|
+
licenses:
|
|
92
|
+
- MIT
|
|
93
|
+
post_install_message:
|
|
94
|
+
rdoc_options: []
|
|
95
|
+
require_paths:
|
|
96
|
+
- lib
|
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
|
+
none: false
|
|
99
|
+
requirements:
|
|
100
|
+
- - ! '>='
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '0'
|
|
103
|
+
segments:
|
|
104
|
+
- 0
|
|
105
|
+
hash: -3381404140353405978
|
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
|
+
none: false
|
|
108
|
+
requirements:
|
|
109
|
+
- - ! '>='
|
|
110
|
+
- !ruby/object:Gem::Version
|
|
111
|
+
version: '0'
|
|
112
|
+
segments:
|
|
113
|
+
- 0
|
|
114
|
+
hash: -3381404140353405978
|
|
115
|
+
requirements: []
|
|
116
|
+
rubyforge_project:
|
|
117
|
+
rubygems_version: 1.8.25
|
|
118
|
+
signing_key:
|
|
119
|
+
specification_version: 3
|
|
120
|
+
summary: Normalize emails like J.oh.n+sneaky@gmail.com into john@gmail.com
|
|
121
|
+
test_files:
|
|
122
|
+
- spec/lib/normailize/email_address_spec.rb
|
|
123
|
+
- spec/lib/normailize/provider/generic_spec.rb
|
|
124
|
+
- spec/lib/normailize/provider/gmail_spec.rb
|
|
125
|
+
- spec/lib/normailize/provider/hotmail_spec.rb
|
|
126
|
+
- spec/lib/normailize/provider/live_spec.rb
|
|
127
|
+
- spec/lib/normailize/provider_spec.rb
|
|
128
|
+
- spec/spec_helper.rb
|