nexmos 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .idea
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use 1.9.3@nexmos --create
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 1.9.2
5
+ - ruby-head
6
+ - jruby-19mode # JRuby in 1.9 mode
7
+ - rbx-19mode
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in nexmo-client.gemspec
4
+ gemspec
5
+ group :development, :test do
6
+ gem 'pry'
7
+ gem 'rake'
8
+ gem 'webmock'
9
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Alexander Simonov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,67 @@
1
+ # Nexmos [![Build Status](https://travis-ci.org/phenomena/nexmos.png)](https://travis-ci.org/phenomena/nexmos)[![Code Climate](https://codeclimate.com/github/phenomena/nexmos.png)](https://codeclimate.com/github/phenomena/nexmos)
2
+
3
+ Nexmo API wrapper
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'nexmos'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install nexmos
18
+
19
+ ## Usage
20
+
21
+ ### Send text message
22
+
23
+ ```ruby
24
+ # Nexmos specific client
25
+ client = ::Nexmos::Message.new('api-key', 'api-secret')
26
+ # get result from Nexmo
27
+ res = client.send_text(from: 'your number', to: '+1234567890', text: 'Hello world!')
28
+ # check if send is success
29
+ if res.success?
30
+ puts "ok"
31
+ else
32
+ puts "fail"
33
+ end
34
+ ```
35
+
36
+ ### Get balance
37
+
38
+ ```ruby
39
+ client = ::Nexmos::Account.new('api-key', 'api-secret')
40
+ res = client.get_balance
41
+ my_balance = res.value
42
+ ```
43
+
44
+ ## Rails integration
45
+
46
+ You can create `config/initializer/nexmos.rb` file with next content:
47
+
48
+ ```ruby
49
+ Nexmos.setup do |n|
50
+ n.api_key = 'api_key'
51
+ n.api_secret = 'api_secret'
52
+ end
53
+ ```
54
+
55
+ And then you can call all clients without providing key and secret.
56
+
57
+ ## More details about api calls
58
+
59
+ More details about api calls you can found in the lib/api.yml file.
60
+
61
+ ## Contributing
62
+
63
+ 1. Fork it
64
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
65
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
66
+ 4. Push to the branch (`git push origin my-new-feature`)
67
+ 5. Create new Pull Request
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,113 @@
1
+ :message:
2
+ :send_text:
3
+ :method: :get
4
+ :url: /sms/json
5
+ :required:
6
+ - from
7
+ - to
8
+ - text
9
+ :send_binary:
10
+ :method: :get
11
+ :url: /sms/json
12
+ :required:
13
+ - body
14
+ - udh
15
+ :params:
16
+ type: binary
17
+ :wap_push:
18
+ :method: :get
19
+ :url: /sms/json
20
+ :required:
21
+ - title
22
+ - url
23
+ :optional:
24
+ - validity
25
+ :params:
26
+ type: wappush
27
+ :search:
28
+ :message:
29
+ :method: :get
30
+ :url: /search/message
31
+ :required:
32
+ - id
33
+ :messages:
34
+ :method: :get
35
+ :url: /search/messages
36
+ :optional:
37
+ - ids
38
+ - date
39
+ - to
40
+ :rejections:
41
+ :method: :get
42
+ :url: /search/rejections
43
+ :required:
44
+ - date
45
+ :optional:
46
+ - to
47
+ :account:
48
+ :get_balance:
49
+ :method: :get
50
+ :url: /account/get-balance
51
+ :return: value
52
+ :get_pricing:
53
+ :method: :get
54
+ :url: /account/get-pricing/outbound
55
+ :required:
56
+ - country
57
+ :get_prefix_pricing:
58
+ :method: :get
59
+ :url: /account/get-prefix-pricing/outbound
60
+ :required:
61
+ - prefix
62
+ :settings:
63
+ :method: :post
64
+ :url: /account/settings
65
+ :optional:
66
+ - new_secret
67
+ - mo_call_back_url
68
+ - dr_call_back_url
69
+ :camelize: true
70
+ :get_numbers:
71
+ :method: :get
72
+ :url: /account/numbers
73
+ :optional:
74
+ - index
75
+ - size
76
+ - pattern
77
+ :top_up:
78
+ :method: :get
79
+ :url: /account/top-up
80
+ :required:
81
+ - trx
82
+ :number:
83
+ :search:
84
+ :method: :get
85
+ :url: /number/search
86
+ :required:
87
+ - country
88
+ :optional:
89
+ - pattern
90
+ - index
91
+ - size
92
+ :buy:
93
+ :method: :post
94
+ :url: /number/buy
95
+ :required:
96
+ - country
97
+ - msisdn
98
+ :cancel:
99
+ :method: :post
100
+ :url: /number/cancel
101
+ :required:
102
+ - country
103
+ - msisdn
104
+ :update:
105
+ :method: :post
106
+ :url: /number/update
107
+ :required:
108
+ - country
109
+ - msisdn
110
+ :optional:
111
+ - mo_http_url
112
+ - mo_smpp_sys_type
113
+ :camelize: true
@@ -0,0 +1,47 @@
1
+ require 'logger'
2
+ require 'active_support/core_ext/hash'
3
+ require 'faraday'
4
+ require 'faraday_middleware'
5
+ require 'nexmos/version'
6
+ require 'nexmos/base'
7
+ module Nexmos
8
+ extend self
9
+ attr_accessor :api_key, :api_secret, :debug
10
+ attr_writer :user_agent, :logger
11
+
12
+ # ensures the setup only gets run once
13
+ @_ran_once = false
14
+
15
+ def reset!
16
+ @logger = nil
17
+ @_ran_once = false
18
+ @user_agent = nil
19
+ @api_key = nil
20
+ @api_secret = nil
21
+ end
22
+
23
+ def user_agent
24
+ @user_agent ||= "Nexmos v#{::Nexmos::VERSION}"
25
+ end
26
+
27
+ def setup
28
+ yield self unless @_ran_once
29
+ @_ran_once = true
30
+ end
31
+
32
+ def logger
33
+ @logger ||= Logger.new(STDOUT)
34
+ end
35
+
36
+ def apis
37
+ @apis ||= YAML.load_file(File.expand_path('api.yml', File.dirname(__FILE__)))
38
+ end
39
+
40
+ reset!
41
+ end
42
+
43
+ require 'nexmos/railties' if defined?(::Rails)
44
+ require 'nexmos/account'
45
+ require 'nexmos/message'
46
+ require 'nexmos/number'
47
+ require 'nexmos/search'
@@ -0,0 +1,5 @@
1
+ module Nexmos
2
+ class Account < Base
3
+ self.define_api_calls(:account)
4
+ end
5
+ end
@@ -0,0 +1,103 @@
1
+ module Nexmos
2
+ class Base
3
+
4
+ def initialize(key = ::Nexmos.api_key, secret = ::Nexmos.api_secret)
5
+ raise 'api_key should be set' if !key.present?
6
+ raise 'api_secret should be set' if !secret.present?
7
+ @default_params = {
8
+ 'api_key' => key,
9
+ 'api_secret' => secret
10
+ }
11
+ end
12
+
13
+ def connection
14
+ self.class.connection.dup
15
+ end
16
+
17
+ def make_api_call(args, params = {})
18
+ normalize_params(params)
19
+ check_required_params(args, params)
20
+ camelize_params(params) if args[:camelize]
21
+ params.merge!(@default_params)
22
+ get_response(args, params)
23
+ end
24
+
25
+ def get_response(args, params)
26
+ method = args[:method]
27
+ url = args[:url]
28
+ raise 'url or method params missing' if !method.present? || !url.present?
29
+ res = connection.__send__(method, url, params)
30
+ if res.success?
31
+ data = if res.body.is_a?(::Hash)
32
+ res.body.merge(:success? => true)
33
+ else
34
+ ::Hashie::Mash.new({:success? => true})
35
+ end
36
+ return data
37
+ end
38
+ failed_res = ::Hashie::Mash.new({:success? => false, :not_authorized? => false, :failed? => false})
39
+ case res.status
40
+ when 401
41
+ failed_res.merge! :not_authorized? => true
42
+ when 420
43
+ failed_res.merge! :failed? => true
44
+ end
45
+ failed_res
46
+ end
47
+
48
+ def normalize_params(params)
49
+ params.stringify_keys!
50
+ end
51
+
52
+ def camelize_params(params)
53
+ if params.respond_to?(:transform_keys!)
54
+ params.transform_keys!{|key| key.camelize(:lower)}
55
+ else
56
+ params.keys.each do |key|
57
+ params[key.camelize(:lower)] = params.delete(key)
58
+ end
59
+ end
60
+ end
61
+
62
+ def check_required_params(args, params)
63
+ if args[:required]
64
+ required = params.slice(*args[:required])
65
+ unless required.keys.sort == args[:required].sort
66
+ missed = (args[:required] - required.keys).join(',')
67
+ raise ArgumentError, "#{missed} params required"
68
+ end
69
+ end
70
+ end
71
+
72
+ class << self
73
+
74
+ def define_api_calls(key)
75
+ ::Nexmos.apis[key].each do |k,v|
76
+ define_method(k) do |*args|
77
+ params = args[0] || {}
78
+ make_api_call(v, params)
79
+ end
80
+ end
81
+ end
82
+
83
+ def faraday_options
84
+ {
85
+ :url => 'https://rest.nexmo.com',
86
+ :headers => {
87
+ :accept => 'application/json',
88
+ :user_agent => ::Nexmos.user_agent
89
+ }
90
+ }
91
+ end
92
+
93
+ def connection
94
+ @connection ||= Faraday::Connection.new(faraday_options) do |conn|
95
+ conn.request :url_encoded
96
+ conn.response :rashify
97
+ conn.response :json, :content_type => /\bjson$/
98
+ conn.adapter Faraday.default_adapter
99
+ end
100
+ end
101
+ end # self
102
+ end # Base
103
+ end # Nexmos
@@ -0,0 +1,5 @@
1
+ module Nexmos
2
+ class Message < Base
3
+ self.define_api_calls(:message)
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Nexmos
2
+ class Number < Base
3
+ self.define_api_calls(:number)
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ module Nexmos
2
+ class Railties < ::Rails::Railtie
3
+ initializer 'Rails logger' do
4
+ ::Nexmos.logger = Rails.logger
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module Nexmos
2
+ class Search < Base
3
+ self.define_api_calls(:search)
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module Nexmos
2
+ VERSION = "0.1"
3
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'nexmos/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "nexmos"
8
+ gem.version = Nexmos::VERSION
9
+ gem.authors = ["Alexander Simonov"]
10
+ gem.email = ["alex@simonov.me"]
11
+ gem.description = %q{Nexmo API client}
12
+ gem.summary = %q{Nexmo API client}
13
+ gem.homepage = "https://github.com/simonoff/nexmos"
14
+ gem.files = `git ls-files`.split($/)
15
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
16
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
17
+ gem.require_paths = ["lib"]
18
+ gem.add_dependency('rash')
19
+ gem.add_dependency('faraday')
20
+ gem.add_dependency('faraday_middleware')
21
+ gem.add_dependency('activesupport', '>= 3.0.0')
22
+ gem.add_development_dependency('rspec')
23
+ gem.add_development_dependency('webmock')
24
+ end
@@ -0,0 +1,188 @@
1
+ require 'spec_helper'
2
+ describe ::Nexmos::Account do
3
+ let(:webmock_default_headers) do
4
+ {
5
+ :headers => {
6
+ 'Accept' => 'application/json',
7
+ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
8
+ 'User-Agent' => ::Nexmos.user_agent
9
+ }
10
+ }
11
+ end
12
+
13
+ let(:finland_prices) do
14
+ {
15
+ "mt" => "0.02500000",
16
+ "country" => "FI",
17
+ "prefix" => "358",
18
+ "networks" =>
19
+ [{"code" => "24491",
20
+ "network" => "sonera, TeleFinland",
21
+ "ranges" => ["35840", "35842", "358450"],
22
+ "mtPrice" => "0.04500000"},
23
+ {"code" => "24414",
24
+ "network" => "GSM Aland",
25
+ "ranges" => ["3584570", "3584573", "3584575"],
26
+ "mtPrice" => "0.00850000"},
27
+ {"code" => "24421",
28
+ "network" => "SAUNALAHTI, EUnet Finland",
29
+ "ranges" => ["358451", "358452", "358453", "358456", "358458"],
30
+ "mtPrice" => "0.05000000"},
31
+ {"code" => "24412",
32
+ "network" => "dna",
33
+ "ranges" =>
34
+ ["35841",
35
+ "35844",
36
+ "3584574",
37
+ "3584576",
38
+ "3584577",
39
+ "3584578",
40
+ "3584579",
41
+ "3584944"],
42
+ "mtPrice" => "0.00850000"},
43
+ {"code" => "24405",
44
+ "network" => "elisa",
45
+ "ranges" => ["35846", "35850"],
46
+ "mtPrice" => "0.05000000"}],
47
+ "name" => "Finland"
48
+ }
49
+ end
50
+
51
+ let(:prefix_prices) do
52
+ {"count" => 1,
53
+ "prices" =>
54
+ [{"mt" => "0.02500000",
55
+ "country" => "FI",
56
+ "prefix" => "358",
57
+ "networks" =>
58
+ [{"code" => "24491",
59
+ "network" => "sonera, TeleFinland",
60
+ "ranges" => nil,
61
+ "mt_price" => "0.04500000"},
62
+ {"code" => "24414",
63
+ "network" => "GSM Aland",
64
+ "ranges" => nil,
65
+ "mtPrice" => "0.00850000"},
66
+ {"code" => "24400",
67
+ "network" => "Unknown Finland",
68
+ "ranges" => nil,
69
+ "mtPrice" => "0.02500000"},
70
+ {"code" => "24421",
71
+ "network" => "SAUNALAHTI, EUnet Finland",
72
+ "ranges" => nil,
73
+ "mtPrice" => "0.05000000"},
74
+ {"code" => "24412",
75
+ "network" => "dna",
76
+ "ranges" => nil,
77
+ "mtPrice" => "0.00850000"},
78
+ {"code" => "24405",
79
+ "network" => "elisa",
80
+ "ranges" => nil,
81
+ "mtPrice" => "0.05000000"}],
82
+ "name" => "Finland"}],
83
+ }
84
+ end
85
+
86
+ before(:each) do
87
+ ::Nexmos.reset!
88
+ ::Nexmos.setup do |c|
89
+ c.api_key = 'default_key'
90
+ c.api_secret = 'default_secret'
91
+ end
92
+ end
93
+
94
+ subject { ::Nexmos::Account.new }
95
+
96
+ context '#get_balance' do
97
+
98
+ it 'should return value' do
99
+ request = stub_request(:get, "https://rest.nexmo.com/account/get-balance?api_key=default_key&api_secret=default_secret").
100
+ with(webmock_default_headers).to_return(:status => 200, :body => {"value" => 4.107}, :headers => {})
101
+ res = subject.get_balance
102
+ res.should be_kind_of(::Hash)
103
+ res.value.should == 4.107
104
+ request.should have_been_made.once
105
+ end
106
+ end
107
+
108
+ context '#get_pricing' do
109
+ it 'should return error on missed param' do
110
+ expect { subject.get_pricing }.to raise_error('country params required')
111
+ end
112
+
113
+ it 'should be success' do
114
+ request = stub_request(:get, "https://rest.nexmo.com/account/get-pricing/outbound?api_key=default_key&api_secret=default_secret&country=FI").
115
+ with(webmock_default_headers).to_return(:status => 200, :body => finland_prices, :headers => {})
116
+ res = subject.get_pricing(:country => 'FI')
117
+ res.should be_kind_of(::Hash)
118
+ res.success?.should be_true
119
+ res.country.should == 'FI'
120
+ res.keys.sort.should == %w(country name prefix mt networks success?).sort
121
+ res.networks.should be_kind_of(::Array)
122
+ res.networks[0].keys.sort.should == %w(code network mt_price ranges).sort
123
+ request.should have_been_made.once
124
+ end
125
+ end
126
+
127
+ context '#get_prefix_pricing' do
128
+ it 'should return error on missed param' do
129
+ expect { subject.get_prefix_pricing }.to raise_error('prefix params required')
130
+ end
131
+
132
+ it 'should be success' do
133
+ request = stub_request(:get, "https://rest.nexmo.com/account/get-prefix-pricing/outbound?api_key=default_key&api_secret=default_secret&prefix=358").
134
+ with(webmock_default_headers).to_return(:status => 200, :body => prefix_prices, :headers => {})
135
+ res = subject.get_prefix_pricing(:prefix => '358')
136
+ res.should be_kind_of(::Hash)
137
+ res.success?.should be_true
138
+ res.keys.sort.should == %w(count prices success?).sort
139
+ res.prices.should be_kind_of(::Array)
140
+ res.prices[0].keys.sort.should == %w(country name prefix mt networks).sort
141
+ res.prices[0].networks.should be_kind_of(::Array)
142
+ res.prices[0].networks[0].keys.sort.should == %w(code network mt_price ranges).sort
143
+ request.should have_been_made.once
144
+ end
145
+ end
146
+
147
+ context '#get_numbers' do
148
+ it 'should return only count on empty numbers' do
149
+ request = stub_request(:get, "https://rest.nexmo.com/account/numbers?api_key=default_key&api_secret=default_secret").
150
+ with(webmock_default_headers).to_return(:status => 200, :body => {:count => 0}, :headers => {})
151
+ res = subject.get_numbers
152
+ res.should be_kind_of(::Hash)
153
+ res.success?.should be_true
154
+ res['count'].should == 0
155
+ request.should have_been_made.once
156
+ end
157
+
158
+ it 'should return numbers array' do
159
+ request = stub_request(:get, "https://rest.nexmo.com/account/numbers?api_key=default_key&api_secret=default_secret").
160
+ with(webmock_default_headers).to_return(:status => 200, :body => { "count" => 1,"numbers" => [{"country" => "ES","msisdn" => "34911067000","type" => "landline"}]}, :headers => {})
161
+ res = subject.get_numbers
162
+ res.should be_kind_of(::Hash)
163
+ res.success?.should be_true
164
+ res['count'].should == 1
165
+ res['numbers'].should be_kind_of(::Array)
166
+ res['numbers'].first.should be_kind_of(::Hash)
167
+ res['numbers'].first.should == {"country" => "ES","msisdn" => "34911067000","type" => "landline"}
168
+ request.should have_been_made.once
169
+ end
170
+ end
171
+
172
+ context '#top_up' do
173
+ it 'should return error on missed param' do
174
+ expect { subject.top_up }.to raise_error('trx params required')
175
+ end
176
+
177
+ it 'should success top up' do
178
+ request = stub_request(:get, "https://rest.nexmo.com/account/top-up?api_key=default_key&api_secret=default_secret&trx=test_trx").
179
+ with(webmock_default_headers).to_return(:status => 200, :body => '', :headers => {})
180
+ res = subject.top_up :trx => 'test_trx'
181
+ res.should be_kind_of(::Hash)
182
+ res.success?.should be_true
183
+ request.should have_been_made.once
184
+ end
185
+
186
+ end
187
+
188
+ end
@@ -0,0 +1,203 @@
1
+ require 'spec_helper'
2
+ describe ::Nexmos::Base do
3
+
4
+ let(:webmock_default_headers) do
5
+ {
6
+ :headers => {
7
+ 'Accept'=>'application/json',
8
+ 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
9
+ 'User-Agent'=> ::Nexmos.user_agent
10
+ }
11
+ }
12
+ end
13
+
14
+ before(:each) do
15
+ ::Nexmos.reset!
16
+ end
17
+ context 'class' do
18
+ subject { ::Nexmos::Base }
19
+ let(:default_faraday_options) do
20
+ {
21
+ :url => 'https://rest.nexmo.com',
22
+ :headers => {
23
+ :accept => 'application/json',
24
+ :user_agent => ::Nexmos.user_agent
25
+ }
26
+ }
27
+ end
28
+
29
+ its(:faraday_options) { should == default_faraday_options }
30
+ its(:connection) { should be_kind_of(::Faraday::Connection) }
31
+
32
+ context 'faraday_options' do
33
+ it 'should have custom user agent' do
34
+ ::Nexmos.setup do |c|
35
+ c.user_agent = 'test user agent'
36
+ end
37
+ default_faraday_options[:headers][:user_agent] = 'test user agent'
38
+ subject.faraday_options.should == default_faraday_options
39
+ end
40
+ end
41
+
42
+ context 'define_api_calls' do
43
+ it 'should call define_method' do
44
+ ::Nexmos.apis[:account].keys.each do |k|
45
+ subject.should_receive(:define_method).with(k)
46
+ end
47
+ subject.define_api_calls(:account)
48
+ end
49
+
50
+ it 'should define dynamic method and call make_api_call inside' do
51
+ subject.define_api_calls(:account)
52
+ instance = subject.new('test_key', 'test_secret')
53
+ instance.should_receive(:make_api_call).with(::Nexmos.apis[:account][:get_balance], {})
54
+ instance.get_balance
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+ context 'instance' do
61
+ subject { ::Nexmos::Base.new('test_api', 'test_secret') }
62
+ context 'new' do
63
+ it 'should raise on empty api_key' do
64
+ expect {::Nexmos::Base.new('', 'test_secret')}.to raise_error('api_key should be set')
65
+ end
66
+ it 'should raise on empty api_secret' do
67
+ expect {::Nexmos::Base.new('test_key', '')}.to raise_error('api_secret should be set')
68
+ end
69
+ it 'should set default_params with values from ::Nexmos module' do
70
+ ::Nexmos.setup do |c|
71
+ c.api_key = 'default_key'
72
+ c.api_secret = 'default_secret'
73
+ end
74
+ instance = ::Nexmos::Base.new
75
+ instance.instance_variable_get('@default_params').should == {'api_key' => 'default_key', 'api_secret' => 'default_secret'}
76
+ end
77
+ it 'should set default_params with custom api key and secret' do
78
+ instance = ::Nexmos::Base.new('test_key', 'test_secret')
79
+ instance.instance_variable_get('@default_params').should == {'api_key' => 'test_key', 'api_secret' => 'test_secret'}
80
+ end
81
+ end
82
+
83
+ its(:connection) { should be_kind_of(::Faraday::Connection) }
84
+
85
+ context 'make_api_call' do
86
+
87
+ before(:each) do
88
+ stub_request(:get, "https://rest.nexmo.com/test/url?api_key=test_api&api_secret=test_secret").
89
+ with(:headers => {'Accept'=>'application/json', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'User-Agent'=> ::Nexmos.user_agent}).
90
+ to_return(:status => 200, :body => {'key' => 'value'}, :headers => {})
91
+ end
92
+
93
+ let(:api_params_without_required) do
94
+ {
95
+ :method => :get,
96
+ :url => '/test/url'
97
+ }
98
+ end
99
+
100
+ let(:api_params_with_required) do
101
+ {
102
+ :method => :get,
103
+ :url => '/test/url',
104
+ :required => %w(key1 key2)
105
+ }
106
+ end
107
+
108
+ it 'should call check_required_params' do
109
+ subject.should_receive(:check_required_params)
110
+ subject.make_api_call(api_params_with_required)
111
+ end
112
+
113
+ it 'should raise if all required params missing' do
114
+ expect{subject.make_api_call(api_params_with_required)}.to raise_error('key1,key2 params required')
115
+ end
116
+
117
+ it 'should raise if some required params missing' do
118
+ expect{subject.make_api_call(api_params_with_required,{:key1 => 'val'})}.to raise_error('key2 params required')
119
+ end
120
+
121
+ it 'should call normalize_params' do
122
+ subject.should_receive(:normalize_params).and_call_original
123
+ subject.make_api_call(api_params_without_required)
124
+ end
125
+
126
+ it 'should not call camelize_params' do
127
+ stub_request(:get, "https://rest.nexmo.com/test/url?api_key=test_api&api_secret=test_secret&test_call=value").
128
+ with(webmock_default_headers).
129
+ to_return(:status => 200, :body => {}, :headers => {})
130
+ subject.should_not_receive(:camelize_params)
131
+ subject.make_api_call(api_params_without_required, {'test_call' => 'value'})
132
+ end
133
+
134
+ it 'should call camelize_params' do
135
+ stub_request(:get, "https://rest.nexmo.com/test/url?api_key=test_api&api_secret=test_secret&testCall=value").
136
+ with(webmock_default_headers).
137
+ to_return(:status => 200, :body => {}, :headers => {})
138
+ subject.should_receive(:camelize_params).and_call_original
139
+ subject.make_api_call(api_params_without_required.merge(:camelize => true), {'test_call' => 'value'})
140
+ end
141
+
142
+ it 'should call get_response' do
143
+ stub_request(:get, "https://rest.nexmo.com/test/url?api_key=test_api&api_secret=test_secret").
144
+ with(webmock_default_headers).
145
+ to_return(:status => 200, :body => {}, :headers => {})
146
+ subject.should_receive(:get_response).and_call_original
147
+ subject.make_api_call(api_params_without_required)
148
+ end
149
+
150
+ it 'should return hash' do
151
+ subject.make_api_call(api_params_without_required).should be_a_kind_of(::Hash)
152
+ end
153
+
154
+ it 'should return Hashie::Mash' do
155
+ subject.make_api_call(api_params_without_required).should be_a_kind_of(::Hashie::Mash)
156
+ end
157
+
158
+ it 'should respond to success? method in result' do
159
+ subject.make_api_call(api_params_without_required).should respond_to(:success?)
160
+ end
161
+
162
+ it 'should have success? key in hash' do
163
+ subject.make_api_call(api_params_without_required)[:success?].should be
164
+ end
165
+
166
+ it 'should have success? == true' do
167
+ subject.make_api_call(api_params_without_required)[:success?].should be_true
168
+ end
169
+
170
+ it 'should have success? == false on response with status != 200' do
171
+ stub_request(:get, "https://rest.nexmo.com/test/url?api_key=test_api&api_secret=test_secret&testCall=value").
172
+ with(webmock_default_headers).
173
+ to_return(:status => 410, :body => {}, :headers => {})
174
+ res = subject.make_api_call(api_params_without_required.merge(:camelize => true), {'test_call' => 'value'})
175
+ res[:success?].should be_false
176
+ res[:failed?].should be_false
177
+ res[:not_authorized?].should be_false
178
+ end
179
+
180
+ it 'should have not_authorized? == true' do
181
+ stub_request(:get, "https://rest.nexmo.com/test/url?api_key=test_api&api_secret=test_secret&testCall=value").
182
+ with(webmock_default_headers).
183
+ to_return(:status => 401, :body => {}, :headers => {})
184
+ res = subject.make_api_call(api_params_without_required.merge(:camelize => true), {'test_call' => 'value'})
185
+ res[:success?].should be_false
186
+ res[:not_authorized?].should be_true
187
+ res[:failed?].should be_false
188
+ end
189
+
190
+ it 'should have failed? == true' do
191
+ stub_request(:get, "https://rest.nexmo.com/test/url?api_key=test_api&api_secret=test_secret&testCall=value").
192
+ with(webmock_default_headers).
193
+ to_return(:status => 420, :body => {}, :headers => {})
194
+ res = subject.make_api_call(api_params_without_required.merge(:camelize => true), {'test_call' => 'value'})
195
+ res[:success?].should be_false
196
+ res[:not_authorized?].should be_false
197
+ res[:failed?].should be_true
198
+ end
199
+
200
+ end
201
+
202
+ end
203
+ end
@@ -0,0 +1,113 @@
1
+ require 'spec_helper'
2
+ describe ::Nexmos::Number do
3
+ let(:webmock_default_headers) do
4
+ {
5
+ :headers => {
6
+ 'Accept' => 'application/json',
7
+ 'Accept-Encoding' => 'gzip;q=1.0,deflate;q=0.6,identity;q=0.3',
8
+ 'User-Agent' => ::Nexmos.user_agent
9
+ }
10
+ }
11
+ end
12
+
13
+ let(:finland_numbers_search) do
14
+ {"numbers" => [
15
+ {"type" => "mobile-lvn",
16
+ "msisdn" => "3584573950816",
17
+ "country" => "FI",
18
+ "cost" => "3.00"},
19
+ {"type" => "mobile-lvn",
20
+ "msisdn" => "3584573950815",
21
+ "country" => "FI",
22
+ "cost" => "3.00"},
23
+ {"type" => "mobile-lvn",
24
+ "msisdn" => "3584573950814",
25
+ "country" => "FI",
26
+ "cost" => "3.00"},
27
+ {"type" => "mobile-lvn",
28
+ "msisdn" => "3584573950813",
29
+ "country" => "FI",
30
+ "cost" => "3.00"},
31
+ {"type" => "mobile-lvn",
32
+ "msisdn" => "3584573950812",
33
+ "country" => "FI",
34
+ "cost" => "3.00"},
35
+ {"type" => "mobile-lvn",
36
+ "msisdn" => "3584573950806",
37
+ "country" => "FI",
38
+ "cost" => "3.00"},
39
+ {"type" => "mobile-lvn",
40
+ "msisdn" => "3584573950805",
41
+ "country" => "FI",
42
+ "cost" => "3.00"},
43
+ {"type" => "mobile-lvn",
44
+ "msisdn" => "3584573950804",
45
+ "country" => "FI",
46
+ "cost" => "3.00"},
47
+ {"type" => "mobile-lvn",
48
+ "msisdn" => "3584573950798",
49
+ "country" => "FI",
50
+ "cost" => "3.00"},
51
+ {"type" => "mobile-lvn",
52
+ "msisdn" => "3584573950796",
53
+ "country" => "FI",
54
+ "cost" => "3.00"}],
55
+ "count" => 22}
56
+ end
57
+
58
+ before(:each) do
59
+ ::Nexmos.reset!
60
+ ::Nexmos.setup do |c|
61
+ c.api_key = 'default_key'
62
+ c.api_secret = 'default_secret'
63
+ end
64
+ end
65
+
66
+ subject { ::Nexmos::Number.new }
67
+
68
+ context '#search' do
69
+ it 'should return error on missed param' do
70
+ expect { subject.search }.to raise_error('country params required')
71
+ end
72
+
73
+ it 'should return list of numbers' do
74
+ request = stub_request(:get, "https://rest.nexmo.com/number/search?api_key=default_key&api_secret=default_secret&country=FI").
75
+ with(webmock_default_headers).to_return(:status => 200, :body => finland_numbers_search, :headers => {})
76
+ res = subject.search(:country => 'FI')
77
+ res.should be_kind_of(::Hash)
78
+ res.success?.should be_true
79
+ res['count'].should == 22
80
+ res['numbers'].should be_kind_of(::Array)
81
+ res['numbers'].size.should == 10
82
+ res['numbers'].first.keys.sort.should == ["cost", "country", "msisdn", "type"]
83
+ request.should have_been_made.once
84
+ end
85
+ end
86
+
87
+ context '#buy' do
88
+ it 'should return error on missed params' do
89
+ expect { subject.buy }.to raise_error('country,msisdn params required')
90
+ end
91
+ it 'should return error on missed params' do
92
+ expect { subject.buy :country => 'FI' }.to raise_error('msisdn params required')
93
+ end
94
+
95
+ it 'should buy number' do
96
+ request = stub_request(:post, "https://rest.nexmo.com/number/buy").
97
+ with(
98
+ :headers => {'Accept'=>'application/json', 'Content-Type'=>'application/x-www-form-urlencoded', 'User-Agent'=> ::Nexmos.user_agent},
99
+ :body => {"api_key"=>"default_key", "api_secret"=>"default_secret", "country"=>"FI", "msisdn"=>"3584573950816"}
100
+ ).to_return(:status => 200, :body => "", :headers => {})
101
+ res = subject.buy(:country => 'FI', :msisdn => '3584573950816' )
102
+ res.should be_kind_of(::Hash)
103
+ res.success?.should be_true
104
+ request.should have_been_made.once
105
+ end
106
+
107
+ end
108
+
109
+ context '#cancel' do
110
+
111
+ end
112
+
113
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+ describe ::Nexmos do
3
+ subject{ ::Nexmos }
4
+
5
+ before(:each) do
6
+ subject.reset!
7
+ end
8
+
9
+ context '#reset!' do
10
+ its(:user_agent) { should == "Nexmos v#{::Nexmos::VERSION}" }
11
+ its(:api_key) { should be_nil }
12
+ its(:api_secret) { should be_nil }
13
+ its(:logger) { should be_kind_of(::Logger) }
14
+ end
15
+
16
+ context '#setup' do
17
+
18
+ context 'single call' do
19
+ it 'should set user_agent' do
20
+ subject.setup do |c|
21
+ c.user_agent = 'Test1245'
22
+ end
23
+ subject.user_agent.should == 'Test1245'
24
+ end
25
+
26
+ it 'should set logger' do
27
+ newlogger = ::Logger.new(STDERR)
28
+ subject.setup do |c|
29
+ c.logger = newlogger
30
+ end
31
+ subject.logger.should == newlogger
32
+ end
33
+
34
+ it 'should set api_key' do
35
+ subject.setup do |c|
36
+ c.api_key = 'test-api-key'
37
+ end
38
+ subject.api_key.should == 'test-api-key'
39
+ end
40
+
41
+ it 'should set api_secret' do
42
+ subject.setup do |c|
43
+ c.api_secret = 'test-api-secret'
44
+ end
45
+ subject.api_secret.should == 'test-api-secret'
46
+ end
47
+
48
+ end
49
+
50
+ context 'double call' do
51
+ it 'should not accept running setup more then once' do
52
+ subject.setup do |c|
53
+ c.api_key = 'test-api-key'
54
+ end
55
+ subject.setup do |c|
56
+ c.api_key = 'test-api-key2'
57
+ end
58
+ subject.api_key.should == 'test-api-key'
59
+ end
60
+ end
61
+ end
62
+
63
+ end
@@ -0,0 +1,21 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ require 'webmock'
8
+ require 'webmock/rspec'
9
+ require 'nexmos'
10
+
11
+ RSpec.configure do |config|
12
+ config.treat_symbols_as_metadata_keys_with_true_values = true
13
+ config.run_all_when_everything_filtered = true
14
+ config.filter_run :focus
15
+
16
+ # Run specs in random order to surface order dependencies. If you find an
17
+ # order dependency and want to debug it, you can fix the order by providing
18
+ # the seed, which is printed after each run.
19
+ # --seed 1234
20
+ config.order = 'random'
21
+ end
metadata ADDED
@@ -0,0 +1,169 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nexmos
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Alexander Simonov
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-02-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rash
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: faraday
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: faraday_middleware
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: activesupport
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: 3.0.0
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: 3.0.0
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: webmock
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ description: Nexmo API client
111
+ email:
112
+ - alex@simonov.me
113
+ executables: []
114
+ extensions: []
115
+ extra_rdoc_files: []
116
+ files:
117
+ - .gitignore
118
+ - .rspec
119
+ - .rvmrc
120
+ - .travis.yml
121
+ - Gemfile
122
+ - LICENSE.txt
123
+ - README.md
124
+ - Rakefile
125
+ - lib/api.yml
126
+ - lib/nexmos.rb
127
+ - lib/nexmos/account.rb
128
+ - lib/nexmos/base.rb
129
+ - lib/nexmos/message.rb
130
+ - lib/nexmos/number.rb
131
+ - lib/nexmos/railties.rb
132
+ - lib/nexmos/search.rb
133
+ - lib/nexmos/version.rb
134
+ - nexmos.gemspec
135
+ - spec/nexmos/account_spec.rb
136
+ - spec/nexmos/base_spec.rb
137
+ - spec/nexmos/number_spec.rb
138
+ - spec/nexmos_spec.rb
139
+ - spec/spec_helper.rb
140
+ homepage: https://github.com/simonoff/nexmos
141
+ licenses: []
142
+ post_install_message:
143
+ rdoc_options: []
144
+ require_paths:
145
+ - lib
146
+ required_ruby_version: !ruby/object:Gem::Requirement
147
+ none: false
148
+ requirements:
149
+ - - ! '>='
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 1.8.24
161
+ signing_key:
162
+ specification_version: 3
163
+ summary: Nexmo API client
164
+ test_files:
165
+ - spec/nexmos/account_spec.rb
166
+ - spec/nexmos/base_spec.rb
167
+ - spec/nexmos/number_spec.rb
168
+ - spec/nexmos_spec.rb
169
+ - spec/spec_helper.rb