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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17572400fdaab440040c753cf23084f2a47868e5c1ed12229e85fd1904e9c937
4
- data.tar.gz: cc917af046906e308830fa1ffa9543db1bc1fe0f79488ccaddef090e6366433d
3
+ metadata.gz: 51e11f3086c12a1418ea7436e291ca9d2f0c7e0aa3091c48c904d05b4be6a210
4
+ data.tar.gz: 5b5c6afc94c0db23f2f1616f6e9edc0ae95ff334e33704c26417705d06d04670
5
5
  SHA512:
6
- metadata.gz: 325caa06934a20bf7a58f573fff7359b7058cf63e3e7576c48faf1bd5d08ac2564810a28e5a775c3ac324170754db4de35d46f43c0b421f8c4977760af19d153
7
- data.tar.gz: e7af674522e09e3fb472b52546f30d10b743e2b2814efd97162d05cb1d4f9b13615dce211cd83e291da16e370a86cf7d8d384b16ad60d8af07c8ced8fbd17f59
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
- [![Build Status](https://travis-ci.org/ankane/ahoy.svg?branch=master)](https://travis-ci.org/ankane/ahoy)
11
+ [![Build Status](https://github.com/ankane/ahoy/workflows/build/badge.svg?branch=master)](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
- For Android, check out [Ahoy Android](https://github.com/instacart/ahoy-android). For other platforms, see the [API spec](#api-spec).
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
- Disable geocoding with:
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 = false
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
- #### Geocoding Performance
333
+ ### Local Geocoding
324
334
 
325
- To avoid calls to a remote API, download the [GeoLite2 City database](https://dev.maxmind.com/geoip/geoip2/geolite2/) and configure Geocoder to use it.
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
- And create an initializer at `config/initializers/geocoder.rb` with:
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: Rails.root.join("lib", "GeoLite2-City.mmdb")
347
+ file: "path/to/GeoLite2-City.mmdb"
340
348
  }
341
349
  )
342
350
  ```
343
351
 
344
- If you use Heroku, you can use an unofficial buildpack like [this one](https://github.com/temedica/heroku-buildpack-maxmind-geolite2) to avoid including the database in your repo.
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
@@ -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.call(controller)
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
@@ -39,12 +39,12 @@ module Ahoy
39
39
  end
40
40
 
41
41
  def set_ahoy_request_store
42
- previous_value = Thread.current[:ahoy]
42
+ previous_value = Ahoy.instance
43
43
  begin
44
- Thread.current[:ahoy] = ahoy
44
+ Ahoy.instance = ahoy
45
45
  yield
46
46
  ensure
47
- Thread.current[:ahoy] = previous_value
47
+ Ahoy.instance = previous_value
48
48
  end
49
49
  end
50
50
  end
data/lib/ahoy/model.rb CHANGED
@@ -7,7 +7,7 @@ module Ahoy
7
7
  end
8
8
  class_eval %{
9
9
  def set_ahoy_visit
10
- self.#{name} ||= Thread.current[:ahoy].try(:visit_or_create)
10
+ self.#{name} ||= Ahoy.instance.try(:visit_or_create)
11
11
  end
12
12
  }
13
13
  end
data/lib/ahoy/tracker.rb CHANGED
@@ -67,16 +67,12 @@ module Ahoy
67
67
  end
68
68
 
69
69
  def geocode(data)
70
- if exclude?
71
- debug "Geocode excluded"
72
- else
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
- @store.geocode(data)
78
- true
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
@@ -1,3 +1,3 @@
1
1
  module Ahoy
2
- VERSION = "3.0.5"
2
+ VERSION = "3.2.0"
3
3
  end
@@ -17,9 +17,7 @@ module Ahoy
17
17
  end
18
18
 
19
19
  def properties_type
20
- # use connection_config instead of connection.adapter
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 >= "5.2"
41
+ ActiveRecord::VERSION::STRING.to_f >= 5.2
34
42
  end
35
43
 
36
44
  def migration_version
@@ -18,3 +18,8 @@ end
18
18
 
19
19
  # set to true for JavaScript tracking
20
20
  Ahoy.api = false
21
+
22
+ # set to true for geocoding
23
+ # we recommend configuring local geocoding first
24
+ # see https://github.com/ankane/ahoy#geocoding
25
+ Ahoy.geocode = false
@@ -3,3 +3,8 @@ end
3
3
 
4
4
  # set to true for JavaScript tracking
5
5
  Ahoy.api = false
6
+
7
+ # set to true for geocoding
8
+ # we recommend configuring local geocoding first
9
+ # see https://github.com/ankane/ahoy#geocoding
10
+ Ahoy.geocode = false
@@ -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.6
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 n=function(n){return void 0===n},e=function(n){return Array.isArray(n)},t=function(n){return n&&"number"==typeof n.size&&"string"==typeof n.type&&"function"==typeof n.slice},s=function(o,i,r,f){return (i=i||{}).indices=!n(i.indices)&&i.indices,i.nullsAsUndefineds=!n(i.nullsAsUndefineds)&&i.nullsAsUndefineds,i.booleansAsIntegers=!n(i.booleansAsIntegers)&&i.booleansAsIntegers,r=r||new FormData,n(o)?r:(null===o?i.nullsAsUndefineds||r.append(f,""):"boolean"!=typeof o?e(o)?o.length&&o.forEach(function(n,e){s(n,i,r,f+"["+(i.indices?e:"")+"]");}):o instanceof Date?r.append(f,o.toISOString()):o!==Object(o)||function(n){return t(n)&&"string"==typeof n.name&&("object"==typeof n.lastModifiedDate||"number"==typeof n.lastModified)}(o)||t(o)?r.append(f,o):Object.keys(o).forEach(function(n){var t=o[n];if(e(t)){ for(;n.length>2&&n.lastIndexOf("[]")===n.length-2;){ n=n.substring(0,n.length-2); } }s(t,i,r,f?f+"["+n+"]":n);}):r.append(f,i.booleansAsIntegers?o?1:0:o),r)};
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
- return matches.apply(element, [selector]);
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 false;
246
+ return null;
153
247
  }
154
248
  }
155
249
 
156
250
  function onEvent(eventName, selector, callback) {
157
251
  document.addEventListener(eventName, function (e) {
158
- if (matchesSelector(e.target, selector)) {
159
- callback(e);
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(), s(data));
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: target.tagName.toLowerCase(),
305
- id: presence(target.id),
306
- "class": presence(target.className),
398
+ tag: this.tagName.toLowerCase(),
399
+ id: presence(this.id),
400
+ "class": presence(this.className),
307
401
  page: page(),
308
- section: getClosestSection(target)
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 target = e.target;
469
- var properties = eventProperties(e);
470
- properties.text = properties.tag == "input" ? target.value : (target.textContent || target.innerText || target.innerHTML).replace(/[\s\r\n]+/g, " ").trim();
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.5
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: 2020-09-10 00:00:00.000000000 Z
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
- - !ruby/object:Gem::Dependency
70
- name: bundler
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.1.2
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: []