sparkpost 0.1.2 → 0.1.4
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 +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
|