signal_api 0.0.1
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.
- data/.gitignore +19 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +43 -0
- data/Rakefile +49 -0
- data/lib/signal_api/carrier.rb +43 -0
- data/lib/signal_api/contact.rb +60 -0
- data/lib/signal_api/core_ext/array.rb +7 -0
- data/lib/signal_api/core_ext/hash.rb +7 -0
- data/lib/signal_api/core_ext/nil_class.rb +7 -0
- data/lib/signal_api/core_ext/string.rb +7 -0
- data/lib/signal_api/coupon_group.rb +47 -0
- data/lib/signal_api/deliver_sms.rb +54 -0
- data/lib/signal_api/exceptions.rb +19 -0
- data/lib/signal_api/list.rb +224 -0
- data/lib/signal_api/mocks/api_mock.rb +70 -0
- data/lib/signal_api/mocks/contact.rb +13 -0
- data/lib/signal_api/mocks/deliver_sms.rb +14 -0
- data/lib/signal_api/mocks/list.rb +19 -0
- data/lib/signal_api/mocks/short_url.rb +9 -0
- data/lib/signal_api/segment.rb +161 -0
- data/lib/signal_api/short_url.rb +56 -0
- data/lib/signal_api/signal_http_api.rb +49 -0
- data/lib/signal_api/util/email_address.rb +10 -0
- data/lib/signal_api/util/phone.rb +37 -0
- data/lib/signal_api/version.rb +3 -0
- data/lib/signal_api.rb +114 -0
- data/signal_api.gemspec +27 -0
- data/test/api/carrier_test.rb +43 -0
- data/test/api/contact_test.rb +93 -0
- data/test/api/coupon_group_test.rb +36 -0
- data/test/api/deliver_sms_test.rb +66 -0
- data/test/api/general_test.rb +26 -0
- data/test/api/list_test.rb +261 -0
- data/test/api/segment_test.rb +144 -0
- data/test/api/short_url_test.rb +50 -0
- data/test/mocks/contact_mock_test.rb +24 -0
- data/test/mocks/deliver_sms_mock_test.rb +21 -0
- data/test/mocks/list_mock_test.rb +33 -0
- data/test/mocks/short_url_mock_test.rb +17 -0
- data/test/test_helper.rb +20 -0
- metadata +248 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
module SignalApi
|
2
|
+
module ApiMock
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
@@mock_method_definitions = {}
|
10
|
+
@@mock_method_calls = {}
|
11
|
+
|
12
|
+
def mock_method_calls
|
13
|
+
@@mock_method_calls
|
14
|
+
end
|
15
|
+
|
16
|
+
def mock_method_definitions
|
17
|
+
@@mock_method_definitions
|
18
|
+
end
|
19
|
+
|
20
|
+
def mock_method(method, *parameter_names)
|
21
|
+
@@mock_method_definitions[method] = parameter_names
|
22
|
+
@@mock_method_calls[method] = []
|
23
|
+
|
24
|
+
define_method method do |*args|
|
25
|
+
method_args = self.class.mock_method_definitions[method]
|
26
|
+
|
27
|
+
called_args = {}
|
28
|
+
method_args.each_with_index do |method_arg, i|
|
29
|
+
called_args[method_arg] = args[i]
|
30
|
+
end
|
31
|
+
|
32
|
+
additional_info_method = method.to_s + "_additional_info"
|
33
|
+
if self.class.method_defined?(additional_info_method)
|
34
|
+
called_args.merge!(send(additional_info_method))
|
35
|
+
end
|
36
|
+
|
37
|
+
self.class.mock_method_calls[method] << called_args
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def mock_class_method(method, *parameter_names)
|
42
|
+
@@mock_method_definitions[method] = parameter_names
|
43
|
+
@@mock_method_calls[method] = []
|
44
|
+
|
45
|
+
(class << self; self; end).instance_eval do
|
46
|
+
define_method method do |*args|
|
47
|
+
method_args = mock_method_definitions[method]
|
48
|
+
|
49
|
+
called_args = {}
|
50
|
+
method_args.each_with_index do |method_arg, i|
|
51
|
+
called_args[method_arg] = args[i]
|
52
|
+
end
|
53
|
+
|
54
|
+
additional_info_method = method.to_s + "_additional_info"
|
55
|
+
if method_defined?(additional_info_method)
|
56
|
+
called_args.merge!(send(additional_info_method))
|
57
|
+
end
|
58
|
+
|
59
|
+
mock_method_calls[method] << called_args
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def clear_mock_data
|
65
|
+
@@mock_method_calls.keys.each { |k| @@mock_method_calls[k] = [] }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'signal_api/mocks/api_mock'
|
2
|
+
|
3
|
+
module SignalApi
|
4
|
+
class List
|
5
|
+
include ApiMock
|
6
|
+
|
7
|
+
mock_method(:create_subscription, :subscription_type, :contact, :options)
|
8
|
+
|
9
|
+
def create_subscription_additional_info
|
10
|
+
{ :list_id => @list_id }
|
11
|
+
end
|
12
|
+
|
13
|
+
mock_method(:destroy_subscription, :subscription_type, :contact)
|
14
|
+
|
15
|
+
def destroy_subscription_additional_info
|
16
|
+
{ :list_id => @list_id }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
module SignalApi
|
2
|
+
|
3
|
+
# The type of segment
|
4
|
+
class SegmentType
|
5
|
+
DYNAMIC = "DYNAMIC"
|
6
|
+
STATIC = "SEGMENT"
|
7
|
+
end
|
8
|
+
|
9
|
+
# Represents a user to be added to a segment
|
10
|
+
class SegmentUser
|
11
|
+
attr_reader :mobile_phone, :email_address, :user_data
|
12
|
+
|
13
|
+
# Create a new segment on the Signal platform.
|
14
|
+
#
|
15
|
+
# @param [String] identifying_attribute The mobile phone or email address of the user
|
16
|
+
# @param [Hash] user_data <b>Optional</b> A collection of key/value pairs to store along
|
17
|
+
# with this user's segment record for later use
|
18
|
+
def initialize(identifying_attribute, user_data={})
|
19
|
+
if Phone.valid?(identifying_attribute)
|
20
|
+
@mobile_phone = identifying_attribute
|
21
|
+
elsif EmailAddress.valid?(identifying_attribute)
|
22
|
+
@email_address = identifying_attribute
|
23
|
+
else
|
24
|
+
raise InvalidParameterException.new("identifying_attribute must be a valid mobile phone number or email address")
|
25
|
+
end
|
26
|
+
|
27
|
+
@user_data = user_data unless user_data.empty?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Create, manage, and add users to a segment.
|
32
|
+
class Segment < SignalHttpApi
|
33
|
+
|
34
|
+
# The name of the segment
|
35
|
+
attr_reader :name
|
36
|
+
|
37
|
+
# The description of the segment
|
38
|
+
attr_reader :description
|
39
|
+
|
40
|
+
# The ID of the segment
|
41
|
+
attr_reader :id
|
42
|
+
|
43
|
+
# The account_id of the segment
|
44
|
+
attr_reader :account_id
|
45
|
+
|
46
|
+
# Type type of the segment
|
47
|
+
attr_reader :segment_type
|
48
|
+
|
49
|
+
|
50
|
+
def initialize(id, name=nil, description=nil, segment_type=nil, account_id=nil)
|
51
|
+
@name = name
|
52
|
+
@description = description
|
53
|
+
@id = id
|
54
|
+
@account_id = account_id
|
55
|
+
|
56
|
+
if segment_type == "DYNAMIC"
|
57
|
+
@segment_type = SegmentType::DYNAMIC
|
58
|
+
elsif segment_type == "SEGMENT"
|
59
|
+
@segment_type = SegmentType::STATIC
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Create a new segment on the Signal platform.
|
64
|
+
#
|
65
|
+
# @param [String] name The name of the segment
|
66
|
+
# @param [String] description A description of the segment
|
67
|
+
# @param [SegmentType] segment_type The type of the segment
|
68
|
+
#
|
69
|
+
# @return [Segment] A Segment object representing the segment on the Signal platform
|
70
|
+
def self.create(name, description, segment_type)
|
71
|
+
if name.blank? || description.blank? || segment_type.blank?
|
72
|
+
raise InvalidParameterException.new("name, description, and segment_type are all required")
|
73
|
+
end
|
74
|
+
|
75
|
+
unless [SegmentType::DYNAMIC, SegmentType::STATIC].include?(segment_type)
|
76
|
+
raise InvalidParameterException.new("Invalid segment type")
|
77
|
+
end
|
78
|
+
|
79
|
+
builder = Builder::XmlMarkup.new
|
80
|
+
body = builder.filter_group do |filter_group|
|
81
|
+
filter_group.description(description)
|
82
|
+
filter_group.name(name)
|
83
|
+
filter_group.filter_group_type(segment_type)
|
84
|
+
end
|
85
|
+
|
86
|
+
SignalApi.logger.info "Attempting to create a segment: name => #{name}, description => \"#{description}\", type = #{segment_type}}"
|
87
|
+
SignalApi.logger.debug "Segment data: #{body}"
|
88
|
+
with_retries do
|
89
|
+
response = post("/api/filter_groups/create.xml",
|
90
|
+
:body => body,
|
91
|
+
:format => :xml,
|
92
|
+
:headers => common_headers)
|
93
|
+
|
94
|
+
if response.code == 200
|
95
|
+
data = response.parsed_response['subscription_list_filter_group']
|
96
|
+
new(data['id'], data['name'], data['description'], lookup_segment_type(data['filter_group_type_id']), data['account_id'])
|
97
|
+
else
|
98
|
+
handle_api_failure(response)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Add mobile phone numbers to a segment.
|
104
|
+
#
|
105
|
+
# @param [Array<SegmentUser>] segment_users An array of SegmentUsers to add to the segment
|
106
|
+
# @return [Hash] A hash containing some stats regarding the operation
|
107
|
+
def add_users(segment_users)
|
108
|
+
if segment_users.blank?
|
109
|
+
raise InvalidParameterException.new("An array of SegmentUser objects must be provided")
|
110
|
+
end
|
111
|
+
|
112
|
+
builder = Builder::XmlMarkup.new
|
113
|
+
body = builder.users(:type => :array) do |users|
|
114
|
+
segment_users.each do |segment_user|
|
115
|
+
users.user do |user|
|
116
|
+
user.mobile_phone(segment_user.mobile_phone) if segment_user.mobile_phone
|
117
|
+
user.email(segment_user.email_address) if segment_user.email_address
|
118
|
+
user.user_data(segment_user.user_data) if segment_user.user_data
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
SignalApi.logger.info "Attempting to add users to segment #{@id}"
|
124
|
+
self.class.with_retries do
|
125
|
+
response = self.class.post("/api/filter_segments/#{@id}/update.xml",
|
126
|
+
:body => body,
|
127
|
+
:format => :xml,
|
128
|
+
:headers => self.class.common_headers)
|
129
|
+
|
130
|
+
if response.code == 200
|
131
|
+
data = response.parsed_response['subscription_list_segment_results']
|
132
|
+
|
133
|
+
if data['users_not_found'] && data['users_not_found']['user_not_found']
|
134
|
+
if data['users_not_found']['user_not_found'].respond_to?(:join)
|
135
|
+
SignalApi.logger.warn data['users_not_found']['user_not_found'].join(", ")
|
136
|
+
else
|
137
|
+
SignalApi.logger.warn data['users_not_found']['user_not_found']
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
{ :total_users_processed => (data['total_users_processed'] || 0).to_i,
|
142
|
+
:total_users_added => (data['total_users_added'] || 0).to_i,
|
143
|
+
:total_users_not_found => (data['total_users_not_found'] || 0).to_i,
|
144
|
+
:total_duplicate_users => (data['total_duplicate_users'] || 0).to_i }
|
145
|
+
else
|
146
|
+
self.class.handle_api_failure(response)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def self.lookup_segment_type(segment_type_id)
|
154
|
+
case segment_type_id
|
155
|
+
when 1 then SegmentType::DYNAMIC
|
156
|
+
when 2 then SegmentType::STATIC
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module SignalApi
|
2
|
+
|
3
|
+
# Manage short URLs via Signal's URL shortening service
|
4
|
+
class ShortUrl < SignalHttpApi
|
5
|
+
|
6
|
+
# The shortened URL
|
7
|
+
attr_reader :short_url
|
8
|
+
|
9
|
+
# The target URL that was shortened
|
10
|
+
attr_reader :target_url
|
11
|
+
|
12
|
+
# The ID of the shortend URL on the Signal platform
|
13
|
+
attr_reader :id
|
14
|
+
|
15
|
+
# The domain of the short URL
|
16
|
+
attr_reader :domain
|
17
|
+
|
18
|
+
def initialize(id, target_url, short_url, domain)
|
19
|
+
@id = id
|
20
|
+
@target_url = target_url
|
21
|
+
@short_url = short_url
|
22
|
+
@domain = domain
|
23
|
+
end
|
24
|
+
|
25
|
+
# Create a short URL for the provided target URL
|
26
|
+
#
|
27
|
+
# @param [String] target The target URL that is to be shortened
|
28
|
+
# @param [String] domain The short URL domain to use
|
29
|
+
#
|
30
|
+
# @return [ShortUrl] A ShortUrl object representing the short URL on the Signal platform
|
31
|
+
def self.create(target, domain)
|
32
|
+
body = <<-END
|
33
|
+
<short_url>
|
34
|
+
<target_url><![CDATA[#{target}]]></target_url>
|
35
|
+
<domain_id>1</domain_id>
|
36
|
+
</short_url>
|
37
|
+
END
|
38
|
+
|
39
|
+
SignalApi.logger.info "Attempting to create a short URL for #{target}"
|
40
|
+
with_retries do
|
41
|
+
response = post('/api/short_urls.xml',
|
42
|
+
:body => body,
|
43
|
+
:format => :xml,
|
44
|
+
:headers => common_headers)
|
45
|
+
|
46
|
+
if response.code == 201
|
47
|
+
data = response.parsed_response['short_url']
|
48
|
+
new(data['id'], data['target_url'], "http://#{domain}/#{data['slug']}", domain)
|
49
|
+
else
|
50
|
+
handle_api_failure(response)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module SignalApi
|
2
|
+
class SignalHttpApi
|
3
|
+
include HTTParty
|
4
|
+
base_uri SignalApi.base_uri
|
5
|
+
default_timeout SignalApi.timeout
|
6
|
+
|
7
|
+
protected
|
8
|
+
|
9
|
+
def self.with_retries
|
10
|
+
if SignalApi.retries <= 0
|
11
|
+
yield
|
12
|
+
else
|
13
|
+
retry_counter = 0
|
14
|
+
begin
|
15
|
+
yield
|
16
|
+
rescue NonRetryableException => e
|
17
|
+
SignalApi.logger.error "Non retryable exception: #{e.message}"
|
18
|
+
raise
|
19
|
+
rescue Exception => e
|
20
|
+
SignalApi.logger.error "Exception: #{e.message}"
|
21
|
+
sleep 1
|
22
|
+
retry_counter += 1
|
23
|
+
|
24
|
+
if retry_counter < SignalApi.retries
|
25
|
+
SignalApi.logger.warn "Re-trying..."
|
26
|
+
retry
|
27
|
+
else
|
28
|
+
SignalApi.logger.error "All retry attempts have failed."
|
29
|
+
raise
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.handle_api_failure(response)
|
36
|
+
if response.code == 401
|
37
|
+
raise AuthFailedException.new("Authentication to the Signal platform failed. Make sure your API key is correct.")
|
38
|
+
else
|
39
|
+
message = "API request failed with a response code of #{response.code}. Respone body: #{response.body}"
|
40
|
+
SignalApi.logger.error message
|
41
|
+
raise ApiException.new(message)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.common_headers
|
46
|
+
{ 'Content-Type' => 'application/xml', 'api_token' => SignalApi.api_key }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module SignalApi
|
2
|
+
class Phone
|
3
|
+
|
4
|
+
# Clean up phone number by removing special characters and country codes (if provided)
|
5
|
+
def self.sanitize(phone_number)
|
6
|
+
return nil if phone_number.nil?
|
7
|
+
|
8
|
+
# Remove all non-numeric characters, ex - "=", "+", "(", ")", ".", "a", "A", " "
|
9
|
+
sanitized_phone_number = phone_number.gsub(/[^\d]/, '')
|
10
|
+
|
11
|
+
# Remove the US/Canadian country code (+1) if was provided
|
12
|
+
if sanitized_phone_number.length > 10 && sanitized_phone_number[0,1] == "1"
|
13
|
+
sanitized_phone_number = sanitized_phone_number[1, sanitized_phone_number.size]
|
14
|
+
end
|
15
|
+
|
16
|
+
sanitized_phone_number
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.valid?(phone_number)
|
20
|
+
return false if phone_number.nil? || phone_number.strip.empty?
|
21
|
+
return false if self.sanitize(phone_number).size != 10
|
22
|
+
return true
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.format(phone_number, international=false)
|
26
|
+
if Phone.valid?(phone_number)
|
27
|
+
phone_number = Phone.sanitize(phone_number)
|
28
|
+
unless international
|
29
|
+
"#{phone_number[0..2]}-#{phone_number[3..5]}-#{phone_number[6..9]}" # 312-343-1326
|
30
|
+
else
|
31
|
+
phone_number
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
data/lib/signal_api.rb
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
require "httparty"
|
2
|
+
require "builder"
|
3
|
+
require "logger"
|
4
|
+
|
5
|
+
module SignalApi
|
6
|
+
|
7
|
+
# Interact with the Signal platform via its published web API.
|
8
|
+
class << self
|
9
|
+
|
10
|
+
# Set your Signal API key.
|
11
|
+
#
|
12
|
+
# @param [String] api_key Your Signal API key
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# SignalApi.api_key = 'foobar123456abcxyz77'
|
16
|
+
def api_key=(api_key)
|
17
|
+
@api_key = api_key
|
18
|
+
end
|
19
|
+
|
20
|
+
# Get your Signal API key.
|
21
|
+
def api_key
|
22
|
+
if @api_key.nil? || @api_key.strip == ""
|
23
|
+
raise InvalidApiKeyException.new("The api_key is blank or nil. Use SignalApi.api_key= to set it.")
|
24
|
+
else
|
25
|
+
@api_key
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Set the logger to be used by Signal.
|
30
|
+
#
|
31
|
+
# @param [Logger] logger The logger you would like Signal to use
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# SignalApi.logger = Rails.logger
|
35
|
+
# SignalApi.logger = Logger.new(STDERR)
|
36
|
+
def logger=(logger)
|
37
|
+
@logger = logger
|
38
|
+
end
|
39
|
+
|
40
|
+
# Get the logger used by Signal.
|
41
|
+
def logger
|
42
|
+
@logger ||= Logger.new("/dev/null")
|
43
|
+
end
|
44
|
+
|
45
|
+
# Set the number of times failed API calls should be retried. Defaults to 0.
|
46
|
+
#
|
47
|
+
# @param [Fixnum] retries The number of times API calls should be retried
|
48
|
+
#
|
49
|
+
# @example
|
50
|
+
# SignalApi.retries = 3
|
51
|
+
def retries=(retries)
|
52
|
+
@retries = retries
|
53
|
+
end
|
54
|
+
|
55
|
+
# Get the number of times failed API calls should be retried.
|
56
|
+
def retries
|
57
|
+
@retries || 0
|
58
|
+
end
|
59
|
+
|
60
|
+
# Set the default timeout for API calls. Defaults to 15 seconds.
|
61
|
+
#
|
62
|
+
# @param [Fixnum] timeout The default timeout (in seconds) for API calls
|
63
|
+
#
|
64
|
+
# @example
|
65
|
+
# SignalApi.timeout = 5
|
66
|
+
def timeout=(timeout)
|
67
|
+
@timeout = timeout
|
68
|
+
api_classes.each { |clazz| clazz.default_timeout @timeout }
|
69
|
+
end
|
70
|
+
|
71
|
+
# Get the default timeout for API calls.
|
72
|
+
def timeout
|
73
|
+
@timeout || 15
|
74
|
+
end
|
75
|
+
|
76
|
+
# @private
|
77
|
+
def base_uri=(base_uri)
|
78
|
+
@base_uri = base_uri
|
79
|
+
api_classes.each { |clazz| clazz.base_uri @base_uri }
|
80
|
+
end
|
81
|
+
|
82
|
+
# @private
|
83
|
+
def base_uri
|
84
|
+
@base_uri || "https://app.signalhq.com"
|
85
|
+
end
|
86
|
+
|
87
|
+
private
|
88
|
+
|
89
|
+
def api_classes
|
90
|
+
[ List, Segment, ShortUrl ]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
require "signal_api/core_ext/nil_class"
|
97
|
+
require "signal_api/core_ext/string"
|
98
|
+
require "signal_api/core_ext/array"
|
99
|
+
require "signal_api/core_ext/hash"
|
100
|
+
|
101
|
+
require "signal_api/util/phone"
|
102
|
+
require "signal_api/util/email_address"
|
103
|
+
|
104
|
+
require "signal_api/contact"
|
105
|
+
require "signal_api/exceptions"
|
106
|
+
require "signal_api/signal_http_api"
|
107
|
+
|
108
|
+
require "signal_api/deliver_sms"
|
109
|
+
require "signal_api/list"
|
110
|
+
require "signal_api/segment"
|
111
|
+
require "signal_api/short_url"
|
112
|
+
require "signal_api/coupon_group"
|
113
|
+
require "signal_api/carrier"
|
114
|
+
|
data/signal_api.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/signal_api/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["John Wood"]
|
6
|
+
gem.email = ["john@signalhq.com"]
|
7
|
+
gem.description = %q{Ruby implementation of the Signal API}
|
8
|
+
gem.summary = %q{Ruby implementation of the Signal API}
|
9
|
+
gem.homepage = "http://dev.signalhq.com"
|
10
|
+
|
11
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
12
|
+
gem.files = `git ls-files`.split("\n")
|
13
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
|
+
gem.name = "signal_api"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = SignalApi::VERSION
|
17
|
+
|
18
|
+
gem.add_dependency('httparty', '~> 0.8.1')
|
19
|
+
gem.add_dependency('builder', '~> 3.0.0')
|
20
|
+
|
21
|
+
gem.add_development_dependency('fakeweb', '~> 1.3.0')
|
22
|
+
gem.add_development_dependency('shoulda', '~> 3.0.1')
|
23
|
+
gem.add_development_dependency('rake', '~> 0.9.2.2')
|
24
|
+
gem.add_development_dependency('yard', '~> 0.7.5')
|
25
|
+
gem.add_development_dependency('bluecloth', '~> 2.2.0')
|
26
|
+
gem.add_development_dependency('mocha', '~> 0.10.5')
|
27
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class CarrierTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
SignalApi.api_key = 'foobar'
|
7
|
+
FakeWeb.allow_net_connect = false
|
8
|
+
end
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
FakeWeb.clean_registry
|
12
|
+
FakeWeb.allow_net_connect = true
|
13
|
+
end
|
14
|
+
|
15
|
+
should "be able to lookup a valid carrier" do
|
16
|
+
body = <<-END
|
17
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
18
|
+
<carrier>
|
19
|
+
<name>AT&T</name>
|
20
|
+
<id type="integer">6</id>
|
21
|
+
</carrier>
|
22
|
+
END
|
23
|
+
|
24
|
+
FakeWeb.register_uri(:get, SignalApi.base_uri + '/app/carriers/lookup/3125551212.xml', :content_type => 'application/xml', :status => ['200', 'Ok'], :body => body)
|
25
|
+
carrier = SignalApi::Carrier.lookup('3125551212')
|
26
|
+
assert_equal 6, carrier.id
|
27
|
+
assert_equal "AT&T", carrier.name
|
28
|
+
end
|
29
|
+
|
30
|
+
should "should throw exceptions for missing params" do
|
31
|
+
assert_raise SignalApi::InvalidParameterException do
|
32
|
+
SignalApi::Carrier.lookup(nil)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
should "show throw and exception for mobile not found" do
|
37
|
+
FakeWeb.register_uri(:get, SignalApi.base_uri + '/app/carriers/lookup/3125551212.xml', :content_type => 'application/xml', :status => '404')
|
38
|
+
assert_raise SignalApi::InvalidMobilePhoneException do
|
39
|
+
SignalApi::Carrier.lookup('3125551212')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|