cellular 2.1.0 → 2.2.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 +4 -4
- data/.travis.yml +0 -2
- data/cellular.gemspec +5 -5
- data/lib/cellular.rb +1 -1
- data/lib/cellular/backends.rb +5 -3
- data/lib/cellular/backends/backend.rb +3 -2
- data/lib/cellular/backends/cool_sms.rb +3 -4
- data/lib/cellular/backends/link_mobility.rb +72 -0
- data/lib/cellular/backends/log.rb +1 -0
- data/lib/cellular/backends/sendega.rb +12 -13
- data/lib/cellular/backends/test.rb +1 -0
- data/lib/cellular/backends/twilio.rb +4 -4
- data/lib/cellular/configuration.rb +3 -6
- data/lib/cellular/jobs.rb +2 -1
- data/lib/cellular/jobs/async_messenger.rb +1 -0
- data/lib/cellular/logger.rb +2 -5
- data/lib/cellular/models/sms.rb +7 -5
- data/lib/cellular/version.rb +1 -1
- data/spec/cellular/backends/backend_spec.rb +19 -0
- data/spec/cellular/backends/cool_sms_spec.rb +31 -27
- data/spec/cellular/backends/link_mobility_spec.rb +118 -0
- data/spec/cellular/backends/log_spec.rb +3 -5
- data/spec/cellular/backends/log_with_rails_spec.rb +5 -7
- data/spec/cellular/backends/sendega_spec.rb +35 -37
- data/spec/cellular/backends/test_spec.rb +1 -12
- data/spec/cellular/backends/twilio_spec.rb +47 -42
- data/spec/cellular/configuration_spec.rb +1 -3
- data/spec/cellular/jobs/async_messenger_spec.rb +4 -4
- data/spec/cellular/logger_spec.rb +0 -2
- data/spec/cellular/models/sms_spec.rb +15 -15
- data/spec/cellular_spec.rb +0 -2
- data/spec/fixtures/backends/link_mobility/failure.json +1 -0
- data/spec/fixtures/backends/link_mobility/success.json +1 -0
- data/spec/spec_helper.rb +0 -2
- metadata +17 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 798ef5b207911f8698d8199cc06900afd9304152
|
4
|
+
data.tar.gz: 4854425f3b5a9348c2e42f1786991a4887c3f0a5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c902309c6f7ec95b0bc5dd478f87fbcceb8cce9a8046e79a1318ee757d978cd19d47e54507eca6bebcf420c98f31ad16756f4da602674133ab2de041ff981ea8
|
7
|
+
data.tar.gz: bb89b59775574a107503149b0a0a089d493b7157e77050a41f4413b232ab0c8867c1b3bcdeee5884b49b9be64ff3cbc8c6a4198cab0d30d28f4085d97259c0ed
|
data/.travis.yml
CHANGED
data/cellular.gemspec
CHANGED
@@ -10,18 +10,18 @@ Gem::Specification.new do |gem|
|
|
10
10
|
gem.version = Cellular::VERSION
|
11
11
|
gem.authors = ['Sindre Moen', 'Tim Kurvers']
|
12
12
|
gem.email = ['ruby@hyper.no']
|
13
|
-
gem.description =
|
14
|
-
gem.summary =
|
13
|
+
gem.description = 'Sending and receiving SMSs through pluggable backends'
|
14
|
+
gem.summary = 'Sending and receiving SMSs through pluggable backends'
|
15
15
|
gem.homepage = ''
|
16
16
|
|
17
17
|
gem.files = `git ls-files`.split($/)
|
18
|
-
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
18
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
19
19
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
20
20
|
gem.require_paths = ['lib']
|
21
21
|
|
22
|
-
gem.add_dependency 'httparty', '~> 0.13
|
22
|
+
gem.add_dependency 'httparty', '~> 0.13'
|
23
23
|
gem.add_dependency 'savon', '~> 2.0'
|
24
|
-
gem.add_dependency 'rails', '
|
24
|
+
gem.add_dependency 'rails', '~> 4.2'
|
25
25
|
|
26
26
|
gem.add_development_dependency 'pry', '~> 0.10'
|
27
27
|
|
data/lib/cellular.rb
CHANGED
@@ -4,6 +4,7 @@ require 'cellular/models/sms'
|
|
4
4
|
require 'cellular/backends'
|
5
5
|
require 'cellular/jobs'
|
6
6
|
|
7
|
+
# Sending and receiving SMSs through pluggable backends
|
7
8
|
module Cellular
|
8
9
|
autoload :Logger, 'cellular/logger'
|
9
10
|
|
@@ -21,5 +22,4 @@ module Cellular
|
|
21
22
|
@config ||= Configuration.new
|
22
23
|
end
|
23
24
|
end
|
24
|
-
|
25
25
|
end
|
data/lib/cellular/backends.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
module Cellular
|
2
|
+
# Encapsulates all available backends for Cellular
|
2
3
|
module Backends
|
3
4
|
autoload :Backend, 'cellular/backends/backend'
|
4
5
|
autoload :CoolSMS, 'cellular/backends/cool_sms'
|
5
6
|
autoload :Sendega, 'cellular/backends/sendega'
|
6
|
-
autoload :Twilio,
|
7
|
-
autoload :
|
8
|
-
autoload :
|
7
|
+
autoload :Twilio, 'cellular/backends/twilio'
|
8
|
+
autoload :LinkMobility, 'cellular/backends/link_mobility'
|
9
|
+
autoload :Log, 'cellular/backends/log'
|
10
|
+
autoload :Test, 'cellular/backends/test'
|
9
11
|
end
|
10
12
|
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
module Cellular
|
2
2
|
module Backends
|
3
|
+
# Base class for a Cellular backend
|
3
4
|
class Backend
|
4
|
-
def self.deliver(
|
5
|
+
def self.deliver(_options = {})
|
5
6
|
raise NotImplementedError
|
6
7
|
end
|
7
8
|
|
8
|
-
def self.receive(
|
9
|
+
def self.receive(_data)
|
9
10
|
raise NotImplementedError
|
10
11
|
end
|
11
12
|
end
|
@@ -2,17 +2,17 @@ require 'httparty'
|
|
2
2
|
|
3
3
|
module Cellular
|
4
4
|
module Backends
|
5
|
+
# Cool SMS backend (http://www.coolsms.com)
|
5
6
|
class CoolSMS < Backend
|
6
|
-
|
7
7
|
# Documentation: http://www.coolsms.com/support/dokumentation/http-gateway.sms
|
8
|
-
GATEWAY_URL = 'https://sms.coolsmsc.dk/'
|
8
|
+
GATEWAY_URL = 'https://sms.coolsmsc.dk/'.freeze
|
9
9
|
|
10
10
|
def self.deliver(options = {})
|
11
11
|
request_queue = {}
|
12
12
|
|
13
13
|
recipients_batch(options).each_with_index do |recipient, index|
|
14
14
|
options[:batch] = recipient
|
15
|
-
result = HTTParty.get(GATEWAY_URL, query: defaults_with(options)
|
15
|
+
result = HTTParty.get(GATEWAY_URL, query: defaults_with(options))
|
16
16
|
request_queue[index] = {
|
17
17
|
recipient: recipient,
|
18
18
|
response: parse_response(result.parsed_response['smsc'])
|
@@ -55,7 +55,6 @@ module Cellular
|
|
55
55
|
options[:recipients]
|
56
56
|
end
|
57
57
|
end
|
58
|
-
|
59
58
|
end
|
60
59
|
end
|
61
60
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
module Cellular
|
4
|
+
module Backends
|
5
|
+
# LinkMobility backend (https://www.linkmobility.com)
|
6
|
+
class LinkMobility < Backend
|
7
|
+
# Documentation: https://www.linkmobility.com/developers/
|
8
|
+
BASE_URL = 'https://wsx.sp247.net/'.freeze
|
9
|
+
|
10
|
+
HTTP_HEADERS = {
|
11
|
+
'Content-Type' => 'application/json; charset=utf-8',
|
12
|
+
}.freeze
|
13
|
+
|
14
|
+
def self.deliver(options = {})
|
15
|
+
request_queue = {}
|
16
|
+
recipients_batch(options).each_with_index do |recipient, index|
|
17
|
+
options[:batch] = recipient
|
18
|
+
|
19
|
+
request = HTTParty.post(
|
20
|
+
sms_url,
|
21
|
+
body: payload(options),
|
22
|
+
basic_auth: link_mobility_config,
|
23
|
+
headers: HTTP_HEADERS
|
24
|
+
)
|
25
|
+
|
26
|
+
request_queue[index] = {
|
27
|
+
recipient: options[:batch],
|
28
|
+
response: parse_response(request)
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
# return first response for now
|
33
|
+
request_queue[0][:response]
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.parse_response(response)
|
37
|
+
[
|
38
|
+
response['description']
|
39
|
+
]
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.sms_url
|
43
|
+
"#{BASE_URL}sms/send"
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.link_mobility_config
|
47
|
+
{
|
48
|
+
username: Cellular.config.username,
|
49
|
+
password: Cellular.config.password
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.payload(options)
|
54
|
+
{
|
55
|
+
source: options[:sender],
|
56
|
+
destination: options[:batch],
|
57
|
+
userData: options[:message],
|
58
|
+
platformId: 'COMMON_API',
|
59
|
+
platformPartnerId: Cellular.config.partner_id,
|
60
|
+
}.to_json
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.recipients_batch(options)
|
64
|
+
if options[:recipients].blank?
|
65
|
+
[options[:recipient]]
|
66
|
+
else
|
67
|
+
options[:recipients]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -2,9 +2,9 @@ require 'savon'
|
|
2
2
|
|
3
3
|
module Cellular
|
4
4
|
module Backends
|
5
|
+
# Sendega backend (http://sendega.com)
|
5
6
|
class Sendega < Backend
|
6
|
-
|
7
|
-
GATEWAY_URL = 'https://smsc.sendega.com/Content.asmx?WSDL'
|
7
|
+
GATEWAY_URL = 'https://smsc.sendega.com/Content.asmx?WSDL'.freeze
|
8
8
|
|
9
9
|
def self.deliver(options = {}, savon_options = {})
|
10
10
|
# Send an SMS and return its initial delivery status code.
|
@@ -45,7 +45,7 @@ module Cellular
|
|
45
45
|
request_queue[index] = {
|
46
46
|
batch: batch,
|
47
47
|
result: result,
|
48
|
-
body:result.body[:send_response][:send_result],
|
48
|
+
body: result.body[:send_response][:send_result],
|
49
49
|
response: map_response(result.body[:send_response][:send_result])
|
50
50
|
}
|
51
51
|
end
|
@@ -54,20 +54,20 @@ module Cellular
|
|
54
54
|
request_queue[0][:response]
|
55
55
|
end
|
56
56
|
|
57
|
-
def self.receive(
|
57
|
+
def self.receive(_data)
|
58
58
|
raise NotImplementedError
|
59
59
|
end
|
60
60
|
|
61
61
|
def self.savon_config
|
62
62
|
{
|
63
|
-
|
64
|
-
|
65
|
-
|
63
|
+
username: Cellular.config.username,
|
64
|
+
password: Cellular.config.password,
|
65
|
+
dlrUrl: Cellular.config.delivery_url
|
66
66
|
}
|
67
67
|
end
|
68
68
|
|
69
69
|
def self.defaults_with(options)
|
70
|
-
|
70
|
+
{
|
71
71
|
sender: options[:sender],
|
72
72
|
destination: options[:batch],
|
73
73
|
pricegroup: options[:price] || 0, # default price to 0
|
@@ -85,9 +85,9 @@ module Cellular
|
|
85
85
|
}.merge!(savon_config)
|
86
86
|
end
|
87
87
|
|
88
|
-
def self.map_response(
|
89
|
-
msg =
|
90
|
-
[
|
88
|
+
def self.map_response(body)
|
89
|
+
msg = body[:success] ? success_message : body[:error_message]
|
90
|
+
[body[:error_number].to_i, msg]
|
91
91
|
end
|
92
92
|
|
93
93
|
def self.success_message
|
@@ -98,10 +98,9 @@ module Cellular
|
|
98
98
|
if options[:recipients].blank?
|
99
99
|
[options[:recipient]]
|
100
100
|
else
|
101
|
-
options[:recipients].each_slice(100).to_a.map{|x| x.join(',') }
|
101
|
+
options[:recipients].each_slice(100).to_a.map { |x| x.join(',') }
|
102
102
|
end
|
103
103
|
end
|
104
|
-
|
105
104
|
end
|
106
105
|
end
|
107
106
|
end
|
@@ -2,10 +2,11 @@ require 'httparty'
|
|
2
2
|
|
3
3
|
module Cellular
|
4
4
|
module Backends
|
5
|
+
# Twilio backend (https://www.twilio.com)
|
5
6
|
class Twilio < Backend
|
6
7
|
# Documentation: https://www.twilio.com/docs/api/rest
|
7
|
-
API_VERSION = '2010-04-01'
|
8
|
-
BASE_URL = 'https://api.twilio.com/'
|
8
|
+
API_VERSION = '2010-04-01'.freeze
|
9
|
+
BASE_URL = 'https://api.twilio.com/'.freeze
|
9
10
|
API_URL = BASE_URL + API_VERSION
|
10
11
|
|
11
12
|
HTTP_HEADERS = {
|
@@ -14,7 +15,7 @@ module Cellular
|
|
14
15
|
'User-Agent' => "cellular/#{Cellular::VERSION}" \
|
15
16
|
" (#{RUBY_ENGINE}/#{RUBY_PLATFORM}" \
|
16
17
|
" #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL})"
|
17
|
-
}
|
18
|
+
}.freeze
|
18
19
|
|
19
20
|
def self.deliver(options = {})
|
20
21
|
request_queue = {}
|
@@ -71,7 +72,6 @@ module Cellular
|
|
71
72
|
options[:recipients]
|
72
73
|
end
|
73
74
|
end
|
74
|
-
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
@@ -1,15 +1,12 @@
|
|
1
1
|
module Cellular
|
2
|
+
# Configuration for Cellular
|
2
3
|
class Configuration
|
3
|
-
|
4
4
|
attr_accessor :username, :password, :delivery_url, :backend
|
5
|
-
|
6
|
-
attr_accessor :country_code, :price, :sender
|
7
|
-
|
5
|
+
attr_accessor :country_code, :price, :sender, :partner_id
|
8
6
|
attr_accessor :logger
|
9
|
-
|
7
|
+
|
10
8
|
def logger
|
11
9
|
@logger ||= Object.const_defined?(:Rails) ? Rails.logger : Logger.new
|
12
10
|
end
|
13
|
-
|
14
11
|
end
|
15
12
|
end
|
data/lib/cellular/jobs.rb
CHANGED
data/lib/cellular/logger.rb
CHANGED
@@ -1,12 +1,9 @@
|
|
1
1
|
module Cellular
|
2
|
-
|
3
|
-
#
|
4
|
-
# logs to stdout
|
2
|
+
# API compatible logger when not in a Rails environment
|
3
|
+
# Logs to stdout
|
5
4
|
class Logger
|
6
5
|
def info(message)
|
7
6
|
$stdout.puts message
|
8
7
|
end
|
9
8
|
end
|
10
|
-
|
11
9
|
end
|
12
|
-
|
data/lib/cellular/models/sms.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
require 'active_support/time'
|
2
2
|
|
3
3
|
module Cellular
|
4
|
+
# Represents an SMS
|
4
5
|
class SMS
|
5
|
-
|
6
6
|
attr_accessor :recipient, :sender, :message, :price, :country_code
|
7
7
|
attr_accessor :recipients, :delivery_status, :delivery_message
|
8
|
+
|
8
9
|
def initialize(options = {})
|
9
10
|
@backend = Cellular.config.backend
|
10
11
|
|
@@ -24,15 +25,17 @@ module Cellular
|
|
24
25
|
end
|
25
26
|
|
26
27
|
def deliver_async(delivery_options = {})
|
27
|
-
Cellular::Jobs::AsyncMessenger.set(delivery_options)
|
28
|
+
Cellular::Jobs::AsyncMessenger.set(delivery_options)
|
29
|
+
.perform_later(options)
|
28
30
|
end
|
31
|
+
|
29
32
|
alias_method :deliver_later, :deliver_async
|
30
33
|
|
31
|
-
def save(
|
34
|
+
def save(_options = {})
|
32
35
|
raise NotImplementedError
|
33
36
|
end
|
34
37
|
|
35
|
-
def receive(
|
38
|
+
def receive(_options = {})
|
36
39
|
raise NotImplementedError
|
37
40
|
end
|
38
41
|
|
@@ -52,6 +55,5 @@ module Cellular
|
|
52
55
|
country_code: @country_code
|
53
56
|
}
|
54
57
|
end
|
55
|
-
|
56
58
|
end
|
57
59
|
end
|
data/lib/cellular/version.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cellular::Backends::Backend do
|
4
|
+
describe '::deliver' do
|
5
|
+
it 'has not been implemented yet' do
|
6
|
+
expect do
|
7
|
+
described_class.deliver
|
8
|
+
end.to raise_error NotImplementedError
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '::receive' do
|
13
|
+
it 'has not been implemented yet' do
|
14
|
+
expect do
|
15
|
+
described_class.receive ''
|
16
|
+
end.to raise_error NotImplementedError
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,20 +1,19 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Cellular::Backends::CoolSMS do
|
4
|
-
|
5
4
|
let(:recipient) { '47xxxxxxxx' }
|
6
5
|
let(:sender) { 'Custom sender' }
|
7
6
|
let(:message) { 'This is an SMS message' }
|
8
7
|
|
9
|
-
let(:options)
|
8
|
+
let(:options) do
|
10
9
|
{
|
11
10
|
recipient: recipient,
|
12
11
|
sender: sender,
|
13
12
|
message: message
|
14
13
|
}
|
15
|
-
|
14
|
+
end
|
16
15
|
|
17
|
-
let(:payload)
|
16
|
+
let(:payload) do
|
18
17
|
{
|
19
18
|
username: 'username',
|
20
19
|
password: 'password',
|
@@ -25,7 +24,7 @@ describe Cellular::Backends::CoolSMS do
|
|
25
24
|
resulttype: 'xml',
|
26
25
|
lang: 'en'
|
27
26
|
}
|
28
|
-
|
27
|
+
end
|
29
28
|
|
30
29
|
before do
|
31
30
|
Cellular.config.username = 'username'
|
@@ -34,13 +33,15 @@ describe Cellular::Backends::CoolSMS do
|
|
34
33
|
|
35
34
|
describe '::deliver' do
|
36
35
|
before do
|
37
|
-
stub_request(:get, 'https://sms.coolsmsc.dk/?charset=utf-8&from=Custom%20sender&lang=en&message=This%20is%20an%20SMS%20message&password=password&resulttype=xml&to=47xxxxxxxx&username=username')
|
38
|
-
to_return headers: { 'Content-Type' => 'text/xml' }, body: fixture('backends/cool_sms/success.xml')
|
36
|
+
stub_request(:get, 'https://sms.coolsmsc.dk/?charset=utf-8&from=Custom%20sender&lang=en&message=This%20is%20an%20SMS%20message&password=password&resulttype=xml&to=47xxxxxxxx&username=username')
|
37
|
+
.to_return headers: { 'Content-Type' => 'text/xml' }, body: fixture('backends/cool_sms/success.xml')
|
39
38
|
end
|
40
39
|
|
41
40
|
it 'uses HTTParty to deliver an SMS' do
|
42
|
-
expect(HTTParty).to receive(:get).with(
|
43
|
-
|
41
|
+
expect(HTTParty).to receive(:get).with(
|
42
|
+
described_class::GATEWAY_URL,
|
43
|
+
query: payload
|
44
|
+
).and_call_original
|
44
45
|
|
45
46
|
described_class.deliver(options)
|
46
47
|
end
|
@@ -56,8 +57,8 @@ describe Cellular::Backends::CoolSMS do
|
|
56
57
|
|
57
58
|
context 'when not successful' do
|
58
59
|
before do
|
59
|
-
stub_request(:get, 'https://sms.coolsmsc.dk/?charset=utf-8&from=Custom%20sender&lang=en&message=This%20is%20an%20SMS%20message&password=password&resulttype=xml&to=47xxxxxxxx&username=username')
|
60
|
-
to_return headers: { 'Content-Type' => 'text/xml' }, body: fixture('backends/cool_sms/failure.xml')
|
60
|
+
stub_request(:get, 'https://sms.coolsmsc.dk/?charset=utf-8&from=Custom%20sender&lang=en&message=This%20is%20an%20SMS%20message&password=password&resulttype=xml&to=47xxxxxxxx&username=username')
|
61
|
+
.to_return headers: { 'Content-Type' => 'text/xml' }, body: fixture('backends/cool_sms/failure.xml')
|
61
62
|
end
|
62
63
|
|
63
64
|
it 'returns failure and a message' do
|
@@ -70,12 +71,14 @@ describe Cellular::Backends::CoolSMS do
|
|
70
71
|
end
|
71
72
|
|
72
73
|
describe '::parse_response' do
|
73
|
-
it '
|
74
|
+
it 'returns the correct response' do
|
74
75
|
message = ['success', 'The message was sent correctly.']
|
75
76
|
|
76
77
|
check = { 'status' => message[0], 'result' => message[1] }
|
77
|
-
second_check =
|
78
|
-
|
78
|
+
second_check = {
|
79
|
+
'status' => message[0],
|
80
|
+
'message' => { 'result' => message[1] }
|
81
|
+
}
|
79
82
|
|
80
83
|
expect(described_class.parse_response(check)).to eq(message)
|
81
84
|
expect(described_class.parse_response(second_check)).to eq(message)
|
@@ -83,31 +86,32 @@ describe Cellular::Backends::CoolSMS do
|
|
83
86
|
end
|
84
87
|
|
85
88
|
describe '::coolsms_config' do
|
86
|
-
it '
|
89
|
+
it 'returns the config for coolsms' do
|
87
90
|
expect(described_class.coolsms_config).to eq(
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
})
|
91
|
+
username: Cellular.config.username,
|
92
|
+
password: Cellular.config.password
|
93
|
+
)
|
92
94
|
end
|
93
95
|
end
|
94
96
|
|
95
97
|
describe '::defaults_with' do
|
96
|
-
it '
|
98
|
+
it 'returns the whole query' do
|
97
99
|
options[:batch] = recipient
|
98
100
|
expect(described_class.defaults_with(options)).to eq(payload)
|
99
101
|
end
|
100
102
|
end
|
101
103
|
|
102
104
|
describe '::recipients_batch' do
|
103
|
-
it '
|
104
|
-
|
105
|
-
|
105
|
+
it 'wraps recipient option into an array' do
|
106
|
+
result = described_class.recipients_batch(recipient: recipient)
|
107
|
+
expect(result).to eq([recipient])
|
106
108
|
end
|
107
|
-
|
108
|
-
|
109
|
-
|
109
|
+
|
110
|
+
it 'returns recipients option as-is' do
|
111
|
+
result = described_class.recipients_batch(
|
112
|
+
recipients: [recipient, recipient]
|
113
|
+
)
|
114
|
+
expect(result).to eq([recipient, recipient])
|
110
115
|
end
|
111
116
|
end
|
112
|
-
|
113
117
|
end
|