pocketmath-advertise 0.0.3 → 0.0.4
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.
- checksums.yaml +4 -4
- data/lib/model/insertion_order_stats.rb +42 -0
- data/lib/pocketmath-advertise.rb +1 -0
- data/lib/pocketmath-advertiser.rb +183 -123
- data/lib/pocketmath-geocode.rb +94 -54
- metadata +11 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1fa5aa04e223ff53658c46d7b519315fb79e8546
|
4
|
+
data.tar.gz: 0d3b61f58a15c21b323ccba55c2244fa82ab1d0e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ceade68a085ea00f3c7bdc1c5bb0b9516a90682135a13cd0ecac309fd74dbb4fe5a30f466a47eee6692a916ca337fc4545da638c3a3c33e2bfa181b8b5275e1b
|
7
|
+
data.tar.gz: e93f468332b6b9fb624148b0778a1631c2090007a113853213c456690bab303d64fa0e08029cc679ee1253ed5cc00fd28e43c5fc1c90ed3b8d040c5c46d724ea
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module PocketMath::Advertiser::V1
|
2
|
+
|
3
|
+
class InsertionOrderStats
|
4
|
+
|
5
|
+
# Cost per thousand Impressions
|
6
|
+
attr_reader :cpm
|
7
|
+
|
8
|
+
# Cost per Click
|
9
|
+
attr_reader :cpc
|
10
|
+
|
11
|
+
# Cost per Action (Cost per Conversion)
|
12
|
+
attr_reader :cpa
|
13
|
+
|
14
|
+
# Click-through Rate (Clicks per impression)
|
15
|
+
attr_reader :ctr
|
16
|
+
|
17
|
+
attr_reader :impressions, :clicks, :conversions
|
18
|
+
|
19
|
+
# Ad spend in currency
|
20
|
+
attr_reader :spend
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
attr_writer :cpm, :cpc, :cpa, :ctr
|
25
|
+
attr_writer :impressions, :clicks, :conversions
|
26
|
+
attr_writer :spend
|
27
|
+
|
28
|
+
public
|
29
|
+
|
30
|
+
# Create a new instance.
|
31
|
+
# * Specify attributes in a hash as { :cpm => 1.25, :cpc => 2.33, ... }
|
32
|
+
def self.create(opts = {})
|
33
|
+
iostats = InsertionOrderStats.new
|
34
|
+
opts.each_pair do |k,v|
|
35
|
+
raise "#{k.to_s}=#{v} was not a number" if !v.is_a?(Numeric)
|
36
|
+
iostats.send(k.to_s + "=", v)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/lib/pocketmath-advertise.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'json'
|
2
|
-
require 'open-uri'
|
3
2
|
require 'net/http'
|
4
3
|
require 'net/https'
|
5
4
|
require 'uri'
|
@@ -10,152 +9,213 @@ require 'curb'
|
|
10
9
|
module PocketMath
|
11
10
|
module PocketMath::Advertiser
|
12
11
|
module PocketMath::Advertiser::V1
|
13
|
-
|
14
|
-
|
12
|
+
|
13
|
+
DEFAULT_API_BASE_URL = "https://api.pocketmath.com"
|
14
|
+
|
15
|
+
def self.open(pocketmath_api_key, pocketmath_api_base_url = DEFAULT_API_BASE_URL)
|
16
|
+
return Client.new(pocketmath_api_key, pocketmath_api_base_url)
|
17
|
+
end
|
18
|
+
|
19
|
+
class PocketMath::Advertiser::V1::Client
|
20
|
+
|
21
|
+
def initialize(pocketmath_api_key, pocketmath_api_base_url)
|
22
|
+
@pocketmath_api_key = pocketmath_api_key
|
23
|
+
@pocketmath_api_base_url = pocketmath_api_base_url
|
24
|
+
end
|
25
|
+
|
26
|
+
def close
|
27
|
+
end
|
15
28
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
29
|
+
def find_gps_list_id_by_name(name)
|
30
|
+
p "get_gps_list_id"
|
31
|
+
url = "#{@pocketmath_api_base_url}/v1/lists/gps/list.json?token=#{@pocketmath_api_key}&limit=10000"
|
32
|
+
response = Net::HTTP.get_response(URI.parse(url))
|
33
|
+
data = response.body
|
34
|
+
obj = JSON.parse(data)
|
35
|
+
obj.each do |result|
|
36
|
+
return result["id"] if result["name"] == name
|
37
|
+
end
|
24
38
|
end
|
25
|
-
end
|
26
39
|
|
27
|
-
|
28
|
-
|
29
|
-
|
40
|
+
def create_gps_list(name)
|
41
|
+
raise "name was nil" if name.nil?
|
42
|
+
raise "name was blank" if name.empty?
|
30
43
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
44
|
+
add_list_json = JSON::generate(
|
45
|
+
{
|
46
|
+
"token" => "#{@pocketmath_api_key}",
|
47
|
+
"list" =>
|
48
|
+
{
|
49
|
+
"name" => "#{name}"
|
50
|
+
}
|
51
|
+
})
|
39
52
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
53
|
+
uri = URI.parse(@pocketmath_api_base_url)
|
54
|
+
response = nil
|
55
|
+
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
|
56
|
+
request = Net::HTTP::Post.new("/v1/lists/gps/add_list.json")
|
57
|
+
request.body = add_list_json
|
58
|
+
request.content_type = "application/json"
|
59
|
+
response = http.request(request)
|
60
|
+
end
|
61
|
+
if !response.nil?
|
62
|
+
data = response.body
|
63
|
+
obj = JSON::parse(data)
|
64
|
+
list_id = obj["id"]
|
65
|
+
return list_id
|
66
|
+
else
|
67
|
+
return nil
|
68
|
+
end
|
55
69
|
end
|
56
|
-
end
|
57
70
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
71
|
+
def upload_gps_list(id, coordinates = [])
|
72
|
+
raise "id was nil" if id.nil?
|
73
|
+
raise "coordinates was nil" if coordinates.nil?
|
74
|
+
raise "coordiantes was empty" if coordinates.empty?
|
62
75
|
|
63
|
-
|
64
|
-
|
76
|
+
c = Curl::Easy.new("#{@pocketmath_api_base_url}/v1/lists/gps/upload.json")
|
77
|
+
c.multipart_form_post = true
|
65
78
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
79
|
+
coordinates_string = ''
|
80
|
+
coordinates.each do |coord|
|
81
|
+
coordinates_string << "#{coord[:latitude]},#{coord[:longitude]}\r\n"
|
82
|
+
end
|
70
83
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
84
|
+
r = Random.new
|
85
|
+
remote_file_name = "pm-advert-client-gps-list-#{r.rand(2*1000*1000*1000)}-#{r.rand(2*1000*1000*1000)}.txt"
|
86
|
+
content_field = Curl::PostField.file('file', remote_file_name) do |field|
|
87
|
+
field.content = coordinates_string
|
88
|
+
end
|
76
89
|
|
77
|
-
|
90
|
+
success = nil
|
78
91
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
92
|
+
success = c.http_post(
|
93
|
+
content_field,
|
94
|
+
Curl::PostField.content('token', @pocketmath_api_key),
|
95
|
+
Curl::PostField.content('mode', 'append'),
|
96
|
+
Curl::PostField.content('list_id', id.to_s )
|
97
|
+
)
|
85
98
|
|
86
|
-
|
87
|
-
end
|
88
|
-
|
89
|
-
private
|
90
|
-
|
91
|
-
def self.deep_copy(o)
|
92
|
-
Marshal.load(Marshal.dump(o))
|
93
|
-
end
|
94
|
-
|
95
|
-
public
|
96
|
-
|
97
|
-
def self.create_insertion_order( opts =
|
98
|
-
{
|
99
|
-
"name" => nil,
|
100
|
-
"start_datetime" => Date.now,
|
101
|
-
"end_datetime" => Date.now + 7.days,
|
102
|
-
"creative_type_ids" => [],
|
103
|
-
"budget" => "1.00",
|
104
|
-
"iab_catgories" => [],
|
105
|
-
"bid_per_impression" => "2.00",
|
106
|
-
"top_level_domain" => "pocketmath.com",
|
107
|
-
"country" => "223",
|
108
|
-
"image_url" => "https://s3.amazonaws.com/pocketmath/pocketmath_320x50.jpg",
|
109
|
-
"landing_page_url" => "www.pocketmath.com",
|
110
|
-
"size_id" => "11"
|
111
|
-
})
|
112
|
-
|
113
|
-
o = deep_copy(opts)
|
114
|
-
|
115
|
-
if o["name"].nil?
|
116
|
-
raise "name was nil"
|
99
|
+
return success
|
117
100
|
end
|
118
101
|
|
119
|
-
|
120
|
-
|
102
|
+
def get_insertion_order_stats(id, start_date = nil, end_date = nil)
|
103
|
+
url = "#{@pocketmath_api_base_url}/v1/stats/id.json?token=#{@pocketmath_api_key}&id=#{URI.encode(id)}"
|
104
|
+
start_date_string = to_date_string(start_date)
|
105
|
+
end_date_string = to_date_string(end_date)
|
106
|
+
url << "&start_date=#{URI.encode(start_date_string)}" if !start_date_string.nil?
|
107
|
+
url << "&end_date=#{URI.encode(end_date_string)}" if !end_date_string.nil?
|
108
|
+
uri = URI.parse(url)
|
109
|
+
|
110
|
+
response = Net::HTTP.get(uri)
|
111
|
+
p response
|
112
|
+
|
113
|
+
if !response.nil?
|
114
|
+
data = response
|
115
|
+
obj = JSON::parse(data)
|
116
|
+
stats = obj["stats"]
|
117
|
+
return nil if stats.nil?
|
118
|
+
io_totals = stats["io_totals"]
|
119
|
+
return nil if io_totals.nil?
|
120
|
+
p io_totals
|
121
|
+
iostats = InsertionOrderStats.create({
|
122
|
+
:impressions => io_totals["imp"].to_i,
|
123
|
+
:clicks => io_totals["clk"].to_i,
|
124
|
+
:conversions => io_totals["conv"].to_i,
|
125
|
+
:spend => io_totals["spend"].gsub(/[^\d\.]/, '').to_f,
|
126
|
+
:cpm => io_totals["cpm"].gsub(/[^\d\.]/, '').to_f,
|
127
|
+
:cpc => io_totals["cpc"].gsub(/[^\d\.]/, '').to_f,
|
128
|
+
:cpa => io_totals["cpa"].gsub(/[^\d\.]/, '').to_f,
|
129
|
+
:ctr => io_totals["ctr"].to_f
|
130
|
+
})
|
131
|
+
return iostats
|
132
|
+
else
|
133
|
+
return nil
|
134
|
+
end
|
121
135
|
end
|
122
136
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
137
|
+
private
|
138
|
+
|
139
|
+
def deep_copy(o)
|
140
|
+
Marshal.load(Marshal.dump(o))
|
127
141
|
end
|
128
142
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
143
|
+
def to_date_string(o)
|
144
|
+
if o.nil?
|
145
|
+
return nil
|
146
|
+
elsif o.is_a?(Date)
|
147
|
+
return o.strftime("%d %b %Y")
|
148
|
+
elsif o.is_a?(String)
|
149
|
+
raise "case not handled"
|
150
|
+
end
|
133
151
|
end
|
152
|
+
|
153
|
+
public
|
154
|
+
|
155
|
+
def create_insertion_order( opts =
|
156
|
+
{
|
157
|
+
"name" => nil,
|
158
|
+
"start_datetime" => Date.now,
|
159
|
+
"end_datetime" => Date.now + 7.days,
|
160
|
+
"creative_type_ids" => [],
|
161
|
+
"budget" => "1.00",
|
162
|
+
"iab_catgories" => [],
|
163
|
+
"bid_per_impression" => "2.00",
|
164
|
+
"top_level_domain" => "pocketmath.com",
|
165
|
+
"country" => "223",
|
166
|
+
"image_url" => "https://s3.amazonaws.com/pocketmath/pocketmath_320x50.jpg",
|
167
|
+
"landing_page_url" => "www.pocketmath.com",
|
168
|
+
"size_id" => "11"
|
169
|
+
})
|
134
170
|
|
135
|
-
|
171
|
+
o = deep_copy(opts)
|
136
172
|
|
137
|
-
|
173
|
+
if o["name"].nil?
|
174
|
+
raise "name was nil"
|
175
|
+
end
|
138
176
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
request = Net::HTTP::Post.new("/v1/io/create.json")
|
143
|
-
request.body = create_io_json
|
144
|
-
request.content_type = "application/json"
|
145
|
-
response = http.request(request)
|
146
|
-
end
|
147
|
-
if !response.nil?
|
148
|
-
data = response.body
|
149
|
-
p response
|
150
|
-
p data
|
151
|
-
obj = JSON::parse(data)
|
152
|
-
io_id = obj["id"]
|
153
|
-
return io_id
|
154
|
-
else
|
155
|
-
return nil
|
156
|
-
end
|
177
|
+
if o["iab_category_codes"].empty?
|
178
|
+
raise "no iab_category_codes specified"
|
179
|
+
end
|
157
180
|
|
158
|
-
|
181
|
+
if o["start_datetime"].is_a?(Date)
|
182
|
+
o["start_datetime"] = o["start_datetime"].strftime("%d %b %Y")
|
183
|
+
elsif ! o["start_datetime"].is_a?(String)
|
184
|
+
raise "unsupported type"
|
185
|
+
end
|
186
|
+
|
187
|
+
if o["end_datetime"].is_a?(Date)
|
188
|
+
o["end_datetime"] = o["end_datetime"].strftime("%d %b %Y")
|
189
|
+
elsif ! o["end_datetime"].is_a?(String)
|
190
|
+
raise "unsupported type"
|
191
|
+
end
|
192
|
+
|
193
|
+
obj = { "token" => @pocketmath_api_key, "io" => o }
|
194
|
+
|
195
|
+
create_io_json = JSON.generate(obj)
|
196
|
+
|
197
|
+
uri = URI.parse(@pocketmath_api_base_url)
|
198
|
+
response = nil
|
199
|
+
Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
|
200
|
+
request = Net::HTTP::Post.new("/v1/io/create.json")
|
201
|
+
request.body = create_io_json
|
202
|
+
request.content_type = "application/json"
|
203
|
+
response = http.request(request)
|
204
|
+
end
|
205
|
+
if !response.nil?
|
206
|
+
data = response.body
|
207
|
+
p response
|
208
|
+
p data
|
209
|
+
obj = JSON::parse(data)
|
210
|
+
io_id = obj["id"]
|
211
|
+
return io_id
|
212
|
+
else
|
213
|
+
return nil
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
end # end Client
|
159
219
|
|
160
220
|
end # module PocketMath::Advertiser::V1
|
161
221
|
end # module PocketMath::Advertiser
|
data/lib/pocketmath-geocode.rb
CHANGED
@@ -1,73 +1,113 @@
|
|
1
1
|
require 'json'
|
2
|
-
require 'open-uri'
|
3
2
|
require 'net/http'
|
4
3
|
require 'uri'
|
5
4
|
|
6
|
-
GEOCODING_PROVIDER = :open # May also use :google (see Google Map API Terms of Service to determine licensing requirements)
|
7
|
-
|
8
5
|
module PocketMath
|
9
6
|
module PocketMath::Geocode
|
10
7
|
|
11
|
-
|
8
|
+
DEFAULT_GEOCODING_PROVIDER = :open # May also use :google (see Google Map API Terms of Service to determine licensing requirements)
|
12
9
|
|
13
|
-
def self.
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
10
|
+
def self.open( opts = { :mapquest_api_key => nil, :provider => DEFAULT_GEOCODING_PROVIDER } )
|
11
|
+
return Geocode::Client.new(opts)
|
12
|
+
end
|
13
|
+
|
14
|
+
class PocketMath::Geocode::Client
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def initialize( opts = { :mapquest_api_key => nil, :provider => DEFAULT_GEOCODING_PROVIDER } )
|
19
|
+
if !opts[:provider].nil?
|
20
|
+
@provider = opts[:provider]
|
21
|
+
else
|
22
|
+
@provider = DEFAULT_GEOCODING_PROVIDER
|
23
|
+
end
|
24
|
+
|
25
|
+
if !opts[:mapquest_api_key].nil?
|
26
|
+
@mapquest_api_key = opts[:mapquest_api_key]
|
27
|
+
else
|
28
|
+
@mapquest_api_key = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
if @provider == :open && @mapquest_api_key.nil?
|
32
|
+
raise "Geocoding provider OPEN requires MapQuest API key. No key was specified. Please specify like this: Geocode.open{ :mapquest_api_key => \"...\" }"
|
25
33
|
end
|
26
34
|
end
|
27
|
-
return nil if gps_coordinates.empty?
|
28
|
-
return gps_coordinates
|
29
|
-
end
|
30
35
|
|
31
|
-
|
36
|
+
private
|
32
37
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
location = geometry["location"]
|
50
|
-
raise "location was unavailable" if location.nil?
|
51
|
-
lat = location["lat"]
|
52
|
-
lng = location["lng"]
|
53
|
-
gps_coordinates << { :latitude => lat, :longitude => lng }
|
54
|
-
n += 1
|
38
|
+
def get_gps_coordinates_open(location, max_results = 1)
|
39
|
+
url = "http://open.mapquestapi.com/geocoding/v1/address?key=#{@mapquest_api_key}&location=#{URI.encode(location)}&maxResults=#{max_results.to_s}&inFormat=kvp&outFormat=json&json=true"
|
40
|
+
response = Net::HTTP.get_response(URI.parse(url))
|
41
|
+
data = response.body
|
42
|
+
obj = JSON.parse(data)
|
43
|
+
p url
|
44
|
+
p obj
|
45
|
+
gps_coordinates = []
|
46
|
+
obj["results"].each do |result|
|
47
|
+
result["locations"].each do |location|
|
48
|
+
lat_lng = location["latLng"]
|
49
|
+
gps_coordinates << { :latitude => lat_lng["lat"], :longitude => lat_lng["lng"] }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
return nil if gps_coordinates.empty?
|
53
|
+
return gps_coordinates
|
55
54
|
end
|
56
|
-
return nil if gps_coordinates.empty?
|
57
|
-
return gps_coordinates
|
58
|
-
end
|
59
55
|
|
60
|
-
|
56
|
+
private
|
61
57
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
58
|
+
#
|
59
|
+
# Use of the Google Map API requires licensing from Google.
|
60
|
+
#
|
61
|
+
def get_gps_coordinates_google(location, max_results = 1)
|
62
|
+
url = "http://maps.googleapis.com/maps/api/geocode/json?address=#{URI.encode(location)}&sensor=true"
|
63
|
+
response = Net::HTTP.get_response(URI.parse(url))
|
64
|
+
data = response.body
|
65
|
+
obj = JSON.parse(data)
|
66
|
+
p url
|
67
|
+
p obj
|
68
|
+
gps_coordinates = []
|
69
|
+
n = 0
|
70
|
+
obj["results"].each do |result|
|
71
|
+
break if n >= max_results
|
72
|
+
geometry = result["geometry"]
|
73
|
+
raise "geometry was unavailable" if geometry.nil?
|
74
|
+
location = geometry["location"]
|
75
|
+
raise "location was unavailable" if location.nil?
|
76
|
+
lat = location["lat"]
|
77
|
+
lng = location["lng"]
|
78
|
+
gps_coordinates << { :latitude => lat, :longitude => lng }
|
79
|
+
n += 1
|
80
|
+
end
|
81
|
+
return nil if gps_coordinates.empty?
|
82
|
+
return gps_coordinates
|
69
83
|
end
|
70
|
-
end
|
71
84
|
|
85
|
+
public
|
86
|
+
|
87
|
+
def get_gps_coordinates(locations, max_results = 1)
|
88
|
+
_locations = nil
|
89
|
+
if (!locations.is_a?(Array))
|
90
|
+
_locations = [ locations ]
|
91
|
+
else
|
92
|
+
_locations = locations
|
93
|
+
end
|
94
|
+
gps_coordinates = []
|
95
|
+
_locations.each do |location|
|
96
|
+
if @provider == :google
|
97
|
+
gps_coordinates = gps_coordinates + get_gps_coordinates_google(location, max_results)
|
98
|
+
elsif @provider == :open
|
99
|
+
gps_coordinates = gps_coordinates + get_gps_coordinates_open(location, max_results)
|
100
|
+
else
|
101
|
+
raise "map provider was not specified"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
gps_coodinates = gps_coordinates.zip
|
105
|
+
return gps_coordinates
|
106
|
+
end
|
107
|
+
|
108
|
+
def close
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
72
112
|
end
|
73
113
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pocketmath-advertise
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Tucker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-01-
|
11
|
+
date: 2014-01-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: curb
|
@@ -16,20 +16,27 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
19
|
+
version: '0.8'
|
20
|
+
- - '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.8.5
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
23
26
|
requirements:
|
24
27
|
- - ~>
|
25
28
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
29
|
+
version: '0.8'
|
30
|
+
- - '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.8.5
|
27
33
|
description: A client to connect to the PocketMath advertising API.
|
28
34
|
email: eric@pocketmath.com
|
29
35
|
executables: []
|
30
36
|
extensions: []
|
31
37
|
extra_rdoc_files: []
|
32
38
|
files:
|
39
|
+
- lib/model/insertion_order_stats.rb
|
33
40
|
- lib/pocketmath-advertise.rb
|
34
41
|
- lib/pocketmath-advertiser.rb
|
35
42
|
- lib/pocketmath-geocode.rb
|