ampersat 0.0.1 → 1.0.0
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 +7 -0
- data/.travis.yml +5 -0
- data/Gemfile +1 -1
- data/README.md +28 -13
- data/Rakefile +2 -0
- data/ampersat.gemspec +16 -11
- data/bin/ampersat +12 -0
- data/lib/ampersat.rb +40 -8
- data/lib/ampersat/cli.rb +30 -0
- data/lib/ampersat/version.rb +1 -1
- data/spec/ampersat_spec.rb +33 -14
- data/spec/support/multiple-columns.csv +6 -0
- data/spec/support/test.csv +4 -2
- metadata +102 -20
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6232057d580f3bbeb66de8d6149fbd19f1d70c67
|
4
|
+
data.tar.gz: 2d3ab791c9798b8b7326f0c20f44bf19c949b052
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 93eddae22b005d6f6b6b56b271cec43d81071f68fdc62d4ad886c65c69b79e4c107cfc290d43e830c8bd2b0ab77955e3c9a5a8c7d70e77e33b7bf03eccdb3574
|
7
|
+
data.tar.gz: 8c74fd344c52e67a5523d17dd0a35762ca421b107e74946c2bef50d7eb55cb5fe898c67b1785c34de1458ce232171dc4f8142207673010ff59578d718ec97331
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Calculate Most Common Domains From Email List
|
2
2
|
|
3
|
+
[](http://travis-ci.org/garethrees/ampersat) [](https://codeclimate.com/github/garethrees/ampersat)
|
4
|
+
|
3
5
|
It's worth checking what email clients your subscribers are using so that you can make sure your emails look good when they view them.
|
4
6
|
|
5
7
|
This gem looks at your subscribers CSV and lists the domains in order of popularity*.
|
@@ -10,24 +12,37 @@ This gem looks at your subscribers CSV and lists the domains in order of popular
|
|
10
12
|
|
11
13
|
### Install
|
12
14
|
|
13
|
-
|
15
|
+
`gem install ampersat`
|
16
|
+
|
17
|
+
### As CLI
|
18
|
+
|
19
|
+
```shell
|
20
|
+
$ ampersat domains --file=~/test.csv
|
21
|
+
example.com: 2
|
22
|
+
example.org: 1
|
23
|
+
example.net: 1
|
24
|
+
```
|
14
25
|
|
15
26
|
### In irb
|
16
27
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
28
|
+
```ruby
|
29
|
+
$ irb
|
30
|
+
> require 'ampersat'
|
31
|
+
=> true
|
32
|
+
> Ampersat.domains('/path/to/csv')
|
33
|
+
=> [['example.com', 2], ['example.org', 1], ['example.net', 1]]
|
34
|
+
```
|
22
35
|
|
23
36
|
### In Your App
|
24
37
|
|
25
|
-
|
38
|
+
```ruby
|
39
|
+
domains = Ampersat.domains('/Users/gareth/test.csv')
|
26
40
|
|
27
|
-
|
28
|
-
|
29
|
-
|
41
|
+
domains.each do |domain, count|
|
42
|
+
puts "#{domain}: #{count}"
|
43
|
+
end
|
30
44
|
|
31
|
-
|
32
|
-
|
33
|
-
|
45
|
+
# example.com: 2
|
46
|
+
# example.org: 1
|
47
|
+
# example.net: 1
|
48
|
+
```
|
data/Rakefile
CHANGED
data/ampersat.gemspec
CHANGED
@@ -1,24 +1,29 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'ampersat/version'
|
4
5
|
|
5
6
|
Gem::Specification.new do |s|
|
6
|
-
s.name =
|
7
|
+
s.name = 'ampersat'
|
7
8
|
s.version = Ampersat::VERSION
|
8
|
-
s.authors = [
|
9
|
-
s.email = [
|
10
|
-
s.homepage =
|
11
|
-
s.summary =
|
12
|
-
s.description =
|
9
|
+
s.authors = ['Gareth Rees', 'Robert Coleman']
|
10
|
+
s.email = ['gareth.h.rees@gmail.com', 'github@robert.net.nz']
|
11
|
+
s.homepage = 'http://github.com/garethrees/ampersat'
|
12
|
+
s.summary = 'Calculates which email domains your subscribers use'
|
13
|
+
s.description = 'Calculates which email domains your subscribers use'
|
13
14
|
|
14
15
|
s.rubyforge_project = "ampersat"
|
15
16
|
|
16
17
|
s.files = `git ls-files`.split("\n")
|
17
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
-
s.require_paths = [
|
20
|
+
s.require_paths = ['lib']
|
20
21
|
|
21
22
|
s.add_development_dependency 'rake'
|
22
|
-
s.add_development_dependency
|
23
|
-
|
23
|
+
s.add_development_dependency 'rspec', '~> 2.7'
|
24
|
+
s.add_dependency 'thor', '~> 0.19.1'
|
25
|
+
s.add_dependency 'public_suffix', '~> 1.4.4'
|
26
|
+
s.add_dependency 'ruby-progressbar', '~> 1.5.1'
|
27
|
+
s.add_dependency 'celluloid', '0.15.2'
|
28
|
+
s.add_dependency 'celluloid-pmap', '~> 0.1.0'
|
24
29
|
end
|
data/bin/ampersat
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'pathname'
|
3
|
+
bin_file = Pathname.new(__FILE__).realpath
|
4
|
+
$:.unshift File.expand_path('../../lib', bin_file)
|
5
|
+
|
6
|
+
Signal.trap('INT') do
|
7
|
+
puts "\nSIGINT recieved.. terminated."
|
8
|
+
exit 1
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'ampersat/cli'
|
12
|
+
Ampersat::CLI.start
|
data/lib/ampersat.rb
CHANGED
@@ -1,21 +1,53 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'csv'
|
2
|
+
require 'public_suffix'
|
3
|
+
require 'ruby-progressbar'
|
4
|
+
require 'resolv'
|
5
|
+
require 'celluloid/pmap'
|
3
6
|
|
4
7
|
module Ampersat
|
5
8
|
|
6
|
-
def self.domains(email_list)
|
9
|
+
def self.domains(email_list, column=0)
|
7
10
|
domains = Hash.new(0)
|
8
|
-
|
11
|
+
|
9
12
|
CSV.foreach(email_list) do |row|
|
10
|
-
domain = Ampersat.find_domain(row
|
11
|
-
domains[domain] = domains[domain] +1
|
13
|
+
domain = Ampersat.find_domain(row[column])
|
14
|
+
domains[domain] = domains[domain] + 1
|
15
|
+
end
|
16
|
+
|
17
|
+
domains.sort_by {|key, value| - value}
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.mxs(email_list, column=0)
|
21
|
+
mxs = {}
|
22
|
+
domains = Ampersat.domains(email_list, column)
|
23
|
+
progressbar = ProgressBar.create(format: '%t: %c / %C |%B|', starting_at: 0, total: domains.length)
|
24
|
+
domains.pmap(100) do |domain, qty|
|
25
|
+
mx = Ampersat.find_mx(domain)
|
26
|
+
mxs[mx] ||= {}
|
27
|
+
mxs[mx]['domains'] ||= []
|
28
|
+
mxs[mx]['domains'] << domain
|
29
|
+
mxs[mx]['addresses'] ||= 0
|
30
|
+
mxs[mx]['addresses'] = mxs[mx]['addresses'] + qty
|
31
|
+
progressbar.increment
|
12
32
|
end
|
13
33
|
|
14
|
-
|
34
|
+
mxs.sort_by {|key, value| - value['addresses'] }
|
15
35
|
end
|
16
36
|
|
17
37
|
def self.find_domain(email)
|
18
|
-
email.split('@').last
|
38
|
+
email.split('@').last.downcase
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.find_mx(domain)
|
42
|
+
@mxs ||= {}
|
43
|
+
@mxs[domain] ||= begin
|
44
|
+
Resolv::DNS.open(nameserver: '8.8.8.8') do |dns|
|
45
|
+
next unless PublicSuffix.valid?(domain)
|
46
|
+
response = dns.getresources(domain, Resolv::DNS::Resource::IN::MX)
|
47
|
+
next unless response.any?
|
48
|
+
response.collect { |r| r.exchange.to_s.downcase }.sort.first
|
49
|
+
end
|
50
|
+
end
|
19
51
|
end
|
20
52
|
|
21
53
|
end
|
data/lib/ampersat/cli.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'ampersat'
|
3
|
+
|
4
|
+
module Ampersat
|
5
|
+
class CLI < Thor
|
6
|
+
|
7
|
+
default_task :help
|
8
|
+
|
9
|
+
desc 'domains </path/to/file.csv>', 'Analyse a CSV, returning domain list'
|
10
|
+
method_option :column, type: :numeric, default: 0
|
11
|
+
method_option :file, required: true, type: :string
|
12
|
+
def domains
|
13
|
+
domains = Ampersat.domains(File.expand_path(options[:file]), options[:column])
|
14
|
+
domains.each do |domain, count|
|
15
|
+
puts "#{ domain }: #{ count }"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
desc 'mx </path/to/file.csv>', 'Analyse a CSV, returning MX list'
|
20
|
+
method_option :column, type: :numeric, default: 0
|
21
|
+
method_option :file, required: true, type: :string
|
22
|
+
def mx
|
23
|
+
mxs = Ampersat.mxs(File.expand_path(options[:file]), options[:column])
|
24
|
+
mxs.each do |mx, value|
|
25
|
+
puts "#{ mx } - #{ value['addresses'] }: #{ value['domains'].join(', ') }"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
data/lib/ampersat/version.rb
CHANGED
data/spec/ampersat_spec.rb
CHANGED
@@ -1,30 +1,49 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
path = File.expand_path(File.dirname(__FILE__) +
|
2
|
+
path = File.expand_path(File.dirname(__FILE__) + '/../lib/')
|
3
3
|
$LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)
|
4
|
-
require
|
5
|
-
|
4
|
+
require 'ampersat'
|
6
5
|
|
7
6
|
describe Ampersat do
|
8
7
|
|
9
|
-
let(:csv_path) { File.expand_path(File.dirname(__FILE__) +
|
10
|
-
let(:email) {
|
11
|
-
let(:multiple_emails) {
|
8
|
+
let(:csv_path) { File.expand_path(File.dirname(__FILE__) + '/support/test.csv') }
|
9
|
+
let(:email) { 'test@example.com' }
|
10
|
+
let(:multiple_emails) { 'jim@example.com, tom@example.com, bob@example.org, james@example.net' }
|
12
11
|
|
13
|
-
it
|
14
|
-
expected_result = [[
|
12
|
+
it 'should return the sum of each email provider' do
|
13
|
+
expected_result = [['example.com', 3], ['example.org', 2], ['example.net', 1]]
|
15
14
|
Ampersat.domains(csv_path).should == expected_result
|
16
15
|
end
|
17
16
|
|
18
|
-
it
|
19
|
-
incorrect_result = [[
|
17
|
+
it 'should return the email providers with the most common first' do
|
18
|
+
incorrect_result = [['example.org', 2],['example.com', 3], ['example.net', 1]]
|
20
19
|
Ampersat.domains(csv_path).should_not == incorrect_result
|
21
20
|
|
22
|
-
expected_result = [[
|
21
|
+
expected_result = [['example.com', 3], ['example.org', 2], ['example.net', 1]]
|
23
22
|
Ampersat.domains(csv_path).should == expected_result
|
24
23
|
end
|
25
24
|
|
26
|
-
it
|
27
|
-
Ampersat.find_domain(email).should ==
|
25
|
+
it 'should find the domain of an email address' do
|
26
|
+
Ampersat.find_domain(email).should == 'example.com'
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'column' do
|
30
|
+
let(:csv_path) { File.expand_path(File.dirname(__FILE__) + '/support/multiple-columns.csv') }
|
31
|
+
let(:email) { 'test@example.com' }
|
32
|
+
let(:multiple_emails) { 'jim@example.com, tom@example.com, bob@example.org, james@example.net' }
|
33
|
+
let(:column) { 1 }
|
34
|
+
|
35
|
+
it 'should return the sum of each email provider' do
|
36
|
+
expected_result = [['example.com', 3], ['example.org', 2], ['example.net', 1]]
|
37
|
+
Ampersat.domains(csv_path, column).should == expected_result
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should return the email providers with the most common first' do
|
41
|
+
incorrect_result = [['example.org', 2],['example.com', 3], ['example.net', 1]]
|
42
|
+
Ampersat.domains(csv_path, column).should_not == incorrect_result
|
43
|
+
|
44
|
+
expected_result = [['example.com', 3], ['example.org', 2], ['example.net', 1]]
|
45
|
+
Ampersat.domains(csv_path, column).should == expected_result
|
46
|
+
end
|
28
47
|
end
|
29
48
|
|
30
|
-
end
|
49
|
+
end
|
data/spec/support/test.csv
CHANGED
metadata
CHANGED
@@ -1,79 +1,161 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ampersat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Gareth Rees
|
8
|
+
- Robert Coleman
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2014-07-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
16
|
-
requirement:
|
17
|
-
none: false
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
18
17
|
requirements:
|
19
|
-
- -
|
18
|
+
- - ">="
|
20
19
|
- !ruby/object:Gem::Version
|
21
20
|
version: '0'
|
22
21
|
type: :development
|
23
22
|
prerelease: false
|
24
|
-
version_requirements:
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
25
28
|
- !ruby/object:Gem::Dependency
|
26
29
|
name: rspec
|
27
|
-
requirement:
|
28
|
-
none: false
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
29
31
|
requirements:
|
30
|
-
- - ~>
|
32
|
+
- - "~>"
|
31
33
|
- !ruby/object:Gem::Version
|
32
34
|
version: '2.7'
|
33
35
|
type: :development
|
34
36
|
prerelease: false
|
35
|
-
version_requirements:
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '2.7'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: thor
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - "~>"
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: 0.19.1
|
49
|
+
type: :runtime
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 0.19.1
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: public_suffix
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 1.4.4
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 1.4.4
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: ruby-progressbar
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - "~>"
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 1.5.1
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - "~>"
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 1.5.1
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: celluloid
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - '='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 0.15.2
|
91
|
+
type: :runtime
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - '='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 0.15.2
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: celluloid-pmap
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - "~>"
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: 0.1.0
|
105
|
+
type: :runtime
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - "~>"
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: 0.1.0
|
36
112
|
description: Calculates which email domains your subscribers use
|
37
113
|
email:
|
38
114
|
- gareth.h.rees@gmail.com
|
39
|
-
|
115
|
+
- github@robert.net.nz
|
116
|
+
executables:
|
117
|
+
- ampersat
|
40
118
|
extensions: []
|
41
119
|
extra_rdoc_files: []
|
42
120
|
files:
|
43
|
-
- .gitignore
|
44
|
-
- .rspec
|
121
|
+
- ".gitignore"
|
122
|
+
- ".rspec"
|
123
|
+
- ".travis.yml"
|
45
124
|
- Gemfile
|
46
125
|
- README.md
|
47
126
|
- Rakefile
|
48
127
|
- ampersat.gemspec
|
128
|
+
- bin/ampersat
|
49
129
|
- lib/ampersat.rb
|
130
|
+
- lib/ampersat/cli.rb
|
50
131
|
- lib/ampersat/version.rb
|
51
132
|
- spec/ampersat_spec.rb
|
133
|
+
- spec/support/multiple-columns.csv
|
52
134
|
- spec/support/test.csv
|
53
135
|
homepage: http://github.com/garethrees/ampersat
|
54
136
|
licenses: []
|
137
|
+
metadata: {}
|
55
138
|
post_install_message:
|
56
139
|
rdoc_options: []
|
57
140
|
require_paths:
|
58
141
|
- lib
|
59
142
|
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
-
none: false
|
61
143
|
requirements:
|
62
|
-
- -
|
144
|
+
- - ">="
|
63
145
|
- !ruby/object:Gem::Version
|
64
146
|
version: '0'
|
65
147
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
-
none: false
|
67
148
|
requirements:
|
68
|
-
- -
|
149
|
+
- - ">="
|
69
150
|
- !ruby/object:Gem::Version
|
70
151
|
version: '0'
|
71
152
|
requirements: []
|
72
153
|
rubyforge_project: ampersat
|
73
|
-
rubygems_version:
|
154
|
+
rubygems_version: 2.2.0
|
74
155
|
signing_key:
|
75
|
-
specification_version:
|
156
|
+
specification_version: 4
|
76
157
|
summary: Calculates which email domains your subscribers use
|
77
158
|
test_files:
|
78
159
|
- spec/ampersat_spec.rb
|
160
|
+
- spec/support/multiple-columns.csv
|
79
161
|
- spec/support/test.csv
|