nexmo 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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