ahoy_matey 3.0.5 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +36 -12
- data/lib/ahoy.rb +9 -0
- data/lib/ahoy/base_store.rb +5 -1
- data/lib/ahoy/controller.rb +3 -3
- data/lib/ahoy/model.rb +1 -1
- data/lib/ahoy/tracker.rb +5 -9
- data/lib/ahoy/version.rb +1 -1
- data/lib/generators/ahoy/activerecord_generator.rb +12 -4
- data/lib/generators/ahoy/templates/base_store_initializer.rb.tt +5 -0
- data/lib/generators/ahoy/templates/database_store_initializer.rb.tt +5 -0
- data/vendor/assets/javascripts/ahoy.js +111 -18
- metadata +8 -162
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 51e11f3086c12a1418ea7436e291ca9d2f0c7e0aa3091c48c904d05b4be6a210
|
|
4
|
+
data.tar.gz: 5b5c6afc94c0db23f2f1616f6e9edc0ae95ff334e33704c26417705d06d04670
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fd75680d3d04b2383c30b19848f88fcb838f1498e8819d2d758aec6443e85bfb2f73a421da968cb54628097631c777ac1f95dd1ca4bae6d6b22d748a44dcb84d
|
|
7
|
+
data.tar.gz: 2d336bd12312cddf4b76f213b1f7f84b1fc2f0b67302e75096d1eb21013982f532064b31894ba217f7ccbafdbaf5eb4c691a3a86350b8abf1449374f66015909
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## 3.2.0 (2021-03-01)
|
|
2
|
+
|
|
3
|
+
- Disabled geocoding by default for new installations
|
|
4
|
+
- Fixed deprecation warning with Active Record 6.1
|
|
5
|
+
|
|
6
|
+
## 3.1.0 (2020-12-04)
|
|
7
|
+
|
|
8
|
+
- Added `instance` method
|
|
9
|
+
- Added `request` argument to `user_method`
|
|
10
|
+
- Updated Ahoy.js to 0.3.8
|
|
11
|
+
- Removed `exclude_method` call when geocoding
|
|
12
|
+
|
|
1
13
|
## 3.0.5 (2020-09-09)
|
|
2
14
|
|
|
3
15
|
- Added `group_prop` method
|
data/README.md
CHANGED
|
@@ -8,7 +8,7 @@ Track visits and events in Ruby, JavaScript, and native apps. Data is stored in
|
|
|
8
8
|
|
|
9
9
|
:tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
|
|
10
10
|
|
|
11
|
-
[](https://github.com/ankane/ahoy/actions)
|
|
12
12
|
|
|
13
13
|
## Installation
|
|
14
14
|
|
|
@@ -70,10 +70,18 @@ Track an event with:
|
|
|
70
70
|
ahoy.track("My second event", {language: "JavaScript"});
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
### Native Apps
|
|
74
|
+
|
|
75
|
+
Check out [Ahoy iOS](https://github.com/namolnad/ahoy-ios) and [Ahoy Android](https://github.com/instacart/ahoy-android).
|
|
76
|
+
|
|
73
77
|
### GDPR Compliance
|
|
74
78
|
|
|
75
79
|
Ahoy provides a number of options to help with GDPR compliance. See the [GDPR section](#gdpr-compliance-1) for more info.
|
|
76
80
|
|
|
81
|
+
### Geocoding Setup
|
|
82
|
+
|
|
83
|
+
To enable geocoding, see the [Geocoding section](#geocoding).
|
|
84
|
+
|
|
77
85
|
## How It Works
|
|
78
86
|
|
|
79
87
|
### Visits
|
|
@@ -145,7 +153,7 @@ See [Ahoy.js](https://github.com/ankane/ahoy.js) for a complete list of features
|
|
|
145
153
|
|
|
146
154
|
#### Native Apps
|
|
147
155
|
|
|
148
|
-
|
|
156
|
+
See the docs for [Ahoy iOS](https://github.com/namolnad/ahoy-ios) and [Ahoy Android](https://github.com/instacart/ahoy-android).
|
|
149
157
|
|
|
150
158
|
#### AMP
|
|
151
159
|
|
|
@@ -308,40 +316,56 @@ Ahoy.cookie_options = {same_site: :lax}
|
|
|
308
316
|
|
|
309
317
|
### Geocoding
|
|
310
318
|
|
|
311
|
-
|
|
319
|
+
Ahoy uses [Geocoder](https://github.com/alexreisner/geocoder) for geocoding. We recommend configuring [local geocoding](#local-geocoding) so IP addresses are not sent to a 3rd party service. If you do use a 3rd party service, be sure to add it to your GDPR subprocessor list. If Ahoy is configured to [mask ips](#ip-masking), the masked IP is used (this increases privacy but can reduce accuracy).
|
|
320
|
+
|
|
321
|
+
To enable geocoding, update `config/initializers/ahoy.rb`:
|
|
312
322
|
|
|
313
323
|
```ruby
|
|
314
|
-
Ahoy.geocode =
|
|
324
|
+
Ahoy.geocode = true
|
|
315
325
|
```
|
|
316
326
|
|
|
317
|
-
The default job queue is `:ahoy`. Change this with:
|
|
327
|
+
Geocoding is performed in a background job so it doesn’t slow down web requests. The default job queue is `:ahoy`. Change this with:
|
|
318
328
|
|
|
319
329
|
```ruby
|
|
320
330
|
Ahoy.job_queue = :low_priority
|
|
321
331
|
```
|
|
322
332
|
|
|
323
|
-
|
|
333
|
+
### Local Geocoding
|
|
324
334
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
Add this line to your application’s Gemfile:
|
|
335
|
+
For privacy and performance, we recommend geocoding locally. Add this line to your application’s Gemfile:
|
|
328
336
|
|
|
329
337
|
```ruby
|
|
330
338
|
gem 'maxminddb'
|
|
331
339
|
```
|
|
332
340
|
|
|
333
|
-
|
|
341
|
+
For city-level geocoding, download the [GeoLite2 City database](https://dev.maxmind.com/geoip/geoip2/geolite2/) and create `config/initializers/geocoder.rb` with:
|
|
334
342
|
|
|
335
343
|
```ruby
|
|
336
344
|
Geocoder.configure(
|
|
337
345
|
ip_lookup: :geoip2,
|
|
338
346
|
geoip2: {
|
|
339
|
-
file:
|
|
347
|
+
file: "path/to/GeoLite2-City.mmdb"
|
|
340
348
|
}
|
|
341
349
|
)
|
|
342
350
|
```
|
|
343
351
|
|
|
344
|
-
|
|
352
|
+
For country-level geocoding, install the `geoip-database` package. It’s preinstalled on Heroku. For Ubuntu, use:
|
|
353
|
+
|
|
354
|
+
```sh
|
|
355
|
+
sudo apt-get install geoip-database
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
And create `config/initializers/geocoder.rb` with:
|
|
359
|
+
|
|
360
|
+
```ruby
|
|
361
|
+
Geocoder.configure(
|
|
362
|
+
ip_lookup: :maxmind_local,
|
|
363
|
+
maxmind_local: {
|
|
364
|
+
file: "/usr/share/GeoIP/GeoIP.dat",
|
|
365
|
+
package: :country
|
|
366
|
+
}
|
|
367
|
+
)
|
|
368
|
+
```
|
|
345
369
|
|
|
346
370
|
### Token Generation
|
|
347
371
|
|
data/lib/ahoy.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# stdlib
|
|
1
2
|
require "ipaddr"
|
|
2
3
|
|
|
3
4
|
# dependencies
|
|
@@ -104,6 +105,14 @@ module Ahoy
|
|
|
104
105
|
addr.mask(48).to_s
|
|
105
106
|
end
|
|
106
107
|
end
|
|
108
|
+
|
|
109
|
+
def self.instance
|
|
110
|
+
Thread.current[:ahoy]
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def self.instance=(value)
|
|
114
|
+
Thread.current[:ahoy] = value
|
|
115
|
+
end
|
|
107
116
|
end
|
|
108
117
|
|
|
109
118
|
ActiveSupport.on_load(:action_controller) do
|
data/lib/ahoy/base_store.rb
CHANGED
|
@@ -24,7 +24,11 @@ module Ahoy
|
|
|
24
24
|
def user
|
|
25
25
|
@user ||= begin
|
|
26
26
|
if Ahoy.user_method.respond_to?(:call)
|
|
27
|
-
Ahoy.user_method.
|
|
27
|
+
if Ahoy.user_method.arity == 1
|
|
28
|
+
Ahoy.user_method.call(controller)
|
|
29
|
+
else
|
|
30
|
+
Ahoy.user_method.call(controller, request)
|
|
31
|
+
end
|
|
28
32
|
else
|
|
29
33
|
controller.send(Ahoy.user_method) if controller.respond_to?(Ahoy.user_method, true)
|
|
30
34
|
end
|
data/lib/ahoy/controller.rb
CHANGED
|
@@ -39,12 +39,12 @@ module Ahoy
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
def set_ahoy_request_store
|
|
42
|
-
previous_value =
|
|
42
|
+
previous_value = Ahoy.instance
|
|
43
43
|
begin
|
|
44
|
-
|
|
44
|
+
Ahoy.instance = ahoy
|
|
45
45
|
yield
|
|
46
46
|
ensure
|
|
47
|
-
|
|
47
|
+
Ahoy.instance = previous_value
|
|
48
48
|
end
|
|
49
49
|
end
|
|
50
50
|
end
|
data/lib/ahoy/model.rb
CHANGED
data/lib/ahoy/tracker.rb
CHANGED
|
@@ -67,16 +67,12 @@ module Ahoy
|
|
|
67
67
|
end
|
|
68
68
|
|
|
69
69
|
def geocode(data)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
data = {
|
|
74
|
-
visit_token: visit_token
|
|
75
|
-
}.merge(data).select { |_, v| v }
|
|
70
|
+
data = {
|
|
71
|
+
visit_token: visit_token
|
|
72
|
+
}.merge(data).select { |_, v| v }
|
|
76
73
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
end
|
|
74
|
+
@store.geocode(data)
|
|
75
|
+
true
|
|
80
76
|
rescue => e
|
|
81
77
|
report_exception(e)
|
|
82
78
|
end
|
data/lib/ahoy/version.rb
CHANGED
|
@@ -17,9 +17,7 @@ module Ahoy
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def properties_type
|
|
20
|
-
|
|
21
|
-
# so database connection isn't needed
|
|
22
|
-
case ActiveRecord::Base.connection_config[:adapter].to_s
|
|
20
|
+
case adapter
|
|
23
21
|
when /postg/i # postgres, postgis
|
|
24
22
|
"jsonb"
|
|
25
23
|
when /mysql/i
|
|
@@ -29,8 +27,18 @@ module Ahoy
|
|
|
29
27
|
end
|
|
30
28
|
end
|
|
31
29
|
|
|
30
|
+
# use connection_config instead of connection.adapter
|
|
31
|
+
# so database connection isn't needed
|
|
32
|
+
def adapter
|
|
33
|
+
if ActiveRecord::VERSION::STRING.to_f >= 6.1
|
|
34
|
+
ActiveRecord::Base.connection_db_config.adapter.to_s
|
|
35
|
+
else
|
|
36
|
+
ActiveRecord::Base.connection_config[:adapter].to_s
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
32
40
|
def rails52?
|
|
33
|
-
ActiveRecord::VERSION::STRING >=
|
|
41
|
+
ActiveRecord::VERSION::STRING.to_f >= 5.2
|
|
34
42
|
end
|
|
35
43
|
|
|
36
44
|
def migration_version
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Ahoy.js
|
|
3
3
|
* Simple, powerful JavaScript analytics
|
|
4
4
|
* https://github.com/ankane/ahoy.js
|
|
5
|
-
* v0.3.
|
|
5
|
+
* v0.3.8
|
|
6
6
|
* MIT License
|
|
7
7
|
*/
|
|
8
8
|
|
|
@@ -12,7 +12,96 @@
|
|
|
12
12
|
(global = global || self, global.ahoy = factory());
|
|
13
13
|
}(this, (function () { 'use strict';
|
|
14
14
|
|
|
15
|
-
var
|
|
15
|
+
var isUndefined = function (value) { return value === undefined; };
|
|
16
|
+
|
|
17
|
+
var isNull = function (value) { return value === null; };
|
|
18
|
+
|
|
19
|
+
var isBoolean = function (value) { return typeof value === 'boolean'; };
|
|
20
|
+
|
|
21
|
+
var isObject = function (value) { return value === Object(value); };
|
|
22
|
+
|
|
23
|
+
var isArray = function (value) { return Array.isArray(value); };
|
|
24
|
+
|
|
25
|
+
var isDate = function (value) { return value instanceof Date; };
|
|
26
|
+
|
|
27
|
+
var isBlob = function (value) { return value &&
|
|
28
|
+
typeof value.size === 'number' &&
|
|
29
|
+
typeof value.type === 'string' &&
|
|
30
|
+
typeof value.slice === 'function'; };
|
|
31
|
+
|
|
32
|
+
var isFile = function (value) { return isBlob(value) &&
|
|
33
|
+
typeof value.name === 'string' &&
|
|
34
|
+
(typeof value.lastModifiedDate === 'object' ||
|
|
35
|
+
typeof value.lastModified === 'number'); };
|
|
36
|
+
|
|
37
|
+
var serialize = function (obj, cfg, fd, pre) {
|
|
38
|
+
cfg = cfg || {};
|
|
39
|
+
|
|
40
|
+
cfg.indices = isUndefined(cfg.indices) ? false : cfg.indices;
|
|
41
|
+
|
|
42
|
+
cfg.nullsAsUndefineds = isUndefined(cfg.nullsAsUndefineds)
|
|
43
|
+
? false
|
|
44
|
+
: cfg.nullsAsUndefineds;
|
|
45
|
+
|
|
46
|
+
cfg.booleansAsIntegers = isUndefined(cfg.booleansAsIntegers)
|
|
47
|
+
? false
|
|
48
|
+
: cfg.booleansAsIntegers;
|
|
49
|
+
|
|
50
|
+
cfg.allowEmptyArrays = isUndefined(cfg.allowEmptyArrays)
|
|
51
|
+
? false
|
|
52
|
+
: cfg.allowEmptyArrays;
|
|
53
|
+
|
|
54
|
+
fd = fd || new FormData();
|
|
55
|
+
|
|
56
|
+
if (isUndefined(obj)) {
|
|
57
|
+
return fd;
|
|
58
|
+
} else if (isNull(obj)) {
|
|
59
|
+
if (!cfg.nullsAsUndefineds) {
|
|
60
|
+
fd.append(pre, '');
|
|
61
|
+
}
|
|
62
|
+
} else if (isBoolean(obj)) {
|
|
63
|
+
if (cfg.booleansAsIntegers) {
|
|
64
|
+
fd.append(pre, obj ? 1 : 0);
|
|
65
|
+
} else {
|
|
66
|
+
fd.append(pre, obj);
|
|
67
|
+
}
|
|
68
|
+
} else if (isArray(obj)) {
|
|
69
|
+
if (obj.length) {
|
|
70
|
+
obj.forEach(function (value, index) {
|
|
71
|
+
var key = pre + '[' + (cfg.indices ? index : '') + ']';
|
|
72
|
+
|
|
73
|
+
serialize(value, cfg, fd, key);
|
|
74
|
+
});
|
|
75
|
+
} else if (cfg.allowEmptyArrays) {
|
|
76
|
+
fd.append(pre + '[]', '');
|
|
77
|
+
}
|
|
78
|
+
} else if (isDate(obj)) {
|
|
79
|
+
fd.append(pre, obj.toISOString());
|
|
80
|
+
} else if (isObject(obj) && !isFile(obj) && !isBlob(obj)) {
|
|
81
|
+
Object.keys(obj).forEach(function (prop) {
|
|
82
|
+
var value = obj[prop];
|
|
83
|
+
|
|
84
|
+
if (isArray(value)) {
|
|
85
|
+
while (prop.length > 2 && prop.lastIndexOf('[]') === prop.length - 2) {
|
|
86
|
+
prop = prop.substring(0, prop.length - 2);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
var key = pre ? pre + '[' + prop + ']' : prop;
|
|
91
|
+
|
|
92
|
+
serialize(value, cfg, fd, key);
|
|
93
|
+
});
|
|
94
|
+
} else {
|
|
95
|
+
fd.append(pre, obj);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return fd;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
var index_module = {
|
|
102
|
+
serialize: serialize,
|
|
103
|
+
};
|
|
104
|
+
var index_module_1 = index_module.serialize;
|
|
16
105
|
|
|
17
106
|
// https://www.quirksmode.org/js/cookies.html
|
|
18
107
|
|
|
@@ -146,17 +235,23 @@
|
|
|
146
235
|
element.webkitMatchesSelector;
|
|
147
236
|
|
|
148
237
|
if (matches) {
|
|
149
|
-
|
|
238
|
+
if (matches.apply(element, [selector])) {
|
|
239
|
+
return element;
|
|
240
|
+
} else if (element.parentElement) {
|
|
241
|
+
return matchesSelector(element.parentElement, selector)
|
|
242
|
+
}
|
|
243
|
+
return null;
|
|
150
244
|
} else {
|
|
151
245
|
log("Unable to match");
|
|
152
|
-
return
|
|
246
|
+
return null;
|
|
153
247
|
}
|
|
154
248
|
}
|
|
155
249
|
|
|
156
250
|
function onEvent(eventName, selector, callback) {
|
|
157
251
|
document.addEventListener(eventName, function (e) {
|
|
158
|
-
|
|
159
|
-
|
|
252
|
+
var matchedElement = matchesSelector(e.target, selector);
|
|
253
|
+
if (matchedElement) {
|
|
254
|
+
callback.call(matchedElement, e);
|
|
160
255
|
}
|
|
161
256
|
});
|
|
162
257
|
}
|
|
@@ -275,7 +370,7 @@
|
|
|
275
370
|
// stringify so we keep the type
|
|
276
371
|
data.events_json = JSON.stringify(data.events);
|
|
277
372
|
delete data.events;
|
|
278
|
-
window.navigator.sendBeacon(eventsUrl(),
|
|
373
|
+
window.navigator.sendBeacon(eventsUrl(), index_module_1(data));
|
|
279
374
|
});
|
|
280
375
|
}
|
|
281
376
|
|
|
@@ -299,13 +394,12 @@
|
|
|
299
394
|
}
|
|
300
395
|
|
|
301
396
|
function eventProperties(e) {
|
|
302
|
-
var target = e.target;
|
|
303
397
|
return cleanObject({
|
|
304
|
-
tag:
|
|
305
|
-
id: presence(
|
|
306
|
-
"class": presence(
|
|
398
|
+
tag: this.tagName.toLowerCase(),
|
|
399
|
+
id: presence(this.id),
|
|
400
|
+
"class": presence(this.className),
|
|
307
401
|
page: page(),
|
|
308
|
-
section: getClosestSection(
|
|
402
|
+
section: getClosestSection(this)
|
|
309
403
|
});
|
|
310
404
|
}
|
|
311
405
|
|
|
@@ -465,24 +559,23 @@
|
|
|
465
559
|
|
|
466
560
|
ahoy.trackClicks = function () {
|
|
467
561
|
onEvent("click", "a, button, input[type=submit]", function (e) {
|
|
468
|
-
var
|
|
469
|
-
|
|
470
|
-
properties.
|
|
471
|
-
properties.href = target.href;
|
|
562
|
+
var properties = eventProperties.call(this, e);
|
|
563
|
+
properties.text = properties.tag == "input" ? this.value : (this.textContent || this.innerText || this.innerHTML).replace(/[\s\r\n]+/g, " ").trim();
|
|
564
|
+
properties.href = this.href;
|
|
472
565
|
ahoy.track("$click", properties);
|
|
473
566
|
});
|
|
474
567
|
};
|
|
475
568
|
|
|
476
569
|
ahoy.trackSubmits = function () {
|
|
477
570
|
onEvent("submit", "form", function (e) {
|
|
478
|
-
var properties = eventProperties(e);
|
|
571
|
+
var properties = eventProperties.call(this, e);
|
|
479
572
|
ahoy.track("$submit", properties);
|
|
480
573
|
});
|
|
481
574
|
};
|
|
482
575
|
|
|
483
576
|
ahoy.trackChanges = function () {
|
|
484
577
|
onEvent("change", "input, textarea, select", function (e) {
|
|
485
|
-
var properties = eventProperties(e);
|
|
578
|
+
var properties = eventProperties.call(this, e);
|
|
486
579
|
ahoy.track("$change", properties);
|
|
487
580
|
});
|
|
488
581
|
};
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ahoy_matey
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.0
|
|
4
|
+
version: 3.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrew Kane
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-03-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -66,162 +66,8 @@ dependencies:
|
|
|
66
66
|
- - ">="
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '0'
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
|
72
|
-
requirements:
|
|
73
|
-
- - ">="
|
|
74
|
-
- !ruby/object:Gem::Version
|
|
75
|
-
version: '0'
|
|
76
|
-
type: :development
|
|
77
|
-
prerelease: false
|
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
-
requirements:
|
|
80
|
-
- - ">="
|
|
81
|
-
- !ruby/object:Gem::Version
|
|
82
|
-
version: '0'
|
|
83
|
-
- !ruby/object:Gem::Dependency
|
|
84
|
-
name: rake
|
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
|
86
|
-
requirements:
|
|
87
|
-
- - ">="
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: '0'
|
|
90
|
-
type: :development
|
|
91
|
-
prerelease: false
|
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
-
requirements:
|
|
94
|
-
- - ">="
|
|
95
|
-
- !ruby/object:Gem::Version
|
|
96
|
-
version: '0'
|
|
97
|
-
- !ruby/object:Gem::Dependency
|
|
98
|
-
name: minitest
|
|
99
|
-
requirement: !ruby/object:Gem::Requirement
|
|
100
|
-
requirements:
|
|
101
|
-
- - ">="
|
|
102
|
-
- !ruby/object:Gem::Version
|
|
103
|
-
version: '0'
|
|
104
|
-
type: :development
|
|
105
|
-
prerelease: false
|
|
106
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
107
|
-
requirements:
|
|
108
|
-
- - ">="
|
|
109
|
-
- !ruby/object:Gem::Version
|
|
110
|
-
version: '0'
|
|
111
|
-
- !ruby/object:Gem::Dependency
|
|
112
|
-
name: combustion
|
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
|
114
|
-
requirements:
|
|
115
|
-
- - ">="
|
|
116
|
-
- !ruby/object:Gem::Version
|
|
117
|
-
version: '0'
|
|
118
|
-
type: :development
|
|
119
|
-
prerelease: false
|
|
120
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
121
|
-
requirements:
|
|
122
|
-
- - ">="
|
|
123
|
-
- !ruby/object:Gem::Version
|
|
124
|
-
version: '0'
|
|
125
|
-
- !ruby/object:Gem::Dependency
|
|
126
|
-
name: rails
|
|
127
|
-
requirement: !ruby/object:Gem::Requirement
|
|
128
|
-
requirements:
|
|
129
|
-
- - ">="
|
|
130
|
-
- !ruby/object:Gem::Version
|
|
131
|
-
version: '0'
|
|
132
|
-
type: :development
|
|
133
|
-
prerelease: false
|
|
134
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
135
|
-
requirements:
|
|
136
|
-
- - ">="
|
|
137
|
-
- !ruby/object:Gem::Version
|
|
138
|
-
version: '0'
|
|
139
|
-
- !ruby/object:Gem::Dependency
|
|
140
|
-
name: sqlite3
|
|
141
|
-
requirement: !ruby/object:Gem::Requirement
|
|
142
|
-
requirements:
|
|
143
|
-
- - ">="
|
|
144
|
-
- !ruby/object:Gem::Version
|
|
145
|
-
version: '0'
|
|
146
|
-
type: :development
|
|
147
|
-
prerelease: false
|
|
148
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
149
|
-
requirements:
|
|
150
|
-
- - ">="
|
|
151
|
-
- !ruby/object:Gem::Version
|
|
152
|
-
version: '0'
|
|
153
|
-
- !ruby/object:Gem::Dependency
|
|
154
|
-
name: pg
|
|
155
|
-
requirement: !ruby/object:Gem::Requirement
|
|
156
|
-
requirements:
|
|
157
|
-
- - ">="
|
|
158
|
-
- !ruby/object:Gem::Version
|
|
159
|
-
version: '0'
|
|
160
|
-
type: :development
|
|
161
|
-
prerelease: false
|
|
162
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
163
|
-
requirements:
|
|
164
|
-
- - ">="
|
|
165
|
-
- !ruby/object:Gem::Version
|
|
166
|
-
version: '0'
|
|
167
|
-
- !ruby/object:Gem::Dependency
|
|
168
|
-
name: mysql2
|
|
169
|
-
requirement: !ruby/object:Gem::Requirement
|
|
170
|
-
requirements:
|
|
171
|
-
- - ">="
|
|
172
|
-
- !ruby/object:Gem::Version
|
|
173
|
-
version: '0'
|
|
174
|
-
type: :development
|
|
175
|
-
prerelease: false
|
|
176
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
177
|
-
requirements:
|
|
178
|
-
- - ">="
|
|
179
|
-
- !ruby/object:Gem::Version
|
|
180
|
-
version: '0'
|
|
181
|
-
- !ruby/object:Gem::Dependency
|
|
182
|
-
name: mongoid
|
|
183
|
-
requirement: !ruby/object:Gem::Requirement
|
|
184
|
-
requirements:
|
|
185
|
-
- - ">="
|
|
186
|
-
- !ruby/object:Gem::Version
|
|
187
|
-
version: '0'
|
|
188
|
-
type: :development
|
|
189
|
-
prerelease: false
|
|
190
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
191
|
-
requirements:
|
|
192
|
-
- - ">="
|
|
193
|
-
- !ruby/object:Gem::Version
|
|
194
|
-
version: '0'
|
|
195
|
-
- !ruby/object:Gem::Dependency
|
|
196
|
-
name: browser
|
|
197
|
-
requirement: !ruby/object:Gem::Requirement
|
|
198
|
-
requirements:
|
|
199
|
-
- - "~>"
|
|
200
|
-
- !ruby/object:Gem::Version
|
|
201
|
-
version: '2.0'
|
|
202
|
-
type: :development
|
|
203
|
-
prerelease: false
|
|
204
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
205
|
-
requirements:
|
|
206
|
-
- - "~>"
|
|
207
|
-
- !ruby/object:Gem::Version
|
|
208
|
-
version: '2.0'
|
|
209
|
-
- !ruby/object:Gem::Dependency
|
|
210
|
-
name: user_agent_parser
|
|
211
|
-
requirement: !ruby/object:Gem::Requirement
|
|
212
|
-
requirements:
|
|
213
|
-
- - ">="
|
|
214
|
-
- !ruby/object:Gem::Version
|
|
215
|
-
version: '0'
|
|
216
|
-
type: :development
|
|
217
|
-
prerelease: false
|
|
218
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
219
|
-
requirements:
|
|
220
|
-
- - ">="
|
|
221
|
-
- !ruby/object:Gem::Version
|
|
222
|
-
version: '0'
|
|
223
|
-
description:
|
|
224
|
-
email: andrew@chartkick.com
|
|
69
|
+
description:
|
|
70
|
+
email: andrew@ankane.org
|
|
225
71
|
executables: []
|
|
226
72
|
extensions: []
|
|
227
73
|
extra_rdoc_files: []
|
|
@@ -266,7 +112,7 @@ homepage: https://github.com/ankane/ahoy
|
|
|
266
112
|
licenses:
|
|
267
113
|
- MIT
|
|
268
114
|
metadata: {}
|
|
269
|
-
post_install_message:
|
|
115
|
+
post_install_message:
|
|
270
116
|
rdoc_options: []
|
|
271
117
|
require_paths:
|
|
272
118
|
- lib
|
|
@@ -281,8 +127,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
281
127
|
- !ruby/object:Gem::Version
|
|
282
128
|
version: '0'
|
|
283
129
|
requirements: []
|
|
284
|
-
rubygems_version: 3.
|
|
285
|
-
signing_key:
|
|
130
|
+
rubygems_version: 3.2.3
|
|
131
|
+
signing_key:
|
|
286
132
|
specification_version: 4
|
|
287
133
|
summary: Simple, powerful, first-party analytics for Rails
|
|
288
134
|
test_files: []
|