nexmo 0.4.0 → 0.5.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.
Files changed (5) hide show
  1. data/README.md +1 -1
  2. data/lib/nexmo.rb +43 -37
  3. data/nexmo.gemspec +3 -3
  4. data/spec/nexmo_spec.rb +27 -32
  5. metadata +11 -11
data/README.md CHANGED
@@ -41,7 +41,7 @@ Troubleshooting
41
41
 
42
42
  Phone numbers should be specified in international format.
43
43
 
44
- The Nexmo documentation contains a [list of error codes](http://nexmo.com/documentation/index.html#dlr_error)
44
+ The Nexmo documentation contains a [list of error codes](http://nexmo.com/documentation/index.html#response_code)
45
45
  which may be useful if you have problems sending a message.
46
46
 
47
47
 
@@ -1,13 +1,15 @@
1
1
  require 'net/http'
2
- require 'net/https'
3
2
  require 'json'
4
3
  require 'uri'
4
+ require 'cgi'
5
5
 
6
6
  module Nexmo
7
7
  class Client
8
- def initialize(key, secret)
8
+ def initialize(key, secret, options = {})
9
9
  @key, @secret = key, secret
10
10
 
11
+ @json = options.fetch(:json) { JSON }
12
+
11
13
  @headers = {'Content-Type' => 'application/x-www-form-urlencoded'}
12
14
 
13
15
  @http = Net::HTTP.new('rest.nexmo.com', 443)
@@ -20,22 +22,22 @@ module Nexmo
20
22
  def send_message(data)
21
23
  response = @http.post('/sms/json', encode(data), headers)
22
24
 
23
- if ok?(response) && json?(response)
24
- object = JSON.parse(response.body)['messages'].first
25
+ if response.code.to_i == 200 && response['Content-Type'].split(?;).first == 'application/json'
26
+ object = @json.load(response.body)['messages'].first
25
27
 
26
28
  status = object['status'].to_i
27
29
 
28
30
  if status == 0
29
- Object.new(:message_id => object['message-id'], :success? => true, :failure? => false)
31
+ Success.new(object['message-id'])
30
32
  else
31
33
  error = Error.new("#{object['error-text']} (status=#{status})")
32
34
 
33
- Object.new(:error => error, :http => response, :status => status, :success? => false, :failure? => true)
35
+ Failure.new(error, response, status)
34
36
  end
35
37
  else
36
38
  error = Error.new("Unexpected HTTP response (code=#{response.code})")
37
39
 
38
- Object.new(:error => error, :http => response, :success? => false, :failure? => true)
40
+ Failure.new(error, response)
39
41
  end
40
42
  end
41
43
 
@@ -67,28 +69,42 @@ module Nexmo
67
69
  get("/search/rejections/#{key}/#{secret}", params)
68
70
  end
69
71
 
72
+ def search_messages(params)
73
+ get("/search/messages/#{key}/#{secret}", Hash === params ? params : {ids: Array(params)})
74
+ end
75
+
70
76
  private
71
77
 
72
78
  def get(path, params = {})
73
- Response.new(@http.get(params.empty? ? path : "#{path}?#{URI.encode_www_form(params)}"))
79
+ Response.new(@http.get(request_uri(path, params)), json: @json)
74
80
  end
75
81
 
76
- def ok?(response)
77
- response.code.to_i == 200
82
+ def encode(data)
83
+ URI.encode_www_form data.merge(:username => @key, :password => @secret)
78
84
  end
79
85
 
80
- def json?(response)
81
- response['Content-Type'].split(?;).first == 'application/json'
86
+ def request_uri(path, hash = {})
87
+ if hash.empty?
88
+ path
89
+ else
90
+ query_params = hash.map do |key, values|
91
+ Array(values).map { |value| "#{escape(key)}=#{escape(value)}" }
92
+ end
93
+
94
+ path + '?' + query_params.flatten.join(?&)
95
+ end
82
96
  end
83
97
 
84
- def encode(data)
85
- URI.encode_www_form data.merge(:username => @key, :password => @secret)
98
+ def escape(component)
99
+ CGI.escape(component.to_s)
86
100
  end
87
101
  end
88
102
 
89
103
  class Response
90
- def initialize(http_response)
104
+ def initialize(http_response, options = {})
91
105
  @http_response = http_response
106
+
107
+ @json = options.fetch(:json) { JSON }
92
108
  end
93
109
 
94
110
  def method_missing(name, *args, &block)
@@ -104,37 +120,27 @@ module Nexmo
104
120
  end
105
121
 
106
122
  def object
107
- JSON.parse(body, object_class: Object)
123
+ @object ||= @json.load(body)
108
124
  end
109
125
  end
110
126
 
111
- class Object
112
- def initialize(attributes = {})
113
- @attributes = attributes.to_hash
114
- end
115
-
116
- def [](name)
117
- @attributes[name]
118
- end
119
-
120
- def []=(name, value)
121
- @attributes[name.to_s.tr(?-, ?_).to_sym] = value
127
+ class Success < Struct.new(:message_id)
128
+ def success?
129
+ true
122
130
  end
123
131
 
124
- def to_hash
125
- @attributes
132
+ def failure?
133
+ false
126
134
  end
135
+ end
127
136
 
128
- def respond_to_missing?(name, include_private = false)
129
- @attributes.has_key?(name)
137
+ class Failure < Struct.new(:error, :http, :status)
138
+ def success?
139
+ false
130
140
  end
131
141
 
132
- def method_missing(name, *args, &block)
133
- if @attributes.has_key?(name) && args.empty? && block.nil?
134
- @attributes[name]
135
- else
136
- super name, *args, &block
137
- end
142
+ def failure?
143
+ true
138
144
  end
139
145
  end
140
146
 
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'nexmo'
3
- s.version = '0.4.0'
3
+ s.version = '0.5.0'
4
4
  s.platform = Gem::Platform::RUBY
5
5
  s.authors = ['Tim Craft']
6
6
  s.email = ['mail@timcraft.com']
@@ -8,7 +8,7 @@ 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_dependency('json', ['~> 1.5'])
12
- s.add_development_dependency('mocha')
11
+ s.add_development_dependency('mocha', '~> 0.9.12')
12
+ s.add_development_dependency('oj', '~> 1.3.7')
13
13
  s.require_path = 'lib'
14
14
  end
@@ -1,9 +1,10 @@
1
1
  require 'minitest/autorun'
2
2
  require 'mocha'
3
+ require 'oj'
3
4
 
4
5
  require_relative '../lib/nexmo'
5
6
 
6
- describe Nexmo::Client do
7
+ describe 'Nexmo::Client' do
7
8
  before do
8
9
  @client = Nexmo::Client.new('key', 'secret')
9
10
  end
@@ -134,9 +135,23 @@ describe Nexmo::Client do
134
135
  @client.get_message_rejections(date: 'YYYY-MM-DD').must_be_instance_of(Nexmo::Response)
135
136
  end
136
137
  end
138
+
139
+ describe 'search_messages method' do
140
+ 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)
142
+
143
+ @client.search_messages(date: 'YYYY-MM-DD', to: 1234567890).must_be_instance_of(Nexmo::Response)
144
+ end
145
+
146
+ 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)
148
+
149
+ @client.search_messages(%w(id1 id2))
150
+ end
151
+ end
137
152
  end
138
153
 
139
- describe Nexmo::Response do
154
+ describe 'Nexmo::Response' do
140
155
  before do
141
156
  @http_response = mock()
142
157
 
@@ -178,46 +193,26 @@ describe Nexmo::Response do
178
193
  end
179
194
 
180
195
  describe 'object method' do
181
- it 'decodes the response body as json and returns an object' do
182
- @http_response.expects(:body).returns('{}')
196
+ it 'decodes the response body as json and returns a hash' do
197
+ @http_response.expects(:body).returns('{"value":0.0}')
183
198
 
184
- @response.object.must_be_instance_of(Nexmo::Object)
199
+ @response.object.must_equal({'value' => 0})
185
200
  end
186
201
  end
187
202
  end
188
203
 
189
- describe Nexmo::Object do
204
+ describe 'Nexmo::Response initialized with a different json implementation' do
190
205
  before do
191
- @value = 'xxx'
192
-
193
- @object = Nexmo::Object.new(message_id: @value)
194
- end
206
+ @http_response = mock()
195
207
 
196
- it 'provides method access for attributes passed to the constructor' do
197
- @object.message_id.must_equal(@value)
208
+ @response = Nexmo::Response.new(@http_response, json: Oj)
198
209
  end
199
210
 
200
- describe 'square brackets method' do
201
- it 'returns the value of the given attribute' do
202
- @object[:message_id].must_equal(@value)
203
- end
204
- end
205
-
206
- describe 'square brackets equals method' do
207
- it 'sets the value of the given attribute' do
208
- @object['message_id'] = 'abc'
209
- @object.message_id.wont_equal(@value)
210
- end
211
-
212
- it 'replaces dashes in keys with underscores' do
213
- @object['message-id'] = 'abc'
214
- @object.message_id.wont_equal(@value)
215
- end
216
- end
211
+ describe 'object method' do
212
+ it 'decodes the response body as json and returns a hash' do
213
+ @http_response.expects(:body).returns('{"value":0.0}')
217
214
 
218
- describe 'to_hash method' do
219
- it 'returns a hash containing the object attributes' do
220
- @object.to_hash.must_equal({message_id: @value})
215
+ @response.object.must_equal({'value' => 0})
221
216
  end
222
217
  end
223
218
  end
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.0
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,40 +9,40 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-06 00:00:00.000000000 Z
12
+ date: 2012-11-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: json
15
+ name: mocha
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: '1.5'
22
- type: :runtime
21
+ version: 0.9.12
22
+ type: :development
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  none: false
26
26
  requirements:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
- version: '1.5'
29
+ version: 0.9.12
30
30
  - !ruby/object:Gem::Dependency
31
- name: mocha
31
+ name: oj
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  none: false
34
34
  requirements:
35
- - - ! '>='
35
+ - - ~>
36
36
  - !ruby/object:Gem::Version
37
- version: '0'
37
+ version: 1.3.7
38
38
  type: :development
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
41
41
  none: false
42
42
  requirements:
43
- - - ! '>='
43
+ - - ~>
44
44
  - !ruby/object:Gem::Version
45
- version: '0'
45
+ version: 1.3.7
46
46
  description: A simple wrapper for the Nexmo API
47
47
  email:
48
48
  - mail@timcraft.com