/
handler.rb
96 lines (80 loc) · 3.01 KB
/
handler.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
class Rack::Tracker::Handler
class << self
def process_track(env, method_name, *args, &block)
new(env).write_event(track(method_name, *args, &block))
end
# overwrite me in the handler subclass if you need more control over the event
def track(name, *event)
{ name.to_s => [event.last.merge('class_name' => event.first.to_s.classify)] }
end
end
class_attribute :position
self.position = :head
class_attribute :allowed_tracker_options
self.allowed_tracker_options = []
attr_accessor :options
attr_accessor :env
# Allow javascript escaping in view templates
include Rack::Tracker::JavaScriptHelper
def initialize(env, options = {})
self.env = env
self.options = options
self.position = options[:position] if options.has_key?(:position)
end
def events
events = env.fetch('tracker', {})[handler_name] || []
events.map { |ev| "#{self.class}::#{ev['class_name']}".constantize.new(ev.except('class_name')) }
end
def render
Tilt.new(File.join(File.dirname(__FILE__), handler_name, 'template', "#{handler_name}.erb") ).render(self)
end
def inject(response)
# default to not inject this tracker if the DNT HTTP header is set
# if the DO_NOT_RESPECT_DNT_HEADER config is set the DNT header is ignored :( - please do respect the DNT header!
if self.dnt_header_opt_out? && !self.options.has_key?(:DO_NOT_RESPECT_DNT_HEADER)
return response
end
# Sub! is enough, in well formed html there's only one head or body tag.
# Block syntax need to be used, otherwise backslashes in input will mess the output.
# @see http://stackoverflow.com/a/4149087/518204 and https://github.com/railslove/rack-tracker/issues/50
response.sub! %r{</#{self.position}>} do |m|
self.render << m.to_s
end
response
end
def write_event(event)
event.deep_stringify_keys! # for consistent hash access use strings (keys from the session are always strings anyway)
if env.key?('tracker')
self.env['tracker'].deep_merge!(event) { |key, old, new| Array.wrap(old) + Array.wrap(new) }
else
self.env['tracker'] = event
end
end
def handler_name
self.class.name.demodulize.underscore
end
def tracker_options
@_tracker_options ||= {}.tap do |tracker_options|
options.slice(*allowed_tracker_options).each do |key, value|
if option_value = value.respond_to?(:call) ? value.call(env) : value
tracker_options[tracker_option_key(key)] = tracker_option_value(option_value)
end
end
end
end
# the request has set the DO NOT TRACK (DNT) and has opted to get not tracked (DNT=1)
def dnt_header_opt_out?
self.env['HTTP_DNT'] && self.env['HTTP_DNT'].to_s == '1'
end
private
# Transformations to be applied to tracker option keys.
# Override in descendants, if necessary.
def tracker_option_key(key)
key.to_sym
end
# Transformations to be applied to tracker option values.
# Override in descendants, if necessary.
def tracker_option_value(value)
value
end
end