quby 4.0.4 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.markdown +0 -1
- data/lib/quby.rb +2 -10
- data/lib/quby/answers/entities/answer.rb +4 -2
- data/lib/quby/answers/services/score_calculator.rb +1 -3
- data/lib/quby/engine.rb +0 -1
- data/lib/quby/questionnaires.rb +1 -0
- data/lib/quby/questionnaires/api.rb +5 -1
- data/lib/quby/questionnaires/deserializer.rb +441 -0
- data/lib/quby/questionnaires/dsl.rb +12 -15
- data/lib/quby/questionnaires/entities.rb +1 -0
- data/lib/quby/questionnaires/entities/charting/line_chart.rb +23 -0
- data/lib/quby/questionnaires/entities/charting/overview_chart.rb +3 -1
- data/lib/quby/questionnaires/entities/definition.rb +3 -5
- data/lib/quby/questionnaires/entities/fields.rb +0 -15
- data/lib/quby/questionnaires/entities/question.rb +9 -32
- data/lib/quby/questionnaires/entities/questionnaire.rb +4 -15
- data/lib/quby/questionnaires/entities/questions/checkbox_question.rb +0 -24
- data/lib/quby/questionnaires/entities/questions/date_question.rb +0 -8
- data/lib/quby/questionnaires/entities/score_calculation.rb +40 -3
- data/lib/quby/questionnaires/repos.rb +1 -0
- data/lib/quby/questionnaires/repos/bundle_disk_repo.rb +51 -0
- data/lib/quby/table_backend/range_tree.rb +0 -51
- data/lib/quby/version.rb +1 -1
- data/spec/features/tables_spec.rb +40 -0
- data/spec/fixtures/score_test.rb +4 -0
- data/spec/internal/log/test-events.log +183 -0
- data/spec/internal/log/test.log +5522 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/00/00nglkSepN01iGiDa7URmJtWQP-xSWffZb9wJgBqUr4.cache +2 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/1V/1VQnRlqKBL0MybpMmC3EVtA2s6-ZX-GSGs2Cza3g3kI.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/1_/1_J_3havMjJDCz3iAQXAXXBh6tBQRJ3OpdWm3W46ss8.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/4G/4gcYvPHmPX3fZw9xr6plMl5Hfbo2xTWwcD7T7lIlD4Y.cache +2 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/4_/4_FK6PMcF1eyIQx7RtVQ5t8c6X7smPQmJWNN5YTImVc.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/4d/4Dd15Upcg8_kiEsx_5wpQNrjM1sCk0tGTtWGhtmCKpg.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/4h/4hd8RzwlWb2IEeLLZN0s-3_sdJXtw6nu2k5baLb9vNs.cache +0 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/5X/5xFJleOz2sGyE9gbs8KPkToDiv3s9bwFzroBRcjPELY.cache +0 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/6Y/6y1tV_fKJP9YIQn-dF847aZ9kza1O7iyTEUht42D7nc.cache +0 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/6d/6dfYZY_DkQe892FZVDUbBbrINslzVUkLZePdnVxO3Ps.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/6w/6WcYsWQCgw0z_URAWGhOsbiKXcqVxZ--ImazY5S-2Gk.cache +2 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/77/77EJjFGVCRzLbhJy6KZZUYe5w0LxsqZQcmFcHAbxKeQ.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/7f/7fvhJnfiJknq6sA-MPtumXlL5qB-rfH__Heye13NyHc.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/8W/8W6AwDwFqo6egmWyt6Cs0vf_XJbT2YxPs2sqbo0Q9kk.cache +2 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/8c/8cQ8uBhUhrouKwor0Z87dDCxyPbqbLvK8KEFEgjHxqM.cache +0 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/9L/9LJo1U9wQdfWrrn3HkNZTgIZc6jeHvWbGk8tJ4m_Qec.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/9o/9oXJXZnA6F49i4EflydD0Ivx6dhSxGGDD69G-N5NSCg.cache +0 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/A1/a1jgtYtDHIb04Og07H6_XNmhXppaAnFiO88kgq80edQ.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/AC/ACV6t4unw39Kpn2DnbBtHeJYLoAHyyBN1DTRXs6a2ik.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/BO/BoVO8e1GTTGHfnJTOByDxMlvVi9fNGyOdSubqCbBITI.cache +2 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/Ba/babjk3aW-jBoEw_ERhmT5ZQprEqilJCWmImrvVskWk8.cache +0 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/Cg/cgb1vvOogMD0V1lqQ5k_mny7Z38rbqBdIumlGh5sZ_E.cache +0 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/Cw/CwjNk_RYiC93RW8vRs7fWsHcwKTg7uE9OLifRm3Y6WA.cache +2 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/DY/Dy1qsY0W-eyFR6RVKSCCli-XsitpaXD4DwTjXL86t2M.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/Dk/DkGOwkJNeDdljv4b8QbwtPVrsghwYuA6EOxx1goEQg0.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/FG/fGmVSU-v7aZV9-CLG5U2OmteGgWTuAotlFcwFyx4Eqs.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/Fd/fDidWZjSZsPN4uAEyVYABV2WFCSR7AZE0l8U-9XOw7U.cache +0 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/G1/G1RRwpldS5MGQ5x-WHyPWzXJWDOd2qyWMMFumuU4-Ms.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/GG/ggGfy_gZryUPmYwgenN3A4jv0q-buxyjCGdLB6wfHxQ.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/GY/gYwYoJrifknCG-a0FXlM1NU6tUj1JXxm27s-a0uP_IE.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/I6/i64Ysik0cyoTrYF0-O63B7sN3AdIgeoJ7zLh9pMC2u4.cache +0 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/Ic/ICKeOd4yOff3JGsfU1XliLgXfJtTPKSbXsqNVZAb1-Y.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/J7/J75M1l--IMcCn-Wy7uWv17SWaj0DFaGiiwac63pENPQ.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/Jh/JHPqsKZsrkvQg23ukphinYoViiIw3askwCMP8VrHTMk.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/K9/k9tOCRdX5tsxa5LImq7MZk0WzC692t8tx5LzLln0l4Q.cache +0 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/LY/ly4TNAIbW9ghgXz8mxfmskR_6AkuiMiG-RIFGhewgQ0.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/Lq/LQ9fP0wIqVc5s-AtP3ESWJr0qpkDe-VpTxpgYl-9FfU.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/MO/MOmnpcaRW98Ke-zTOOCSZ0ODnnQntKhQr0vFc_un1_A.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/OX/OxOBsUA5EpScoZgEt_UhsHzhu-GGmxKnHpCwnhbTwiM.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/Ot/oTVAc3-iuSlg7XAM-YIAhw3cdc5yhgL2-tK3N7sfOfU.cache +0 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/PK/pKNcBOgAbCyIwsWIvnlmiPiFxrw6nUo_nTz7wWFDr80.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/QB/QBMvSW7SYbYcm5lSjybgO7fhHDFIQjJWOvefH0MQC-A.cache +0 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/Qs/QSbtm1y8JKPV0MQkpiC0hEisaSjKZ3tp2AWHSrhO30Y.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/Sp/SpyGDguFy3tp0sim1miZOehEDpE97oueO7wl3oUFYcE.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/TW/TwtJPRSE9lmwTuSP0lezWSRSBp2u43zuF196FQcHY-c.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/VX/Vxn9zv60MCKUBfRhrjefo-MEzFej81PPEutxTPQ4VLQ.cache +0 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/Vr/vrqPEzlsuORocHY0EbtGdFomRmrcoAa6wWSDMx642-Q.cache +2 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/WH/WHVQ0GBe51hbYqv2g7YYo7EIw9PSzt9-RqU7hKP2dc4.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/_B/_B796ezRHfk7H8YKj7zr3-gRy6Mw2IVn2NbHu-k20ug.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/_W/_Wh-7b1t-Xm19wg3KPtkXq7DOpohaL5OhnLggzJLpj4.cache +0 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/b2/B2y-2qTbQYKRm6_sCQ6qfUeVfl9rKXUvotTDm56w4bs.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/bw/bwFR2MLpvJvPSAPJzSLWk6TUDCw5TlBFUUuq7z_Y9vg.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/c7/c7ubvrHhbhAYh-K4srvM9EqwWdbWTLrsLMgjG5XQDbY.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/cX/CXpMzZYfJy6HIOVXN0IyYilvy6J4CDgFZIwqKm8OQEU.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/eN/EN0enu5dkKEnIz-DVCpbhkfeph7wImeXnlqb7SXMrjE.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/fu/fuP9zP6C6rj650HLkypoTfYN2KD1ecB9HdtlbhbA2cg.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/gr/gRPXI3EsVPwysy9YKW_6yDxaqRRr4Idxtexf7zCHECw.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/h0/h0P63ZZdlSbtztDOe0V9r7jtCoy0L2bAf_iDNKLJ0nk.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/i-/i-Or0Xuxbbm3-HdE_xGIf6sAx2vhUa3eVMpbT37lyEo.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/iF/iFP67If98izMEAAMKnAFi2dWAb8TNlHNayZKNjXdAMs.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/iH/Ih2svq5ul-xibfRUfd1fxigouli6U19Rf80FrTSoMak.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/ka/Ka_YEbZNQxpS8XAA7xZturgPr2vLYQq60KK1uwou4Lo.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/kq/KqkIGfAdJjTcr53lFl1aDAMUeqhhKdXGyTlHVlCz0R4.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/mR/mRDPkwomGSfjpIWEKtPPBSx5cBHssvH8v0gCSI33P3Y.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/n4/n4qaNjjNvKB0VAbVJlP_BjFlcLf70TsBzcIMc7VO9dw.cache +2 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/nY/nykt5oy2ExUYa8g1phLCDRqwb55BuUot5ZBbRdNuCCw.cache +2 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/nv/nvmgm4bOtxCbD6EA14ZIwDcYO8fxXOoEk_s7V-uRMMM.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/oG/og5ypFjbFAX_nH7oxK6Bn5Ejh81BMDBSMxbGcL5ZbQs.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/oO/oO4iBwOm5E7uLH39zeR8zun4eBM-WxZKvEMpIYKx6SU.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/pN/PnQ-dEclV6jTDE4kkqw4G9dBpHArAgUnATOpRrQAsGc.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/pe/pet4fFbc2Cm2SD_ZBO_s83Gey29EXE26u-7lwn2O8gM.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/qo/Qoqb-JjTe1BiY4rICKHm5e6bsPt-DHXZc4ADXESjw2I.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/qx/QXICLj9xx1EI9rBeXLXpKOeHGll_LBWHRWlpb1DK424.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/rM/rMF4Y2UGkmBABLlC1eSSqb6y6g_Z3uUCLBtFvz_LoyI.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/ty/ty1qAnpL07anYdhIJoiPYLcsWKejuzy6JaxU9mI7egw.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/uH/UHs9nE45XS7v4QlMjSjhwHbqYIKC06FsEjMSMIfKanU.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/v8/v8VXJ3AQom-JqxBYAB7tOjV-tt4IdDb6YyFEzlsWV8c.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/vD/VDI2CxkTg7-DuMcLmofLvch0yukSl88oI_AjGgN-hQ8.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/wq/wqhk46aZc1Bbb8gTCOZKxTvwTV0ANLSz8VdQYACo03E.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/xy/Xy8Yk--iYZNupHMjUtYX1AQ0BppsvThCh_ZAizblCb0.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/zu/zUCfHRTHprn06F5WxH6wp_BLs9-yhs-foc0j0Y7BYbg.cache +1 -0
- data/spec/internal/tmp/cache/assets/sprockets/v3.0/zx/ZX2IY3eKQjBy93tlH7_Xg7zGZKYuaQ-E8YPvtPT_4vM.cache +1 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-35.705.html +1 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-35.705.png +0 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-36.005.html +1 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-36.005.png +0 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-36.276.html +1 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-36.276.png +0 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-36.556.html +1 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-36.556.png +0 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-36.818.html +1 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-36.818.png +0 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-37.083.html +1 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-37.083.png +0 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-37.350.html +1 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-37.350.png +0 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-37.620.html +1 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-37.620.png +0 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-37.885.html +1 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-37.885.png +0 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-38.152.html +1 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-27-38.152.png +0 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-28-14.063.html +207 -0
- data/spec/internal/tmp/capybara/screenshot_2020-11-17-14-28-14.063.png +0 -0
- data/spec/quby/answers/entities/score_spec.rb +4 -0
- data/spec/quby/answers/services/answer_validations_spec.rb +8 -8
- data/spec/quby/answers/services/score_calculator_spec.rb +4 -14
- data/spec/quby/questionnaires/deserializer/questionnaire_spec.rb +237 -0
- data/spec/quby/questionnaires/dsl_spec.rb +0 -9
- data/spec/quby/questionnaires/entities/fields_spec.rb +3 -3
- data/spec/quby/questionnaires/entities/question_spec.rb +0 -8
- data/spec/quby/questionnaires/entities/questionnaire_spec.rb +2 -26
- data/spec/quby/table_backend/range_tree_spec.rb +46 -13
- data/spec/spec_helper.rb +1 -1
- metadata +230 -53
- data/lib/quby/lookup_table.rb +0 -29
- data/lib/quby/lookup_table_repo.rb +0 -24
- data/lib/quby/questionnaires/dsl/base.rb +0 -20
- data/lib/quby/questionnaires/dsl/calls_custom_methods.rb +0 -29
- data/lib/quby/questionnaires/dsl/charting/bar_chart_builder.rb +0 -18
- data/lib/quby/questionnaires/dsl/charting/chart_builder.rb +0 -91
- data/lib/quby/questionnaires/dsl/charting/line_chart_builder.rb +0 -57
- data/lib/quby/questionnaires/dsl/charting/overview_chart_builder.rb +0 -31
- data/lib/quby/questionnaires/dsl/charting/radar_chart_builder.rb +0 -18
- data/lib/quby/questionnaires/dsl/helpers.rb +0 -51
- data/lib/quby/questionnaires/dsl/panel_builder.rb +0 -80
- data/lib/quby/questionnaires/dsl/question_builder.rb +0 -40
- data/lib/quby/questionnaires/dsl/questionnaire_builder.rb +0 -260
- data/lib/quby/questionnaires/dsl/questions/base.rb +0 -179
- data/lib/quby/questionnaires/dsl/questions/checkbox_question_builder.rb +0 -20
- data/lib/quby/questionnaires/dsl/questions/date_question_builder.rb +0 -18
- data/lib/quby/questionnaires/dsl/questions/deprecated_question_builder.rb +0 -18
- data/lib/quby/questionnaires/dsl/questions/float_question_builder.rb +0 -21
- data/lib/quby/questionnaires/dsl/questions/integer_question_builder.rb +0 -21
- data/lib/quby/questionnaires/dsl/questions/radio_question_builder.rb +0 -20
- data/lib/quby/questionnaires/dsl/questions/select_question_builder.rb +0 -18
- data/lib/quby/questionnaires/dsl/questions/string_question_builder.rb +0 -20
- data/lib/quby/questionnaires/dsl/questions/text_question_builder.rb +0 -22
- data/lib/quby/questionnaires/dsl/score_builder.rb +0 -22
- data/lib/quby/questionnaires/dsl/standardized_panel_generators.rb +0 -33
- data/lib/quby/questionnaires/dsl/table_builder.rb +0 -48
- data/lib/quby/questionnaires/services/definition_validator.rb +0 -298
- data/spec/benchmarks/load_normscore_csv.rb +0 -18
- data/spec/quby/lookup_table_repo_spec.rb +0 -20
- data/spec/quby/lookup_table_spec.rb +0 -38
- data/spec/quby/questionnaires/dsl/calls_custom_methods_spec.rb +0 -38
- data/spec/quby/questionnaires/dsl/charting/bar_chart_builder_spec.rb +0 -41
- data/spec/quby/questionnaires/dsl/charting/chart_builder_spec.rb +0 -127
- data/spec/quby/questionnaires/dsl/charting/line_chart_builder_spec.rb +0 -66
- data/spec/quby/questionnaires/dsl/charting/radar_chart_builder_spec.rb +0 -41
- data/spec/quby/questionnaires/dsl/helpers_spec.rb +0 -80
- data/spec/quby/questionnaires/dsl/questionnaire_builder_spec.rb +0 -480
- data/spec/quby/questionnaires/services/definition_validator_spec.rb +0 -793
- data/spec/support/examples_for_chart_builders.rb +0 -59
@@ -1,27 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'quby/questionnaires/dsl/base'
|
4
|
-
require 'quby/questionnaires/dsl/helpers'
|
5
|
-
require 'quby/questionnaires/dsl/questionnaire_builder'
|
6
|
-
|
7
3
|
module Quby
|
8
4
|
module Questionnaires
|
9
5
|
module DSL
|
6
|
+
# Deprecated, precompile elsewhere and use from_json
|
10
7
|
def self.build_from_definition(definition)
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
questionnaire.callback_after_dsl_enhance_on_questions
|
15
|
-
end
|
8
|
+
compiled = Quby::Compiler.compile(definition.key, definition.sourcecode, seeds: [], lookup_tables: {}, path: definition.path, last_update: definition.timestamp)
|
9
|
+
data = JSON.parse(compiled[:outputs][:quby_frontend_v1].content)
|
10
|
+
Deserializer.from_json(data)
|
16
11
|
end
|
17
12
|
|
13
|
+
# Deprecated, precompile elsewhere and use from_json
|
18
14
|
def self.build(key, sourcecode = nil, timestamp: nil, &block)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
15
|
+
compiled = Quby::Compiler.compile(key, sourcecode, seeds: [], lookup_tables: {}, last_update: timestamp, &block)
|
16
|
+
data = JSON.parse(compiled[:outputs][:quby_frontend_v1].content)
|
17
|
+
Deserializer.from_json(data)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.from_json(hash)
|
21
|
+
Deserializer.from_json(hash)
|
25
22
|
end
|
26
23
|
end
|
27
24
|
end
|
@@ -13,6 +13,7 @@ require 'quby/questionnaires/entities/fields'
|
|
13
13
|
|
14
14
|
require 'quby/questionnaires/entities/charting/charts'
|
15
15
|
require 'quby/questionnaires/entities/charting/chart'
|
16
|
+
require 'quby/questionnaires/entities/charting/overview_chart'
|
16
17
|
require 'quby/questionnaires/entities/charting/line_chart'
|
17
18
|
require 'quby/questionnaires/entities/charting/bar_chart'
|
18
19
|
require 'quby/questionnaires/entities/charting/radar_chart'
|
@@ -27,10 +27,33 @@ module Quby
|
|
27
27
|
self.clinically_relevant_change = clinically_relevant_change
|
28
28
|
end
|
29
29
|
|
30
|
+
def baseline
|
31
|
+
@baseline_proc ||= make_baseline_proc
|
32
|
+
end
|
33
|
+
|
30
34
|
def tonality=(value)
|
31
35
|
fail "Invalid tonality: #{value}" unless [:higher_is_better, :lower_is_better].include?(value)
|
32
36
|
@tonality = value
|
33
37
|
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def make_baseline_proc
|
42
|
+
return unless @baseline
|
43
|
+
|
44
|
+
case @baseline
|
45
|
+
when Hash
|
46
|
+
->(age, gender) {
|
47
|
+
age_match = @baseline.find { |age_range, _v| age && age_range === age }
|
48
|
+
hash_by_gender = (age_match&.last || @baseline.stringify_keys["default"])
|
49
|
+
|
50
|
+
gender_match = hash_by_gender.find {|gender_key, _v| gender && gender_key.to_s == gender.to_s }
|
51
|
+
gender_match&.last || hash_by_gender.stringify_keys['default']
|
52
|
+
}
|
53
|
+
else
|
54
|
+
->(age, gender) { @baseline }
|
55
|
+
end
|
56
|
+
end
|
34
57
|
end
|
35
58
|
end
|
36
59
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'active_model'
|
4
|
-
require 'quby/questionnaires/services/definition_validator'
|
5
4
|
|
6
5
|
module Quby
|
7
6
|
module Questionnaires
|
@@ -10,16 +9,15 @@ module Quby
|
|
10
9
|
extend ActiveModel::Naming
|
11
10
|
include ActiveModel::Validations
|
12
11
|
|
13
|
-
attr_accessor :key, :sourcecode, :timestamp, :path
|
12
|
+
attr_accessor :key, :sourcecode, :json, :timestamp, :path
|
14
13
|
|
15
|
-
def initialize(key:, path:, sourcecode: "", timestamp: nil)
|
14
|
+
def initialize(key:, path:, sourcecode: "", json: nil, timestamp: nil)
|
16
15
|
@path = path
|
17
16
|
@key = key
|
18
17
|
@sourcecode = sourcecode
|
18
|
+
@json = json
|
19
19
|
@timestamp = timestamp
|
20
20
|
end
|
21
|
-
|
22
|
-
validates_with Services::DefinitionValidator
|
23
21
|
end
|
24
22
|
end
|
25
23
|
end
|
@@ -35,11 +35,6 @@ module Quby
|
|
35
35
|
new_answer_keys = Set.new(question.answer_keys)
|
36
36
|
new_input_keys = Set.new(question.input_keys)
|
37
37
|
|
38
|
-
# This is probably the best place to ensure that keys don't collide. However,our current set of questionnaires
|
39
|
-
# does have a few collisions between +v_1+ option +a9+ and its subquestion +v_1_a9+, so we have excluded
|
40
|
-
# those questionnaires from this check through @questionnaire.check_key_clashes.
|
41
|
-
check_key_clashes(new_answer_keys, new_input_keys) if @questionnaire.check_key_clashes
|
42
|
-
|
43
38
|
@question_hash[question.key] = question
|
44
39
|
@input_keys.merge(new_input_keys)
|
45
40
|
@answer_keys.merge(new_answer_keys)
|
@@ -48,16 +43,6 @@ module Quby
|
|
48
43
|
end
|
49
44
|
end
|
50
45
|
|
51
|
-
def check_key_clashes(new_answer_keys, new_input_keys)
|
52
|
-
if @answer_keys.intersect?(new_answer_keys)
|
53
|
-
fail "Duplicate answer keys: #{@answer_keys.intersection(new_answer_keys).inspect}"
|
54
|
-
end
|
55
|
-
|
56
|
-
if @input_keys.intersect?(new_input_keys)
|
57
|
-
fail "Duplicate input keys: #{@input_keys.intersection(new_input_keys).inspect}"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
46
|
def key_in_use?(key)
|
62
47
|
@question_hash.key?(key) || input_keys.include?(key.to_sym)
|
63
48
|
end
|
@@ -8,8 +8,6 @@ module Quby
|
|
8
8
|
class Question < Item
|
9
9
|
MARKDOWN_ATTRIBUTES = %w(description title).freeze
|
10
10
|
|
11
|
-
set_callback :after_dsl_enhance, :expand_depends_on_input_keys
|
12
|
-
|
13
11
|
# Standard attributes
|
14
12
|
attr_accessor :key
|
15
13
|
validates :key, presence: true, 'quby/type': {is_a: Symbol}
|
@@ -140,7 +138,7 @@ module Quby
|
|
140
138
|
@description = options[:description]
|
141
139
|
@display_modes = options[:display_modes]
|
142
140
|
@presentation = options[:presentation]
|
143
|
-
@validations = []
|
141
|
+
@validations = options[:validations] || []
|
144
142
|
@parent = options[:parent]
|
145
143
|
@hidden = options[:hidden]
|
146
144
|
@table = options[:table]
|
@@ -150,12 +148,13 @@ module Quby
|
|
150
148
|
@deselectable = (options[:deselectable].nil? || options[:deselectable])
|
151
149
|
@disallow_bulk = options[:disallow_bulk]
|
152
150
|
@score_header = options[:score_header] || :none
|
153
|
-
@sets_textvar =
|
151
|
+
@sets_textvar = options[:sets_textvar]
|
154
152
|
@unit = options[:unit]
|
155
153
|
@lines = options[:lines] || 6
|
156
154
|
@cols = options[:cols] || 40
|
157
155
|
@default_invisible = options[:default_invisible] || false
|
158
|
-
@labels
|
156
|
+
@labels = options[:labels] || []
|
157
|
+
@size = options[:size]
|
159
158
|
|
160
159
|
@col_span = options[:col_span] || 1
|
161
160
|
@row_span = options[:row_span] || 1
|
@@ -169,16 +168,6 @@ module Quby
|
|
169
168
|
@input_data = {}
|
170
169
|
@input_data[:value_tooltip] = true if options[:value_tooltip]
|
171
170
|
|
172
|
-
# Require subquestions of required questions by default
|
173
|
-
options[:required] = true if @parent&.validations&.first&.fetch(:type, nil) == :requires_answer
|
174
|
-
@validations << {type: :requires_answer, explanation: options[:error_explanation]} if options[:required]
|
175
|
-
|
176
|
-
if @type == :float
|
177
|
-
@validations << {type: :valid_float, explanation: options[:error_explanation]}
|
178
|
-
elsif @type == :integer
|
179
|
-
@validations << {type: :valid_integer, explanation: options[:error_explanation]}
|
180
|
-
end
|
181
|
-
|
182
171
|
if options[:minimum] and (@type == :integer || @type == :float)
|
183
172
|
fail "deprecated" # pretty sure this is not used anywhere
|
184
173
|
end
|
@@ -186,17 +175,6 @@ module Quby
|
|
186
175
|
fail "deprecated" # pretty sure this is not used anywhere
|
187
176
|
end
|
188
177
|
@default_position = options[:default_position]
|
189
|
-
|
190
|
-
if @question_group
|
191
|
-
if @group_minimum_answered
|
192
|
-
@validations << {type: :answer_group_minimum, group: @question_group, value: @group_minimum_answered,
|
193
|
-
explanation: options[:error_explanation]}
|
194
|
-
end
|
195
|
-
if @group_maximum_answered
|
196
|
-
@validations << {type: :answer_group_maximum, group: @question_group, value: @group_maximum_answered,
|
197
|
-
explanation: options[:error_explanation]}
|
198
|
-
end
|
199
|
-
end
|
200
178
|
end
|
201
179
|
# rubocop:enable CyclomaticComplexity, Metrics/MethodLength
|
202
180
|
|
@@ -212,12 +190,11 @@ module Quby
|
|
212
190
|
@context_free_title || @title
|
213
191
|
end
|
214
192
|
|
215
|
-
def
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
raise e.class, "Question #{key} depends_on contains an error: #{e.message}"
|
193
|
+
def extra_data
|
194
|
+
result = @extra_data
|
195
|
+
result = result.merge(:"depends-on" => @depends_on.to_json) if @depends_on
|
196
|
+
result = result.merge(:placeholder => @options.find { |option| option.placeholder }&.key)
|
197
|
+
result
|
221
198
|
end
|
222
199
|
|
223
200
|
def col_span
|
@@ -29,8 +29,9 @@ module Quby
|
|
29
29
|
|
30
30
|
RESPONDENT_TYPES = %i( profess patient parent second_parent teacher caregiver )
|
31
31
|
|
32
|
-
def initialize(key, last_update: Time.now)
|
32
|
+
def initialize(key, attributes = {}, last_update: Time.now)
|
33
33
|
@key = key
|
34
|
+
@attributes = attributes
|
34
35
|
@sbg_domains = []
|
35
36
|
@last_update = Time.at(last_update.to_i)
|
36
37
|
@score_calculations = {}.with_indifferent_access
|
@@ -54,6 +55,8 @@ module Quby
|
|
54
55
|
@lookup_tables = {}
|
55
56
|
end
|
56
57
|
|
58
|
+
attr_reader :attributes
|
59
|
+
|
57
60
|
attr_accessor :key
|
58
61
|
attr_accessor :title
|
59
62
|
attr_accessor :description
|
@@ -136,20 +139,6 @@ module Quby
|
|
136
139
|
end
|
137
140
|
end
|
138
141
|
|
139
|
-
def callback_after_dsl_enhance_on_questions
|
140
|
-
question_hash.each_value do |q|
|
141
|
-
q.run_callbacks :after_dsl_enhance
|
142
|
-
end
|
143
|
-
ensure_scores_have_schemas if Quby::Settings.require_score_schemas
|
144
|
-
end
|
145
|
-
|
146
|
-
def ensure_scores_have_schemas
|
147
|
-
missing_schemas = scores.map(&:key).map(&:to_s) - score_schemas.keys
|
148
|
-
missing_schemas.each do |key|
|
149
|
-
errors.add "Score #{key}", 'is missing a score schema'
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
142
|
def validate_questions
|
154
143
|
question_hash.each_value do |q|
|
155
144
|
unless q.valid?
|
@@ -24,30 +24,6 @@ module Quby
|
|
24
24
|
@uncheck_all_option = options[:uncheck_all_option]
|
25
25
|
@maximum_checked_allowed = options[:maximum_checked_allowed]
|
26
26
|
@minimum_checked_required = options[:minimum_checked_required]
|
27
|
-
|
28
|
-
if @check_all_option
|
29
|
-
@validations << {type: :not_all_checked,
|
30
|
-
check_all_key: @check_all_option,
|
31
|
-
explanation: options[:error_explanation]}
|
32
|
-
end
|
33
|
-
|
34
|
-
if @uncheck_all_option
|
35
|
-
@validations << {type: :too_many_checked,
|
36
|
-
uncheck_all_key: @uncheck_all_option,
|
37
|
-
explanation: options[:error_explanation]}
|
38
|
-
end
|
39
|
-
|
40
|
-
if @maximum_checked_allowed
|
41
|
-
@validations << {type: :maximum_checked_allowed,
|
42
|
-
maximum_checked_value: @maximum_checked_allowed,
|
43
|
-
explanation: options[:error_explanation]}
|
44
|
-
end
|
45
|
-
|
46
|
-
if @minimum_checked_required
|
47
|
-
@validations << {type: :minimum_checked_required,
|
48
|
-
minimum_checked_value: @minimum_checked_required,
|
49
|
-
explanation: options[:error_explanation]}
|
50
|
-
end
|
51
27
|
end
|
52
28
|
|
53
29
|
def variable_descriptions
|
@@ -32,14 +32,6 @@ module Quby
|
|
32
32
|
component_key = options[:"#{component}_key"] || "#{key}_#{COMPONENT_KEYS[component]}"
|
33
33
|
instance_variable_set("@#{component}_key", component_key.to_sym)
|
34
34
|
end
|
35
|
-
|
36
|
-
add_date_validation(options[:error_explanation])
|
37
|
-
end
|
38
|
-
|
39
|
-
def add_date_validation(explanation)
|
40
|
-
@validations << {type: :valid_date,
|
41
|
-
subtype: :"valid_date_#{components.sort.join('_')}",
|
42
|
-
explanation: explanation}
|
43
35
|
end
|
44
36
|
|
45
37
|
def claimed_keys
|
@@ -3,15 +3,52 @@
|
|
3
3
|
module Quby
|
4
4
|
module Questionnaires
|
5
5
|
module Entities
|
6
|
+
# method_source gem gives us the full score source code including the initial `score() do` DSL call.
|
7
|
+
# This module helps strip off that outer DSL call.
|
8
|
+
module StripOuterScoreCall
|
9
|
+
def self.score(*args, &block)
|
10
|
+
block
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.variable(*args, &block)
|
14
|
+
block
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.attention(*args, &block)
|
18
|
+
block
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.alarm(*args, &block)
|
22
|
+
block
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.completion(*args, &block)
|
26
|
+
block
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.subscore(*args, &block)
|
30
|
+
block
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
6
34
|
class ScoreCalculation
|
7
|
-
attr_accessor :key, :label, :sbg_key, :options
|
35
|
+
attr_accessor :key, :label, :sbg_key, :options
|
8
36
|
|
9
37
|
def initialize(key, options, &block)
|
10
38
|
@key = key
|
11
39
|
@label = options[:label]
|
12
40
|
@sbg_key = options[:sbg_key]
|
13
|
-
@options = options
|
14
|
-
@
|
41
|
+
@options = options[:options] || options # TODO remove `|| options`
|
42
|
+
@sourcecode = options[:sourcecode]
|
43
|
+
@block = block
|
44
|
+
end
|
45
|
+
|
46
|
+
def calculation
|
47
|
+
if @block
|
48
|
+
@block
|
49
|
+
else
|
50
|
+
StripOuterScoreCall.instance_eval(@sourcecode)
|
51
|
+
end
|
15
52
|
end
|
16
53
|
|
17
54
|
def score
|
@@ -6,6 +6,7 @@ module Quby
|
|
6
6
|
autoload :Base, 'quby/questionnaires/repos/base'
|
7
7
|
autoload :MemoryRepo, 'quby/questionnaires/repos/memory_repo'
|
8
8
|
autoload :DiskRepo, 'quby/questionnaires/repos/disk_repo'
|
9
|
+
autoload :BundleDiskRepo, 'quby/questionnaires/repos/bundle_disk_repo'
|
9
10
|
|
10
11
|
QuestionnaireNotFound = Class.new(StandardError)
|
11
12
|
DuplicateQuestionnaire = Class.new(StandardError)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'quby/questionnaires/repos'
|
4
|
+
require 'quby/questionnaires'
|
5
|
+
|
6
|
+
module Quby
|
7
|
+
module Questionnaires
|
8
|
+
module Repos
|
9
|
+
class BundleDiskRepo < Base
|
10
|
+
attr_reader :path
|
11
|
+
|
12
|
+
def initialize(path)
|
13
|
+
@path = path
|
14
|
+
@questionnaire_cache = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def keys
|
18
|
+
Dir[File.join(path, "*.rb")].map do |filename|
|
19
|
+
File.basename(filename, '.rb')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def find(key)
|
24
|
+
fail(QuestionnaireNotFound, key) unless exists?(key)
|
25
|
+
json = read(key)
|
26
|
+
timestamp = Time.zone.parse(json["last_update"])
|
27
|
+
Entities::Definition.new(key: key, path: questionnaire_path(key), json: json, timestamp: timestamp)
|
28
|
+
end
|
29
|
+
|
30
|
+
def exists?(key)
|
31
|
+
questionnaire_path = questionnaire_path(key)
|
32
|
+
File.exist?(questionnaire_path)
|
33
|
+
end
|
34
|
+
|
35
|
+
def timestamp(key)
|
36
|
+
Time.zone.parse(read(key)["last_update"])
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def read(key)
|
42
|
+
JSON.parse(File.read(questionnaire_path(key)))
|
43
|
+
end
|
44
|
+
|
45
|
+
def questionnaire_path(key)
|
46
|
+
File.join(path,key, "quby-frontend-v1.json")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -2,8 +2,6 @@
|
|
2
2
|
|
3
3
|
# A lookup tree to find values by multiple arguments.
|
4
4
|
#
|
5
|
-
# Created by LookupTable from a csv file or by add_lookup_tree from dsl.
|
6
|
-
#
|
7
5
|
# Example tree:
|
8
6
|
# Inhibitie:
|
9
7
|
# male:
|
@@ -36,27 +34,6 @@ module Quby::TableBackend
|
|
36
34
|
@tree = tree
|
37
35
|
end
|
38
36
|
|
39
|
-
# load csv data into a tree.
|
40
|
-
# each row is a path through the tree.
|
41
|
-
# String and float types are used to make an exact match.
|
42
|
-
# A range is always a range between two floats where the range is between
|
43
|
-
# the low value (inclusive) and the high value (exclusive),
|
44
|
-
# written as 4:5 (low:high). These boundaries can be given as floats or
|
45
|
-
# integers, but internally they are always treated as a floats.
|
46
|
-
# The low and high values of a range cannot be equal.
|
47
|
-
# Use minfinity or infinity to create infinite ranges.
|
48
|
-
#
|
49
|
-
# @params levels [Array<String>] An array of column names
|
50
|
-
# @param compare [Array<String>]An array of lookup types (string, float or range) for each column
|
51
|
-
# @param data [Array<Array<>>] The rows describing a path through the tree.
|
52
|
-
def self.from_csv(levels:, compare:, data:)
|
53
|
-
tree = data.each_with_object({}) do |row, tree|
|
54
|
-
add_to_tree(tree, row, levels, compare)
|
55
|
-
end
|
56
|
-
new(levels: levels, tree: tree)
|
57
|
-
end
|
58
|
-
|
59
|
-
|
60
37
|
# Given a parameters hash that contains a value or range for every
|
61
38
|
# level in the tree, find and return the normscore.
|
62
39
|
# ie. `lookup({age: 10, raw: 5, scale: 'Inhibitie', gender: 'male'})` => 39
|
@@ -67,34 +44,6 @@ module Quby::TableBackend
|
|
67
44
|
|
68
45
|
private
|
69
46
|
|
70
|
-
def self.add_to_tree(tree, (value, *path), (level, *levels), (compare, *compares))
|
71
|
-
key = case compare
|
72
|
-
when 'string' then value.to_s
|
73
|
-
when 'float' then parse_float(value)
|
74
|
-
when 'range' then create_range(value)
|
75
|
-
end
|
76
|
-
|
77
|
-
if levels.empty?
|
78
|
-
return key
|
79
|
-
end
|
80
|
-
|
81
|
-
tree.merge! key => add_to_tree(tree[key] || {}, path, levels, compares)
|
82
|
-
end
|
83
|
-
|
84
|
-
def self.create_range(value)
|
85
|
-
min, max = value.split(':').map { |val| parse_float(val) }
|
86
|
-
fail 'Cannot create range between two equal values' if min == max
|
87
|
-
(min...max)
|
88
|
-
end
|
89
|
-
|
90
|
-
def self.parse_float(value)
|
91
|
-
case value
|
92
|
-
when 'infinity' then Float::INFINITY
|
93
|
-
when 'minfinity' then -Float::INFINITY
|
94
|
-
else Float(value)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
47
|
# All parameters must be present to do a lookup but the order does not matter.
|
99
48
|
def validate_parameters(parameters)
|
100
49
|
if @levels[0...-1].sort != parameters.keys.map(&:to_s).sort
|