sparkpost 0.1.2 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +13 -0
- data/.travis.yml +1 -0
- data/README.md +53 -3
- data/Rakefile +5 -4
- data/bin/console +3 -3
- data/examples/template/list.rb +8 -0
- data/examples/transmission/attachment.txt +1 -0
- data/examples/transmission/send.rb +12 -0
- data/examples/transmission/with_attachment.rb +29 -0
- data/examples/transmission/with_substitution.rb +14 -0
- data/examples/transmission/with_template.rb +18 -0
- data/lib/sparkpost.rb +2 -1
- data/lib/sparkpost/client.rb +20 -17
- data/lib/sparkpost/helpers.rb +23 -0
- data/lib/sparkpost/request.rb +45 -13
- data/lib/sparkpost/template.rb +112 -0
- data/lib/sparkpost/transmission.rb +47 -31
- data/lib/sparkpost/version.rb +1 -1
- data/sparkpost.gemspec +14 -13
- data/spec/lib/sparkpost/client_spec.rb +36 -17
- data/spec/lib/sparkpost/core_extensions/object_spec.rb +18 -19
- data/spec/lib/sparkpost/helpers_spec.rb +91 -0
- data/spec/lib/sparkpost/request_spec.rb +96 -22
- data/spec/lib/sparkpost/template_spec.rb +276 -0
- data/spec/lib/sparkpost/transmission_spec.rb +263 -38
- data/spec/lib/sparkpost/version_spec.rb +1 -1
- data/spec/spec_helper.rb +7 -59
- metadata +34 -8
- data/examples/transmission.rb +0 -8
@@ -1,6 +1,5 @@
|
|
1
1
|
require 'net/http'
|
2
2
|
require 'uri'
|
3
|
-
require 'http'
|
4
3
|
require_relative '../core_extensions/object'
|
5
4
|
require_relative 'request'
|
6
5
|
require_relative 'exceptions'
|
@@ -12,49 +11,66 @@ module SparkPost
|
|
12
11
|
def initialize(api_key, api_host)
|
13
12
|
@api_key = api_key
|
14
13
|
@api_host = api_host
|
14
|
+
@base_endpoint = "#{@api_host}/api/v1/transmissions"
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
|
17
|
+
def send_payload(data = {})
|
18
|
+
# TODO: consider refactoring this into send_message in v2
|
19
|
+
request(endpoint, @api_key, data)
|
19
20
|
end
|
20
21
|
|
21
22
|
def send_message(to, from, subject, html_message = nil, **options)
|
22
|
-
#
|
23
|
-
|
24
|
-
|
25
|
-
end
|
23
|
+
# TODO: add validations for to, from
|
24
|
+
html_message = content_from(options, :html) || html_message
|
25
|
+
text_message = content_from(options, :text) || options[:text_message]
|
26
26
|
|
27
|
-
if html_message.blank? &&
|
28
|
-
|
27
|
+
if html_message.blank? && text_message.blank?
|
28
|
+
raise ArgumentError, 'Content missing. Either provide html_message or
|
29
|
+
text_message in options parameter'
|
29
30
|
end
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
)
|
43
|
-
|
44
|
-
|
32
|
+
options_from_args = {
|
33
|
+
recipients: prepare_recipients(to),
|
34
|
+
content: {
|
35
|
+
from: from,
|
36
|
+
subject: subject,
|
37
|
+
text: options.delete(:text_message),
|
38
|
+
html: html_message
|
39
|
+
},
|
40
|
+
options: {}
|
41
|
+
}
|
42
|
+
|
43
|
+
options.merge!(options_from_args) { |_k, opts, _args| opts }
|
44
|
+
add_attachments(options)
|
45
|
+
|
46
|
+
send_payload(options)
|
45
47
|
end
|
46
48
|
|
47
|
-
private
|
48
49
|
def prepare_recipients(recipients)
|
49
|
-
recipients
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
50
|
+
recipients = [recipients] unless recipients.is_a?(Array)
|
51
|
+
recipients.map { |recipient| prepare_recipient(recipient) }
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def add_attachments(options)
|
57
|
+
if options[:attachments].present?
|
58
|
+
options[:content][:attachments] = options.delete(:attachments)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def prepare_recipient(recipient)
|
63
|
+
if recipient.is_a?(Hash)
|
64
|
+
raise ArgumentError,
|
65
|
+
"email missing - '#{recipient.inspect}'" unless recipient[:email]
|
66
|
+
{ address: recipient }
|
67
|
+
else
|
68
|
+
{ address: { email: recipient } }
|
55
69
|
end
|
56
70
|
end
|
57
71
|
|
72
|
+
def content_from(options, key)
|
73
|
+
(options || {}).fetch(:content, {}).fetch(key, nil)
|
74
|
+
end
|
58
75
|
end
|
59
76
|
end
|
60
|
-
|
data/lib/sparkpost/version.rb
CHANGED
data/sparkpost.gemspec
CHANGED
@@ -4,25 +4,26 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require './lib/sparkpost/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'sparkpost'
|
8
8
|
spec.version = SparkPost::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email =
|
11
|
-
spec.summary =
|
12
|
-
spec.homepage =
|
13
|
-
spec.license =
|
9
|
+
spec.authors = ['SparkPost', 'Aimee Knight', 'Mohammad Hossain']
|
10
|
+
spec.email = 'developers@sparkpost.com'
|
11
|
+
spec.summary = 'SparkPost Ruby API client'
|
12
|
+
spec.homepage = 'https://github.com/SparkPost/ruby-sparkpost'
|
13
|
+
spec.license = 'Apache-2.0'
|
14
14
|
|
15
15
|
spec.files = `git ls-files -z`.split("\x0")
|
16
16
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
-
spec.require_paths = [
|
18
|
+
spec.require_paths = ['lib']
|
19
19
|
|
20
20
|
spec.add_dependency 'http', '0.9.8'
|
21
21
|
|
22
|
-
spec.add_development_dependency
|
23
|
-
spec.add_development_dependency
|
24
|
-
spec.add_development_dependency
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.add_development_dependency
|
22
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
23
|
+
spec.add_development_dependency 'rake', '<11'
|
24
|
+
spec.add_development_dependency 'rspec', '~> 3.3.0'
|
25
|
+
spec.add_development_dependency 'simplecov', '~> 0.11.1'
|
26
|
+
spec.add_development_dependency 'webmock', '~> 1.22.3'
|
27
|
+
spec.add_development_dependency 'coveralls'
|
28
|
+
spec.add_development_dependency 'rubocop', '~> 0.37.2'
|
28
29
|
end
|
@@ -1,39 +1,58 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe SparkPost::Transmission do
|
4
|
-
describe '#initialize' do
|
4
|
+
describe '#initialize' do
|
5
5
|
context 'when api key and host are passed'
|
6
6
|
let(:client) { SparkPost::Client.new('123', 'http://sparkpost.com') }
|
7
7
|
|
8
8
|
it { expect(client.instance_variables).to include(:@api_key) }
|
9
9
|
it { expect(client.instance_variables).to include(:@api_host) }
|
10
10
|
it { expect(client.instance_variable_get(:@api_key)).to eq('123') }
|
11
|
-
it
|
11
|
+
it do
|
12
|
+
expect(client.instance_variable_get(:@api_host))
|
13
|
+
.to eq('http://sparkpost.com')
|
14
|
+
end
|
12
15
|
|
13
|
-
context 'when api key not passed' do
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
16
|
+
context 'when api key not passed' do
|
17
|
+
before do
|
18
|
+
ENV['SPARKPOST_API_KEY'] = nil
|
19
|
+
end
|
20
|
+
it { expect { SparkPost::Client.new }.to raise_error(ArgumentError) }
|
18
21
|
end
|
19
22
|
|
20
|
-
context 'when api host not passed' do
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
context 'when api host not passed' do
|
24
|
+
before do
|
25
|
+
ENV['SPARKPOST_API_HOST'] = nil
|
26
|
+
end
|
27
|
+
it do
|
28
|
+
client = SparkPost::Client.new('abc')
|
29
|
+
expect(client.instance_variable_get(:@api_host))
|
30
|
+
.to eq('https://api.sparkpost.com')
|
31
|
+
end
|
32
|
+
it do
|
33
|
+
expect { SparkPost::Client.new('abc', nil) }
|
34
|
+
.to raise_error(ArgumentError)
|
35
|
+
end
|
26
36
|
end
|
27
37
|
end
|
28
38
|
|
29
|
-
describe '#transmission' do
|
39
|
+
describe '#transmission' do
|
30
40
|
let(:client) { SparkPost::Client.new('123', 'http://sparkpost.com') }
|
31
41
|
|
32
42
|
it { expect(client.transmission).to be_kind_of(SparkPost::Transmission) }
|
33
43
|
|
34
|
-
it 'returns same instances on subsequent call' do
|
35
|
-
|
44
|
+
it 'returns same instances on subsequent call' do
|
45
|
+
expect(client.transmission).to eq(client.transmission)
|
36
46
|
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#template' do
|
50
|
+
let(:client) { SparkPost::Client.new('123', 'http://sparkpost.com') }
|
51
|
+
|
52
|
+
it { expect(client.template).to be_kind_of(SparkPost::Template) }
|
37
53
|
|
54
|
+
it 'returns same instances on subsequent call' do
|
55
|
+
expect(client.template).to eq(client.template)
|
56
|
+
end
|
38
57
|
end
|
39
|
-
end
|
58
|
+
end
|
@@ -1,22 +1,21 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
describe 'Object' do
|
4
|
+
describe '#blank?' do
|
5
|
+
it { expect(''.blank?).to be(true) }
|
6
|
+
it { expect(nil.blank?).to be(true) }
|
7
|
+
it { expect(true.blank?).to be(false) }
|
8
|
+
it { expect({}.blank?).to be(true) }
|
9
|
+
it { expect({}.blank?).to be(true) }
|
10
|
+
it { expect([].blank?).to be(true) }
|
11
|
+
end
|
3
12
|
|
4
|
-
describe '
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
describe '#present?' do
|
15
|
-
it { expect(''.present?).to be(false)}
|
16
|
-
it { expect(nil.present?).to be(false)}
|
17
|
-
it { expect(true.present?).to be(true)}
|
18
|
-
it { expect(Hash.new.present?).to be(false)}
|
19
|
-
it { expect({}.present?).to be(false)}
|
20
|
-
it { expect([].present?).to be(false)}
|
21
|
-
end
|
22
|
-
end
|
13
|
+
describe '#present?' do
|
14
|
+
it { expect(''.present?).to be(false) }
|
15
|
+
it { expect(nil.present?).to be(false) }
|
16
|
+
it { expect(true.present?).to be(true) }
|
17
|
+
it { expect({}.present?).to be(false) }
|
18
|
+
it { expect({}.present?).to be(false) }
|
19
|
+
it { expect([].present?).to be(false) }
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe SparkPost::Helpers do
|
4
|
+
let(:helpers) { SparkPost::Helpers }
|
5
|
+
|
6
|
+
describe '#copy_value' do
|
7
|
+
context 'when source is empty' do
|
8
|
+
let(:src_hash) { {} }
|
9
|
+
let(:dst_hash) { { dkey: 'val' } }
|
10
|
+
|
11
|
+
copied_hash = { dkey: 'val' }
|
12
|
+
|
13
|
+
it 'does not copy values' do
|
14
|
+
helpers.copy_value(src_hash, :skey, dst_hash, :dkey)
|
15
|
+
expect(dst_hash).to eq(copied_hash)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when source is not empty' do
|
20
|
+
let(:src_hash) { { skey: 'val' } }
|
21
|
+
let(:dst_hash) { {} }
|
22
|
+
|
23
|
+
copied_hash = { dkey: 'val' }
|
24
|
+
|
25
|
+
it 'copies values' do
|
26
|
+
helpers.copy_value(src_hash, :skey, dst_hash, :dkey)
|
27
|
+
expect(dst_hash).to eq(copied_hash)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#deep_merge' do
|
33
|
+
context 'when source_hash and other_hash have different keys' do
|
34
|
+
let(:source_hash) { { key1: 'val1', key2: 'val2' } }
|
35
|
+
let(:other_hash) { { key3: 'val3', key4: 'val4' } }
|
36
|
+
|
37
|
+
merged_hash = {
|
38
|
+
key1: 'val1',
|
39
|
+
key2: 'val2',
|
40
|
+
key3: 'val3',
|
41
|
+
key4: 'val4'
|
42
|
+
}
|
43
|
+
|
44
|
+
it 'merges source_hash and other_hash' do
|
45
|
+
expect(helpers.deep_merge(source_hash, other_hash)).to eq(merged_hash)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when other_hash has nil value' do
|
50
|
+
let(:source_hash) { { key1: 'val1', key2: 'val2' } }
|
51
|
+
let(:other_hash) { { key1: nil } }
|
52
|
+
|
53
|
+
merged_hash = {
|
54
|
+
key1: 'val1',
|
55
|
+
key2: 'val2'
|
56
|
+
}
|
57
|
+
|
58
|
+
it 'merges source_hash and other_hash' do
|
59
|
+
expect(helpers.deep_merge(source_hash, other_hash)).to eq(merged_hash)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'when source_hash has nil value' do
|
64
|
+
let(:source_hash) { { key1: nil } }
|
65
|
+
let(:other_hash) { { key1: 'val1', key2: 'val2' } }
|
66
|
+
|
67
|
+
merged_hash = {
|
68
|
+
key1: 'val1',
|
69
|
+
key2: 'val2'
|
70
|
+
}
|
71
|
+
|
72
|
+
it 'merges source_hash and other_hash' do
|
73
|
+
expect(helpers.deep_merge(source_hash, other_hash)).to eq(merged_hash)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'when source_hash and other_hash have nested hash' do
|
78
|
+
let(:source_hash) { { key1: { s1: 'sv1' } } }
|
79
|
+
let(:other_hash) { { key1: { s2: 'sv2' }, key2: 'val2' } }
|
80
|
+
|
81
|
+
merged_hash = {
|
82
|
+
key1: { s1: 'sv1', s2: 'sv2' },
|
83
|
+
key2: 'val2'
|
84
|
+
}
|
85
|
+
|
86
|
+
it 'merges source_hash and other_hash' do
|
87
|
+
expect(helpers.deep_merge(source_hash, other_hash)).to eq(merged_hash)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -1,26 +1,100 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe SparkPost::Request do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
4
|
+
describe '#request' do
|
5
|
+
api_url = 'https://api.sparkpost.com/api/'
|
6
|
+
|
7
|
+
let(:api_key) { '123' }
|
8
|
+
let(:request) { SparkPost::Request.request }
|
9
|
+
|
10
|
+
success_response = {
|
11
|
+
results: {
|
12
|
+
'total_rejected_recipients' => 0,
|
13
|
+
'total_accepted_recipients' => 1,
|
14
|
+
'id' => '123456789123456789'
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
context 'when GET request was successful' do
|
19
|
+
before do
|
20
|
+
stub_request(:get, api_url).to_return(
|
21
|
+
body: JSON.generate(success_response),
|
22
|
+
status: 200)
|
23
|
+
end
|
24
|
+
it do
|
25
|
+
expect(SparkPost::Request.request(api_url, '123', {}, 'GET'))
|
26
|
+
.to eq(success_response[:results])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when PUT request was successful' do
|
31
|
+
before do
|
32
|
+
stub_request(:put, api_url).to_return(
|
33
|
+
body: JSON.generate(success_response),
|
34
|
+
status: 200)
|
35
|
+
end
|
36
|
+
it do
|
37
|
+
expect(SparkPost::Request.request(api_url, '123', {}, 'PUT'))
|
38
|
+
.to eq(success_response[:results])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when DELETE request was successful' do
|
43
|
+
before do
|
44
|
+
stub_request(:delete, api_url).to_return(
|
45
|
+
body: JSON.generate(success_response),
|
46
|
+
status: 200)
|
47
|
+
end
|
48
|
+
it do
|
49
|
+
expect(SparkPost::Request.request(api_url, '123', {}, 'DELETE'))
|
50
|
+
.to eq(success_response[:results])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when POST request was successful' do
|
55
|
+
before do
|
56
|
+
stub_request(:post, api_url).to_return(
|
57
|
+
body: JSON.generate(success_response),
|
58
|
+
status: 200)
|
59
|
+
end
|
60
|
+
it do
|
61
|
+
expect(SparkPost::Request.request(api_url, '123', {}))
|
62
|
+
.to eq(success_response[:results])
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when request was not successful' do
|
67
|
+
response = { errors: { message: 'end of world' } }
|
68
|
+
before do
|
69
|
+
stub_request(:post, api_url).to_return(
|
70
|
+
body: JSON.generate(response),
|
71
|
+
status: 500)
|
72
|
+
end
|
73
|
+
|
74
|
+
it do
|
75
|
+
expect { SparkPost::Request.request(api_url, '123', {}) }
|
76
|
+
.to raise_error(SparkPost::DeliveryException).with_message(
|
77
|
+
/end of world/)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe 'json encoding' do
|
82
|
+
api_url = 'https://api.sparkpost.com/api/'
|
83
|
+
before do
|
84
|
+
stub_request(:post, api_url).to_return(
|
85
|
+
body: JSON.generate({}),
|
86
|
+
status: 200)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'encodes hash to json' do
|
90
|
+
allow(JSON).to receive(:generate).with(foo: 'bar')
|
91
|
+
SparkPost::Request.request(api_url, '123', foo: 'bar')
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'does not encode nil to json' do
|
95
|
+
expect(JSON).to_not receive(:generate)
|
96
|
+
SparkPost::Request.request(api_url, '123', nil)
|
97
|
+
end
|
25
98
|
end
|
26
|
-
end
|
99
|
+
end
|
100
|
+
end
|