Skip to content

Commit 686e157

Browse files
committed
Initial Commit
0 parents  commit 686e157

37 files changed

+1674
-0
lines changed

.coveralls.yml

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
service_name: travis-ci

.gitignore

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
*.gem
2+
*.rbc
3+
.bundle
4+
.config
5+
.yardoc
6+
Gemfile.lock
7+
InstalledFiles
8+
_yardoc
9+
coverage
10+
doc/
11+
lib/bundler/man
12+
pkg
13+
rdoc
14+
spec/reports
15+
test/tmp
16+
test/version_tmp
17+
tmp

.rspec

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
--color
2+
--warnings
3+
--require spec_helper

.travis.yml

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
language: ruby
2+
cache: bundler
3+
4+
rvm:
5+
- 2.1.0
6+
- 2.0.0
7+
- 1.9.3
8+
9+
script: 'bundle exec rake'

Gemfile

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
source 'https://rubygems.org'
2+
gemspec

Guardfile

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
guard :bundler do
2+
watch('Gemfile')
3+
watch(/^.+\.gemspec/)
4+
end
5+
6+
guard :rspec, cmd: 'bundle exec rspec' do
7+
watch(%r{^spec/.+_spec\.rb$})
8+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
9+
watch('spec/spec_helper.rb') { "spec" }
10+
end
11+

LICENSE.txt

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Copyright (c) 2014 Patrick Perey
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.

README.md

+156
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
PossibleEmail
2+
=========
3+
A Ruby Gem to find someone's possible email address using their first name, last name, and domain.
4+
5+
More information in my [blog post](http://patrickperey.com/possible-email "blog post") at [PatrickPerey.com](http://patrickperey.com "Patrick Perey Blog")
6+
7+
Installation
8+
------------
9+
Install the gem:
10+
11+
```
12+
$ gem install possible_email
13+
```
14+
15+
Basic Usage
16+
-----
17+
18+
### Command Line Interface
19+
20+
21+
Enter target's first name, last name, and possible domain name into the terminal using `search`
22+
23+
```
24+
$ possible_email search first_name last_name domain
25+
```
26+
27+
Not sure about the domain name? Just add multiple domains at the end
28+
29+
```
30+
$ possible_email search first_name last_name gmail.com, yahoo.com, live.com
31+
```
32+
33+
34+
Just want to Confirm a single email address? Use `find_profile`
35+
36+
```
37+
$ possible_email find_profile [email protected]
38+
```
39+
Multiple email address? Same `find_profile`
40+
41+
```
42+
$ possible_email find_profile [email protected] [email protected]
43+
```
44+
### Ruby
45+
46+
```ruby
47+
require 'possible_email'
48+
49+
profiles = PossibleEmail.search('Kevin', 'Rose', 'gmail.com')
50+
profiles #=> "#<PossibleEmail::Response>"
51+
first_profile = profiles.first
52+
53+
first_profile.name #=> 'Kevin Rose'
54+
first_profile.email #=> '[email protected]'
55+
first_profile.location #=> 'San Francisco Bay Area'
56+
```
57+
Documentation
58+
-------------
59+
### PossibleEmail
60+
61+
Available methods:
62+
63+
**search(first_name, last_name, *domain)**
64+
65+
Accepts three arguments `first_name`, `last_name`, and `domain`. PossibleEmail will use these three arguments to generate possible email addresses based on common email address patterns. PossibleEmail would then attempt to verify and return an email profile for each email address.
66+
67+
```ruby
68+
# Single domain name
69+
PossibleEmail.search('bob', 'jones', 'gmail.com')
70+
71+
# Multiple domain names as Strings
72+
PossibleEmail.search('bob', 'jones', 'gmail.com', 'yahoo.com')
73+
74+
# Multiple domain names as an Array
75+
domains = ['gmail.com', 'yahoo.com', 'live.com']
76+
PossibleEmail.search('bob', 'jones', domains)
77+
```
78+
79+
**find_profile(*emails)**
80+
81+
Accepts a list of email address string arguments or an array. Instead of generating email addresses based on name arguments, PossibleEmail would attempt to verify and return an email profile for each email addresses passed into the method.
82+
83+
```ruby
84+
# Comma-splitted email arguments
85+
PossibleEmail.find_profile('[email protected]', '[email protected]')
86+
87+
# Array of emails
88+
PossibleEmail.find_profile(['[email protected]', '[email protected]'])
89+
```
90+
91+
Both methods return a `PossibleEmail::Response` object. `PossibleEmail::Response` includes the `Enumerable` module, so all the methods you need to iterate through the profiles are available. The only exception when neither the `search` or `find_profile` is when there is only one profile within the response. In this case, the method returns the single Profile.
92+
93+
### Profile
94+
95+
Class for the associated data connnected with a specific email address.
96+
97+
`Profile` attribute list:
98+
99+
* `email` - Returns the profile's email address
100+
* `name` - Full name
101+
* `first_name` - First name
102+
* `last_name` - Last name
103+
* `friendly_name` - First name or named used to address this person
104+
* `location` - Location
105+
* `headline` - Short blurb about person
106+
* `success` - Type of response returned back from Rapportive API
107+
* `occupations` - Array of Occupation objects
108+
* `memberships` - Array of social network Membership objects
109+
* `images` - Array of Image objects
110+
111+
### Occupation
112+
113+
Class for person's jobs.
114+
115+
`Occupation` attribute list:
116+
117+
* `job_title` - Job title
118+
* `company` - Company
119+
120+
### Membership
121+
122+
Class for Social Network Accounts
123+
124+
`Membership` attribute list:
125+
126+
* `profile_url` - URL to person's website membership
127+
* `profile_id` - Website profile ID
128+
* `username` - Username
129+
* `site_name` - Name of the website membership
130+
131+
### Image
132+
133+
Class for images associated with email profile.
134+
135+
`Image` attribute list:
136+
137+
* `url` - Image url
138+
* `service` - Where the image is located
139+
* `url_proxied` - Rapportive image proxied URL
140+
141+
Notes
142+
-----
143+
* With great power, comes great responsibly
144+
* Wrapper around the undocumented Rapportive API.
145+
* Valid results may be hidden due to API's limitations
146+
* Send Bitcoin `18fZ6muNmBrtENMZhnAjUw8eEsytmY8mZJ`
147+
148+
149+
Contributing
150+
------------
151+
152+
1. Fork it ( http://github.com/the4dpatrick/possible-email )
153+
2. Create your feature branch (`git checkout -b my-new-feature`)
154+
3. Commit your changes (`git commit -am 'Add some feature'`)
155+
4. Push to the branch (`git push origin my-new-feature`)
156+
5. Create new Pull Request

Rakefile

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env rake
2+
3+
require 'bundler/gem_tasks'
4+
require 'rspec/core/rake_task'
5+
6+
desc "Run all specs"
7+
RSpec::Core::RakeTask.new(:spec) do |t|
8+
t.rspec_opts = ['--color', '--format', 'nested']
9+
t.pattern = 'spec/**/*_spec.rb'
10+
t.verbose = false
11+
end
12+
13+
task :default => :spec

bin/possible_email

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env ruby
2+
3+
require 'possible_email'
4+
require 'possible_email/cli'
5+
6+
PossibleEmail::CLI.start(ARGV)

lib/possible_email.rb

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
require 'possible_email/error'
2+
require 'possible_email/version'
3+
require 'possible_email/permutator'
4+
require 'possible_email/rapportive_requester'
5+
6+
require 'httpi'
7+
require 'json'
8+
9+
HTTPI.log = false
10+
11+
EMAIL_REGEX = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
12+
DOMAIN_REGEX = /^[^@]([\w\-]+\.)+([\w]{2,})$/
13+
NAME_REGEX = /^\b[a-zA-Z]+\b$/
14+
15+
module PossibleEmail
16+
class InvalidNameFormat < ArgumentError; end
17+
class InvalidEmailFormat < ArgumentError; end
18+
19+
module_function
20+
21+
def search(first_name, last_name, *domain)
22+
assign_instance_variables first_name, last_name, domain
23+
24+
fail InvalidNameFormat, "Name arguments were not formatted correctly #{[@first_name, @last_name, *@domain].inspect}" unless valid_names?
25+
26+
permutations = Permutator.call(@first_name, @last_name, @domain)
27+
RapportiveRequester.request(permutations)
28+
end
29+
30+
def find_profile(*emails)
31+
@emails = emails.flatten
32+
33+
fail InvalidEmailFormat, "Email arguments were not formatted correctly #{@emails.inspect}" if invalid_emails?
34+
35+
RapportiveRequester.request(@emails)
36+
end
37+
38+
private_class_method
39+
40+
def assign_instance_variables(first_name, last_name, domain)
41+
@first_name = first_name
42+
@last_name = last_name
43+
@domain = domain.flatten
44+
end
45+
46+
def invalid_emails?
47+
@emails.any? { |email| email !~ EMAIL_REGEX }
48+
end
49+
50+
def valid_names?
51+
valid_domain = @domain.all? { |d| d =~ DOMAIN_REGEX }
52+
valid_names = [@first_name, @last_name].all? { |n| n =~ NAME_REGEX }
53+
54+
valid_domain && valid_names
55+
end
56+
end

lib/possible_email/cli.rb

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
require 'thor'
2+
3+
module PossibleEmail
4+
class CLI < Thor
5+
# possible_email search
6+
7+
desc 'search', 'Search for valid emails using first name, last name, and domain name'
8+
long_desc <<-LONGDESC
9+
Takes in a first name, last name, and domain name.
10+
11+
Domain name can be a single domain like 'gmail.com', or multiple domain names like 'gmail.com', 'yahoo.com'
12+
13+
Prints out all of the found email profiles for valid email addresses with associated information
14+
LONGDESC
15+
16+
def search(first_name, last_name, *domain)
17+
profiles = PossibleEmail.search(first_name, last_name, domain)
18+
puts profiles
19+
end
20+
21+
# possible_email find_profile
22+
23+
desc 'find_profile', 'return a profile for one or more email addresses'
24+
long_desc <<-LONGDESC
25+
Prints out all of the found email profiles for valid email addresses with associated information
26+
LONGDESC
27+
28+
def find_profile(*emails)
29+
profiles = PossibleEmail.find_profile(emails)
30+
puts profiles
31+
end
32+
end
33+
end

lib/possible_email/error.rb

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module PossibleEmail
2+
3+
end

lib/possible_email/patterns.rb

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
PATTERNS = <<PATTERNS
2+
{first_name}@{domain}
3+
{last_name}@{domain}
4+
{first_initial}@{domain}
5+
{last_initial}@{domain}
6+
{first_name}{last_name}@{domain}
7+
{first_name}.{last_name}@{domain}
8+
{first_initial}{last_name}@{domain}
9+
{first_initial}.{last_name}@{domain}
10+
{first_name}{last_initial}@{domain}
11+
{first_name}.{last_initial}@{domain}
12+
{first_initial}{last_initial}@{domain}
13+
{first_initial}.{last_initial}@{domain}
14+
{last_name}{first_name}@{domain}
15+
{last_name}.{first_name}@{domain}
16+
{last_name}{first_initial}@{domain}
17+
{last_name}.{first_initial}@{domain}
18+
{last_initial}{first_name}@{domain}
19+
{last_initial}.{first_name}@{domain}
20+
{last_initial}{first_initial}@{domain}
21+
{last_initial}.{first_initial}@{domain}
22+
{first_name}-{last_name}@{domain}
23+
{first_initial}-{last_name}@{domain}
24+
{first_name}-{last_initial}@{domain}
25+
{first_initial}-{last_initial}@{domain}
26+
{last_name}-{first_name}@{domain}
27+
{last_name}-{first_initial}@{domain}
28+
{last_initial}-{first_name}@{domain}
29+
{last_initial}-{first_initial}@{domain}
30+
{first_name}_{last_name}@{domain}
31+
{first_initial}_{last_name}@{domain}
32+
{first_name}_{last_initial}@{domain}
33+
{first_initial}_{last_initial}@{domain}
34+
{last_name}_{first_name}@{domain}
35+
{last_name}_{first_initial}@{domain}
36+
{last_initial}_{first_name}@{domain}
37+
{last_initial}_{first_initial}@{domain}
38+
PATTERNS

0 commit comments

Comments
 (0)