ga_events 3.0.0 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/CHANGELOG.md +26 -0
- data/Gemfile +1 -1
- data/README.md +12 -51
- data/app/assets/javascripts/ga_events.js.coffee +40 -78
- data/ga_events.gemspec +1 -1
- data/lib/ga_events/event.rb +24 -6
- data/lib/ga_events/list.rb +7 -2
- data/lib/ga_events/middleware.rb +12 -20
- 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 +4 -4
- metadata +8 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af13dc202f2b24f7fa7ba45345d90fea5158e4b50c5e55fbb6bbc68752c6083b
|
4
|
+
data.tar.gz: bbd3f2173bba05a2ce2d1dc4315a288b83b469810327dd2cbccd30799f6e595a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb529a2794580ae3c52a2a226c620b94ba79b278dc1171fcda5a27bdc511901b95f2d9243028285484a2a8d66af2feeb6a40539e82e5def320ed0974bf62e74e
|
7
|
+
data.tar.gz: 9b9adf95d667f066198b222cb45e233b83b03420e84a6743cd93cfba70b90bbaed7982b070d552f37e69c148a21800159a18223af176d6dac955049fe8f02971
|
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
|
@@ -201,7 +163,6 @@ Yes please! Use pull requests.
|
|
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
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)
|
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,26 @@ 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('test', { 'cool' => 'stuff' })
|
37
37
|
[200, { 'Content-Type' => 'text/html' }, response_body]
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
context '
|
41
|
+
context 'when no body closing tag exists' do
|
42
42
|
let(:response) { request.get('/') }
|
43
43
|
it 'leaves everything as it was' do
|
44
44
|
expect(response.body).to eq response_body
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
context '
|
48
|
+
context 'when a body closing tag exists' do
|
49
49
|
let(:response) { request.get('/') }
|
50
50
|
let(:response_body) { 'something awesome!</body>' }
|
51
51
|
|
52
52
|
it 'injects data-ga-events' do
|
53
53
|
expect(response.body).to eq(
|
54
54
|
'something awesome!' \
|
55
|
-
"<div data-ga-events='
|
55
|
+
"<div data-ga-events='[{\"__event__\":\"test\",\"cool\":\"stuff\"}]'></div></body>"
|
56
56
|
)
|
57
57
|
end
|
58
58
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ga_events
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Florian Dütsch
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2023-08-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -49,6 +49,8 @@ files:
|
|
49
49
|
- lib/ga_events/list.rb
|
50
50
|
- lib/ga_events/middleware.rb
|
51
51
|
- lib/ga_events/version.rb
|
52
|
+
- spec/event_spec.rb
|
53
|
+
- spec/list_spec.rb
|
52
54
|
- spec/middleware_spec.rb
|
53
55
|
- spec/spec_helper.rb
|
54
56
|
homepage: https://github.com/Nix-wie-weg/ga_events
|
@@ -63,15 +65,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
63
65
|
requirements:
|
64
66
|
- - ">="
|
65
67
|
- !ruby/object:Gem::Version
|
66
|
-
version: '2
|
68
|
+
version: '3.2'
|
67
69
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
70
|
requirements:
|
69
71
|
- - ">="
|
70
72
|
- !ruby/object:Gem::Version
|
71
73
|
version: '0'
|
72
74
|
requirements: []
|
73
|
-
|
74
|
-
rubygems_version: 2.7.6.2
|
75
|
+
rubygems_version: 3.4.6
|
75
76
|
signing_key:
|
76
77
|
specification_version: 4
|
77
78
|
summary: This gem allows you to annotate events everywhere in the code of your Rails
|
@@ -81,5 +82,7 @@ summary: This gem allows you to annotate events everywhere in the code of your R
|
|
81
82
|
extracts this data on the client side and pushes it to Google Analytics via ga.js
|
82
83
|
or Google Tag Manager.
|
83
84
|
test_files:
|
85
|
+
- spec/event_spec.rb
|
86
|
+
- spec/list_spec.rb
|
84
87
|
- spec/middleware_spec.rb
|
85
88
|
- spec/spec_helper.rb
|