nexmo 0.5.0 → 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.
- data/README.md +28 -23
- data/lib/nexmo.rb +29 -43
- data/nexmo.gemspec +9 -3
- data/spec/nexmo_spec.rb +43 -55
- metadata +23 -7
data/README.md
CHANGED
@@ -2,50 +2,55 @@ A simple wrapper for the [Nexmo](http://nexmo.com/) API
|
|
2
2
|
=======================================================
|
3
3
|
|
4
4
|
|
5
|
-
Requirements
|
6
|
-
------------
|
7
|
-
|
8
|
-
Ruby 1.9; Ruby 1.8 is not currently supported.
|
9
|
-
|
10
|
-
|
11
5
|
Installation
|
12
6
|
------------
|
13
7
|
|
14
|
-
gem install nexmo
|
8
|
+
$ gem install nexmo
|
15
9
|
|
16
10
|
|
17
11
|
Quick Start
|
18
12
|
-----------
|
19
13
|
|
14
|
+
Use the `send_message!` for a "fire and forget" approach to sending a message:
|
15
|
+
|
20
16
|
```ruby
|
21
17
|
require 'nexmo'
|
22
18
|
|
23
19
|
nexmo = Nexmo::Client.new('...API KEY...', '...API SECRET...')
|
24
20
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
21
|
+
nexmo.send_message!({:to => '...NUMBER...', :from => 'Ruby', :text => 'Hello world'})
|
22
|
+
```
|
23
|
+
|
24
|
+
This method call returns the message id if the message was sent successfully,
|
25
|
+
or raises an exception if there was an error. For more robust error handling
|
26
|
+
use the `send_message` method instead. This returns the HTTP response wrapped
|
27
|
+
in a `Nexmo::Response` object.
|
28
|
+
|
29
|
+
|
30
|
+
JSON Implementation
|
31
|
+
-------------------
|
32
|
+
|
33
|
+
The "json" library is used by default. This is available in the Ruby 1.9
|
34
|
+
standard library, and as a gem for Ruby 1.8. You can specify an alternate
|
35
|
+
implementation that you wish to use explicitly when constructing a client
|
36
|
+
object. For example, to use [multi_json](https://rubygems.org/gems/multi_json):
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
require 'nexmo'
|
40
|
+
require 'multi_json'
|
41
|
+
|
42
|
+
nexmo = Nexmo::Client.new('...API KEY...', '...API SECRET...', :json => MultiJson)
|
36
43
|
```
|
37
44
|
|
45
|
+
Ditto for anything that is compatible with the default implementation.
|
46
|
+
|
38
47
|
|
39
48
|
Troubleshooting
|
40
49
|
---------------
|
41
50
|
|
42
|
-
|
51
|
+
Remember that phone numbers should be specified in international format.
|
43
52
|
|
44
53
|
The Nexmo documentation contains a [list of error codes](http://nexmo.com/documentation/index.html#response_code)
|
45
54
|
which may be useful if you have problems sending a message.
|
46
55
|
|
47
|
-
|
48
|
-
Bugs/Issues
|
49
|
-
-----------
|
50
|
-
|
51
56
|
Please report all bugs/issues via the GitHub issue tracker.
|
data/lib/nexmo.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'net/http'
|
2
|
+
require 'net/https' if RUBY_VERSION == '1.8.7'
|
2
3
|
require 'json'
|
3
|
-
require 'uri'
|
4
4
|
require 'cgi'
|
5
5
|
|
6
6
|
module Nexmo
|
@@ -10,34 +10,32 @@ module Nexmo
|
|
10
10
|
|
11
11
|
@json = options.fetch(:json) { JSON }
|
12
12
|
|
13
|
-
@
|
14
|
-
|
15
|
-
@http = Net::HTTP.new('rest.nexmo.com', 443)
|
13
|
+
@http = Net::HTTP.new('rest.nexmo.com', Net::HTTP.https_default_port)
|
16
14
|
|
17
15
|
@http.use_ssl = true
|
18
16
|
end
|
19
17
|
|
20
|
-
attr_accessor :key, :secret, :http
|
18
|
+
attr_accessor :key, :secret, :http
|
19
|
+
|
20
|
+
def send_message(params)
|
21
|
+
post('/sms/json', params)
|
22
|
+
end
|
21
23
|
|
22
|
-
def send_message(
|
23
|
-
response =
|
24
|
+
def send_message!(params)
|
25
|
+
response = send_message(params)
|
24
26
|
|
25
|
-
if response.
|
26
|
-
|
27
|
+
if response.ok? && response.json?
|
28
|
+
item = response.object['messages'].first
|
27
29
|
|
28
|
-
status =
|
30
|
+
status = item['status'].to_i
|
29
31
|
|
30
32
|
if status == 0
|
31
|
-
|
33
|
+
item['message-id']
|
32
34
|
else
|
33
|
-
|
34
|
-
|
35
|
-
Failure.new(error, response, status)
|
35
|
+
raise Error, "#{item['error-text']} (status=#{status})"
|
36
36
|
end
|
37
37
|
else
|
38
|
-
|
39
|
-
|
40
|
-
Failure.new(error, response)
|
38
|
+
raise Error, "Unexpected HTTP response (code=#{response.code})"
|
41
39
|
end
|
42
40
|
end
|
43
41
|
|
@@ -70,17 +68,21 @@ module Nexmo
|
|
70
68
|
end
|
71
69
|
|
72
70
|
def search_messages(params)
|
73
|
-
get("/search/messages/#{key}/#{secret}", Hash === params ? params : {ids
|
71
|
+
get("/search/messages/#{key}/#{secret}", Hash === params ? params : {:ids => Array(params)})
|
74
72
|
end
|
75
73
|
|
76
74
|
private
|
77
75
|
|
78
76
|
def get(path, params = {})
|
79
|
-
Response.new(@http.get(request_uri(path, params)), json
|
77
|
+
Response.new(@http.get(request_uri(path, params)), :json => @json)
|
80
78
|
end
|
81
79
|
|
82
|
-
def
|
83
|
-
|
80
|
+
def post(path, params)
|
81
|
+
Response.new(@http.post(path, encode(params), {'Content-Type' => 'application/json'}), :json => @json)
|
82
|
+
end
|
83
|
+
|
84
|
+
def encode(params)
|
85
|
+
JSON.dump(params.merge(:username => @key, :password => @secret))
|
84
86
|
end
|
85
87
|
|
86
88
|
def request_uri(path, hash = {})
|
@@ -91,7 +93,7 @@ module Nexmo
|
|
91
93
|
Array(values).map { |value| "#{escape(key)}=#{escape(value)}" }
|
92
94
|
end
|
93
95
|
|
94
|
-
path + '?' + query_params.flatten.join(
|
96
|
+
path + '?' + query_params.flatten.join('&')
|
95
97
|
end
|
96
98
|
end
|
97
99
|
|
@@ -107,6 +109,10 @@ module Nexmo
|
|
107
109
|
@json = options.fetch(:json) { JSON }
|
108
110
|
end
|
109
111
|
|
112
|
+
def respond_to_missing?(name, include_private = false)
|
113
|
+
@http_response.respond_to?(name)
|
114
|
+
end
|
115
|
+
|
110
116
|
def method_missing(name, *args, &block)
|
111
117
|
@http_response.send(name, *args, &block)
|
112
118
|
end
|
@@ -116,7 +122,7 @@ module Nexmo
|
|
116
122
|
end
|
117
123
|
|
118
124
|
def json?
|
119
|
-
self['Content-Type'].split(
|
125
|
+
self['Content-Type'].split(';').first == 'application/json'
|
120
126
|
end
|
121
127
|
|
122
128
|
def object
|
@@ -124,26 +130,6 @@ module Nexmo
|
|
124
130
|
end
|
125
131
|
end
|
126
132
|
|
127
|
-
class Success < Struct.new(:message_id)
|
128
|
-
def success?
|
129
|
-
true
|
130
|
-
end
|
131
|
-
|
132
|
-
def failure?
|
133
|
-
false
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
class Failure < Struct.new(:error, :http, :status)
|
138
|
-
def success?
|
139
|
-
false
|
140
|
-
end
|
141
|
-
|
142
|
-
def failure?
|
143
|
-
true
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
133
|
class Error < StandardError
|
148
134
|
end
|
149
135
|
end
|
data/nexmo.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'nexmo'
|
3
|
-
s.version = '0.
|
3
|
+
s.version = '1.0.0'
|
4
4
|
s.platform = Gem::Platform::RUBY
|
5
5
|
s.authors = ['Tim Craft']
|
6
6
|
s.email = ['mail@timcraft.com']
|
@@ -8,7 +8,13 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.description = 'A simple wrapper for the Nexmo API'
|
9
9
|
s.summary = 'See description'
|
10
10
|
s.files = Dir.glob('{lib,spec}/**/*') + %w(README.md nexmo.gemspec)
|
11
|
-
s.add_development_dependency('
|
12
|
-
s.add_development_dependency('
|
11
|
+
s.add_development_dependency('rake', '>= 0.9.3')
|
12
|
+
s.add_development_dependency('mocha', '~> 0.10.3')
|
13
|
+
s.add_development_dependency('multi_json', '~> 1.3.6')
|
13
14
|
s.require_path = 'lib'
|
15
|
+
|
16
|
+
if RUBY_VERSION == '1.8.7'
|
17
|
+
s.add_development_dependency('minitest', '>= 4.2.0')
|
18
|
+
s.add_development_dependency('json', '>= 1.6.5')
|
19
|
+
end
|
14
20
|
end
|
data/spec/nexmo_spec.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
require 'minitest/autorun'
|
2
2
|
require 'mocha'
|
3
|
-
require '
|
4
|
-
|
5
|
-
require_relative '../lib/nexmo'
|
3
|
+
require 'multi_json'
|
4
|
+
require 'nexmo'
|
6
5
|
|
7
6
|
describe 'Nexmo::Client' do
|
8
7
|
before do
|
@@ -16,67 +15,55 @@ describe 'Nexmo::Client' do
|
|
16
15
|
end
|
17
16
|
end
|
18
17
|
|
19
|
-
describe 'headers method' do
|
20
|
-
it 'returns a hash' do
|
21
|
-
@client.headers.must_be_kind_of(Hash)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
18
|
describe 'send_message method' do
|
26
|
-
it 'posts to the sms resource' do
|
27
|
-
|
28
|
-
http_response.expects(:[]).with('Content-Type').returns('application/json;charset=utf-8')
|
19
|
+
it 'posts to the sms json resource and returns a response object' do
|
20
|
+
data = regexp_matches(/\{".+?":".+?"(,".+?":".+?")+\}/)
|
29
21
|
|
30
|
-
|
22
|
+
headers = has_entry('Content-Type', 'application/json')
|
31
23
|
|
32
|
-
|
24
|
+
params = {:from => 'ruby', :to => 'number', :text => 'Hey!'}
|
33
25
|
|
34
|
-
@client.http.expects(:post).with('/sms/json', data, headers).returns(
|
26
|
+
@client.http.expects(:post).with('/sms/json', data, headers).returns(stub)
|
35
27
|
|
36
|
-
@client.send_message(
|
28
|
+
@client.send_message(params).must_be_instance_of(Nexmo::Response)
|
37
29
|
end
|
30
|
+
end
|
38
31
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
http_response.expects(:[]).with('Content-Type').returns('application/json;charset=utf-8')
|
43
|
-
|
44
|
-
@client.http.stubs(:post).returns(http_response)
|
32
|
+
describe 'send_message bang method' do
|
33
|
+
before do
|
34
|
+
@params = {:from => 'ruby', :to => 'number', :text => 'Hey!'}
|
45
35
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
response.message_id.must_equal('id')
|
50
|
-
end
|
36
|
+
@http_response = mock()
|
37
|
+
@http_response.stubs(:[]).with('Content-Type').returns('application/json;charset=utf-8')
|
38
|
+
@http_response.stubs(:code).returns('200')
|
51
39
|
end
|
52
40
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
41
|
+
it 'posts to the sms json resource and returns the message id' do
|
42
|
+
data = regexp_matches(/\{".+?":".+?"(,".+?":".+?")+\}/)
|
43
|
+
|
44
|
+
headers = has_entry('Content-Type', 'application/json')
|
45
|
+
|
46
|
+
@http_response.stubs(:body).returns('{"messages":[{"status":0,"message-id":"id"}]}')
|
47
|
+
|
48
|
+
@client.http.expects(:post).with('/sms/json', data, headers).returns(@http_response)
|
49
|
+
|
50
|
+
@client.send_message!(@params).must_equal('id')
|
51
|
+
end
|
57
52
|
|
58
|
-
|
53
|
+
it 'raises an exception if the response code is not expected' do
|
54
|
+
@http_response.stubs(:code).returns('500')
|
59
55
|
|
60
|
-
|
56
|
+
@client.http.stubs(:post).returns(@http_response)
|
61
57
|
|
62
|
-
|
63
|
-
response.failure?.must_equal(true)
|
64
|
-
response.error.to_s.must_equal('Missing from param (status=2)')
|
65
|
-
response.http.wont_be_nil
|
66
|
-
end
|
58
|
+
proc { @client.send_message!(@params) }.must_raise(Nexmo::Error)
|
67
59
|
end
|
68
60
|
|
69
|
-
|
70
|
-
|
71
|
-
@client.http.stubs(:post).returns(stub(code: '503'))
|
61
|
+
it 'raises an exception if the response body contains an error' do
|
62
|
+
@http_response.stubs(:body).returns('{"messages":[{"status":2,"error-text":"Missing from param"}]}')
|
72
63
|
|
73
|
-
|
64
|
+
@client.http.stubs(:post).returns(@http_response)
|
74
65
|
|
75
|
-
|
76
|
-
response.failure?.must_equal(true)
|
77
|
-
response.error.to_s.must_equal('Unexpected HTTP response (code=503)')
|
78
|
-
response.http.wont_be_nil
|
79
|
-
end
|
66
|
+
proc { @client.send_message!(@params) }.must_raise(Nexmo::Error)
|
80
67
|
end
|
81
68
|
end
|
82
69
|
|
@@ -106,9 +93,9 @@ describe 'Nexmo::Client' do
|
|
106
93
|
|
107
94
|
describe 'get_account_numbers method' do
|
108
95
|
it 'fetches the account numbers resource with the given parameters and returns a response object' do
|
109
|
-
@client.http.expects(:get).with('/account/numbers/key/secret?size=25&pattern=33').returns(stub)
|
96
|
+
@client.http.expects(:get).with(has_equivalent_query_string('/account/numbers/key/secret?size=25&pattern=33')).returns(stub)
|
110
97
|
|
111
|
-
@client.get_account_numbers(size
|
98
|
+
@client.get_account_numbers(:size => 25, :pattern => 33).must_be_instance_of(Nexmo::Response)
|
112
99
|
end
|
113
100
|
end
|
114
101
|
|
@@ -116,7 +103,7 @@ describe 'Nexmo::Client' do
|
|
116
103
|
it 'fetches the number search resource for the given country with the given parameters and returns a response object' do
|
117
104
|
@client.http.expects(:get).with('/number/search/key/secret/CA?size=25').returns(stub)
|
118
105
|
|
119
|
-
@client.number_search(:CA, size
|
106
|
+
@client.number_search(:CA, :size => 25).must_be_instance_of(Nexmo::Response)
|
120
107
|
end
|
121
108
|
end
|
122
109
|
|
@@ -132,19 +119,19 @@ describe 'Nexmo::Client' do
|
|
132
119
|
it 'fetches the message rejections resource with the given parameters and returns a response object' do
|
133
120
|
@client.http.expects(:get).with('/search/rejections/key/secret?date=YYYY-MM-DD').returns(stub)
|
134
121
|
|
135
|
-
@client.get_message_rejections(date
|
122
|
+
@client.get_message_rejections(:date => 'YYYY-MM-DD').must_be_instance_of(Nexmo::Response)
|
136
123
|
end
|
137
124
|
end
|
138
125
|
|
139
126
|
describe 'search_messages method' do
|
140
127
|
it 'fetches the search messages resource with the given parameters and returns a response object' do
|
141
|
-
@client.http.expects(:get).with('/search/messages/key/secret?date=YYYY-MM-DD&to=1234567890').returns(stub)
|
128
|
+
@client.http.expects(:get).with(has_equivalent_query_string('/search/messages/key/secret?date=YYYY-MM-DD&to=1234567890')).returns(stub)
|
142
129
|
|
143
|
-
@client.search_messages(date
|
130
|
+
@client.search_messages(:date => 'YYYY-MM-DD', :to => 1234567890).must_be_instance_of(Nexmo::Response)
|
144
131
|
end
|
145
132
|
|
146
133
|
it 'should encode a non hash argument as a list of ids' do
|
147
|
-
@client.http.expects(:get).with('/search/messages/key/secret?ids=id1&ids=id2').returns(stub)
|
134
|
+
@client.http.expects(:get).with(has_equivalent_query_string('/search/messages/key/secret?ids=id1&ids=id2')).returns(stub)
|
148
135
|
|
149
136
|
@client.search_messages(%w(id1 id2))
|
150
137
|
end
|
@@ -161,6 +148,7 @@ describe 'Nexmo::Response' do
|
|
161
148
|
it 'delegates to the underlying http response' do
|
162
149
|
@http_response.expects(:code).returns('200')
|
163
150
|
|
151
|
+
@response.must_respond_to(:code) unless RUBY_VERSION == '1.8.7'
|
164
152
|
@response.code.must_equal('200')
|
165
153
|
end
|
166
154
|
|
@@ -205,7 +193,7 @@ describe 'Nexmo::Response initialized with a different json implementation' do
|
|
205
193
|
before do
|
206
194
|
@http_response = mock()
|
207
195
|
|
208
|
-
@response = Nexmo::Response.new(@http_response, json
|
196
|
+
@response = Nexmo::Response.new(@http_response, :json => MultiJson)
|
209
197
|
end
|
210
198
|
|
211
199
|
describe 'object method' do
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nexmo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-11-
|
12
|
+
date: 2012-11-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.9.3
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.9.3
|
14
30
|
- !ruby/object:Gem::Dependency
|
15
31
|
name: mocha
|
16
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -18,7 +34,7 @@ dependencies:
|
|
18
34
|
requirements:
|
19
35
|
- - ~>
|
20
36
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.
|
37
|
+
version: 0.10.3
|
22
38
|
type: :development
|
23
39
|
prerelease: false
|
24
40
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,15 +42,15 @@ dependencies:
|
|
26
42
|
requirements:
|
27
43
|
- - ~>
|
28
44
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.
|
45
|
+
version: 0.10.3
|
30
46
|
- !ruby/object:Gem::Dependency
|
31
|
-
name:
|
47
|
+
name: multi_json
|
32
48
|
requirement: !ruby/object:Gem::Requirement
|
33
49
|
none: false
|
34
50
|
requirements:
|
35
51
|
- - ~>
|
36
52
|
- !ruby/object:Gem::Version
|
37
|
-
version: 1.3.
|
53
|
+
version: 1.3.6
|
38
54
|
type: :development
|
39
55
|
prerelease: false
|
40
56
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -42,7 +58,7 @@ dependencies:
|
|
42
58
|
requirements:
|
43
59
|
- - ~>
|
44
60
|
- !ruby/object:Gem::Version
|
45
|
-
version: 1.3.
|
61
|
+
version: 1.3.6
|
46
62
|
description: A simple wrapper for the Nexmo API
|
47
63
|
email:
|
48
64
|
- mail@timcraft.com
|