framed_rails 0.1.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.
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