framed_rails 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/.gitignore +11 -0
  2. data/.ruby-version +1 -0
  3. data/CHANGELOG +1 -0
  4. data/Gemfile +3 -0
  5. data/LICENSE +1 -0
  6. data/README.md +107 -0
  7. data/framed_rails.gemspec +37 -0
  8. data/lib/framed/client.rb +34 -0
  9. data/lib/framed/emitters.rb +113 -0
  10. data/lib/framed/example.rb +17 -0
  11. data/lib/framed/exceptions.rb +13 -0
  12. data/lib/framed/okjson.rb +602 -0
  13. data/lib/framed/rails.rb +43 -0
  14. data/lib/framed/railtie.rb +9 -0
  15. data/lib/framed/utils.rb +54 -0
  16. data/lib/framed/version.rb +4 -0
  17. data/lib/framed_rails.rb +71 -0
  18. data/vendor/gems/excon-0.45.3/data/cacert.pem +3860 -0
  19. data/vendor/gems/excon-0.45.3/lib/excon/connection.rb +469 -0
  20. data/vendor/gems/excon-0.45.3/lib/excon/constants.rb +142 -0
  21. data/vendor/gems/excon-0.45.3/lib/excon/errors.rb +155 -0
  22. data/vendor/gems/excon-0.45.3/lib/excon/extensions/uri.rb +33 -0
  23. data/vendor/gems/excon-0.45.3/lib/excon/headers.rb +83 -0
  24. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/base.rb +24 -0
  25. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/decompress.rb +35 -0
  26. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/escape_path.rb +11 -0
  27. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/expects.rb +18 -0
  28. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/idempotent.rb +33 -0
  29. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/instrumentor.rb +34 -0
  30. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/mock.rb +51 -0
  31. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/redirect_follower.rb +56 -0
  32. data/vendor/gems/excon-0.45.3/lib/excon/middlewares/response_parser.rb +12 -0
  33. data/vendor/gems/excon-0.45.3/lib/excon/pretty_printer.rb +45 -0
  34. data/vendor/gems/excon-0.45.3/lib/excon/response.rb +212 -0
  35. data/vendor/gems/excon-0.45.3/lib/excon/socket.rb +310 -0
  36. data/vendor/gems/excon-0.45.3/lib/excon/ssl_socket.rb +151 -0
  37. data/vendor/gems/excon-0.45.3/lib/excon/standard_instrumentor.rb +27 -0
  38. data/vendor/gems/excon-0.45.3/lib/excon/unix_socket.rb +40 -0
  39. data/vendor/gems/excon-0.45.3/lib/excon/utils.rb +87 -0
  40. data/vendor/gems/excon-0.45.3/lib/excon.rb +234 -0
  41. metadata +91 -0
@@ -0,0 +1,602 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # Copyright 2011, 2012 Keith Rarick
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ # See https://github.com/kr/okjson for updates.
24
+
25
+ require 'stringio'
26
+
27
+ # Some parts adapted from
28
+ # https://golang.org/src/encoding/json/decode.go and
29
+ # https://golang.org/src/unicode/utf8/utf8.go
30
+ module FramedRails
31
+ module OkJson
32
+ Upstream = '43'
33
+ extend self
34
+
35
+
36
+ # Decodes a json document in string s and
37
+ # returns the corresponding ruby value.
38
+ # String s must be valid UTF-8. If you have
39
+ # a string in some other encoding, convert
40
+ # it first.
41
+ #
42
+ # String values in the resulting structure
43
+ # will be UTF-8.
44
+ def decode(s)
45
+ ts = lex(s)
46
+ v, ts = textparse(ts)
47
+ if ts.length > 0
48
+ raise Error, 'trailing garbage'
49
+ end
50
+ v
51
+ end
52
+
53
+
54
+ # Encodes x into a json text. It may contain only
55
+ # Array, Hash, String, Numeric, true, false, nil.
56
+ # (Note, this list excludes Symbol.)
57
+ # X itself must be an Array or a Hash.
58
+ # No other value can be encoded, and an error will
59
+ # be raised if x contains any other value, such as
60
+ # Nan, Infinity, Symbol, and Proc, or if a Hash key
61
+ # is not a String.
62
+ # Strings contained in x must be valid UTF-8.
63
+ def encode(x)
64
+ case x
65
+ when Hash then objenc(x)
66
+ when Array then arrenc(x)
67
+ else
68
+ raise Error, 'root value must be an Array or a Hash'
69
+ end
70
+ end
71
+
72
+
73
+ def valenc(x)
74
+ case x
75
+ when Hash then objenc(x)
76
+ when Array then arrenc(x)
77
+ when String then strenc(x)
78
+ when Numeric then numenc(x)
79
+ when true then "true"
80
+ when false then "false"
81
+ when nil then "null"
82
+ else
83
+ raise Error, "cannot encode #{x.class}: #{x.inspect}"
84
+ end
85
+ end
86
+
87
+
88
+ private
89
+
90
+
91
+ # Parses a "json text" in the sense of RFC 4627.
92
+ # Returns the parsed value and any trailing tokens.
93
+ # Note: this is almost the same as valparse,
94
+ # except that it does not accept atomic values.
95
+ def textparse(ts)
96
+ if ts.length <= 0
97
+ raise Error, 'empty'
98
+ end
99
+
100
+ typ, _, val = ts[0]
101
+ case typ
102
+ when '{' then objparse(ts)
103
+ when '[' then arrparse(ts)
104
+ else
105
+ raise Error, "unexpected #{val.inspect}"
106
+ end
107
+ end
108
+
109
+
110
+ # Parses a "value" in the sense of RFC 4627.
111
+ # Returns the parsed value and any trailing tokens.
112
+ def valparse(ts)
113
+ if ts.length <= 0
114
+ raise Error, 'empty'
115
+ end
116
+
117
+ typ, _, val = ts[0]
118
+ case typ
119
+ when '{' then objparse(ts)
120
+ when '[' then arrparse(ts)
121
+ when :val,:str then [val, ts[1..-1]]
122
+ else
123
+ raise Error, "unexpected #{val.inspect}"
124
+ end
125
+ end
126
+
127
+
128
+ # Parses an "object" in the sense of RFC 4627.
129
+ # Returns the parsed value and any trailing tokens.
130
+ def objparse(ts)
131
+ ts = eat('{', ts)
132
+ obj = {}
133
+
134
+ if ts[0][0] == '}'
135
+ return obj, ts[1..-1]
136
+ end
137
+
138
+ k, v, ts = pairparse(ts)
139
+ obj[k] = v
140
+
141
+ if ts[0][0] == '}'
142
+ return obj, ts[1..-1]
143
+ end
144
+
145
+ loop do
146
+ ts = eat(',', ts)
147
+
148
+ k, v, ts = pairparse(ts)
149
+ obj[k] = v
150
+
151
+ if ts[0][0] == '}'
152
+ return obj, ts[1..-1]
153
+ end
154
+ end
155
+ end
156
+
157
+
158
+ # Parses a "member" in the sense of RFC 4627.
159
+ # Returns the parsed values and any trailing tokens.
160
+ def pairparse(ts)
161
+ (typ, _, k), ts = ts[0], ts[1..-1]
162
+ if typ != :str
163
+ raise Error, "unexpected #{k.inspect}"
164
+ end
165
+ ts = eat(':', ts)
166
+ v, ts = valparse(ts)
167
+ [k, v, ts]
168
+ end
169
+
170
+
171
+ # Parses an "array" in the sense of RFC 4627.
172
+ # Returns the parsed value and any trailing tokens.
173
+ def arrparse(ts)
174
+ ts = eat('[', ts)
175
+ arr = []
176
+
177
+ if ts[0][0] == ']'
178
+ return arr, ts[1..-1]
179
+ end
180
+
181
+ v, ts = valparse(ts)
182
+ arr << v
183
+
184
+ if ts[0][0] == ']'
185
+ return arr, ts[1..-1]
186
+ end
187
+
188
+ loop do
189
+ ts = eat(',', ts)
190
+
191
+ v, ts = valparse(ts)
192
+ arr << v
193
+
194
+ if ts[0][0] == ']'
195
+ return arr, ts[1..-1]
196
+ end
197
+ end
198
+ end
199
+
200
+
201
+ def eat(typ, ts)
202
+ if ts[0][0] != typ
203
+ raise Error, "expected #{typ} (got #{ts[0].inspect})"
204
+ end
205
+ ts[1..-1]
206
+ end
207
+
208
+
209
+ # Scans s and returns a list of json tokens,
210
+ # excluding white space (as defined in RFC 4627).
211
+ def lex(s)
212
+ ts = []
213
+ while s.length > 0
214
+ typ, lexeme, val = tok(s)
215
+ if typ == nil
216
+ raise Error, "invalid character at #{s[0,10].inspect}"
217
+ end
218
+ if typ != :space
219
+ ts << [typ, lexeme, val]
220
+ end
221
+ s = s[lexeme.length..-1]
222
+ end
223
+ ts
224
+ end
225
+
226
+
227
+ # Scans the first token in s and
228
+ # returns a 3-element list, or nil
229
+ # if s does not begin with a valid token.
230
+ #
231
+ # The first list element is one of
232
+ # '{', '}', ':', ',', '[', ']',
233
+ # :val, :str, and :space.
234
+ #
235
+ # The second element is the lexeme.
236
+ #
237
+ # The third element is the value of the
238
+ # token for :val and :str, otherwise
239
+ # it is the lexeme.
240
+ def tok(s)
241
+ case s[0]
242
+ when ?{ then ['{', s[0,1], s[0,1]]
243
+ when ?} then ['}', s[0,1], s[0,1]]
244
+ when ?: then [':', s[0,1], s[0,1]]
245
+ when ?, then [',', s[0,1], s[0,1]]
246
+ when ?[ then ['[', s[0,1], s[0,1]]
247
+ when ?] then [']', s[0,1], s[0,1]]
248
+ when ?n then nulltok(s)
249
+ when ?t then truetok(s)
250
+ when ?f then falsetok(s)
251
+ when ?" then strtok(s)
252
+ when Spc, ?\t, ?\n, ?\r then [:space, s[0,1], s[0,1]]
253
+ else
254
+ numtok(s)
255
+ end
256
+ end
257
+
258
+
259
+ def nulltok(s); s[0,4] == 'null' ? [:val, 'null', nil] : [] end
260
+ def truetok(s); s[0,4] == 'true' ? [:val, 'true', true] : [] end
261
+ def falsetok(s); s[0,5] == 'false' ? [:val, 'false', false] : [] end
262
+
263
+
264
+ def numtok(s)
265
+ m = /-?([1-9][0-9]+|[0-9])([.][0-9]+)?([eE][+-]?[0-9]+)?/.match(s)
266
+ if m && m.begin(0) == 0
267
+ if !m[2] && !m[3]
268
+ [:val, m[0], Integer(m[0])]
269
+ elsif m[2]
270
+ [:val, m[0], Float(m[0])]
271
+ else
272
+ [:val, m[0], Integer(m[1])*(10**m[3][1..-1].to_i(10))]
273
+ end
274
+ else
275
+ []
276
+ end
277
+ end
278
+
279
+
280
+ def strtok(s)
281
+ m = /"([^"\\]|\\["\/\\bfnrt]|\\u[0-9a-fA-F]{4})*"/.match(s)
282
+ if ! m
283
+ raise Error, "invalid string literal at #{abbrev(s)}"
284
+ end
285
+ [:str, m[0], unquote(m[0])]
286
+ end
287
+
288
+
289
+ def abbrev(s)
290
+ t = s[0,10]
291
+ p = t['`']
292
+ t = t[0,p] if p
293
+ t = t + '...' if t.length < s.length
294
+ '`' + t + '`'
295
+ end
296
+
297
+
298
+ # Converts a quoted json string literal q into a UTF-8-encoded string.
299
+ # The rules are different than for Ruby, so we cannot use eval.
300
+ # Unquote will raise an error if q contains control characters.
301
+ def unquote(q)
302
+ q = q[1...-1]
303
+ a = q.dup # allocate a big enough string
304
+ # In ruby >= 1.9, a[w] is a codepoint, not a byte.
305
+ if rubydoesenc?
306
+ a.force_encoding('UTF-8')
307
+ end
308
+ r, w = 0, 0
309
+ while r < q.length
310
+ c = q[r]
311
+ if c == ?\\
312
+ r += 1
313
+ if r >= q.length
314
+ raise Error, "string literal ends with a \"\\\": \"#{q}\""
315
+ end
316
+
317
+ case q[r]
318
+ when ?",?\\,?/,?'
319
+ a[w] = q[r]
320
+ r += 1
321
+ w += 1
322
+ when ?b,?f,?n,?r,?t
323
+ a[w] = Unesc[q[r]]
324
+ r += 1
325
+ w += 1
326
+ when ?u
327
+ r += 1
328
+ uchar = begin
329
+ hexdec4(q[r,4])
330
+ rescue RuntimeError => e
331
+ raise Error, "invalid escape sequence \\u#{q[r,4]}: #{e}"
332
+ end
333
+ r += 4
334
+ if surrogate? uchar
335
+ if q.length >= r+6
336
+ uchar1 = hexdec4(q[r+2,4])
337
+ uchar = subst(uchar, uchar1)
338
+ if uchar != Ucharerr
339
+ # A valid pair; consume.
340
+ r += 6
341
+ end
342
+ end
343
+ end
344
+ if rubydoesenc?
345
+ a[w] = '' << uchar
346
+ w += 1
347
+ else
348
+ w += ucharenc(a, w, uchar)
349
+ end
350
+ else
351
+ raise Error, "invalid escape char #{q[r]} in \"#{q}\""
352
+ end
353
+ elsif c == ?" || c < Spc
354
+ raise Error, "invalid character in string literal \"#{q}\""
355
+ else
356
+ # Copy anything else byte-for-byte.
357
+ # Valid UTF-8 will remain valid UTF-8.
358
+ # Invalid UTF-8 will remain invalid UTF-8.
359
+ # In ruby >= 1.9, c is a codepoint, not a byte,
360
+ # in which case this is still what we want.
361
+ a[w] = c
362
+ r += 1
363
+ w += 1
364
+ end
365
+ end
366
+ a[0,w]
367
+ end
368
+
369
+
370
+ # Encodes unicode character u as UTF-8
371
+ # bytes in string a at position i.
372
+ # Returns the number of bytes written.
373
+ def ucharenc(a, i, u)
374
+ if u <= Uchar1max
375
+ a[i] = (u & 0xff).chr
376
+ 1
377
+ elsif u <= Uchar2max
378
+ a[i+0] = (Utag2 | ((u>>6)&0xff)).chr
379
+ a[i+1] = (Utagx | (u&Umaskx)).chr
380
+ 2
381
+ elsif u <= Uchar3max
382
+ a[i+0] = (Utag3 | ((u>>12)&0xff)).chr
383
+ a[i+1] = (Utagx | ((u>>6)&Umaskx)).chr
384
+ a[i+2] = (Utagx | (u&Umaskx)).chr
385
+ 3
386
+ else
387
+ a[i+0] = (Utag4 | ((u>>18)&0xff)).chr
388
+ a[i+1] = (Utagx | ((u>>12)&Umaskx)).chr
389
+ a[i+2] = (Utagx | ((u>>6)&Umaskx)).chr
390
+ a[i+3] = (Utagx | (u&Umaskx)).chr
391
+ 4
392
+ end
393
+ end
394
+
395
+
396
+ def hexdec4(s)
397
+ if s.length != 4
398
+ raise Error, 'short'
399
+ end
400
+ (nibble(s[0])<<12) | (nibble(s[1])<<8) | (nibble(s[2])<<4) | nibble(s[3])
401
+ end
402
+
403
+
404
+ def subst(u1, u2)
405
+ if Usurr1 <= u1 && u1 < Usurr2 && Usurr2 <= u2 && u2 < Usurr3
406
+ return ((u1-Usurr1)<<10) | (u2-Usurr2) + Usurrself
407
+ end
408
+ return Ucharerr
409
+ end
410
+
411
+
412
+ def surrogate?(u)
413
+ Usurr1 <= u && u < Usurr3
414
+ end
415
+
416
+
417
+ def nibble(c)
418
+ if ?0 <= c && c <= ?9 then c.ord - ?0.ord
419
+ elsif ?a <= c && c <= ?z then c.ord - ?a.ord + 10
420
+ elsif ?A <= c && c <= ?Z then c.ord - ?A.ord + 10
421
+ else
422
+ raise Error, "invalid hex code #{c}"
423
+ end
424
+ end
425
+
426
+
427
+ def objenc(x)
428
+ '{' + x.map{|k,v| keyenc(k) + ':' + valenc(v)}.join(',') + '}'
429
+ end
430
+
431
+
432
+ def arrenc(a)
433
+ '[' + a.map{|x| valenc(x)}.join(',') + ']'
434
+ end
435
+
436
+
437
+ def keyenc(k)
438
+ case k
439
+ when String then strenc(k)
440
+ else
441
+ raise Error, "Hash key is not a string: #{k.inspect}"
442
+ end
443
+ end
444
+
445
+
446
+ def strenc(s)
447
+ t = StringIO.new
448
+ t.putc(?")
449
+ r = 0
450
+
451
+ while r < s.length
452
+ case s[r]
453
+ when ?" then t.print('\\"')
454
+ when ?\\ then t.print('\\\\')
455
+ when ?\b then t.print('\\b')
456
+ when ?\f then t.print('\\f')
457
+ when ?\n then t.print('\\n')
458
+ when ?\r then t.print('\\r')
459
+ when ?\t then t.print('\\t')
460
+ else
461
+ c = s[r]
462
+ # In ruby >= 1.9, s[r] is a codepoint, not a byte.
463
+ if rubydoesenc?
464
+ begin
465
+ # c.ord will raise an error if c is invalid UTF-8
466
+ if c.ord < Spc.ord
467
+ c = "\\u%04x" % [c.ord]
468
+ end
469
+ t.write(c)
470
+ rescue
471
+ t.write(Ustrerr)
472
+ end
473
+ elsif c < Spc
474
+ t.write("\\u%04x" % c)
475
+ elsif Spc <= c && c <= ?~
476
+ t.putc(c)
477
+ else
478
+ n = ucharcopy(t, s, r) # ensure valid UTF-8 output
479
+ r += n - 1 # r is incremented below
480
+ end
481
+ end
482
+ r += 1
483
+ end
484
+ t.putc(?")
485
+ t.string
486
+ end
487
+
488
+
489
+ def numenc(x)
490
+ if ((x.nan? || x.infinite?) rescue false)
491
+ raise Error, "Numeric cannot be represented: #{x}"
492
+ end
493
+ "#{x}"
494
+ end
495
+
496
+
497
+ # Copies the valid UTF-8 bytes of a single character
498
+ # from string s at position i to I/O object t, and
499
+ # returns the number of bytes copied.
500
+ # If no valid UTF-8 char exists at position i,
501
+ # ucharcopy writes Ustrerr and returns 1.
502
+ def ucharcopy(t, s, i)
503
+ n = s.length - i
504
+ raise Utf8Error if n < 1
505
+
506
+ c0 = s[i].ord
507
+
508
+ # 1-byte, 7-bit sequence?
509
+ if c0 < Utagx
510
+ t.putc(c0)
511
+ return 1
512
+ end
513
+
514
+ raise Utf8Error if c0 < Utag2 # unexpected continuation byte?
515
+
516
+ raise Utf8Error if n < 2 # need continuation byte
517
+ c1 = s[i+1].ord
518
+ raise Utf8Error if c1 < Utagx || Utag2 <= c1
519
+
520
+ # 2-byte, 11-bit sequence?
521
+ if c0 < Utag3
522
+ raise Utf8Error if ((c0&Umask2)<<6 | (c1&Umaskx)) <= Uchar1max
523
+ t.putc(c0)
524
+ t.putc(c1)
525
+ return 2
526
+ end
527
+
528
+ # need second continuation byte
529
+ raise Utf8Error if n < 3
530
+
531
+ c2 = s[i+2].ord
532
+ raise Utf8Error if c2 < Utagx || Utag2 <= c2
533
+
534
+ # 3-byte, 16-bit sequence?
535
+ if c0 < Utag4
536
+ u = (c0&Umask3)<<12 | (c1&Umaskx)<<6 | (c2&Umaskx)
537
+ raise Utf8Error if u <= Uchar2max
538
+ t.putc(c0)
539
+ t.putc(c1)
540
+ t.putc(c2)
541
+ return 3
542
+ end
543
+
544
+ # need third continuation byte
545
+ raise Utf8Error if n < 4
546
+ c3 = s[i+3].ord
547
+ raise Utf8Error if c3 < Utagx || Utag2 <= c3
548
+
549
+ # 4-byte, 21-bit sequence?
550
+ if c0 < Utag5
551
+ u = (c0&Umask4)<<18 | (c1&Umaskx)<<12 | (c2&Umaskx)<<6 | (c3&Umaskx)
552
+ raise Utf8Error if u <= Uchar3max
553
+ t.putc(c0)
554
+ t.putc(c1)
555
+ t.putc(c2)
556
+ t.putc(c3)
557
+ return 4
558
+ end
559
+
560
+ raise Utf8Error
561
+ rescue Utf8Error
562
+ t.write(Ustrerr)
563
+ return 1
564
+ end
565
+
566
+
567
+ def rubydoesenc?
568
+ ::String.method_defined?(:force_encoding)
569
+ end
570
+
571
+
572
+ class Utf8Error < ::StandardError
573
+ end
574
+
575
+
576
+ class Error < ::StandardError
577
+ end
578
+
579
+
580
+ Utagx = 0b1000_0000
581
+ Utag2 = 0b1100_0000
582
+ Utag3 = 0b1110_0000
583
+ Utag4 = 0b1111_0000
584
+ Utag5 = 0b1111_1000
585
+ Umaskx = 0b0011_1111
586
+ Umask2 = 0b0001_1111
587
+ Umask3 = 0b0000_1111
588
+ Umask4 = 0b0000_0111
589
+ Uchar1max = (1<<7) - 1
590
+ Uchar2max = (1<<11) - 1
591
+ Uchar3max = (1<<16) - 1
592
+ Ucharerr = 0xFFFD # unicode "replacement char"
593
+ Ustrerr = "\xef\xbf\xbd" # unicode "replacement char"
594
+ Usurrself = 0x10000
595
+ Usurr1 = 0xd800
596
+ Usurr2 = 0xdc00
597
+ Usurr3 = 0xe000
598
+
599
+ Spc = ' '[0]
600
+ Unesc = {?b=>?\b, ?f=>?\f, ?n=>?\n, ?r=>?\r, ?t=>?\t}
601
+ end
602
+ end
@@ -0,0 +1,43 @@
1
+ class ApplicationController < ActionController::Base
2
+
3
+ after_filter :framed_report_page_view
4
+
5
+ def pv_event_name
6
+ "#{request.method}_#{params[:controller]}\##{params[:action]}"
7
+ end
8
+
9
+ def framed_report_page_view
10
+ begin
11
+ anonymous_id = cookies.signed[Framed.anonymous_cookie]
12
+ user_id = send(Framed.user_id_controller_method)
13
+
14
+ if user_id.nil? && anonymous_id.nil?
15
+ anonymous_id = Framed.new_anonymous_id
16
+ cookies.signed.permanent[Framed.anonymous_cookie] = { :value => anonymous_id, :httponly => true}
17
+ end
18
+
19
+ cleaned_params = params.except(:controller, :action).to_h
20
+ Framed.report({
21
+ :type => :track,
22
+ :anonymous_id => anonymous_id,
23
+ :user_id => user_id,
24
+ :event => pv_event_name,
25
+ :context => {
26
+ :path => request.path,
27
+ :request_method => request.method,
28
+ :rails_controller => params[:controller],
29
+ :rails_action => params[:action]
30
+ },
31
+ :properties => Framed::Utils.flattened_hash({
32
+ :params => cleaned_params
33
+ })
34
+ })
35
+ rescue StandardError => exc
36
+ Framed.logger.error("Failed to report page_view #{exc}")
37
+ end
38
+ end
39
+
40
+ def framed_devise_user_id
41
+ current_user.try(:id)
42
+ end
43
+ end
@@ -0,0 +1,9 @@
1
+ module Framed
2
+ class Railtie < ::Rails::Railtie
3
+ config.after_initialize do
4
+ Framed.configure do |config|
5
+ config[:logger] ||= ::Rails.logger
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,54 @@
1
+ require 'securerandom'
2
+ require 'time'
3
+
4
+ begin
5
+ require 'uuid'
6
+ rescue LoadError
7
+ end
8
+
9
+ module Framed
10
+ module Utils
11
+ class << self
12
+ def uuid
13
+ begin
14
+ UUID.new.generate
15
+ rescue NameError
16
+ SecureRandom.uuid
17
+ end
18
+ end
19
+
20
+ # Adapted from Rails in case it isn't available.
21
+ def try(o, *a, &b)
22
+ try!(o, *a, &b) if a.empty? || o.respond_to?(a.first)
23
+ end
24
+
25
+ def try!(o, *a, &b)
26
+ if a.empty? && block_given?
27
+ if b.arity.zero?
28
+ o.instance_eval(&b)
29
+ else
30
+ yield o
31
+ end
32
+ else
33
+ o.public_send(*a, &b)
34
+ end
35
+ end
36
+
37
+ def serialize_date(dt)
38
+ dt.utc.iso8601
39
+ end
40
+
41
+ def flattened_hash(h, namespace = '', memo = {})
42
+ h.reduce(memo) { |memo, (key, value)|
43
+ value = value.to_h if value.respond_to?(:to_h)
44
+ if value.instance_of?(Hash)
45
+ memo.merge!(flattened_hash(value, "#{namespace}#{key}_", memo))
46
+ else
47
+ memo["#{namespace}#{key}"] = value
48
+ end
49
+ memo
50
+ }
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,4 @@
1
+ # encoding: utf-8
2
+ module Framed
3
+ VERSION = "0.1.0"
4
+ end