ga_events 3.0.0 → 4.0.1
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/.gitignore +3 -0
- data/CHANGELOG.md +26 -0
- data/Gemfile +1 -1
- data/README.md +13 -52
- data/app/assets/javascripts/ga_events.js.coffee +40 -78
- data/ga_events.gemspec +3 -4
- data/lib/ga_events/event.rb +24 -6
- data/lib/ga_events/list.rb +7 -2
- data/lib/ga_events/middleware.rb +18 -21
- data/lib/ga_events/version.rb +1 -1
- data/spec/event_spec.rb +68 -0
- data/spec/list_spec.rb +40 -0
- data/spec/middleware_spec.rb +17 -4
- metadata +10 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '08583d04c842b3ab9c4efa4df756662a83b04dfe3fba2d979dd7d1be3426d173'
|
4
|
+
data.tar.gz: 1bab40e8a318ca3b540430ab69734960f97dac17a6b250df2b95c5f32378e64d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3a07495ef1e66b621c4bf3e3d8d06ba22add1965003148a53a50ac31bb256ea5faa9519b706c36e568099f0dbf1e4a8929012966b6378c416f58562bfa137b1
|
7
|
+
data.tar.gz: 066c9032ada9d87d16202bf00fb435b0420a0ae247f1f21cf22bb6ddece372380c2bd5a2bec1532ffdc3d1972b84a084c38b588c48a6a551a3f74f3a925da8c3
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -64,3 +64,29 @@ The format suggested at http://keepachangelog.com/ is used.
|
|
64
64
|
- Universal Analytics Adapter can be configured to use a custom name for the
|
65
65
|
analytics object (defaults to `window.ga()` for `analytics.js` and
|
66
66
|
`window.gtag()` for `gtag.js`)
|
67
|
+
|
68
|
+
## 4.0.0 - 2023-08-xx
|
69
|
+
|
70
|
+
### Added
|
71
|
+
- Support for GA4 using the `GTagAdapter`
|
72
|
+
|
73
|
+
### Breaking
|
74
|
+
- Dropped support for older rubies. The gem requires at least ruby 3.2 now
|
75
|
+
- UniversalAnalyticsAdapter and GoogleAnalyticsAdapter removed
|
76
|
+
- The `GaEvent::Event` constructor changed to conform to the new newer
|
77
|
+
GA4 event interface.
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
# 3.x and before
|
81
|
+
GaEvents::Event.new('category', 'action', 'label', 'value')
|
82
|
+
|
83
|
+
# 4.x onwards
|
84
|
+
GaEvents::Event.new('event_name', {
|
85
|
+
custom_dimension: 'xxx',
|
86
|
+
custom_dimension2: 'yyy'
|
87
|
+
})
|
88
|
+
```
|
89
|
+
- Events that should be kept on redirects are no longer mixed into rails
|
90
|
+
flashes. Redirect events are stored inside a custom rack session variable
|
91
|
+
instead.
|
92
|
+
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -7,13 +7,13 @@ app.
|
|
7
7
|
A rack middleware is automatically inserted into the stack. It transports
|
8
8
|
the event data to the client. Normal requests get a DIV injected, Ajax requests
|
9
9
|
get a data-pounded custom HTTP header appended. In case of redirects the data
|
10
|
-
survives inside
|
10
|
+
survives inside of rack a rack session.
|
11
11
|
The asset pipeline-ready CoffeeScript extracts this data on the client-side and
|
12
|
-
pushes it to Google Analytics via
|
12
|
+
pushes it to Google Analytics via gtag.js or Google Tag Manager.
|
13
13
|
|
14
14
|
## Dependencies
|
15
15
|
|
16
|
-
* Ruby >= 2
|
16
|
+
* Ruby >= 3.2
|
17
17
|
* Rails 4.2 onwards
|
18
18
|
* jQuery
|
19
19
|
|
@@ -35,42 +35,11 @@ Add to the top of your `application.js` (but after requiring jQuery):
|
|
35
35
|
|
36
36
|
After requiring `ga_events.js`, you have to choose an adapter.
|
37
37
|
|
38
|
-
### Google Analytics (
|
38
|
+
### Google Analytics 4 (gtag.js)
|
39
39
|
|
40
40
|
```javascript
|
41
41
|
GaEvents.Event.adapter = function() {
|
42
|
-
return new GaEvents.
|
43
|
-
}
|
44
|
-
```
|
45
|
-
|
46
|
-
### Google Universal Analytics
|
47
|
-
|
48
|
-
#### analytics.js
|
49
|
-
|
50
|
-
```javascript
|
51
|
-
GaEvents.Event.adapter = function() {
|
52
|
-
return new GaEvents.GoogleUniversalAnalyticsAdapter();
|
53
|
-
}
|
54
|
-
```
|
55
|
-
|
56
|
-
Optionally you can specify a custom send method to call and a custom tracker
|
57
|
-
name:
|
58
|
-
|
59
|
-
```javascript
|
60
|
-
GaEvents.Event.adapter = function() {
|
61
|
-
return new GaEvents.GoogleUniversalAnalyticsAdapter(
|
62
|
-
{send_method_name: "sendNow", tracker_name: "customTracker"}
|
63
|
-
);
|
64
|
-
}
|
65
|
-
```
|
66
|
-
|
67
|
-
#### gtag.js
|
68
|
-
|
69
|
-
```javascript
|
70
|
-
GaEvents.Event.adapter = function() {
|
71
|
-
return new GaEvents.GoogleUniversalAnalyticsAdapter(
|
72
|
-
{use_gtag_variant: true}
|
73
|
-
);
|
42
|
+
return new GaEvents.GTagAdapter();
|
74
43
|
}
|
75
44
|
```
|
76
45
|
|
@@ -79,21 +48,20 @@ your events to be sent to:
|
|
79
48
|
|
80
49
|
```javascript
|
81
50
|
GaEvents.Event.adapter = function() {
|
82
|
-
return new GaEvents.
|
83
|
-
{
|
51
|
+
return new GaEvents.GTagAdapter(
|
52
|
+
{tracker_name: "GA_MEASUREMENT_ID"}
|
84
53
|
);
|
85
54
|
}
|
86
55
|
```
|
87
56
|
|
88
57
|
#### Optional custom object name
|
89
58
|
|
90
|
-
The default names of the analytics object
|
91
|
-
|
92
|
-
you can specify the name:
|
59
|
+
The default names of the analytics object for `gtag.js` is `window.gtag()`. If
|
60
|
+
you have renamed your analytics object, you can specify the name:
|
93
61
|
|
94
62
|
```javascript
|
95
63
|
GaEvents.Event.adapter = function() {
|
96
|
-
return new GaEvents.
|
64
|
+
return new GaEvents.GTagAdapter(
|
97
65
|
{analytics_object_name: "analytics"} // calls window.analytics()
|
98
66
|
);
|
99
67
|
}
|
@@ -138,24 +106,18 @@ HTTP header is added to the response.
|
|
138
106
|
You can create a new event like this:
|
139
107
|
|
140
108
|
```ruby
|
141
|
-
GaEvents::Event.new(
|
109
|
+
GaEvents::Event.new('example_event', { extra: 'dimension' })
|
142
110
|
```
|
143
111
|
|
144
112
|
On the client-side there is a similar interface to GaEvents:
|
145
113
|
|
146
114
|
```javascript
|
147
|
-
new GaEvents.Event(
|
115
|
+
new GaEvents.Event('example_event', { extra: 'dimension' })
|
148
116
|
```
|
149
117
|
|
150
118
|
We have taken special care of tracking events while the DOM is loading.
|
151
119
|
Events get collected until the DOM is ready and flushed afterwards.
|
152
120
|
|
153
|
-
### Default values
|
154
|
-
|
155
|
-
While collecting hundreds of thousands of events on a daily basis in
|
156
|
-
Google Analytics we found corrupted aggregated events when the event label or
|
157
|
-
value is omitted. We now enforce a default label ("-") and value (1).
|
158
|
-
|
159
121
|
### Too many events
|
160
122
|
|
161
123
|
Use something like this snippet to get informed of bloating HTTP headers with
|
@@ -194,14 +156,13 @@ Yes please! Use pull requests.
|
|
194
156
|
|
195
157
|
### Credits
|
196
158
|
|
197
|
-
* [danielbayerlein](https://github.com/danielbayerlein) former core committer
|
159
|
+
* [danielbayerlein](https://github.com/danielbayerlein), [der-flo](https://github.com/der-flo), [svenwin](https://github.com/svenwin) former core committer
|
198
160
|
* [jhilden](https://github.com/jhilden) for ideas and bug reports
|
199
161
|
* [brain-geek](https://github.com/brain-geek) for bug fixes, specs, features
|
200
162
|
|
201
163
|
## More docs and tools
|
202
164
|
|
203
165
|
* [Google Analytics: Event Tracking](https://developers.google.com/analytics/devguides/collection/gajs/eventTrackerGuide)
|
204
|
-
* [Google Universal Analytics: Event Tracking (analytics.js)](https://developers.google.com/analytics/devguides/collection/analyticsjs/events)
|
205
166
|
* [Google Universal Analytics: Event Tracking (gtag.js)](https://developers.google.com/analytics/devguides/collection/gtagjs/events)
|
206
167
|
* [Google Tag Manager: Custom Events](http://support.google.com/tagmanager/answer/2574372#GoogleAnalytics)
|
207
168
|
* [Chrome Web Store: Tag Assistant](https://chrome.google.com/webstore/detail/tag-assistant-legacy-by-g/kejbdjndbnbjgmefkgdddjlbokphdefk)
|
@@ -7,21 +7,25 @@ class GaEvents.Event
|
|
7
7
|
adapter: null
|
8
8
|
@list: []
|
9
9
|
@may_flush: false
|
10
|
-
@header_key: "
|
10
|
+
@header_key: "x-ga-events"
|
11
11
|
@html_key: "ga-events"
|
12
12
|
@require_user_consent: false
|
13
13
|
@user_consent_given: false
|
14
14
|
klass: @
|
15
15
|
|
16
16
|
# Decompose an event-string (ruby side) into an event object.
|
17
|
-
@
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
@from_json: (string) ->
|
18
|
+
events = JSON.parse(string)
|
19
|
+
|
20
|
+
$.map events, (event) =>
|
21
|
+
if event_name = event.__event__
|
22
|
+
delete event.__event__
|
23
|
+
new @(event_name, event)
|
21
24
|
|
22
25
|
@from_dom: ->
|
23
|
-
|
24
|
-
|
26
|
+
data_attribute = "data-#{@html_key}"
|
27
|
+
dom_events = $("div[#{data_attribute}]").attr data_attribute
|
28
|
+
@from_json dom_events if dom_events?
|
25
29
|
|
26
30
|
# Events should not be sent to an adapter unless the DOM has finished loading.
|
27
31
|
@flush: ->
|
@@ -32,32 +36,18 @@ class GaEvents.Event
|
|
32
36
|
@list = []
|
33
37
|
|
34
38
|
# Add all events to a queue to flush them later
|
35
|
-
constructor: (@
|
39
|
+
constructor: (@event_name, @options = {}) ->
|
36
40
|
@klass.list.push @
|
37
41
|
@klass.flush()
|
38
42
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
.replace(/ß/g, "ss")
|
48
|
-
|
49
|
-
to_hash: ->
|
50
|
-
# Category, action and label must be escaped and of type string.
|
51
|
-
action: @escape(@action)
|
52
|
-
category: @escape(@category)
|
53
|
-
label: @escape(@label)
|
54
|
-
# Value has to be a positive integer or defaults to 1
|
55
|
-
value: @to_positive_integer(@value)
|
56
|
-
|
57
|
-
to_positive_integer: (n) ->
|
58
|
-
if isFinite(n) and parseInt(n) >= 0 then parseInt n else 1
|
59
|
-
|
60
|
-
push_to_adapter: -> @klass.adapter().push @to_hash()
|
43
|
+
push_to_adapter: ->
|
44
|
+
if @is_valid_event_name()
|
45
|
+
@klass.adapter().push(@event_name, @options)
|
46
|
+
else
|
47
|
+
console.warn("GA4 event name \"#{@event_name}\" is invalid.") if console
|
48
|
+
|
49
|
+
# https://support.google.com/analytics/answer/13316687?hl=en#zippy=%2Cweb
|
50
|
+
is_valid_event_name: -> /^[a-z]+[a-z0-9_]*$/i.test(@event_name)
|
61
51
|
|
62
52
|
jQuery =>
|
63
53
|
@may_flush = true
|
@@ -65,7 +55,7 @@ class GaEvents.Event
|
|
65
55
|
|
66
56
|
process_xhr = (xhr) =>
|
67
57
|
xhr_events = xhr.getResponseHeader @header_key
|
68
|
-
@
|
58
|
+
@from_json decodeURIComponent(xhr_events) if xhr_events?
|
69
59
|
|
70
60
|
$(document).ajaxComplete((_, xhr) -> process_xhr(xhr))
|
71
61
|
$(document).on "turbolinks:request-end", (event) ->
|
@@ -75,59 +65,31 @@ class GaEvents.Event
|
|
75
65
|
@from_dom()
|
76
66
|
|
77
67
|
|
78
|
-
class GaEvents.
|
79
|
-
constructor: (@event = "ga_event") ->
|
80
|
-
push: (data) ->
|
81
|
-
data.event = @event
|
82
|
-
data.non_interaction = true
|
83
|
-
window.dataLayer.push data
|
84
|
-
|
85
|
-
class GaEvents.GoogleUniversalAnalyticsAdapter
|
68
|
+
class GaEvents.GTagAdapter
|
86
69
|
constructor: (options) ->
|
87
|
-
@
|
88
|
-
@analytics_object_name =
|
89
|
-
options?.analytics_object_name ||
|
90
|
-
(if @use_gtag_variant then "gtag" else "ga")
|
91
|
-
|
92
|
-
# Only relevant for analytics.js
|
93
|
-
@send_method_name = options?.send_method_name || "send"
|
70
|
+
@analytics_object_name = options?.analytics_object_name || 'gtag'
|
94
71
|
|
95
72
|
# https://developers.google.com/analytics/devguides/migration/ua/analyticsjs-to-gtagjs#measure_pageviews_with_specified_trackers
|
96
73
|
@tracker_name = options?.tracker_name || false
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
"event_label": data.label,
|
102
|
-
"value": data.value,
|
103
|
-
"non_interaction": true
|
104
|
-
}
|
105
|
-
options["send_to"] = @tracker_name if @tracker_name
|
106
|
-
window[@analytics_object_name]("event", data.action, options)
|
107
|
-
else
|
108
|
-
method_call_name =
|
109
|
-
if @tracker_name
|
110
|
-
"#{@tracker_name}.#{@send_method_name}"
|
111
|
-
else
|
112
|
-
@send_method_name
|
113
|
-
window[@analytics_object_name](
|
114
|
-
method_call_name, "event",
|
115
|
-
data.category, data.action, data.label, data.value,
|
116
|
-
{"nonInteraction": true}
|
117
|
-
)
|
118
|
-
|
119
|
-
class GaEvents.GoogleAnalyticsAdapter
|
120
|
-
# https://developers.google.com/analytics/devguides/collection/gajs/eventTrackerGuide#SettingUpEventTracking
|
121
|
-
# Send events non_interactive => no influence on bounce rates
|
122
|
-
push: (data) ->
|
123
|
-
window._gaq.push(
|
124
|
-
["_trackEvent", data.category, data.action, data.label, data.value, true]
|
125
|
-
)
|
74
|
+
|
75
|
+
push: (event_name, data) ->
|
76
|
+
data.send_to = @tracker_name if @tracker_name
|
77
|
+
window[@analytics_object_name]("event", event_name, data)
|
126
78
|
|
127
79
|
class GaEvents.NullAdapter
|
128
|
-
push: (
|
80
|
+
push: (event_name, data) -> console.log(event_name, data) if console?
|
81
|
+
|
82
|
+
class GaEvents.GoogleTagManagerAdapter
|
83
|
+
constructor: (@event = "ga_event") ->
|
84
|
+
|
85
|
+
push: (event_name, data) ->
|
86
|
+
data.event = @event
|
87
|
+
data.event_name = event_name
|
88
|
+
data.non_interaction = true
|
89
|
+
window.dataLayer.push data
|
129
90
|
|
130
91
|
class GaEvents.TestAdapter
|
131
|
-
push: (
|
92
|
+
push: (event_name, data) ->
|
93
|
+
loggedEvent = Object.assign({ event_name: event_name }, data)
|
132
94
|
window.events = [] unless window.events?
|
133
|
-
window.events.push
|
95
|
+
window.events.push(loggedEvent)
|
data/ga_events.gemspec
CHANGED
@@ -3,9 +3,8 @@
|
|
3
3
|
require File.expand_path('lib/ga_events/version', __dir__)
|
4
4
|
|
5
5
|
Gem::Specification.new do |gem|
|
6
|
-
gem.authors = ['
|
7
|
-
gem.email = ['
|
8
|
-
'sven.winkler@nix-wie-weg.de']
|
6
|
+
gem.authors = ['Nix-wie-weg Team']
|
7
|
+
gem.email = ['admin@nix-wie-weg.de']
|
9
8
|
gem.description =
|
10
9
|
"Google Analytics' Event Tracking everywhere in your Rails app)"
|
11
10
|
gem.summary = 'This gem allows you to annotate events everywhere in ' \
|
@@ -27,6 +26,6 @@ Gem::Specification.new do |gem|
|
|
27
26
|
gem.version = GaEvents::VERSION
|
28
27
|
gem.licenses = ['MIT']
|
29
28
|
|
30
|
-
gem.required_ruby_version = '>= 2
|
29
|
+
gem.required_ruby_version = '>= 3.2'
|
31
30
|
gem.add_dependency 'rails', '>= 4.2'
|
32
31
|
end
|
data/lib/ga_events/event.rb
CHANGED
@@ -1,19 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module GaEvents
|
4
|
-
Event
|
4
|
+
class Event
|
5
|
+
attr_reader :event_name, :event_params
|
6
|
+
|
5
7
|
# Default values are set here, see README.md for details.
|
6
|
-
def initialize(
|
7
|
-
|
8
|
+
def initialize(event_name, event_params = {})
|
9
|
+
@event_name = event_name
|
10
|
+
@event_params = event_params
|
8
11
|
GaEvents::List << self
|
9
12
|
end
|
10
13
|
|
11
14
|
def to_s
|
12
|
-
|
15
|
+
JSON.generate({ __event__: event_name, **event_params })
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_h
|
19
|
+
{ event_name:, event_params: event_params.symbolize_keys }
|
20
|
+
end
|
21
|
+
|
22
|
+
def deconstruct_keys(keys)
|
23
|
+
keys ? to_h.slice(*keys) : to_h
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.from_hash(event_hash)
|
27
|
+
if event_name = event_hash.delete('__event__')
|
28
|
+
new(event_name, event_hash)
|
29
|
+
end
|
13
30
|
end
|
14
31
|
|
15
|
-
def
|
16
|
-
|
32
|
+
def ==(other)
|
33
|
+
self.class == other.class && event_name == other.event_name &&
|
34
|
+
event_params == other.event_params
|
17
35
|
end
|
18
36
|
end
|
19
37
|
end
|
data/lib/ga_events/list.rb
CHANGED
@@ -12,13 +12,18 @@ module GaEvents
|
|
12
12
|
def_delegators :data, :<<, :present?
|
13
13
|
|
14
14
|
def to_s
|
15
|
-
data.collect(&:to_s).join('
|
15
|
+
"[#{data.collect(&:to_s).join(',')}]"
|
16
16
|
end
|
17
17
|
|
18
18
|
# Init list, optionally with a string of serialized events
|
19
19
|
def init(str = nil)
|
20
20
|
Thread.current[:ga_events] = []
|
21
|
-
|
21
|
+
if str.present?
|
22
|
+
raw_events = JSON.parse(str)
|
23
|
+
raw_events.each { |raw_event| GaEvents::Event.from_hash(raw_event) }
|
24
|
+
end
|
25
|
+
rescue JSON::ParserError
|
26
|
+
nil
|
22
27
|
end
|
23
28
|
|
24
29
|
private
|
data/lib/ga_events/middleware.rb
CHANGED
@@ -4,6 +4,8 @@ require 'rack/utils'
|
|
4
4
|
|
5
5
|
module GaEvents
|
6
6
|
class Middleware
|
7
|
+
SESSION_GA_EVENTS_KEY = 'ga_events.events'
|
8
|
+
|
7
9
|
def initialize(app)
|
8
10
|
@app = app
|
9
11
|
end
|
@@ -20,12 +22,11 @@ module GaEvents
|
|
20
22
|
serialized = GaEvents::List.to_s
|
21
23
|
if xhr_or_turbolinks?(request)
|
22
24
|
# AJAX request
|
23
|
-
headers['
|
24
|
-
|
25
|
+
headers['x-ga-events'] = CGI.escapeURIComponent(serialized)
|
25
26
|
elsif redirect?(status)
|
26
|
-
# 30x/redirect? Then add event list to
|
27
|
-
|
28
|
-
|
27
|
+
# 30x/redirect? Then add event list to rack session to survive the
|
28
|
+
# redirect.
|
29
|
+
add_events_to_session(env, serialized)
|
29
30
|
elsif html?(status, headers)
|
30
31
|
response = inject_div(response, serialized)
|
31
32
|
end
|
@@ -37,23 +38,14 @@ module GaEvents
|
|
37
38
|
private
|
38
39
|
|
39
40
|
def init_event_list(env)
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
# The key has to be removed from the flash here to ensure it does not
|
44
|
-
# remain after the finished redirect. This copies the behaviour of the
|
45
|
-
# "#use" and "#sweep" methods of the rails flash middleware:
|
46
|
-
# https://github.com/rails/rails/blob/v3.2.14/actionpack/lib/action_dispatch/middleware/flash.rb#L220
|
47
|
-
GaEvents::List.init(flash&.delete('ga_events'))
|
41
|
+
events = env['rack.session']&.delete(SESSION_GA_EVENTS_KEY)
|
42
|
+
GaEvents::List.init(events)
|
48
43
|
end
|
49
44
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
return unless flash
|
55
|
-
|
56
|
-
flash['ga_events'] = serialized_data
|
45
|
+
def add_events_to_session env, serialized_data
|
46
|
+
if session = env.dig('rack.session')
|
47
|
+
session[SESSION_GA_EVENTS_KEY] = serialized_data
|
48
|
+
end
|
57
49
|
end
|
58
50
|
|
59
51
|
def normalize_response(response)
|
@@ -64,7 +56,12 @@ module GaEvents
|
|
64
56
|
|
65
57
|
def inject_div(response, serialized_data)
|
66
58
|
r = normalize_response(response)
|
67
|
-
|
59
|
+
serialized_data = CGI.escapeHTML(serialized_data)
|
60
|
+
[
|
61
|
+
r.sub('</body>') do |body|
|
62
|
+
"<div data-ga-events=\"#{serialized_data}\"></div>#{body}"
|
63
|
+
end
|
64
|
+
]
|
68
65
|
end
|
69
66
|
|
70
67
|
# Taken from:
|
data/lib/ga_events/version.rb
CHANGED
data/spec/event_spec.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe GaEvents::Event do
|
4
|
+
it 'has a custom #to_s implementation ' do
|
5
|
+
expect(
|
6
|
+
described_class.new('test', { p1: 'my-action', p2: 'my-label' }).to_s
|
7
|
+
).to eq('{"__event__":"test","p1":"my-action","p2":"my-label"}')
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'can be restored from hash' do
|
11
|
+
initialized_event =
|
12
|
+
described_class.new(
|
13
|
+
'test',
|
14
|
+
{
|
15
|
+
'category' => 'my-category',
|
16
|
+
'label' => 'my-label',
|
17
|
+
'value' => 'my-value'
|
18
|
+
}
|
19
|
+
)
|
20
|
+
from_hash_event =
|
21
|
+
described_class.from_hash(
|
22
|
+
{
|
23
|
+
'category' => 'my-category',
|
24
|
+
'__event__' => 'test',
|
25
|
+
'label' => 'my-label',
|
26
|
+
'value' => 'my-value'
|
27
|
+
}
|
28
|
+
)
|
29
|
+
expect(from_hash_event).to eq initialized_event
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'adds itself to GaEvents::List' do
|
33
|
+
described_class.from_hash(
|
34
|
+
{
|
35
|
+
'__event__' => 'test',
|
36
|
+
'category' => 'my-category',
|
37
|
+
'label' => 'my-label',
|
38
|
+
'value' => 'first-value'
|
39
|
+
}
|
40
|
+
)
|
41
|
+
described_class.new('clicked', { some: 'thing' })
|
42
|
+
|
43
|
+
expect(GaEvents::List.to_s).to eq(<<~EVENTS.tr("\n", ''))
|
44
|
+
[{"__event__":"test","category":"my-category","label":"my-label","value":"first-value"},
|
45
|
+
{"__event__":"clicked","some":"thing"}]
|
46
|
+
EVENTS
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'can be initialized with a hash' do
|
50
|
+
expect(
|
51
|
+
described_class.new('one_value', { stars: 5 }).to_s
|
52
|
+
).to eq '{"__event__":"one_value","stars":5}'
|
53
|
+
expect(
|
54
|
+
described_class.new('two_values', { stars: 5, mode: 'main' }).to_s
|
55
|
+
).to eq '{"__event__":"two_values","stars":5,"mode":"main"}'
|
56
|
+
expect(
|
57
|
+
described_class.new('with_array', { list: [5, 'stars'] }).to_s
|
58
|
+
).to eq '{"__event__":"with_array","list":[5,"stars"]}'
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'can be pattern matched against' do
|
62
|
+
event = described_class.new('test', { stars: 5 })
|
63
|
+
event => {
|
64
|
+
event_name: 'test', event_params: { stars: Integer => five_stars }
|
65
|
+
}
|
66
|
+
expect(five_stars).to eq 5
|
67
|
+
end
|
68
|
+
end
|
data/spec/list_spec.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe 'GaEvents::List' do
|
4
|
+
describe '#to_s' do
|
5
|
+
it 'generates valid json' do
|
6
|
+
GaEvents::Event.new('clicked', { a: 'a' })
|
7
|
+
GaEvents::Event.new('clicked', { b: 'b' })
|
8
|
+
expect(JSON.parse(GaEvents::List.to_s)).to eq(
|
9
|
+
[
|
10
|
+
{ '__event__' => 'clicked', 'a' => 'a' },
|
11
|
+
{ '__event__' => 'clicked', 'b' => 'b' }
|
12
|
+
]
|
13
|
+
)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'can be initialized with a json string' do
|
18
|
+
GaEvents::List.init(<<~JSON.squish)
|
19
|
+
[
|
20
|
+
{ "__event__": "clicked", "a": "a" }
|
21
|
+
]
|
22
|
+
JSON
|
23
|
+
|
24
|
+
expect(
|
25
|
+
GaEvents::List.send(:data).to_h { [_1.event_name, _1.event_params] }
|
26
|
+
).to eq({ 'clicked' => { 'a' => 'a' } })
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'can be initialized with a broken json string' do
|
30
|
+
GaEvents::List.init(<<~JSON.squish)
|
31
|
+
[
|
32
|
+
{ "__event__": "clicked", "trailing": "comma triggers ParserError", }
|
33
|
+
]
|
34
|
+
JSON
|
35
|
+
|
36
|
+
expect(
|
37
|
+
GaEvents::List.send(:data).to_h { [_1.event_name, _1.event_params] }
|
38
|
+
).to be_empty
|
39
|
+
end
|
40
|
+
end
|
data/spec/middleware_spec.rb
CHANGED
@@ -33,26 +33,39 @@ describe GaEvents::Middleware do
|
|
33
33
|
context 'events present in GaEvents::List' do
|
34
34
|
let(:app) do
|
35
35
|
proc do |_|
|
36
|
-
GaEvents::Event.new(
|
36
|
+
GaEvents::Event.new(
|
37
|
+
'test',
|
38
|
+
'cool' => 'stuff',
|
39
|
+
'ding' => ["it's a bug", 'this is "fine"', 'x=1&y=2', '>:3<']
|
40
|
+
)
|
37
41
|
[200, { 'Content-Type' => 'text/html' }, response_body]
|
38
42
|
end
|
39
43
|
end
|
40
44
|
|
41
|
-
context '
|
45
|
+
context 'when no body closing tag exists' do
|
42
46
|
let(:response) { request.get('/') }
|
43
47
|
it 'leaves everything as it was' do
|
44
48
|
expect(response.body).to eq response_body
|
45
49
|
end
|
46
50
|
end
|
47
51
|
|
48
|
-
context '
|
52
|
+
context 'when a body closing tag exists' do
|
49
53
|
let(:response) { request.get('/') }
|
50
54
|
let(:response_body) { 'something awesome!</body>' }
|
51
55
|
|
52
56
|
it 'injects data-ga-events' do
|
53
57
|
expect(response.body).to eq(
|
54
58
|
'something awesome!' \
|
55
|
-
|
59
|
+
'<div data-ga-events="[{' \
|
60
|
+
'"__event__":"test",' \
|
61
|
+
'"cool":"stuff",' \
|
62
|
+
'"ding":[' \
|
63
|
+
'"it's a bug",' \
|
64
|
+
'"this is \"fine\"",' \
|
65
|
+
'"x=1&y=2",' \
|
66
|
+
'">:3<"' \
|
67
|
+
']' \
|
68
|
+
'}]"></div></body>'
|
56
69
|
)
|
57
70
|
end
|
58
71
|
end
|
metadata
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ga_events
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
8
|
-
- Sven Winkler
|
7
|
+
- Nix-wie-weg Team
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2025-01-08 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rails
|
@@ -27,8 +26,7 @@ dependencies:
|
|
27
26
|
version: '4.2'
|
28
27
|
description: Google Analytics' Event Tracking everywhere in your Rails app)
|
29
28
|
email:
|
30
|
-
-
|
31
|
-
- sven.winkler@nix-wie-weg.de
|
29
|
+
- admin@nix-wie-weg.de
|
32
30
|
executables: []
|
33
31
|
extensions: []
|
34
32
|
extra_rdoc_files: []
|
@@ -49,6 +47,8 @@ files:
|
|
49
47
|
- lib/ga_events/list.rb
|
50
48
|
- lib/ga_events/middleware.rb
|
51
49
|
- lib/ga_events/version.rb
|
50
|
+
- spec/event_spec.rb
|
51
|
+
- spec/list_spec.rb
|
52
52
|
- spec/middleware_spec.rb
|
53
53
|
- spec/spec_helper.rb
|
54
54
|
homepage: https://github.com/Nix-wie-weg/ga_events
|
@@ -63,15 +63,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
63
63
|
requirements:
|
64
64
|
- - ">="
|
65
65
|
- !ruby/object:Gem::Version
|
66
|
-
version: '2
|
66
|
+
version: '3.2'
|
67
67
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
68
|
requirements:
|
69
69
|
- - ">="
|
70
70
|
- !ruby/object:Gem::Version
|
71
71
|
version: '0'
|
72
72
|
requirements: []
|
73
|
-
|
74
|
-
rubygems_version: 2.7.6.2
|
73
|
+
rubygems_version: 3.4.6
|
75
74
|
signing_key:
|
76
75
|
specification_version: 4
|
77
76
|
summary: This gem allows you to annotate events everywhere in the code of your Rails
|
@@ -81,5 +80,7 @@ summary: This gem allows you to annotate events everywhere in the code of your R
|
|
81
80
|
extracts this data on the client side and pushes it to Google Analytics via ga.js
|
82
81
|
or Google Tag Manager.
|
83
82
|
test_files:
|
83
|
+
- spec/event_spec.rb
|
84
|
+
- spec/list_spec.rb
|
84
85
|
- spec/middleware_spec.rb
|
85
86
|
- spec/spec_helper.rb
|