ctm 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +2 -0
- data/README.md +125 -0
- data/Rakefile +10 -0
- data/TODO +38 -0
- data/ctm.gemspec +20 -0
- data/examples/buy_numbers.rb +14 -0
- data/examples/example.rb +38 -0
- data/examples/manage_numbers.rb +45 -0
- data/examples/manage_receivng_numbers.rb +25 -0
- data/examples/manage_sources.rb +25 -0
- data/examples/manage_users.rb +31 -0
- data/examples/manage_webhooks.rb +16 -0
- data/lib/ctm.rb +20 -0
- data/lib/ctm/account.rb +38 -0
- data/lib/ctm/auth.rb +24 -0
- data/lib/ctm/available_number.rb +18 -0
- data/lib/ctm/base.rb +49 -0
- data/lib/ctm/call.rb +11 -0
- data/lib/ctm/error.rb +16 -0
- data/lib/ctm/list.rb +80 -0
- data/lib/ctm/number.rb +25 -0
- data/lib/ctm/number_list.rb +63 -0
- data/lib/ctm/receiving_number.rb +25 -0
- data/lib/ctm/receiving_number_list.rb +39 -0
- data/lib/ctm/sale.rb +8 -0
- data/lib/ctm/source.rb +33 -0
- data/lib/ctm/token.rb +15 -0
- data/lib/ctm/user.rb +30 -0
- data/lib/ctm/webhook.rb +15 -0
- metadata +189 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Gemfile.lock
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
CallTrackingMetrics Ruby API
|
2
|
+
============================
|
3
|
+
|
4
|
+
Installation
|
5
|
+
------------
|
6
|
+
|
7
|
+
gem install ctm
|
8
|
+
|
9
|
+
|
10
|
+
Usage
|
11
|
+
-----
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
|
15
|
+
require 'ctm'
|
16
|
+
|
17
|
+
# get an access token
|
18
|
+
access_token = CTM::Auth.authenticate(ENV['CTM_TOKEN'], ENV['CTM_SECRET'])
|
19
|
+
|
20
|
+
# see the list of accounts
|
21
|
+
puts CTM::Account.list(access_token).inspect
|
22
|
+
|
23
|
+
# use this access token globally, instead of passing it to each method
|
24
|
+
CTM::Auth.token = access_token
|
25
|
+
|
26
|
+
# get my first account
|
27
|
+
account = CTM::Account.first
|
28
|
+
|
29
|
+
# get an account by name
|
30
|
+
account = CTM::Account.find("name" => "My Account Name")
|
31
|
+
|
32
|
+
# get a list of numbers within this account, returns 10 at a time by default
|
33
|
+
numbers = account.numbers
|
34
|
+
puts numbers.first.inspect
|
35
|
+
puts numbers.total_entries.inspect
|
36
|
+
puts numbers.page.inspect
|
37
|
+
puts numbers.per_page.inspect
|
38
|
+
numbers.each {|number|
|
39
|
+
puts number.id
|
40
|
+
puts "#{number.name} #{number.number} -> #{number.formatted}"
|
41
|
+
}
|
42
|
+
|
43
|
+
# get the next 20 numbers on page 2
|
44
|
+
numbers = account.numbers(:page => 2, :per_page => 20)
|
45
|
+
|
46
|
+
# search for new numbers to purchase
|
47
|
+
numbers = account.numbers.search("+1", :areacode => "410")
|
48
|
+
numbers = account.numbers.search("+1", :tollfree => true, :areacode => "888")
|
49
|
+
numbers = account.number.search("+44", :contains => "55")
|
50
|
+
|
51
|
+
# purchase a new number
|
52
|
+
number = account.numbers.buy(numbers.first.digits)
|
53
|
+
if number.purchased?
|
54
|
+
puts "successfully purchased the number: #{number.digits_formated}"
|
55
|
+
else
|
56
|
+
puts "failed to purchase that number"
|
57
|
+
end
|
58
|
+
|
59
|
+
# release the number, removing it from the account
|
60
|
+
number.release!
|
61
|
+
|
62
|
+
# create a source from a predefined source
|
63
|
+
source = account.sources.create(predefined: 'google_adwords')
|
64
|
+
|
65
|
+
# list predefined sources
|
66
|
+
predefined = account.predefined
|
67
|
+
|
68
|
+
# customize a source
|
69
|
+
source = account.sources.find(:name => "Google Adwords")
|
70
|
+
source.landing_url = "utm_campaign=MyCampaign"
|
71
|
+
source.save
|
72
|
+
|
73
|
+
# assign a source to a number
|
74
|
+
source.numbers.add(number)
|
75
|
+
|
76
|
+
# get a list of receiving numbers
|
77
|
+
receiving_numbers = account.receiving_numbers
|
78
|
+
|
79
|
+
# add a receiving number, note +1 country code is required
|
80
|
+
receiving_number = account.receiving_numbers.create(name: "my number", number:"+15555555555")
|
81
|
+
|
82
|
+
# assign a receiving number to the tracking number
|
83
|
+
number.receiving_numbers.add(receiving_number)
|
84
|
+
# get the list of receiving numbers for this number
|
85
|
+
puts number.receiving_numbers.inspect
|
86
|
+
number.save
|
87
|
+
|
88
|
+
# modify the routing preference for the number
|
89
|
+
number.routing = :simultaneous # :round_robin, :least_connected
|
90
|
+
number.save
|
91
|
+
|
92
|
+
# add a new user to the account
|
93
|
+
account.users.create(first_name: 'First', last_name: 'Last', email: 'email@example.com', notify: true)
|
94
|
+
|
95
|
+
# list the users
|
96
|
+
users = account.users
|
97
|
+
|
98
|
+
# create a webhook to send call data at the start of the call
|
99
|
+
account.webhooks.create(weburl: "http://myhost.com/new_calls", position: 'start')
|
100
|
+
|
101
|
+
# create a webhook to send call data at the end of the call
|
102
|
+
account.webhooks.create(weburl: "http://myhost.com/new_calls", position: 'end')
|
103
|
+
|
104
|
+
# list webhooks
|
105
|
+
account.webhooks
|
106
|
+
|
107
|
+
# calls - list the calls
|
108
|
+
account.calls
|
109
|
+
|
110
|
+
call = account.calls.first
|
111
|
+
|
112
|
+
call.notes = "some notes to attach to the call"
|
113
|
+
call.save
|
114
|
+
|
115
|
+
# get sale record
|
116
|
+
call.sale
|
117
|
+
|
118
|
+
# create sale record, marking the call as a conversion
|
119
|
+
call.sale.create(name: "Who", score: 5, conversion: true, value: 34, date: '2013-04-24T00:00:00Z')
|
120
|
+
# or update the sale record
|
121
|
+
sale = call.sale
|
122
|
+
sale.name = "Todd"
|
123
|
+
sale.save
|
124
|
+
|
125
|
+
```
|
data/Rakefile
ADDED
data/TODO
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
* Accounts
|
2
|
+
x list accounts
|
3
|
+
- create account with shared billing
|
4
|
+
- create account without shared billing
|
5
|
+
* Numbers
|
6
|
+
x list numbers
|
7
|
+
x buy number
|
8
|
+
x search available numbers
|
9
|
+
x list receiving numbers
|
10
|
+
x add receiving number
|
11
|
+
x rem receiving number
|
12
|
+
x get assigned source
|
13
|
+
x add source
|
14
|
+
- rem source
|
15
|
+
|
16
|
+
* Receiving Numbers
|
17
|
+
x list receiving numbers
|
18
|
+
x add receiving number
|
19
|
+
x rem receiving number
|
20
|
+
* Sources
|
21
|
+
x list sources
|
22
|
+
x add source
|
23
|
+
x rem source
|
24
|
+
x list numbers for the source
|
25
|
+
* Users
|
26
|
+
x list users
|
27
|
+
x add user
|
28
|
+
x update user
|
29
|
+
x rem user
|
30
|
+
* Webhooks
|
31
|
+
x list webhooks for account
|
32
|
+
x add webhook
|
33
|
+
x rem webhook
|
34
|
+
* Calls
|
35
|
+
- list calls
|
36
|
+
- show call
|
37
|
+
- add sale to call
|
38
|
+
- rem sale from call
|
data/ctm.gemspec
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "ctm"
|
3
|
+
s.version = "0.0.1"
|
4
|
+
s.authors = ["CallTrackingMetrics", "Todd Fisher"]
|
5
|
+
s.email = "info@calltrackingmetrics.com"
|
6
|
+
s.files = `git ls-files`.split("\n")
|
7
|
+
s.test_files = `git ls-files -- {test}/*`.split("\n")
|
8
|
+
s.homepage = "http://github.com/calltracking/ctm-ruby"
|
9
|
+
s.require_path = "lib"
|
10
|
+
s.rubygems_version = "1.3.5"
|
11
|
+
s.summary = "API Library for CallTrackingMetrics"
|
12
|
+
s.add_runtime_dependency "phony"
|
13
|
+
s.add_runtime_dependency "httparty"
|
14
|
+
s.add_runtime_dependency "activesupport"
|
15
|
+
s.add_development_dependency "rack", '~> 1.3.0'
|
16
|
+
s.add_development_dependency "mocha"
|
17
|
+
s.add_development_dependency 'fakeweb', '~> 1.3.0'
|
18
|
+
s.add_development_dependency "rake"
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__),"..", "lib")))
|
2
|
+
require 'ctm'
|
3
|
+
|
4
|
+
access_token = CTM::Auth.authenticate(ENV['CTM_TOKEN'], ENV['CTM_SECRET'])
|
5
|
+
account = access_token.accounts.first
|
6
|
+
|
7
|
+
availble_numbers = account.numbers.search("US", :area_code => "410")
|
8
|
+
availble_numbers.each do|num|
|
9
|
+
puts "#{num.friendly_name} -> #{num.phone_number}"
|
10
|
+
end
|
11
|
+
number_to_buy = availble_numbers.first
|
12
|
+
|
13
|
+
number = account.numbers.buy("+15005550006")
|
14
|
+
puts "purchased: #{number.formatted} #{number.number}"
|
data/examples/example.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__),"..", "lib")))
|
2
|
+
require 'ctm'
|
3
|
+
|
4
|
+
access_token = CTM::Auth.authenticate(ENV['CTM_TOKEN'], ENV['CTM_SECRET'])
|
5
|
+
puts "Accounts you have access to:"
|
6
|
+
access_token.accounts.each do|account|
|
7
|
+
puts "#{account.name} -> #{account.status}, #{account.balance}, #{account.stats.inspect}"
|
8
|
+
end
|
9
|
+
account = access_token.accounts.first
|
10
|
+
|
11
|
+
numbers = account.numbers
|
12
|
+
puts "Tracking Numbers #{numbers.total_entries} within the Account"
|
13
|
+
numbers.each do|number|
|
14
|
+
puts "#{number.id}: #{number.name} #{number.number} -> #{number.formatted}"
|
15
|
+
end
|
16
|
+
receiving_numbers = account.receiving_numbers
|
17
|
+
puts "Receiving Numbers #{receiving_numbers.total_entries} within the Account"
|
18
|
+
receiving_numbers.each do|number|
|
19
|
+
puts "#{number.id}: #{number.name} #{number.number} -> #{number.formatted}"
|
20
|
+
end
|
21
|
+
|
22
|
+
sources = account.sources
|
23
|
+
puts "Tracking Sources #{sources.total_entries} within the Account"
|
24
|
+
sources.each do|source|
|
25
|
+
puts "#{source.id}: #{source.name} #{source.referring_url} -> #{source.landing_url}"
|
26
|
+
end
|
27
|
+
|
28
|
+
users = account.users
|
29
|
+
puts "Users #{users.total_entries} within the Account"
|
30
|
+
users.each do|user|
|
31
|
+
puts "#{user.id}: #{user.name} #{user.email} -> #{user.role}"
|
32
|
+
end
|
33
|
+
|
34
|
+
webhooks = account.webhooks
|
35
|
+
puts "Webhooks #{webhooks.total_entries} within the Account"
|
36
|
+
webhooks.each do|wh|
|
37
|
+
puts "#{wh.id}: #{wh.weburl} #{wh.with_resource_url} -> #{wh.position}"
|
38
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__),"..", "lib")))
|
2
|
+
require 'ctm'
|
3
|
+
|
4
|
+
access_token = CTM::Auth.authenticate(ENV['CTM_TOKEN'], ENV['CTM_SECRET'])
|
5
|
+
account = access_token.accounts.first
|
6
|
+
|
7
|
+
numbers = account.numbers
|
8
|
+
puts "Tracking Numbers #{numbers.total_entries} within the Account"
|
9
|
+
numbers.each do|number|
|
10
|
+
puts "#{number.id}: #{number.name} #{number.number} -> #{number.formatted}"
|
11
|
+
end
|
12
|
+
|
13
|
+
number = numbers.first
|
14
|
+
# add receiving number
|
15
|
+
receiving_numbers = number.receiving_numbers
|
16
|
+
puts "Receiving Numbers #{receiving_numbers.total_entries} assigned to the tracking number"
|
17
|
+
receiving_numbers.each do|number|
|
18
|
+
puts "#{number.id}: #{number.name} #{number.number} -> #{number.formatted}"
|
19
|
+
end
|
20
|
+
receiving_number = account.receiving_numbers.find(:name => "laures phone").first
|
21
|
+
puts "Adding and removing: #{receiving_number.number}"
|
22
|
+
number.receiving_numbers.add(receiving_number)
|
23
|
+
number.receiving_numbers.rem(receiving_number)
|
24
|
+
|
25
|
+
# add tracking source
|
26
|
+
source = account.sources.find(:name => "Google Organic").first
|
27
|
+
puts source.name
|
28
|
+
source.numbers.each do|number|
|
29
|
+
puts "#{number.id}: #{number.name} #{number.number} -> #{number.formatted}"
|
30
|
+
end
|
31
|
+
|
32
|
+
source = account.sources.find(:name => "test source1").first
|
33
|
+
if !source
|
34
|
+
source = account.sources.create(:name => "test source1")
|
35
|
+
end
|
36
|
+
|
37
|
+
number = account.numbers.find(:name => "test number1").first
|
38
|
+
puts number.formatted
|
39
|
+
|
40
|
+
number.receiving_numbers.add(receiving_number)
|
41
|
+
|
42
|
+
source.numbers.add(number)
|
43
|
+
source.numbers.each do|number|
|
44
|
+
puts "#{number.id}: #{number.name} #{number.number} -> #{number.formatted}"
|
45
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__),"..", "lib")))
|
2
|
+
require 'ctm'
|
3
|
+
|
4
|
+
access_token = CTM::Auth.authenticate(ENV['CTM_TOKEN'], ENV['CTM_SECRET'])
|
5
|
+
account = access_token.accounts.first
|
6
|
+
|
7
|
+
receiving_numbers = account.receiving_numbers
|
8
|
+
puts "Receiving Numbers #{receiving_numbers.total_entries} within the Account"
|
9
|
+
receiving_numbers.each do|number|
|
10
|
+
puts "#{number.id}: #{number.name} #{number.number} -> #{number.formatted}"
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
rn = account.receiving_numbers.create(:number => "+14109999999", :name => "test number")
|
15
|
+
rescue CTM::Error::Create => e
|
16
|
+
if e.message.match(/already exists/)
|
17
|
+
rn = account.receiving_numbers.find(:number => "+14109999999").first
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
puts rn.inspect
|
22
|
+
rn.name = "another test"
|
23
|
+
rn.save
|
24
|
+
|
25
|
+
rn.release!
|
@@ -0,0 +1,25 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__),"..", "lib")))
|
2
|
+
require 'ctm'
|
3
|
+
|
4
|
+
access_token = CTM::Auth.authenticate(ENV['CTM_TOKEN'], ENV['CTM_SECRET'])
|
5
|
+
account = access_token.accounts.first
|
6
|
+
|
7
|
+
sources = account.sources
|
8
|
+
puts "Tracking Sources #{sources.total_entries} within the Account"
|
9
|
+
sources.each do|source|
|
10
|
+
puts "#{source.id}: #{source.name} #{source.referring_url} -> #{source.landing_url}"
|
11
|
+
end
|
12
|
+
|
13
|
+
source = account.sources.create(:name => "My Source",
|
14
|
+
:referring_url => "google",
|
15
|
+
:landing_url => "utm_campaign=paid",
|
16
|
+
:online => true)
|
17
|
+
puts source.name
|
18
|
+
puts source.referring_url
|
19
|
+
puts source.landing_url
|
20
|
+
|
21
|
+
source.name = "Foo bar"
|
22
|
+
|
23
|
+
source.save
|
24
|
+
|
25
|
+
source.release!
|
@@ -0,0 +1,31 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__),"..", "lib")))
|
2
|
+
require 'ctm'
|
3
|
+
access_token = CTM::Auth.authenticate(ENV['CTM_TOKEN'], ENV['CTM_SECRET'])
|
4
|
+
account = access_token.accounts.first
|
5
|
+
|
6
|
+
# find user by email
|
7
|
+
users = account.users.find(:email => "todd@calltrackingmetrics.com")
|
8
|
+
users.each do|user|
|
9
|
+
puts "#{user.id}: #{user.name} #{user.email} -> #{user.role}"
|
10
|
+
end
|
11
|
+
|
12
|
+
# find by last name
|
13
|
+
users = account.users.find(:last_name => "fisher")
|
14
|
+
users.each do|user|
|
15
|
+
puts "#{user.id}: #{user.name} #{user.email} -> #{user.role}"
|
16
|
+
end
|
17
|
+
|
18
|
+
# add a new user
|
19
|
+
user = account.users.create(:email => "foo@bar11#{Time.now.to_i}.com",
|
20
|
+
:first_name => "Me",
|
21
|
+
:last_name => "You",
|
22
|
+
:password => "foobar1234",
|
23
|
+
:role => "call_manager")
|
24
|
+
# update user
|
25
|
+
user.first_name = "No"
|
26
|
+
user.last_name = "Yes"
|
27
|
+
user.role = "admin"
|
28
|
+
user.save
|
29
|
+
|
30
|
+
# remove user from account
|
31
|
+
user.release!
|
@@ -0,0 +1,16 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__),"..", "lib")))
|
2
|
+
require 'ctm'
|
3
|
+
|
4
|
+
access_token = CTM::Auth.authenticate(ENV['CTM_TOKEN'], ENV['CTM_SECRET'])
|
5
|
+
account = access_token.accounts.first
|
6
|
+
|
7
|
+
webhooks = account.webhooks
|
8
|
+
puts "Webhooks #{webhooks.total_entries} within the Account"
|
9
|
+
webhooks.each do|wh|
|
10
|
+
puts "#{wh.id}: #{wh.weburl} #{wh.with_resource_url} -> #{wh.position}"
|
11
|
+
end
|
12
|
+
|
13
|
+
# get requests when the call starts
|
14
|
+
webhook = webhooks.create(:weburl => "http://example.com/myhook", :position => "start")
|
15
|
+
|
16
|
+
webhook.release!
|
data/lib/ctm.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module CTM ; end
|
2
|
+
require 'httparty'
|
3
|
+
require 'active_support/inflector'
|
4
|
+
|
5
|
+
require 'ctm/error'
|
6
|
+
require 'ctm/base'
|
7
|
+
require 'ctm/list'
|
8
|
+
require 'ctm/account'
|
9
|
+
require 'ctm/auth'
|
10
|
+
require 'ctm/available_number'
|
11
|
+
require 'ctm/call'
|
12
|
+
require 'ctm/number'
|
13
|
+
require 'ctm/number_list'
|
14
|
+
require 'ctm/receiving_number'
|
15
|
+
require 'ctm/receiving_number_list'
|
16
|
+
require 'ctm/sale'
|
17
|
+
require 'ctm/source'
|
18
|
+
require 'ctm/token'
|
19
|
+
require 'ctm/user'
|
20
|
+
require 'ctm/webhook'
|
data/lib/ctm/account.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module CTM
|
2
|
+
class Account < Base
|
3
|
+
attr_reader :id
|
4
|
+
attr_accessor :name, :status, :stats, :balance
|
5
|
+
|
6
|
+
# {"id"=>25, "name"=>"CallTrackingMetrics", "user_role"=>"admin", "status"=>"active",
|
7
|
+
# "stats"=>{"calls"=>{"2013-04-18"=>3, "2013-04-25"=>1}, "tracking_numbers"=>48},
|
8
|
+
# "url"=>"http://ctmdev.co/api/v1/accounts/25.json", "balance"=>{"cents"=>23739, "currency"=>"USD", "precision"=>2}}
|
9
|
+
def initialize(data, token=nil)
|
10
|
+
super(data, token)
|
11
|
+
@id = data['id']
|
12
|
+
@name = data['name']
|
13
|
+
@status = data['status']
|
14
|
+
@stats = data['stats']['calls']
|
15
|
+
@balance = "$" + (data['balance']['cents'].to_i / 100).to_s + "." + (data['balance']['cents'].to_i % 100).to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
def numbers(options={})
|
19
|
+
CTM::NumberList.new(options.merge(:account_id => @id), @token)
|
20
|
+
end
|
21
|
+
|
22
|
+
def receiving_numbers(options={})
|
23
|
+
CTM::List.new('ReceivingNumber', options.merge(:account_id => @id), @token)
|
24
|
+
end
|
25
|
+
|
26
|
+
def sources(options={})
|
27
|
+
CTM::List.new('Source', options.merge(:account_id => @id), @token)
|
28
|
+
end
|
29
|
+
|
30
|
+
def users(options={})
|
31
|
+
CTM::List.new('User', options.merge(:account_id => @id), @token)
|
32
|
+
end
|
33
|
+
|
34
|
+
def webhooks(options={})
|
35
|
+
CTM::List.new('Webhook', options.merge(:account_id => @id), @token)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/ctm/auth.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module CTM
|
2
|
+
class Auth
|
3
|
+
include HTTParty
|
4
|
+
base_uri ENV["CTM_URL"] || "api.calltrackingmetrics.com"
|
5
|
+
|
6
|
+
def self.token=(token)
|
7
|
+
@token = token
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.token
|
11
|
+
@token
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.authenticate(token, secret)
|
15
|
+
res = self.post("/api/v1/authentication", :body => {:token => token, :secret => secret})
|
16
|
+
if res.parsed_response && res.parsed_response['success']
|
17
|
+
CTM::Token.new(res.parsed_response)
|
18
|
+
else
|
19
|
+
raise CTM::Error::Auth.new("Failed to authenticate")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module CTM
|
2
|
+
class AvailableNumber < Base
|
3
|
+
attr_reader :friendly_name, :latitude, :longitude, :rate_center, :lata, :region, :postal_code, :iso_country, :phone_number
|
4
|
+
|
5
|
+
def initialize(data, token=nil)
|
6
|
+
super(data, token)
|
7
|
+
@friendly_name = data['friendly_name']
|
8
|
+
@latitude = data['latitude']
|
9
|
+
@longitude = data['longitude']
|
10
|
+
@lata = data['lata']
|
11
|
+
@region = data['region']
|
12
|
+
@postal_code = data['postal_code']
|
13
|
+
@iso_country = data['iso_country']
|
14
|
+
@phone_number = data['phone_number']
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
data/lib/ctm/base.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
module CTM
|
2
|
+
class Base
|
3
|
+
include HTTParty
|
4
|
+
base_uri ENV["CTM_URL"] || "api.calltrackingmetrics.com"
|
5
|
+
|
6
|
+
attr_reader :token, :account_id
|
7
|
+
|
8
|
+
|
9
|
+
def initialize(data, token=nil)
|
10
|
+
@token = token || CTM::Auth.token
|
11
|
+
@account_id = data['account_id']
|
12
|
+
@list_token_type = self.class.to_s.sub(/CTM::/,'').underscore.pluralize
|
13
|
+
if @account_id
|
14
|
+
@list_type_path = "accounts/#{@account_id}/#{@list_token_type}"
|
15
|
+
else
|
16
|
+
@list_type_path = @list_token_type
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def save(options={})
|
21
|
+
puts "save: #{options.inspect}"
|
22
|
+
path_str = "/api/v1/#{@list_type_path}/#{@id}.json"
|
23
|
+
res = self.class.put(path_str, :body => options.merge(:auth_token => @token))
|
24
|
+
end
|
25
|
+
|
26
|
+
def release!
|
27
|
+
path_str = "/api/v1/#{@list_type_path}/#{@id}.json"
|
28
|
+
res = self.class.delete(path_str, :body => {:auth_token => @token})
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.create(options)
|
32
|
+
list_type_path = options.delete(:list_type_path)
|
33
|
+
list_token_type = options.delete(:list_token_type)
|
34
|
+
account_id = options.delete(:account_id)
|
35
|
+
token = options.delete(:token)
|
36
|
+
path_str = "/api/v1/#{list_type_path}.json"
|
37
|
+
puts "create: #{self} -> #{options.inspect}"
|
38
|
+
res = self.post(path_str, :body => options.merge(:auth_token => token))
|
39
|
+
puts "result: #{res.parsed_response.inspect}"
|
40
|
+
puts "properties: #{list_type_path.inspect} -> #{list_token_type.inspect} -> #{account_id}"
|
41
|
+
if res.parsed_response['status'] == 'error'
|
42
|
+
raise CTM::Error::Create.new(res.parsed_response['reason'])
|
43
|
+
else
|
44
|
+
self.new(res.parsed_response[list_token_type.singularize], token)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
data/lib/ctm/call.rb
ADDED
data/lib/ctm/error.rb
ADDED
data/lib/ctm/list.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# Generic List Object to handle paginated lists of objects
|
2
|
+
module CTM
|
3
|
+
class List
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
include HTTParty
|
7
|
+
base_uri ENV["CTM_URL"] || "api.calltrackingmetrics.com"
|
8
|
+
|
9
|
+
attr_reader :list_type, :token, :per_page, :page, :total_entries, :objects
|
10
|
+
|
11
|
+
# e.g. Account, token
|
12
|
+
def initialize(list_type, options={}, token=nil, fetched_objects=nil)
|
13
|
+
@list_type = list_type
|
14
|
+
@list_token_type = list_type.underscore.pluralize
|
15
|
+
@object_klass = CTM.module_eval(list_type)
|
16
|
+
@token = token || CTM::Auth.token
|
17
|
+
@account_id = options[:account_id]
|
18
|
+
if @account_id
|
19
|
+
@list_type_path = "accounts/#{@account_id}/#{@list_token_type}"
|
20
|
+
else
|
21
|
+
@list_type_path = @list_token_type
|
22
|
+
end
|
23
|
+
if fetched_objects
|
24
|
+
map_data(fetched_objects)
|
25
|
+
else
|
26
|
+
fetch_page(options)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def each &block
|
31
|
+
@objects.each do |obj|
|
32
|
+
if block_given?
|
33
|
+
block.call obj
|
34
|
+
else
|
35
|
+
yield obj
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def create(options)
|
41
|
+
@object_klass.create(options.merge(:list_type_path => @list_type_path,
|
42
|
+
:list_token_type => @list_token_type,
|
43
|
+
:account_id => @account_id,
|
44
|
+
:token => @token))
|
45
|
+
end
|
46
|
+
|
47
|
+
def find(options)
|
48
|
+
first_name = options.delete(:first_name)
|
49
|
+
last_name = options.delete(:last_name)
|
50
|
+
options[:filter] = options.delete(:filter) || "#{first_name} #{last_name}".strip if first_name || last_name
|
51
|
+
|
52
|
+
fetch_page(options)
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
protected
|
57
|
+
|
58
|
+
def fetch_page(options={})
|
59
|
+
options = {:per_page => 10, :page => 1}.merge(options)
|
60
|
+
path_str = "/api/v1/#{@list_type_path}.json"
|
61
|
+
res = self.class.get(path_str, :query => options.merge(:auth_token => @token))
|
62
|
+
data = res.parsed_response
|
63
|
+
if data["status"] && data["status"] == "error"
|
64
|
+
puts data.inspect
|
65
|
+
raise CTM::Error::List.new(data["message"] || data["reason"])
|
66
|
+
end
|
67
|
+
map_data(data)
|
68
|
+
end
|
69
|
+
|
70
|
+
def map_data(data)
|
71
|
+
@page = data['page']
|
72
|
+
@per_page = data['per_page']
|
73
|
+
@total_entries = data['total_entries']
|
74
|
+
@objects = data[@list_token_type].map {|obj|
|
75
|
+
@object_klass.new(obj, @token)
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
data/lib/ctm/number.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module CTM
|
2
|
+
class Number < Base
|
3
|
+
attr_reader :id, :account_id
|
4
|
+
attr_accessor :name, :number, :formatted, :split, :routing
|
5
|
+
|
6
|
+
def initialize(data, token=nil)
|
7
|
+
super(data, token)
|
8
|
+
@id = data['id']
|
9
|
+
@account_id = data['account_id']
|
10
|
+
@name = data['name']
|
11
|
+
@number = data['number']
|
12
|
+
@formatted = data['formatted']
|
13
|
+
@split = data['split']
|
14
|
+
@routing = data['routing']
|
15
|
+
end
|
16
|
+
|
17
|
+
def receiving_numbers(options={})
|
18
|
+
CTM::ReceivingNumberList.new(options.merge(:account_id => @account_id, :number_id => @id), @token)
|
19
|
+
end
|
20
|
+
|
21
|
+
def source
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module CTM
|
2
|
+
class NumberList < List
|
3
|
+
def initialize(options={}, token=nil)
|
4
|
+
super('Number', options, token)
|
5
|
+
@source_id = options[:source_id]
|
6
|
+
if @source_id && @account_id
|
7
|
+
@list_type_path = "accounts/#{@account_id}/sources/#{@source_id}/#{@list_token_type}"
|
8
|
+
elsif @account_id
|
9
|
+
@list_type_path = "accounts/#{@account_id}/#{@list_token_type}"
|
10
|
+
else
|
11
|
+
@list_type_path = @list_token_type
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# find a number within the given country/region and options like area_code or containing with contains
|
16
|
+
def search(country_code, options={})
|
17
|
+
options = {:country_code => country_code}.merge(options)
|
18
|
+
path_str = "/api/v1/#{@list_type_path}/search.json"
|
19
|
+
res = self.class.get(path_str, :query => options.merge(:auth_token => @token))
|
20
|
+
data = res.parsed_response
|
21
|
+
if data["status"] == "success"
|
22
|
+
list_data = {'available_numbers' => data['results'].map {|res| res.merge('account_id' => @account_id) },
|
23
|
+
'page' => 1,
|
24
|
+
'per_page' => data['results'].size,
|
25
|
+
'total_entries' => data['results'].size}
|
26
|
+
CTM::List.new('AvailableNumber', {:account_id => @account_id}, @token, list_data)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# buy number with the digits
|
31
|
+
def buy(digits)
|
32
|
+
path_str = "/api/v1/#{@list_type_path}.json"
|
33
|
+
res = self.class.post(path_str, :body => {:phone_number => digits}.merge(:auth_token => @token))
|
34
|
+
if res && res['status'] == 'success'
|
35
|
+
CTM::Number.new(res['number'], @token)
|
36
|
+
else
|
37
|
+
puts res.inspect
|
38
|
+
raise CTM::Error::Buy.new(res["reason"])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# add trackng number to tracking source
|
43
|
+
def add(number)
|
44
|
+
path_str = "/api/v1/#{@list_type_path}/#{number.id}/add.json"
|
45
|
+
puts "Add to #{@account_id}:#{@source_id} -> #{number.id} -> #{path_str}"
|
46
|
+
# accounts/25 /sources/5012 /numbers
|
47
|
+
# /api/v1/accounts/:account_id/sources/:source_id/numbers/:id/add
|
48
|
+
res = self.class.post(path_str, :body => {}.merge(:auth_token => @token))
|
49
|
+
if res && res['status'] == 'success'
|
50
|
+
CTM::Source.new(res['source'], @token)
|
51
|
+
else
|
52
|
+
puts res.inspect
|
53
|
+
raise CTM::Error::Add.new(res["reason"])
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def rem
|
58
|
+
puts "Rem to #{@account_id}:#{@source_id} -> #{number.id} -> #{@list_type_path}"
|
59
|
+
# /api/v1/accounts/:account_id/sources/:source_id/numbers/:id/rem
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module CTM
|
2
|
+
class ReceivingNumber < Base
|
3
|
+
attr_reader :id, :account_id
|
4
|
+
attr_accessor :name, :number, :formatted, :split
|
5
|
+
|
6
|
+
def initialize(data, token=nil)
|
7
|
+
super(data, token)
|
8
|
+
@id = data['id']
|
9
|
+
@account_id = data['account_id']
|
10
|
+
@name = data['name']
|
11
|
+
@number = data['number']
|
12
|
+
@formatted = data['formatted']
|
13
|
+
@split = data['split']
|
14
|
+
end
|
15
|
+
|
16
|
+
def save
|
17
|
+
options = {
|
18
|
+
:name => @name,
|
19
|
+
:number => @number
|
20
|
+
}
|
21
|
+
super(options)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module CTM
|
2
|
+
class ReceivingNumberList < List
|
3
|
+
def initialize(options={}, token=nil)
|
4
|
+
super('ReceivingNumber', options, token)
|
5
|
+
@account_id = options[:account_id]
|
6
|
+
@number_id = options[:number_id]
|
7
|
+
if @number_id && @account_id
|
8
|
+
@list_type_path = "accounts/#{@account_id}/numbers/#{@number_id}/#{@list_token_type}"
|
9
|
+
elsif @account_id
|
10
|
+
@list_type_path = "accounts/#{@account_id}/#{@list_token_type}"
|
11
|
+
else
|
12
|
+
@list_type_path = @list_token_type
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def add(receiving_number)
|
17
|
+
path_str = "/api/v1/#{@list_type_path}/#{receiving_number.id}/add.json"
|
18
|
+
res = self.class.post(path_str, :body => {}.merge(:auth_token => @token))
|
19
|
+
if res && res['status'] == 'success'
|
20
|
+
CTM::Number.new(res['receiving_number'], @token)
|
21
|
+
else
|
22
|
+
puts res.inspect
|
23
|
+
raise CTM::Error::Add.new(res["reason"])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def rem(receiving_number)
|
28
|
+
path_str = "/api/v1/#{@list_type_path}/#{receiving_number.id}/rem.json"
|
29
|
+
res = self.class.delete(path_str, :body => {}.merge(:auth_token => @token))
|
30
|
+
if res && res['status'] == 'success'
|
31
|
+
CTM::Number.new(res['receiving_number'], @token)
|
32
|
+
else
|
33
|
+
puts res.inspect
|
34
|
+
raise CTM::Error::Add.new(res["reason"])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
data/lib/ctm/sale.rb
ADDED
data/lib/ctm/source.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module CTM
|
2
|
+
class Source < Base
|
3
|
+
attr_reader :id, :account_id
|
4
|
+
attr_accessor :name, :referring_url, :landing_url, :position, :online
|
5
|
+
|
6
|
+
def initialize(data, token=nil)
|
7
|
+
super(data, token)
|
8
|
+
@id = data['id']
|
9
|
+
@account_id = data['account_id']
|
10
|
+
@name = data['name']
|
11
|
+
@referring_url = data['referring_url']
|
12
|
+
@landing_url = data['landing_url']
|
13
|
+
@position = data['position']
|
14
|
+
@online = data['online']
|
15
|
+
end
|
16
|
+
|
17
|
+
def save
|
18
|
+
options = {
|
19
|
+
:name => @name,
|
20
|
+
:position => @position,
|
21
|
+
:online => @online,
|
22
|
+
:referring_url => @referring_url,
|
23
|
+
:landing_url => @landing_url
|
24
|
+
}
|
25
|
+
super(options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def numbers(options={})
|
29
|
+
CTM::NumberList.new(options.merge(:account_id => @account_id, :source_id => @id), @token)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
data/lib/ctm/token.rb
ADDED
data/lib/ctm/user.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module CTM
|
2
|
+
class User < Base
|
3
|
+
attr_reader :id
|
4
|
+
attr_accessor :first_name, :last_name, :email, :role
|
5
|
+
|
6
|
+
def name
|
7
|
+
"#{first_name} #{last_name}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(data, token=nil)
|
11
|
+
super(data, token)
|
12
|
+
@id = data['id']
|
13
|
+
@first_name = data['first_name']
|
14
|
+
@last_name = data['last_name']
|
15
|
+
@email = data['email']
|
16
|
+
@role = data['role']
|
17
|
+
end
|
18
|
+
|
19
|
+
def save
|
20
|
+
options = {
|
21
|
+
:first_name => @first_name,
|
22
|
+
:last_name => @last_name,
|
23
|
+
:email => @email,
|
24
|
+
:role => @role
|
25
|
+
}
|
26
|
+
super(options)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
data/lib/ctm/webhook.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module CTM
|
2
|
+
class Webhook < Base
|
3
|
+
attr_reader :id
|
4
|
+
attr_accessor :weburl, :with_resource_url, :position
|
5
|
+
|
6
|
+
def initialize(data, token=nil)
|
7
|
+
super(data, token)
|
8
|
+
@id = data['id']
|
9
|
+
@weburl = data['weburl']
|
10
|
+
@with_resource_url = data['with_resource_url']
|
11
|
+
@position = data['position']
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ctm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- CallTrackingMetrics
|
9
|
+
- Todd Fisher
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2013-04-30 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: phony
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '0'
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: httparty
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
type: :runtime
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: activesupport
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: rack
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ~>
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: 1.3.0
|
71
|
+
type: :development
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ~>
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 1.3.0
|
79
|
+
- !ruby/object:Gem::Dependency
|
80
|
+
name: mocha
|
81
|
+
requirement: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
type: :development
|
88
|
+
prerelease: false
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: fakeweb
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ~>
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 1.3.0
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ~>
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.3.0
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rake
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ! '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ! '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
description:
|
128
|
+
email: info@calltrackingmetrics.com
|
129
|
+
executables: []
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- .gitignore
|
134
|
+
- Gemfile
|
135
|
+
- Gemfile.lock
|
136
|
+
- README.md
|
137
|
+
- Rakefile
|
138
|
+
- TODO
|
139
|
+
- ctm.gemspec
|
140
|
+
- examples/buy_numbers.rb
|
141
|
+
- examples/example.rb
|
142
|
+
- examples/manage_numbers.rb
|
143
|
+
- examples/manage_receivng_numbers.rb
|
144
|
+
- examples/manage_sources.rb
|
145
|
+
- examples/manage_users.rb
|
146
|
+
- examples/manage_webhooks.rb
|
147
|
+
- lib/ctm.rb
|
148
|
+
- lib/ctm/account.rb
|
149
|
+
- lib/ctm/auth.rb
|
150
|
+
- lib/ctm/available_number.rb
|
151
|
+
- lib/ctm/base.rb
|
152
|
+
- lib/ctm/call.rb
|
153
|
+
- lib/ctm/error.rb
|
154
|
+
- lib/ctm/list.rb
|
155
|
+
- lib/ctm/number.rb
|
156
|
+
- lib/ctm/number_list.rb
|
157
|
+
- lib/ctm/receiving_number.rb
|
158
|
+
- lib/ctm/receiving_number_list.rb
|
159
|
+
- lib/ctm/sale.rb
|
160
|
+
- lib/ctm/source.rb
|
161
|
+
- lib/ctm/token.rb
|
162
|
+
- lib/ctm/user.rb
|
163
|
+
- lib/ctm/webhook.rb
|
164
|
+
homepage: http://github.com/calltracking/ctm-ruby
|
165
|
+
licenses: []
|
166
|
+
post_install_message:
|
167
|
+
rdoc_options: []
|
168
|
+
require_paths:
|
169
|
+
- lib
|
170
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
171
|
+
none: false
|
172
|
+
requirements:
|
173
|
+
- - ! '>='
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: '0'
|
176
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
177
|
+
none: false
|
178
|
+
requirements:
|
179
|
+
- - ! '>='
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
requirements: []
|
183
|
+
rubyforge_project:
|
184
|
+
rubygems_version: 1.8.24
|
185
|
+
signing_key:
|
186
|
+
specification_version: 3
|
187
|
+
summary: API Library for CallTrackingMetrics
|
188
|
+
test_files: []
|
189
|
+
has_rdoc:
|