retention_magic 0.1beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +70 -0
- data/Rakefile +37 -0
- data/app/assets/javascripts/retention_magic/application.js +13 -0
- data/app/assets/javascripts/retention_magic/graphs.js +2 -0
- data/app/assets/stylesheets/retention_magic/application.css.scss +4 -0
- data/app/assets/stylesheets/retention_magic/graphs.css +4 -0
- data/app/controllers/retention_magic/application_controller.rb +4 -0
- data/app/controllers/retention_magic/graphs_controller.rb +66 -0
- data/app/helpers/retention_magic/application_helper.rb +4 -0
- data/app/helpers/retention_magic/graphs_helper.rb +4 -0
- data/app/views/layouts/retention_magic/application.html.erb +16 -0
- data/app/views/retention_magic/graphs/index.html.erb +89 -0
- data/config/routes.rb +3 -0
- data/lib/generators/retention_magic/USAGE +8 -0
- data/lib/generators/retention_magic/retention_magic_generator.rb +7 -0
- data/lib/generators/retention_magic/templates/initializer.rb +35 -0
- data/lib/retention_magic/engine.rb +12 -0
- data/lib/retention_magic/version.rb +3 -0
- data/lib/retention_magic.rb +12 -0
- data/lib/tasks/retention_magic_tasks.rake +4 -0
- data/test/controllers/retention_magic/graphs_controller_test.rb +23 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/user.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config/application.rb +26 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20151101172105_create_users.rb +9 -0
- data/test/dummy/db/schema.rb +23 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +26 -0
- data/test/dummy/log/test.log +351 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/test/fixtures/users.yml +4 -0
- data/test/dummy/test/models/user_test.rb +7 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/-EKyd_oC6THd4BAbS2D2_kyeDou-bW4JObOLLVZdOFk.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/0IXJ0VwHQ1myWjMoMI7sj6gyiBaic9dSuMA3qhCMyho.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/0KdY4zdTDqNuaIJrQ46aMabzHNOb19sHqHrL-T-9odo.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/0PUkfyQ2F9eMxvUV8pyj2kygYIV-ZWTH_kAfKlkGaE4.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/1SLJFn9dWUy2htivBqUV8ucgSlP7r0QZYNw6XQh54pY.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/1aaKiOcr5FbgDvjzrt8PyAtDIXL3Iw6MuktoXQHT-DI.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/1d0uHMVXfRc1ubXJOg4RNR-jFY7kbtcrrtcJyMarsrs.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/2jdPyIpUrJSIPDOKPkhPxNeg-j4qHvt1VHdFf_tsTDA.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/2pO6RFzcN1Y8PCTq3llcln7dDtLWIzkH9w-gMrmA7y8.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/2vyShy4Koxrr6CCOuHHgIPA8EnnBDHWoLnKrKffPGHM.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/46wIoc02CPB2GCNyyJXx9EkY0xDY3Gof-_7BDtyZDWg.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/48kpnqEQf9dHol_tLyx0ttDovvreVfaF8jApACJRaIY.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/4WCxJusnwndd61nvbz9hVTvOmvpASHHtDPppXFyIiB0.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/4xk-ivYrUYRYDj18blTMzPBfyCGkfqk52EvNDJdg8Gw.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/5-8uEo8hS619UqNHig2Sy6R_8DBHlRhx_JPRAgm633Y.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/5T97e3PPG1jPbak-xL1QALWbI788ykSahMBFsi8vwG8.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/5WQeJuCgZcGOO9OT532YBlD9ZmnyHiG53__RfG9uArA.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/6GxOkIes97PX5qrlf-PQxWpQodYBc2c6XthOoHLsfc0.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/7EbGNSBp5zAr296AGwwKjCoz7adk1BPYxpsoSJJDR6M.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/7X0L1kmfoaaWSV9v92CzU-VFFML7pwyxPQSv8zb8Euk.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/7wtcEbVdZtLO6mIle552GCSiudjk0gxju8nMFzuyz2U.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/8JFJ5ZRniT_qi9ZFTFRIcahIoL6_wWBN1-pMBlfQC6I.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/97ROeS4YmJH6SC9UrDeVamgzl13LnYF-m-KPtSX5X4o.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/9ha1JF0TIWGGGZbM5RneU6jTeifw9szeHQjR1BMXTJA.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/9k23WG9g9slSyMm-y3AzkUjImqkvFgwm2dCqkyFHEkM.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/AJeh7APM3yZ_RMKzfI3PejI4R39QYn21Fp39a_va72A.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Aoo3-y8-e2WidsFoszZoTy1kWVs0Sqfo7gQQs08Zpsc.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Azw3pKwmffO6DeR1gLBznj9QXVfkNYEljwr0oVfzUHM.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/B3oQ8oVtmuO6dHRqMYEVhXJIKUUAkvDdwjHsR3It-pY.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/B4bjb0h4g1XfVxaawDaUoArqTUERksbzw2v4_5xtL-M.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/BByX-5b5NhhAFKL9AFIiLcwjDpRSFGRfYeZBRRIbn4k.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/BMMc_DZkRTbZGMN0AKKS6c1GEZiv0eoo7SLegSW1YiE.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/BeDSqsni6kaxsFxWrKlJDFlZXfg_k4JQzl9H1FL3zMw.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/CG2RdeoqplTH74BR5aGSu_Sz1Pq4ayHk5g0yvaybTG0.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/CNzTeGX0-4KuQmrsIua6RNJACn9NHo-ntJho20bxkoE.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/D03tiXUEwshAmTAAiTbrw0xLZnhLyXu-5xdpGTbfrJ0.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Ds7fuV01MCUyi5syLmeAjrcxBCUQFF1iljMmyHSWXdU.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/E5uoYk_12nfa5QUZBBNWvNthUdhKxh6lfxD1byCmrgE.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/E7O3ZVvlIClzTE4qlgK552_QNrJlOut1QQY8Gwiexn0.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/F0lC3ybVOwcG5sWSIeV_d-pSEdTNCidiZmytdMN6eg8.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/F6f_HA-LQxV4A19DQ29EgarCISD7gs5YjDqqfwEszus.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/FsOBl7WIN6osDeZQjmppclnUHcrJsXo6rRboCotrlR4.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Gc6qjXGofmVaTOuiRcOst8jwX8MPAX2MED8-BJeQl0M.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Gdol55f3KGdSF4uvTV0C2nX3nrWSgo-g133KQrRorIk.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Gm9IQbSlfLJhpuIplwTTmyo5MmK-5-Iy3oeclZQadjE.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/H6xqgdhJmmqeriDQv9dkBi3WS0SmEosd8DZBWMl2KMQ.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/HLOzIn2VxQVdNIk_b2D5_9_x7fNky_fbmLsOZj92FzM.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/HPdAYtq1zyup9-UheS_JBk_TSRDW0gW1ZViIVjJJJAc.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/HbwGa3RgCWHIn430P1fhatvtVOhsPVZ85FTHU1W6k_I.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Hcl3KIwjCwfyCrNGw7CDKkg3dmwFwqt3gUk-DCvy_3Q.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/HliGHzlTBFZ9VrZVBDwSQuVR3y-QLReDRktd3pc1Ie4.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/HrDQmheAOkeYpJpoeazmpi-3ntUC0ekSgg2xeokHlhg.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/I03OktI9g5iAyp0Gkf56cWOFA-hwktqQaXGoKXTJs2c.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/I3pA2lvdTEV-UZI1eLyiPoQ5xp_TxcfHGlcM8HhjrUA.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/IIa1m3-koAyF7ousfrCjjXvh7EvXMFn5qiRnVdaJKOo.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/INm9W1Sg6a5miV559fyouUIgYnK7Npk6UBO6BW33hBc.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/JRQT9hJaSGDAR9S4tmweurzqG2BOXdy_BZ6KnHAZrag.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/K4Fn3ShoKuf1Q7IZV4A6YqUcdS6LbU1mWaISi24iNZQ.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/KAoCDny0VK_Wz7naD1kO6pxf6TXm_IFqidCAK6E1Kd0.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/KJOPG9V8VgEFmEQQ6MJn8qVI32fzGDrDkJ6ILCsyH1U.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Kc7bYAdTodpOkblJghsvVRY-3bfLrTReNdaDK-Ymri8.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Ks6_Jn6KD4ijdqpG9Ht9JMbSDYp-J6g42ClLSODG9IE.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/KvCV4Wjiqpl3vgQGyRopP4yaNgux1lzR9mycwPwioiw.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/L54qL0Fr1bZphva1U3QQyAxDsiAbWBn02lW_hWV8y0g.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/LGLT0wKtzQ5uBvOGeCkUzrrUAR-q21mL7u3LkyDgatI.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/LIUsE_pyu8gX78rXC9lk5oW2piuHW6-kMIOQfglx4fA.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/LLAPppHM6ppiQSHF-hDydoEIuUf1Dxieoz1t5xYRAP8.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/LtC4evqWVY3uCDJB316h9JsUU2periD3YqM0RsoBPKU.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/MWefbnf248C65h3kquViTc8719lfYZ4gWKsTNLP-WfY.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/MZIhxLeOUL8hep_dj7lG8RgLuFQkYErGynAhvnr9UjI.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/N5zJMoY9oYwvrmNKCqGQgOFN7pv2LFFTbYBhiIlqYLs.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/N8WOOX1_9iJ9WZK44CCW_lwAvJtcXMIBLgiEPrd89vc.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/NSNWigQmmN5-OouXizA3EcGHev5yYtBgWQnBxYEjzKo.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/O1mI7v-D0L5CBUODatg7wE_zhEyrClrCHdaqCF8bSPY.cache +3 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/P71FxTLHyPRgPID6QyqafCqUQOxZ84ZetezV25ZVpfE.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/PhaTrZUT9VTiI6H1r7GwyFLMHfxR-uhJOTGQmAQJmeo.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Plkl-T9w9SEqJb0yJCeRmCy3AHmmER29ux_VsT6L0vI.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Pqaxh3i1B1XY9-QwwatlN2JaJQRHTsdQYw34go35a1I.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/PuN9uwfQ3pF7bH5_Yu_Cmv-OvkSjfglTC5uktgCZHH4.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/QJJxx57fvCElwjGPgh5_u_d1QEPvmijPGOjEbSEc2-M.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/QM1wS11IzZu3nP2jnh_cerz_CHOgj4vWQeVHjleMOac.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/QaDwLv3GTns1gLXUVeL7Iq-smjTU83xncOxvy6Qua-I.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Qb4zSr4wAGR-pBB5y-frIa-DczVEmTEVKSnDr6pjiok.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/QoZ0dgQgLjisiKyOdyzbO9i-meAS1_zIUYEiDpZnsJ8.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/QyKzcMq479m5BEBS8DRpSj0rXSIHJ0h8E7_Lgomnk_0.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/RP1L5wMZC8y60-e-vUs1uk29O0QQXVSqwfiRZDV4ExY.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/RPp1_DK3ZnQmIap9UwlPbZExlW9jGa7pxUBDjfLfMog.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Rf8f5x1LTUk6Pw0UmmoP0IWIYXw1duoxu4P5oEfmJ1M.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Rhd6hnFqWNCNvb6opnuFEgc0-qhqY24zfw0M8zUgXro.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/T3qq89UZq_AApGEhQc5ocZUI6K0lWQraH_KEZfzCzOI.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/T8Gfg7Ei7Wu5vOngrFKdDrPwjbCID7bdYO3iKfEPAtw.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/TKNYFXbdXmxy25OzSRy3azMyGjIEfwvpCpGgLMvUGDM.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Tgp5r1BHz15ac6Kc5XNVHTSYgnFX-FzGGOq_J7kSJek.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/UMHrIsutdIGDrWZnC-WT_LlebvXYLe9Q-kBwsGjUYDk.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/UjKNoV10XsZsza-Y_IDpQ-T15ZbjDYX_ArYgaKaioJw.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Uq_MH1E2yYlQizQ0b9lws-iQIbAzOag2Z7t8WdRpoRw.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/UuNRtuRFLhpzApXAN86VXFNEVeowlOJmTZb_scjcTos.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/VHhvIp0_BrEMbC3ikJ1CaO56Z2kURWBEmLhoYLLwwbc.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/VOR4wLdJwpQWV0536YrOZ-swnKpifVnZbeqWDJ-7zX0.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/VXBor9dwTUP10zaznHwJF_Lz2rfrIDSOD5gZQDebx50.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Vz2PZ-uVHlp1Oh_jvW6YWZn9nsjZSX2AuC0LjmyjW8c.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/WTaoAjPu9uN8yuhj-OMyOYtgvuWBpyXMv4UOnPuJXdk.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/X6i9SJn0xUJ79TIu86mjf4yed0VvoMg9zK46SAZjqyU.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/XIPuM90puf2NC0mCb1ohCwvCq-_crN8GTAgnC3H-5Q8.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/Y2wpnHO7rXxkiVYDKjKBHl_uuQBbiNFtpkEdBkmZSFY.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/YP9xV25kSnMAzZtQCGDKbMa5rnWJoz0HjPtwMgo_xPU.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/YeEFcUmV3ejuoluv6njOF3lM2wZstXlWql2HtJGyRmc.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/YhssBxTBZZ0VN1uZitFeSz7__TsAS0i6i1EppMAHSjE.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/_H6Ve9WSmlWh_hFbod2dF6BzbhZVoQgsTxK4ii4b6UM.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/_ZL02pb6iMwsP2OfoXDbeAdjfTboJaDjEw1MrzLQZBw.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/aMk5X7CaiVsWDtcbcvGNzTE4NQFxiOio3NPFrRWk-aY.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/aiWrIgIqKFjh94HgI2FFduAtjHjx5nUrbpjPWvsNnBQ.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/b2B7EHgldqGlfHzXVvibMrrw4LNBbunZq4w6gaDVWx4.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/b4ruyRBNV-oqDqlmIy5_CyVppjSIuK26MHuENLGmfjI.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/c-N46x-NrMFRW8S_810IyJiHYhL_jiv2F7ZfJXlMcVE.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/cJ3j-2V8Ux5ICPLbh-IB1tlbZH50axMUMsnppzerQTw.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/cS6hnEsSxznsSwkbZ-lP4BmJBLBjTwRZXtIGkelZ3no.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/dmiOzg8MvuzpBYCtf9V5ZAQ5gBG-l943hKo7wlylvgU.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/e--k3SqXrQ-xk_n0MhVpIb-nwgsLje8cfB0kNJkShdg.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/e3ohEoJjQIlR9i6WiywBRlRqkvMCrAICU9C0kh3j8TQ.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ee9Azbf8pzNyeZIpa5H4pincDB9FJG9j8zmeEWlHbYk.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/efhaSkZCpODzDmSSYjXgUHjVSih51fl1r-oZsqSAXlw.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/exNnl3s_DehZw67_Jc0DpyfJ-2tJA6NGh-4_mIYFknM.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/fTx4MdEv6r_k4VWYNgG0wcW5hD6iymeoCE-xCt8IlHc.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/fVv5x3R_qH8TfabaN2RrNsDis0tvONKaroxnBQ4NhC0.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/fgvjqHQBcZafnbxw24c2krRS1eQyVWyji9soIydxQpM.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/fkeLw2-ZA-k4vQ7-t6fxz-bTFiXiQdalmSIg_Ku7YbE.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/fnjqObfqhUe-NMN4ssK-qG07__lW6mc2NdHZZLkM104.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ft0XA4vE0DbCjJqIVVv9pIzcc7yOy5pJme5_OcLtRgs.cache +3 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/gXfIMjV9DutecKWRfAKn_pkXuIbAgpJuDNfr6lEd8cU.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/gcZXXv113or0WrMEtv0ZgNO8GNMDKVlyNPeszuuGGFY.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/h7qa0K2-ItM4KdMMVybYeFcvMaCaP8mDsqjbiANbQ1I.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/hIbpUjZKtxj1f7ha3uBd4sfVGrG_mSlAeLvHOpVKiTc.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/hPTVTLRn5esx7FcjCYkGT49exawTe0kFYSZuuQsnpW0.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/huuOa_ZYJ6H2lVwNlZM5aLaEghkmBR1nXB18w7Wr1vk.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/i-IkmambRaQoPG7Uy_AqvTtjdJBpwLAer-enykzM8Go.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/iaDLUe0Qh-UyAp6UAEwtebxpd6Kizza16SzGxXeEaTo.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ikhuyZtsbCFrWYHI4Wd5gDIs9qFJt0-ldB5XLn_ZnnQ.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/j03eD60i0Z9OBiFBFuJI79ZLVOANKBYcf60_WBYVB_s.cache +3 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/jcFoU3Hn00ZaTV_W6PDDo1pxhsDJtZjfeVN3eMWEpy8.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/jpADL_4RCzMnO_aSGmDcgBLniID7FsBl6rXUgQzMgXY.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/jwi50-NjNb6-JUbjpmXXg7GHkKhPKBEgYTv4zAH09HE.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/khT6fQ0szWvnfYIw0sJwt51Y9cfa48JxWbTpxmHanY0.cache +3 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/l3XYoUMMINtweMsF6k3sar_dIRFbWKhUFpwKvoAJ2E0.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/l6wMdkcs_r1UM6OU_SkKId-3fyP1zjNwiVo3cjpEa4Q.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ljhtUl9VWqUCWCs6x2hwFc-TzbGvFSj47RVAQrr66to.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/lvVXDxtxrKNXrEQF_4wKjF86DasK57HgPC7Zc13_E1s.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/m0F3RxYCdIy6Yw6_kNzi0U4NLV5l-eP9oz2czcdOKEk.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/mA9L9Wxvf1vOBaTTzZgijBD0uQsXffX3H2J2mc29quA.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/mUbjAVHaaKujwp09t8pMkPsNn9eJxUHOz9oIMf9DrEA.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/mVjsA2NqkynEWhz6MmtXo_-QW0RjVRzaszGl6-RPfJc.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/mt8Lt_jAlLZ4U-1zbCN5mGG0amfxS0hBkbKGD_gtlws.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/naXoSDtfOxk3NXO18x0Q6LY-BcQCH-NtHgPOiQww8yg.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/o1Z0uv2WT2ccxCCkASmBB4msZNreyGx6lN1wqBrj6CI.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/or70b6whbsuqQA5EHtqWYVRgD2H79KBvoguOoe8z1Ao.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/pGa0ZX7gIbDjBf207EhUUk2CqlzjoVTXKv412vHjmE4.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/pHkS-yERUmBWL117Z9Qo2jlmvztGkOjgtk9ztQbkJzE.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/pKgCH-5O50hIDG4VwyXAyoK51_qP1C4p4W8PAXn19JQ.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/pOZ2fwSZWtmW5khq-b49H9fyEUMH3VBJ-N83dHvMAwI.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/pVHxPRPevuSeRHS3HbHCHB5Vc0ASCOpMLe-2Sj1dcb4.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/pYE29BrK_w79ww7TYHd3S4LxdhTIvhTq_Wetnw2z3M8.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/qYKZL8-s66wvUJhzzIZod4WjW6wDk_yeFKkR6Zl3XBo.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/q_fqn08IcQkT28olIwaaRDUUYQ1SQEii5WWrclckyl8.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/rJANshMQoojwXLVKughpVE7BOqzP7Bcmo_kZBt2pkGU.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/rPsIbIVGHbdh46Y080NkUVUj_97v2gEiZIWXGt6Cfeo.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/rt59MaJHnqS58TNd10uIuar6UKj3sbEyWDYMCuI7zZk.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ruMxNQHvuLsXZHZ2tDEx4yt97-fDQwEtLojFEhsus5Y.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/t-q6C2Daeh64PWWMnwuzNDOK6yrt1etjkF9BIhpJ9HY.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/tK-1NOEZed_qRbueyxbPw-NMOutZw5bdI1eFsku57C0.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/tavug0h1LdqZzksd99OpyhMSewn2b27dg9_LNrTRtec.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/tgU4lSUXxSVZskPkAhhVkYWyVltIicmlEW5jy28bbv4.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/tyXAPHB9HRUCMajT1hhEu_RXxJQWVmg5poJx_yjabkY.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/u10gUBcaxCuyfXyqfdhqRz1-hkXbdNiTwhYHBsnCWlo.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/uhLckzCtpe1MhodZ9Eha9L5_cAHVnnAjpssEGgK0gJE.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/uvH6dyEoLVE7wLKdp5Uw5oXsSlcVfajHDJuA1ACITuY.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/vKQPBwSZr3pjWm6WP9gbpyBUvnO1hko-bd7V5Rkc7zk.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/vQmahYg2BSlOHoOBc98t4M3mpRWO23GY213nygOLUWs.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/vcb0UMCAV3BZuyISepHgEt30xYcf2QqRUBbe1yiDPTk.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/vr2Ky26kBfoj1Lzdgcfeda5c_U_6k3NQ-b9Bqc3vy8s.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/vz3IHo7GXPR4vHQMnNjAVdGv_yYRAjn17iYUqt_MBwg.cache +2 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/wMd3bN8GIHJ1GyviGomDxVL_RtfQERcsj6KPRmgF3QA.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/xF2X7Her13dCj5pm2QdP_W74A2SHCOF19zTC3OPN4fA.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/xiw2N0hcvLMQgaG1U0IV1tMut4PC1SPN2g1FlfqgOLQ.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/xnjydYZBm9KXbjh9DylByrHTn7NxJNHIIGgiltYbDtA.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/yMl_Z-8144OMa18Tx43HXEOcxNsN77AOOzBeL69y_V8.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/yfLOXzBPETp_ubxEzuXpiAr-lcNGdkSKg3PcQbIMfhE.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/yida6X11pHMGq-7wTwl2E3wxEqbbTb0HoSOyarEcO54.cache +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/ylZ4k6cqpUGn1n_r7uOXYSDs18qyGM03ikeWWK3ebXk.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/z3PYleH-yQuUROj3MWExEdDbritBOUSKmAyBElXh5EY.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/zRxSnjNpkoxlOFcoVVJ0JvwmY0oLaW4sa25eEFoblc0.cache +1 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/z_5KfyOVpIF1xrjaFJn3pll3SvoKIFLKzMAtbEqo_cM.cache +3 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/v3.0/zhFnH12w2VXfUa648KwVjTztyUv6GJQoLj2DOtjzHmo.cache +0 -0
- data/test/dummy/tmp/generators/config/initializers/retention_magic.rb +35 -0
- data/test/integration/navigation_test.rb +8 -0
- data/test/lib/generators/retention_magic/retenion_magic_generator_test.rb +16 -0
- data/test/retention_magic_test.rb +7 -0
- data/test/test_helper.rb +21 -0
- 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,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,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,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,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>.
|
data/test/dummy/Rakefile
ADDED
@@ -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,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>
|
data/test/dummy/bin/rake
ADDED
@@ -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
|
+
|