retention_magic 0.1beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (264) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +70 -0
  4. data/Rakefile +37 -0
  5. data/app/assets/javascripts/retention_magic/application.js +13 -0
  6. data/app/assets/javascripts/retention_magic/graphs.js +2 -0
  7. data/app/assets/stylesheets/retention_magic/application.css.scss +4 -0
  8. data/app/assets/stylesheets/retention_magic/graphs.css +4 -0
  9. data/app/controllers/retention_magic/application_controller.rb +4 -0
  10. data/app/controllers/retention_magic/graphs_controller.rb +66 -0
  11. data/app/helpers/retention_magic/application_helper.rb +4 -0
  12. data/app/helpers/retention_magic/graphs_helper.rb +4 -0
  13. data/app/views/layouts/retention_magic/application.html.erb +16 -0
  14. data/app/views/retention_magic/graphs/index.html.erb +89 -0
  15. data/config/routes.rb +3 -0
  16. data/lib/generators/retention_magic/USAGE +8 -0
  17. data/lib/generators/retention_magic/retention_magic_generator.rb +7 -0
  18. data/lib/generators/retention_magic/templates/initializer.rb +35 -0
  19. data/lib/retention_magic/engine.rb +12 -0
  20. data/lib/retention_magic/version.rb +3 -0
  21. data/lib/retention_magic.rb +12 -0
  22. data/lib/tasks/retention_magic_tasks.rake +4 -0
  23. data/test/controllers/retention_magic/graphs_controller_test.rb +23 -0
  24. data/test/dummy/README.rdoc +28 -0
  25. data/test/dummy/Rakefile +6 -0
  26. data/test/dummy/app/assets/javascripts/application.js +13 -0
  27. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  28. data/test/dummy/app/controllers/application_controller.rb +5 -0
  29. data/test/dummy/app/helpers/application_helper.rb +2 -0
  30. data/test/dummy/app/models/user.rb +2 -0
  31. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  32. data/test/dummy/bin/bundle +3 -0
  33. data/test/dummy/bin/rails +4 -0
  34. data/test/dummy/bin/rake +4 -0
  35. data/test/dummy/bin/setup +29 -0
  36. data/test/dummy/config/application.rb +26 -0
  37. data/test/dummy/config/boot.rb +5 -0
  38. data/test/dummy/config/database.yml +25 -0
  39. data/test/dummy/config/environment.rb +5 -0
  40. data/test/dummy/config/environments/development.rb +41 -0
  41. data/test/dummy/config/environments/production.rb +79 -0
  42. data/test/dummy/config/environments/test.rb +42 -0
  43. data/test/dummy/config/initializers/assets.rb +11 -0
  44. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  45. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  46. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  47. data/test/dummy/config/initializers/inflections.rb +16 -0
  48. data/test/dummy/config/initializers/mime_types.rb +4 -0
  49. data/test/dummy/config/initializers/session_store.rb +3 -0
  50. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  51. data/test/dummy/config/locales/en.yml +23 -0
  52. data/test/dummy/config/routes.rb +4 -0
  53. data/test/dummy/config/secrets.yml +22 -0
  54. data/test/dummy/config.ru +4 -0
  55. data/test/dummy/db/development.sqlite3 +0 -0
  56. data/test/dummy/db/migrate/20151101172105_create_users.rb +9 -0
  57. data/test/dummy/db/schema.rb +23 -0
  58. data/test/dummy/db/test.sqlite3 +0 -0
  59. data/test/dummy/log/development.log +26 -0
  60. data/test/dummy/log/test.log +351 -0
  61. data/test/dummy/public/404.html +67 -0
  62. data/test/dummy/public/422.html +67 -0
  63. data/test/dummy/public/500.html +66 -0
  64. data/test/dummy/public/favicon.ico +0 -0
  65. data/test/dummy/test/fixtures/users.yml +4 -0
  66. data/test/dummy/test/models/user_test.rb +7 -0
  67. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/-EKyd_oC6THd4BAbS2D2_kyeDou-bW4JObOLLVZdOFk.cache +0 -0
  68. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/0IXJ0VwHQ1myWjMoMI7sj6gyiBaic9dSuMA3qhCMyho.cache +2 -0
  69. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/0KdY4zdTDqNuaIJrQ46aMabzHNOb19sHqHrL-T-9odo.cache +1 -0
  70. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/0PUkfyQ2F9eMxvUV8pyj2kygYIV-ZWTH_kAfKlkGaE4.cache +1 -0
  71. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/1SLJFn9dWUy2htivBqUV8ucgSlP7r0QZYNw6XQh54pY.cache +1 -0
  72. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/1aaKiOcr5FbgDvjzrt8PyAtDIXL3Iw6MuktoXQHT-DI.cache +0 -0
  73. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/1d0uHMVXfRc1ubXJOg4RNR-jFY7kbtcrrtcJyMarsrs.cache +0 -0
  74. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/2jdPyIpUrJSIPDOKPkhPxNeg-j4qHvt1VHdFf_tsTDA.cache +0 -0
  75. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/2pO6RFzcN1Y8PCTq3llcln7dDtLWIzkH9w-gMrmA7y8.cache +1 -0
  76. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/2vyShy4Koxrr6CCOuHHgIPA8EnnBDHWoLnKrKffPGHM.cache +0 -0
  77. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/46wIoc02CPB2GCNyyJXx9EkY0xDY3Gof-_7BDtyZDWg.cache +1 -0
  78. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/48kpnqEQf9dHol_tLyx0ttDovvreVfaF8jApACJRaIY.cache +1 -0
  79. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/4WCxJusnwndd61nvbz9hVTvOmvpASHHtDPppXFyIiB0.cache +0 -0
  80. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/4xk-ivYrUYRYDj18blTMzPBfyCGkfqk52EvNDJdg8Gw.cache +0 -0
  81. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/5-8uEo8hS619UqNHig2Sy6R_8DBHlRhx_JPRAgm633Y.cache +0 -0
  82. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/5T97e3PPG1jPbak-xL1QALWbI788ykSahMBFsi8vwG8.cache +0 -0
  83. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/5WQeJuCgZcGOO9OT532YBlD9ZmnyHiG53__RfG9uArA.cache +2 -0
  84. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/6GxOkIes97PX5qrlf-PQxWpQodYBc2c6XthOoHLsfc0.cache +1 -0
  85. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/7EbGNSBp5zAr296AGwwKjCoz7adk1BPYxpsoSJJDR6M.cache +0 -0
  86. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/7X0L1kmfoaaWSV9v92CzU-VFFML7pwyxPQSv8zb8Euk.cache +1 -0
  87. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/7wtcEbVdZtLO6mIle552GCSiudjk0gxju8nMFzuyz2U.cache +1 -0
  88. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/8JFJ5ZRniT_qi9ZFTFRIcahIoL6_wWBN1-pMBlfQC6I.cache +1 -0
  89. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/97ROeS4YmJH6SC9UrDeVamgzl13LnYF-m-KPtSX5X4o.cache +1 -0
  90. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/9ha1JF0TIWGGGZbM5RneU6jTeifw9szeHQjR1BMXTJA.cache +1 -0
  91. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/9k23WG9g9slSyMm-y3AzkUjImqkvFgwm2dCqkyFHEkM.cache +1 -0
  92. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/AJeh7APM3yZ_RMKzfI3PejI4R39QYn21Fp39a_va72A.cache +1 -0
  93. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Aoo3-y8-e2WidsFoszZoTy1kWVs0Sqfo7gQQs08Zpsc.cache +0 -0
  94. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Azw3pKwmffO6DeR1gLBznj9QXVfkNYEljwr0oVfzUHM.cache +0 -0
  95. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/B3oQ8oVtmuO6dHRqMYEVhXJIKUUAkvDdwjHsR3It-pY.cache +0 -0
  96. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/B4bjb0h4g1XfVxaawDaUoArqTUERksbzw2v4_5xtL-M.cache +2 -0
  97. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/BByX-5b5NhhAFKL9AFIiLcwjDpRSFGRfYeZBRRIbn4k.cache +2 -0
  98. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/BMMc_DZkRTbZGMN0AKKS6c1GEZiv0eoo7SLegSW1YiE.cache +2 -0
  99. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/BeDSqsni6kaxsFxWrKlJDFlZXfg_k4JQzl9H1FL3zMw.cache +1 -0
  100. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/CG2RdeoqplTH74BR5aGSu_Sz1Pq4ayHk5g0yvaybTG0.cache +0 -0
  101. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/CNzTeGX0-4KuQmrsIua6RNJACn9NHo-ntJho20bxkoE.cache +1 -0
  102. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/D03tiXUEwshAmTAAiTbrw0xLZnhLyXu-5xdpGTbfrJ0.cache +0 -0
  103. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Ds7fuV01MCUyi5syLmeAjrcxBCUQFF1iljMmyHSWXdU.cache +0 -0
  104. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/E5uoYk_12nfa5QUZBBNWvNthUdhKxh6lfxD1byCmrgE.cache +1 -0
  105. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/E7O3ZVvlIClzTE4qlgK552_QNrJlOut1QQY8Gwiexn0.cache +0 -0
  106. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/F0lC3ybVOwcG5sWSIeV_d-pSEdTNCidiZmytdMN6eg8.cache +1 -0
  107. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/F6f_HA-LQxV4A19DQ29EgarCISD7gs5YjDqqfwEszus.cache +0 -0
  108. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/FsOBl7WIN6osDeZQjmppclnUHcrJsXo6rRboCotrlR4.cache +0 -0
  109. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Gc6qjXGofmVaTOuiRcOst8jwX8MPAX2MED8-BJeQl0M.cache +0 -0
  110. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Gdol55f3KGdSF4uvTV0C2nX3nrWSgo-g133KQrRorIk.cache +1 -0
  111. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Gm9IQbSlfLJhpuIplwTTmyo5MmK-5-Iy3oeclZQadjE.cache +0 -0
  112. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/H6xqgdhJmmqeriDQv9dkBi3WS0SmEosd8DZBWMl2KMQ.cache +0 -0
  113. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/HLOzIn2VxQVdNIk_b2D5_9_x7fNky_fbmLsOZj92FzM.cache +1 -0
  114. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/HPdAYtq1zyup9-UheS_JBk_TSRDW0gW1ZViIVjJJJAc.cache +0 -0
  115. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/HbwGa3RgCWHIn430P1fhatvtVOhsPVZ85FTHU1W6k_I.cache +0 -0
  116. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Hcl3KIwjCwfyCrNGw7CDKkg3dmwFwqt3gUk-DCvy_3Q.cache +0 -0
  117. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/HliGHzlTBFZ9VrZVBDwSQuVR3y-QLReDRktd3pc1Ie4.cache +0 -0
  118. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/HrDQmheAOkeYpJpoeazmpi-3ntUC0ekSgg2xeokHlhg.cache +0 -0
  119. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/I03OktI9g5iAyp0Gkf56cWOFA-hwktqQaXGoKXTJs2c.cache +1 -0
  120. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/I3pA2lvdTEV-UZI1eLyiPoQ5xp_TxcfHGlcM8HhjrUA.cache +1 -0
  121. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/IIa1m3-koAyF7ousfrCjjXvh7EvXMFn5qiRnVdaJKOo.cache +1 -0
  122. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/INm9W1Sg6a5miV559fyouUIgYnK7Npk6UBO6BW33hBc.cache +1 -0
  123. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/JRQT9hJaSGDAR9S4tmweurzqG2BOXdy_BZ6KnHAZrag.cache +1 -0
  124. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/K4Fn3ShoKuf1Q7IZV4A6YqUcdS6LbU1mWaISi24iNZQ.cache +0 -0
  125. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/KAoCDny0VK_Wz7naD1kO6pxf6TXm_IFqidCAK6E1Kd0.cache +0 -0
  126. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/KJOPG9V8VgEFmEQQ6MJn8qVI32fzGDrDkJ6ILCsyH1U.cache +0 -0
  127. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Kc7bYAdTodpOkblJghsvVRY-3bfLrTReNdaDK-Ymri8.cache +1 -0
  128. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Ks6_Jn6KD4ijdqpG9Ht9JMbSDYp-J6g42ClLSODG9IE.cache +0 -0
  129. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/KvCV4Wjiqpl3vgQGyRopP4yaNgux1lzR9mycwPwioiw.cache +2 -0
  130. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/L54qL0Fr1bZphva1U3QQyAxDsiAbWBn02lW_hWV8y0g.cache +0 -0
  131. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/LGLT0wKtzQ5uBvOGeCkUzrrUAR-q21mL7u3LkyDgatI.cache +1 -0
  132. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/LIUsE_pyu8gX78rXC9lk5oW2piuHW6-kMIOQfglx4fA.cache +0 -0
  133. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/LLAPppHM6ppiQSHF-hDydoEIuUf1Dxieoz1t5xYRAP8.cache +2 -0
  134. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/LtC4evqWVY3uCDJB316h9JsUU2periD3YqM0RsoBPKU.cache +1 -0
  135. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/MWefbnf248C65h3kquViTc8719lfYZ4gWKsTNLP-WfY.cache +0 -0
  136. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/MZIhxLeOUL8hep_dj7lG8RgLuFQkYErGynAhvnr9UjI.cache +0 -0
  137. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/N5zJMoY9oYwvrmNKCqGQgOFN7pv2LFFTbYBhiIlqYLs.cache +0 -0
  138. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/N8WOOX1_9iJ9WZK44CCW_lwAvJtcXMIBLgiEPrd89vc.cache +1 -0
  139. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/NSNWigQmmN5-OouXizA3EcGHev5yYtBgWQnBxYEjzKo.cache +1 -0
  140. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/O1mI7v-D0L5CBUODatg7wE_zhEyrClrCHdaqCF8bSPY.cache +3 -0
  141. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/P71FxTLHyPRgPID6QyqafCqUQOxZ84ZetezV25ZVpfE.cache +1 -0
  142. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/PhaTrZUT9VTiI6H1r7GwyFLMHfxR-uhJOTGQmAQJmeo.cache +0 -0
  143. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Plkl-T9w9SEqJb0yJCeRmCy3AHmmER29ux_VsT6L0vI.cache +0 -0
  144. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Pqaxh3i1B1XY9-QwwatlN2JaJQRHTsdQYw34go35a1I.cache +1 -0
  145. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/PuN9uwfQ3pF7bH5_Yu_Cmv-OvkSjfglTC5uktgCZHH4.cache +1 -0
  146. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/QJJxx57fvCElwjGPgh5_u_d1QEPvmijPGOjEbSEc2-M.cache +2 -0
  147. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/QM1wS11IzZu3nP2jnh_cerz_CHOgj4vWQeVHjleMOac.cache +0 -0
  148. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/QaDwLv3GTns1gLXUVeL7Iq-smjTU83xncOxvy6Qua-I.cache +2 -0
  149. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Qb4zSr4wAGR-pBB5y-frIa-DczVEmTEVKSnDr6pjiok.cache +1 -0
  150. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/QoZ0dgQgLjisiKyOdyzbO9i-meAS1_zIUYEiDpZnsJ8.cache +0 -0
  151. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/QyKzcMq479m5BEBS8DRpSj0rXSIHJ0h8E7_Lgomnk_0.cache +0 -0
  152. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/RP1L5wMZC8y60-e-vUs1uk29O0QQXVSqwfiRZDV4ExY.cache +1 -0
  153. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/RPp1_DK3ZnQmIap9UwlPbZExlW9jGa7pxUBDjfLfMog.cache +0 -0
  154. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Rf8f5x1LTUk6Pw0UmmoP0IWIYXw1duoxu4P5oEfmJ1M.cache +0 -0
  155. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Rhd6hnFqWNCNvb6opnuFEgc0-qhqY24zfw0M8zUgXro.cache +1 -0
  156. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/T3qq89UZq_AApGEhQc5ocZUI6K0lWQraH_KEZfzCzOI.cache +0 -0
  157. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/T8Gfg7Ei7Wu5vOngrFKdDrPwjbCID7bdYO3iKfEPAtw.cache +2 -0
  158. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/TKNYFXbdXmxy25OzSRy3azMyGjIEfwvpCpGgLMvUGDM.cache +1 -0
  159. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Tgp5r1BHz15ac6Kc5XNVHTSYgnFX-FzGGOq_J7kSJek.cache +0 -0
  160. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/UMHrIsutdIGDrWZnC-WT_LlebvXYLe9Q-kBwsGjUYDk.cache +1 -0
  161. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/UjKNoV10XsZsza-Y_IDpQ-T15ZbjDYX_ArYgaKaioJw.cache +2 -0
  162. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Uq_MH1E2yYlQizQ0b9lws-iQIbAzOag2Z7t8WdRpoRw.cache +0 -0
  163. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/UuNRtuRFLhpzApXAN86VXFNEVeowlOJmTZb_scjcTos.cache +1 -0
  164. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/VHhvIp0_BrEMbC3ikJ1CaO56Z2kURWBEmLhoYLLwwbc.cache +0 -0
  165. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/VOR4wLdJwpQWV0536YrOZ-swnKpifVnZbeqWDJ-7zX0.cache +0 -0
  166. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/VXBor9dwTUP10zaznHwJF_Lz2rfrIDSOD5gZQDebx50.cache +2 -0
  167. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Vz2PZ-uVHlp1Oh_jvW6YWZn9nsjZSX2AuC0LjmyjW8c.cache +0 -0
  168. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/WTaoAjPu9uN8yuhj-OMyOYtgvuWBpyXMv4UOnPuJXdk.cache +0 -0
  169. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/X6i9SJn0xUJ79TIu86mjf4yed0VvoMg9zK46SAZjqyU.cache +0 -0
  170. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/XIPuM90puf2NC0mCb1ohCwvCq-_crN8GTAgnC3H-5Q8.cache +0 -0
  171. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Y2wpnHO7rXxkiVYDKjKBHl_uuQBbiNFtpkEdBkmZSFY.cache +0 -0
  172. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/YP9xV25kSnMAzZtQCGDKbMa5rnWJoz0HjPtwMgo_xPU.cache +0 -0
  173. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/YeEFcUmV3ejuoluv6njOF3lM2wZstXlWql2HtJGyRmc.cache +0 -0
  174. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/YhssBxTBZZ0VN1uZitFeSz7__TsAS0i6i1EppMAHSjE.cache +0 -0
  175. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/_H6Ve9WSmlWh_hFbod2dF6BzbhZVoQgsTxK4ii4b6UM.cache +1 -0
  176. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/_ZL02pb6iMwsP2OfoXDbeAdjfTboJaDjEw1MrzLQZBw.cache +0 -0
  177. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/aMk5X7CaiVsWDtcbcvGNzTE4NQFxiOio3NPFrRWk-aY.cache +0 -0
  178. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/aiWrIgIqKFjh94HgI2FFduAtjHjx5nUrbpjPWvsNnBQ.cache +1 -0
  179. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/b2B7EHgldqGlfHzXVvibMrrw4LNBbunZq4w6gaDVWx4.cache +1 -0
  180. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/b4ruyRBNV-oqDqlmIy5_CyVppjSIuK26MHuENLGmfjI.cache +1 -0
  181. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/c-N46x-NrMFRW8S_810IyJiHYhL_jiv2F7ZfJXlMcVE.cache +1 -0
  182. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/cJ3j-2V8Ux5ICPLbh-IB1tlbZH50axMUMsnppzerQTw.cache +1 -0
  183. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/cS6hnEsSxznsSwkbZ-lP4BmJBLBjTwRZXtIGkelZ3no.cache +0 -0
  184. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/dmiOzg8MvuzpBYCtf9V5ZAQ5gBG-l943hKo7wlylvgU.cache +1 -0
  185. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/e--k3SqXrQ-xk_n0MhVpIb-nwgsLje8cfB0kNJkShdg.cache +1 -0
  186. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/e3ohEoJjQIlR9i6WiywBRlRqkvMCrAICU9C0kh3j8TQ.cache +0 -0
  187. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ee9Azbf8pzNyeZIpa5H4pincDB9FJG9j8zmeEWlHbYk.cache +0 -0
  188. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/efhaSkZCpODzDmSSYjXgUHjVSih51fl1r-oZsqSAXlw.cache +1 -0
  189. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/exNnl3s_DehZw67_Jc0DpyfJ-2tJA6NGh-4_mIYFknM.cache +1 -0
  190. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/fTx4MdEv6r_k4VWYNgG0wcW5hD6iymeoCE-xCt8IlHc.cache +0 -0
  191. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/fVv5x3R_qH8TfabaN2RrNsDis0tvONKaroxnBQ4NhC0.cache +1 -0
  192. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/fgvjqHQBcZafnbxw24c2krRS1eQyVWyji9soIydxQpM.cache +0 -0
  193. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/fkeLw2-ZA-k4vQ7-t6fxz-bTFiXiQdalmSIg_Ku7YbE.cache +0 -0
  194. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/fnjqObfqhUe-NMN4ssK-qG07__lW6mc2NdHZZLkM104.cache +1 -0
  195. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ft0XA4vE0DbCjJqIVVv9pIzcc7yOy5pJme5_OcLtRgs.cache +3 -0
  196. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/gXfIMjV9DutecKWRfAKn_pkXuIbAgpJuDNfr6lEd8cU.cache +1 -0
  197. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/gcZXXv113or0WrMEtv0ZgNO8GNMDKVlyNPeszuuGGFY.cache +1 -0
  198. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/h7qa0K2-ItM4KdMMVybYeFcvMaCaP8mDsqjbiANbQ1I.cache +2 -0
  199. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/hIbpUjZKtxj1f7ha3uBd4sfVGrG_mSlAeLvHOpVKiTc.cache +1 -0
  200. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/hPTVTLRn5esx7FcjCYkGT49exawTe0kFYSZuuQsnpW0.cache +2 -0
  201. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/huuOa_ZYJ6H2lVwNlZM5aLaEghkmBR1nXB18w7Wr1vk.cache +0 -0
  202. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/i-IkmambRaQoPG7Uy_AqvTtjdJBpwLAer-enykzM8Go.cache +2 -0
  203. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/iaDLUe0Qh-UyAp6UAEwtebxpd6Kizza16SzGxXeEaTo.cache +1 -0
  204. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ikhuyZtsbCFrWYHI4Wd5gDIs9qFJt0-ldB5XLn_ZnnQ.cache +1 -0
  205. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/j03eD60i0Z9OBiFBFuJI79ZLVOANKBYcf60_WBYVB_s.cache +3 -0
  206. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/jcFoU3Hn00ZaTV_W6PDDo1pxhsDJtZjfeVN3eMWEpy8.cache +1 -0
  207. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/jpADL_4RCzMnO_aSGmDcgBLniID7FsBl6rXUgQzMgXY.cache +1 -0
  208. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/jwi50-NjNb6-JUbjpmXXg7GHkKhPKBEgYTv4zAH09HE.cache +0 -0
  209. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/khT6fQ0szWvnfYIw0sJwt51Y9cfa48JxWbTpxmHanY0.cache +3 -0
  210. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/l3XYoUMMINtweMsF6k3sar_dIRFbWKhUFpwKvoAJ2E0.cache +0 -0
  211. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/l6wMdkcs_r1UM6OU_SkKId-3fyP1zjNwiVo3cjpEa4Q.cache +0 -0
  212. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ljhtUl9VWqUCWCs6x2hwFc-TzbGvFSj47RVAQrr66to.cache +1 -0
  213. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/lvVXDxtxrKNXrEQF_4wKjF86DasK57HgPC7Zc13_E1s.cache +0 -0
  214. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/m0F3RxYCdIy6Yw6_kNzi0U4NLV5l-eP9oz2czcdOKEk.cache +0 -0
  215. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/mA9L9Wxvf1vOBaTTzZgijBD0uQsXffX3H2J2mc29quA.cache +1 -0
  216. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/mUbjAVHaaKujwp09t8pMkPsNn9eJxUHOz9oIMf9DrEA.cache +1 -0
  217. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/mVjsA2NqkynEWhz6MmtXo_-QW0RjVRzaszGl6-RPfJc.cache +0 -0
  218. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/mt8Lt_jAlLZ4U-1zbCN5mGG0amfxS0hBkbKGD_gtlws.cache +0 -0
  219. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/naXoSDtfOxk3NXO18x0Q6LY-BcQCH-NtHgPOiQww8yg.cache +1 -0
  220. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/o1Z0uv2WT2ccxCCkASmBB4msZNreyGx6lN1wqBrj6CI.cache +1 -0
  221. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/or70b6whbsuqQA5EHtqWYVRgD2H79KBvoguOoe8z1Ao.cache +1 -0
  222. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/pGa0ZX7gIbDjBf207EhUUk2CqlzjoVTXKv412vHjmE4.cache +0 -0
  223. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/pHkS-yERUmBWL117Z9Qo2jlmvztGkOjgtk9ztQbkJzE.cache +0 -0
  224. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/pKgCH-5O50hIDG4VwyXAyoK51_qP1C4p4W8PAXn19JQ.cache +1 -0
  225. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/pOZ2fwSZWtmW5khq-b49H9fyEUMH3VBJ-N83dHvMAwI.cache +0 -0
  226. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/pVHxPRPevuSeRHS3HbHCHB5Vc0ASCOpMLe-2Sj1dcb4.cache +0 -0
  227. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/pYE29BrK_w79ww7TYHd3S4LxdhTIvhTq_Wetnw2z3M8.cache +0 -0
  228. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/qYKZL8-s66wvUJhzzIZod4WjW6wDk_yeFKkR6Zl3XBo.cache +1 -0
  229. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/q_fqn08IcQkT28olIwaaRDUUYQ1SQEii5WWrclckyl8.cache +1 -0
  230. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/rJANshMQoojwXLVKughpVE7BOqzP7Bcmo_kZBt2pkGU.cache +0 -0
  231. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/rPsIbIVGHbdh46Y080NkUVUj_97v2gEiZIWXGt6Cfeo.cache +1 -0
  232. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/rt59MaJHnqS58TNd10uIuar6UKj3sbEyWDYMCuI7zZk.cache +0 -0
  233. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ruMxNQHvuLsXZHZ2tDEx4yt97-fDQwEtLojFEhsus5Y.cache +1 -0
  234. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/t-q6C2Daeh64PWWMnwuzNDOK6yrt1etjkF9BIhpJ9HY.cache +1 -0
  235. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/tK-1NOEZed_qRbueyxbPw-NMOutZw5bdI1eFsku57C0.cache +0 -0
  236. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/tavug0h1LdqZzksd99OpyhMSewn2b27dg9_LNrTRtec.cache +0 -0
  237. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/tgU4lSUXxSVZskPkAhhVkYWyVltIicmlEW5jy28bbv4.cache +0 -0
  238. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/tyXAPHB9HRUCMajT1hhEu_RXxJQWVmg5poJx_yjabkY.cache +1 -0
  239. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/u10gUBcaxCuyfXyqfdhqRz1-hkXbdNiTwhYHBsnCWlo.cache +1 -0
  240. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/uhLckzCtpe1MhodZ9Eha9L5_cAHVnnAjpssEGgK0gJE.cache +0 -0
  241. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/uvH6dyEoLVE7wLKdp5Uw5oXsSlcVfajHDJuA1ACITuY.cache +1 -0
  242. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/vKQPBwSZr3pjWm6WP9gbpyBUvnO1hko-bd7V5Rkc7zk.cache +0 -0
  243. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/vQmahYg2BSlOHoOBc98t4M3mpRWO23GY213nygOLUWs.cache +2 -0
  244. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/vcb0UMCAV3BZuyISepHgEt30xYcf2QqRUBbe1yiDPTk.cache +0 -0
  245. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/vr2Ky26kBfoj1Lzdgcfeda5c_U_6k3NQ-b9Bqc3vy8s.cache +1 -0
  246. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/vz3IHo7GXPR4vHQMnNjAVdGv_yYRAjn17iYUqt_MBwg.cache +2 -0
  247. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/wMd3bN8GIHJ1GyviGomDxVL_RtfQERcsj6KPRmgF3QA.cache +0 -0
  248. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/xF2X7Her13dCj5pm2QdP_W74A2SHCOF19zTC3OPN4fA.cache +1 -0
  249. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/xiw2N0hcvLMQgaG1U0IV1tMut4PC1SPN2g1FlfqgOLQ.cache +1 -0
  250. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/xnjydYZBm9KXbjh9DylByrHTn7NxJNHIIGgiltYbDtA.cache +0 -0
  251. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/yMl_Z-8144OMa18Tx43HXEOcxNsN77AOOzBeL69y_V8.cache +0 -0
  252. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/yfLOXzBPETp_ubxEzuXpiAr-lcNGdkSKg3PcQbIMfhE.cache +0 -0
  253. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/yida6X11pHMGq-7wTwl2E3wxEqbbTb0HoSOyarEcO54.cache +0 -0
  254. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ylZ4k6cqpUGn1n_r7uOXYSDs18qyGM03ikeWWK3ebXk.cache +1 -0
  255. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/z3PYleH-yQuUROj3MWExEdDbritBOUSKmAyBElXh5EY.cache +1 -0
  256. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/zRxSnjNpkoxlOFcoVVJ0JvwmY0oLaW4sa25eEFoblc0.cache +1 -0
  257. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/z_5KfyOVpIF1xrjaFJn3pll3SvoKIFLKzMAtbEqo_cM.cache +3 -0
  258. data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/zhFnH12w2VXfUa648KwVjTztyUv6GJQoLj2DOtjzHmo.cache +0 -0
  259. data/test/dummy/tmp/generators/config/initializers/retention_magic.rb +35 -0
  260. data/test/integration/navigation_test.rb +8 -0
  261. data/test/lib/generators/retention_magic/retenion_magic_generator_test.rb +16 -0
  262. data/test/retention_magic_test.rb +7 -0
  263. data/test/test_helper.rb +21 -0
  264. metadata +606 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 202a0352d4733122ab78e0761e9ef41d5477d13c
4
+ data.tar.gz: bcd0445686ed5e9bb71528a937d3e0fcc2911840
5
+ SHA512:
6
+ metadata.gz: abc384b5ef612dee76e75ec282d5ffd2381ede9612e00bf5d48e215996fa9a201cd7804f760962504bcc416c2e575b9c6086a92a588d410d027dec581e24bed2
7
+ data.tar.gz: 80dd27806353b8d83801cd0b666f0e10929935829b88dd3e97d1c1d0d1ad69853339a2baa88f9a4bd2700f8c520a1dca318a4ec390f26148d8a27d9075b7165f
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2015 Michiel Sikkes
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ RetentionMagic
2
+ ==============
3
+
4
+ Simple cohorts analysis and retention graphs in your Rails app
5
+
6
+ RetentionMagic is a drop-in gem that uses your current models and records in
7
+ your database to generate simple cohort analysis and retention graphs for your
8
+ app. There is no need to integrate an external service or explicitly add event
9
+ tracking code to your controllers or views. All data stays in your app.
10
+
11
+ Installation
12
+ ------------
13
+
14
+ In your Gemfile:
15
+
16
+ ```ruby
17
+ gem "retention_magic"
18
+ ```
19
+
20
+ And run bundler:
21
+
22
+ ```
23
+ $ bundle install
24
+ ```
25
+
26
+ Then, generate the `config/initializers/retention_magic.rb` configuration file:
27
+
28
+ ```
29
+ $ rails generate retention_magic
30
+ ```
31
+
32
+ Configuration
33
+ -------------
34
+
35
+ Open `config/initializers/retention_magic.rb` and customize the sample
36
+ configuration to your app.
37
+
38
+ Then, make the RetentionMagic page available on a route in your app. For
39
+ example, in your `config/routes.rb`:
40
+
41
+ ```ruby
42
+ Rails.application.routes.draw do
43
+ mount RetentionMagic::Engine => "/retention_magic"
44
+
45
+ # your application routes
46
+ end
47
+ ```
48
+
49
+ Securing the RetentionMagic route
50
+ --------------------------------
51
+
52
+ *Devise*
53
+
54
+ If you want to secure that page and your app uses Devise, you can use the following
55
+ routing snipper:
56
+
57
+ ```ruby
58
+ Rails.application.routes.draw do
59
+ authenticated :admin do
60
+ mount RetentionMagic::Engine => "/retention_magic"
61
+ end
62
+
63
+ # your application routes
64
+ end
65
+ ```
66
+
67
+ *Sorcery*
68
+
69
+ The same can be be achieved in a similar manner with with Sorcery. Take a look
70
+ at this Wiki page: https://github.com/NoamB/sorcery/wiki/Routes-Constraints
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'RetentionMagic'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+
37
+ task default: :test
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,2 @@
1
+ // Place all the behaviors and hooks related to the matching controller here.
2
+ // All this logic will automatically be available in application.js.
@@ -0,0 +1,4 @@
1
+ @charset "utf-8";
2
+
3
+ @import "bootstrap-sprockets";
4
+ @import "bootstrap";
@@ -0,0 +1,4 @@
1
+ /*
2
+ Place all the styles related to the matching controller here.
3
+ They will automatically be included in application.css.
4
+ */
@@ -0,0 +1,4 @@
1
+ module RetentionMagic
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,66 @@
1
+ require_dependency "retention_magic/application_controller"
2
+
3
+ module RetentionMagic
4
+ class GraphsController < ApplicationController
5
+ def index
6
+ # RetentionMagic configuration setup
7
+ @user_class = RetentionMagic.user_class.constantize
8
+
9
+
10
+ first_user = @user_class.order(:created_at).first
11
+ first_cohort = @first_user.created_at.beginning_of_month
12
+ today = Date.today
13
+
14
+ # For presenting the widgets
15
+ @first_cohort_label = first_cohort.strftime("%h %Y")
16
+ @current_cohort_label = today.strftime("%h %Y")
17
+ @number_of_months = (today.year * 12 + today.month) - (first_cohort.year * 12 + first_cohort.month)
18
+
19
+ @graphs = {
20
+ activation: {
21
+ signup_without_activation: {},
22
+ one_activation: {},
23
+ five_activations: {},
24
+ },
25
+ retention: {}
26
+ }
27
+
28
+ retention_models = RetentionMagic.retention_models.map { |class_name| class_name.constantize }
29
+ activation_fields_for_query = RetentionMagic.activation_counter_columns.join(" + ")
30
+
31
+ 0.upto(@number_of_months - 1) do |month|
32
+ cohort_start = @first_user.created_at.beginning_of_month + month.months
33
+ cohort_start_end = (cohort_start + 1.month).beginning_of_month
34
+
35
+ cohort_users = @user_class.where(created_at: cohort_start..cohort_start_end)
36
+
37
+ @graphs[:activation][:signup_without_activation][cohort_start] = cohort_users.where("#{activation_fields_for_query} = 0").count
38
+ @graphs[:activation][:one_activation][cohort_start] = cohort_users.where("#{activation_fields_for_query} = 1").count
39
+ @graphs[:activation][:five_activations][cohort_start] = cohort_users.where("#{activation_fields_for_query} >= 5").count
40
+
41
+ cohort_start_label = cohort_start.strftime("%h %y")
42
+ @graphs[:retention][cohort_start_label] = {}
43
+ cohort_user_ids = cohort_users.pluck(:id)
44
+
45
+ -1.upto((Date.today.year * 12 + Date.today.month) - (cohort_start.year * 12 + cohort_start.month) - 1) do |month|
46
+ retention_month = (cohort_start + month.months).beginning_of_month
47
+ retention_month_end = (retention_month + 1.month).beginning_of_month
48
+
49
+ records_per_user = {}
50
+
51
+ retention_models.each do |model|
52
+ count_per_user = model.where(user_id: cohort_user_ids).where(created_at: retention_month..retention_month_end).group("user_id").count
53
+ count_per_user.each do |uid, count|
54
+ records_per_user[uid] ||= 0
55
+ records_per_user[uid] += count
56
+ end
57
+ end
58
+
59
+ @graphs[:retention][cohort_start_label][retention_month] = records_per_user.keys.size
60
+ end
61
+ end
62
+
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,4 @@
1
+ module RetentionMagic
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module RetentionMagic
2
+ module GraphsHelper
3
+ end
4
+ end
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>RetentionMagic</title>
5
+ <%= stylesheet_link_tag "retention_magic/application", media: "all" %>
6
+ <%= javascript_include_tag "retention_magic/application" %>
7
+
8
+ <%= javascript_include_tag "//www.google.com/jsapi", "chartkick" %>
9
+ <%= csrf_meta_tags %>
10
+ </head>
11
+ <body>
12
+
13
+ <%= yield %>
14
+
15
+ </body>
16
+ </html>
@@ -0,0 +1,89 @@
1
+ <div class="container">
2
+ <div class="row">
3
+ <div class="col-xs-12">
4
+ <h1>How is your app doing?</h1>
5
+ <p class="lead">This page shows how your app is doing in cohorts of monthly signups. Analyzing
6
+ your app's usage in monthly cohorts helps you pinpoint important changes
7
+ to your app and or marketing strategy.</p>
8
+ <p class="lead">The <b>Activation</b> graph tells you how your app
9
+ is growing and which cohort performed the most subsequent actions in your app.<br>The
10
+ <b>Retention</b> graph shows you how many users stay active in your app in the months
11
+ after signing up.</p>
12
+ </div>
13
+ </div>
14
+ <div class="row">
15
+ <div class="col-xs-6 col-sm-3">
16
+ <div class="panel panel-default">
17
+ <div class="panel-heading">Users</div>
18
+ <div class="panel-body">
19
+ <%= @user_class.count %>
20
+ </div>
21
+ </div>
22
+ </div>
23
+ <div class="col-xs-6 col-sm-3">
24
+ <div class="panel panel-default">
25
+ <div class="panel-heading">Cohorts</div>
26
+ <div class="panel-body">
27
+ <%= @number_of_months %>
28
+ </div>
29
+ </div>
30
+ </div>
31
+ <div class="col-xs-6 col-sm-3">
32
+ <div class="panel panel-default">
33
+ <div class="panel-heading">First Cohort</div>
34
+ <div class="panel-body">
35
+ <%= @first_cohort %>
36
+ </div>
37
+ </div>
38
+ </div>
39
+ <div class="col-xs-6 col-sm-3">
40
+ <div class="panel panel-default">
41
+ <div class="panel-heading">Current Cohort</div>
42
+ <div class="panel-body">
43
+ <%= @current_cohort %>
44
+ </div>
45
+ </div>
46
+ </div>
47
+ </div>
48
+ <div class="row">
49
+ <div class="col-xs-12">
50
+
51
+ <div class="panel panel-default">
52
+ <div class="panel-heading">
53
+ <h3 class="panel-title">Activation</h3>
54
+ </div>
55
+ <div class="panel-body">
56
+
57
+ <%= area_chart(
58
+ [
59
+ {
60
+ name: ">= 5 interactions",
61
+ data: @graphs[:activation][:five_activations]
62
+ },
63
+ {
64
+ name: "One interaction",
65
+ data: @graphs[:activation][:one_activation]
66
+ },
67
+ {
68
+ name: "Signup without interacting",
69
+ data: @graphs[:activation][:signup_without_activation]
70
+ }], library: { legend: { position: "bottom" } } )%>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ <div class="col-xs-12">
75
+
76
+ <div class="panel panel-default">
77
+ <div class="panel-heading">
78
+ <h3 class="panel-title">Retention</h3>
79
+ </div>
80
+ <div class="panel-body">
81
+ <%= area_chart(@graphs[:retention].map { |k,v| {name: k, data: v}}, library: { legend: { position: "bottom" } } ) %>
82
+
83
+ </div>
84
+ </div>
85
+ </div>
86
+
87
+ </div>
88
+ </div>
89
+ </div>
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ RetentionMagic::Engine.routes.draw do
2
+ root to: "graphs#index"
3
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ RetentionMagic install generator
3
+
4
+ Example:
5
+ rails generate retention_magic
6
+
7
+ This will create config/initializers/retention_magic.rb with sample
8
+ configuration options for using RetentionMagic.
@@ -0,0 +1,7 @@
1
+ class RetentionMagicGenerator < Rails::Generators::Base
2
+ source_root File.expand_path('../templates', __FILE__)
3
+
4
+ def copy_initializer_file
5
+ copy_file "initializer.rb", "config/initializers/retention_magic.rb"
6
+ end
7
+ end
@@ -0,0 +1,35 @@
1
+ # This file contains the nessesary configuration options for RetentionMagic.
2
+
3
+ # ==> User Class
4
+ # The user class that is used by RetentionMagic. The records of this class
5
+ # will be tracked and automatically devided into monthly cohort groups.
6
+ RetentionMagic.user_class = "User"
7
+
8
+ # ==> Activation Counters
9
+ # This is a list of columns that contain counters towards a user's activation
10
+ # actions over the total lifetime of the user.
11
+ #
12
+ # For example, when you have a blogging app and the number of posts someone
13
+ # writes is an important metric for your app you would specify:
14
+ #
15
+ # RetentionMagic.activation_counter_columns = [ :posts_count ]
16
+ #
17
+ # These column need to be present on the model you specified as user_class.
18
+ # For example, you can use Rails counter_cache on a Post=>belongs_to=>User
19
+ # relation to keep the posts_count column up-to-date.
20
+ #
21
+ RetentionMagic.activation_counter_columns = [ ]
22
+
23
+ # ==> Retention Models
24
+ # This is the list of model class names that you want to track retention for.
25
+ # RetentionMagic will use the model's created_at column to build a retention
26
+ # graph for your users. If you add more than one model, any of them count
27
+ # towards the retention of your user.
28
+ #
29
+ # For example, when you run a blogging app or maybe a forum app and writing
30
+ # posts and commenting on other people's post is your metric for activation,
31
+ # you would specify:
32
+ #
33
+ # RetentionMagic.retention_models = %w( Post Comment )
34
+ #
35
+ RetentionMagic.retention_models = %w()
@@ -0,0 +1,12 @@
1
+ require "chartkick"
2
+ require "bootstrap-sass"
3
+
4
+ module RetentionMagic
5
+ class Engine < ::Rails::Engine
6
+ isolate_namespace RetentionMagic
7
+
8
+ config.to_prepare do
9
+ ActionView::Base.send :include, Chartkick::Helper
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ module RetentionMagic
2
+ VERSION = "0.1beta2"
3
+ end
@@ -0,0 +1,12 @@
1
+ require "retention_magic/engine"
2
+
3
+ module RetentionMagic
4
+ mattr_accessor :user_class do
5
+ "User"
6
+ end
7
+ mattr_accessor :activation_counter_columns do
8
+ []
9
+ mattr_accessor :retention_models do
10
+ []
11
+ end
12
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :retention_magic do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,23 @@
1
+ require 'test_helper'
2
+
3
+ module RetentionMagic
4
+ class GraphsControllerTest < ActionController::TestCase
5
+ setup do
6
+ @routes = Engine.routes
7
+ end
8
+
9
+ test "index" do
10
+ RetentionMagic.user_class = "User"
11
+ RetentionMagic.activation_counter_columns = [ :posts_count ]
12
+ RetentionMagic.retention_models = %w()
13
+
14
+ User.create!(name: "John", created_at: Date.civil(2015, 10, 1), posts_count: 10)
15
+
16
+ get :index
17
+
18
+ assert_response :success
19
+ assert_equal "Oct 2015", assigns(:first_cohort)
20
+ assert_equal User, assigns(:user_class)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,28 @@
1
+ == README
2
+
3
+ This README would normally document whatever steps are necessary to get the
4
+ application up and running.
5
+
6
+ Things you may want to cover:
7
+
8
+ * Ruby version
9
+
10
+ * System dependencies
11
+
12
+ * Configuration
13
+
14
+ * Database creation
15
+
16
+ * Database initialization
17
+
18
+ * How to run the test suite
19
+
20
+ * Services (job queues, cache servers, search engines, etc.)
21
+
22
+ * Deployment instructions
23
+
24
+ * ...
25
+
26
+
27
+ Please feel free to use a different markup language if you do not plan to run
28
+ <tt>rake doc:app</tt>.
@@ -0,0 +1,6 @@
1
+ # Add your own tasks in files placed in lib/tasks ending in .rake,
2
+ # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
+
4
+ require File.expand_path('../config/application', __FILE__)
5
+
6
+ Rails.application.load_tasks
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,5 @@
1
+ class ApplicationController < ActionController::Base
2
+ # Prevent CSRF attacks by raising an exception.
3
+ # For APIs, you may want to use :null_session instead.
4
+ protect_from_forgery with: :exception
5
+ end
@@ -0,0 +1,2 @@
1
+ module ApplicationHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ class User < ActiveRecord::Base
2
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Dummy</title>
5
+ <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
6
+ <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3
+ load Gem.bin_path('bundler', 'bundle')
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
3
+ require_relative '../config/boot'
4
+ require 'rails/commands'
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative '../config/boot'
3
+ require 'rake'
4
+ Rake.application.run
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pathname'
3
+
4
+ # path to your application root.
5
+ APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
6
+
7
+ Dir.chdir APP_ROOT do
8
+ # This script is a starting point to setup your application.
9
+ # Add necessary setup steps to this file:
10
+
11
+ puts "== Installing dependencies =="
12
+ system "gem install bundler --conservative"
13
+ system "bundle check || bundle install"
14
+
15
+ # puts "\n== Copying sample files =="
16
+ # unless File.exist?("config/database.yml")
17
+ # system "cp config/database.yml.sample config/database.yml"
18
+ # end
19
+
20
+ puts "\n== Preparing database =="
21
+ system "bin/rake db:setup"
22
+
23
+ puts "\n== Removing old logs and tempfiles =="
24
+ system "rm -f log/*"
25
+ system "rm -rf tmp/cache"
26
+
27
+ puts "\n== Restarting application server =="
28
+ system "touch tmp/restart.txt"
29
+ end
@@ -0,0 +1,26 @@
1
+ require File.expand_path('../boot', __FILE__)
2
+
3
+ require 'rails/all'
4
+
5
+ Bundler.require(*Rails.groups)
6
+ require "retention_magic"
7
+
8
+ module Dummy
9
+ class Application < Rails::Application
10
+ # Settings in config/environments/* take precedence over those specified here.
11
+ # Application configuration should go into files in config/initializers
12
+ # -- all .rb files in that directory are automatically loaded.
13
+
14
+ # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
15
+ # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
16
+ # config.time_zone = 'Central Time (US & Canada)'
17
+
18
+ # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
19
+ # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
20
+ # config.i18n.default_locale = :de
21
+
22
+ # Do not swallow errors in after_commit/after_rollback callbacks.
23
+ config.active_record.raise_in_transactional_callbacks = true
24
+ end
25
+ end
26
+
@@ -0,0 +1,5 @@
1
+ # Set up gems listed in the Gemfile.
2
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
3
+
4
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5
+ $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)