From 3b40411eb2536070fdc35a522688e183e0f99a0b Mon Sep 17 00:00:00 2001 From: Jorn van de Beek <jornvandebeek@roqua.nl> Date: Mon, 5 Jul 2021 16:35:38 +0200 Subject: [PATCH 1/4] Serialize outcome tables from dsl calls into roqua.json --- lib/quby/compiler/entities/outcome_table.rb | 15 +++++- lib/quby/compiler/outputs/roqua_serializer.rb | 39 ++++++++++++++- .../compiler/entities/outcome_table_spec.rb | 20 ++++++++ .../compiler/outputs/roqua_serializer_spec.rb | 48 +++++++++++++++++-- 4 files changed, 114 insertions(+), 8 deletions(-) diff --git a/lib/quby/compiler/entities/outcome_table.rb b/lib/quby/compiler/entities/outcome_table.rb index 64d042e..1879b6d 100644 --- a/lib/quby/compiler/entities/outcome_table.rb +++ b/lib/quby/compiler/entities/outcome_table.rb @@ -12,9 +12,9 @@ module Quby include ActiveModel::Model attr_accessor :score_keys, :subscore_keys, :name, :default_collapsed, :questionnaire, :key - validates :score_keys, :subscore_keys, :questionnaire, :key, presence: true validates :name, presence: true, if: proc { |table| table.default_collapsed } validate :references_existing_score_keys + validate :no_outcome_tables_defined_in_score_schemas def references_existing_score_keys (score_keys - questionnaire.score_schemas.values.map(&:key)).each do |missing_key| @@ -25,7 +25,18 @@ module Quby errors.add :subscore_keys, "#{missing_key.inspect} not found in subscore schemas" end end + + def no_outcome_tables_defined_in_score_schemas + if questionnaire.score_schemas.values.any? do |schema| + schema.subscore_schemas.any? do |subscore| + subscore.outcome_table != :main + end + end + errors.add :score_schemas, + "Outcome table associations defined in score schemas should not be combined with explicit outcome tables" + end + end end end end -end +end \ No newline at end of file diff --git a/lib/quby/compiler/outputs/roqua_serializer.rb b/lib/quby/compiler/outputs/roqua_serializer.rb index bf03072..b5f40cd 100644 --- a/lib/quby/compiler/outputs/roqua_serializer.rb +++ b/lib/quby/compiler/outputs/roqua_serializer.rb @@ -84,11 +84,46 @@ module Quby # <subscore_key:Symbol>: <subscore.label:String> # headers for each subscore key for all tables. def outcome_tables_schema + if questionnaire.outcome_tables.present? + outcome_tables_from_definition + else + outcome_tables_from_score_schemas + end + end + + def outcome_tables_from_definition + # hash of tables, with the score keys (rows) and subscore keys (columns) used for each + tables = {} + # hash of `subscore_key: subscore_label` pairs used in tables + headers = {} + + questionnaire.outcome_tables.each do |table| + tables[table.key] = {name: table.name, + default_collapsed: table.default_collapsed, + score_keys: table.score_keys, + subscore_keys: table.subscore_keys}.compact + table.score_keys.each do |score_key| + table.subscore_keys.each do |subscore_key| + subschema = questionnaire.score_schemas[score_key].subscore_schemas.find do |subschema| + subschema.key == subscore_key + end + headers[subscore_key] = subschema.label + end + end + end + + { + headers: headers, + tables: tables, + } + end + + def outcome_tables_from_score_schemas # hash of tables, with the score keys (rows) and subscore keys (columns) used for each tables = Hash.new{ |hash, key| hash[key] = {score_keys: Set.new, subscore_keys: Set.new } } # hash of `subscore_key: subscore_label` pairs used in tables headers = {} - + questionnaire.score_schemas.values.each do |schema| schema.subscore_schemas.each do |subschema| next if subschema.outcome_table.blank? @@ -97,7 +132,7 @@ module Quby headers[subschema.key] = subschema.label end end - + { headers: headers, tables: tables, diff --git a/spec/quby/compiler/entities/outcome_table_spec.rb b/spec/quby/compiler/entities/outcome_table_spec.rb index f87e919..52b982d 100644 --- a/spec/quby/compiler/entities/outcome_table_spec.rb +++ b/spec/quby/compiler/entities/outcome_table_spec.rb @@ -29,5 +29,25 @@ module Quby::Compiler::Entities "Subscore keys :unknown_key_2 not found in subscore schemas"]) end end + + describe '#no_outcome_tables_defined_in_score_schemas' do + let(:questionnaire) do + Quby::Compiler::DSL.build("test") do + score(:key, + label: 'score', + schema: [{key: :value, label: 'Score', export_key: :key, outcome_table: :something}]) { {value: 'oh1'} } + score(:key2, label: 'score2', schema: [{key: :value, label: 'Score 2', export_key: :key2}]) { {value: 'oh2'} } + end + end + it 'checks all score schemas don\'t have a outcome table defined already' do + table = described_class.new(key: :test_outcome_table, + score_keys: %i[key key2], + subscore_keys: [:value], + questionnaire: questionnaire) + table.valid? + expect(table.errors.full_messages).to \ + eq(["Outcome table associations defined in score schemas should not be combined with explicit outcome tables"]) + end + end end end diff --git a/spec/quby/compiler/outputs/roqua_serializer_spec.rb b/spec/quby/compiler/outputs/roqua_serializer_spec.rb index 47f0a85..f623230 100644 --- a/spec/quby/compiler/outputs/roqua_serializer_spec.rb +++ b/spec/quby/compiler/outputs/roqua_serializer_spec.rb @@ -1,7 +1,47 @@ require 'spec_helper' describe Quby::Compiler::Outputs::RoquaSerializer do - it 'generates outcome schemas' do + it 'generates outcome tables schema from questionnaire defined outcome tables' do + questionnaire = dsl("test") do + title "Test Quest" + + score_schema :score0, 'Score 0' do + subscore(:value, 'Nog iets', export_key: :score0) { 'Iets' } + end + + score_schema :score1, 'Score 1' do + subscore(:value, 'Waarde', export_key: :score1) { 1 } + subscore(:int, 'Interpretatie', export_key: :score1_i) { 'Wah' } + end + + outcome_table name: 'Alleen score 0', + key: :only_score0, + score_keys: [:score0], + default_collapsed: true, + subscore_keys: %i[value] + + outcome_table name: 'Scores', + key: :scores, + score_keys: [:score0, :score1], + subscore_keys: %i[value] + end + serializer = described_class.new(questionnaire) + + expected = { + outcome_tables_schema: + {headers: {value: "Waarde"}, + tables: {only_score0: {default_collapsed: true, + name: "Alleen score 0", + score_keys: [:score0], + subscore_keys: [:value]}, + scores: {name: "Scores", + score_keys: [:score0, :score1], + subscore_keys: [:value]}}} + } + expect(serializer.as_json).to include(expected) + end + + it 'generates outcome tables schema from score schema outcome tables' do questionnaire = dsl("test") do title "Test Quest" @@ -50,9 +90,9 @@ describe Quby::Compiler::Outputs::RoquaSerializer do outcome_tables_schema: { headers: {int: "Interpretatie", mean: "Gemiddelde", something: "Nog iets", value: "Waarde"}, tables: { - main: {:score_keys => [:score0], :subscore_keys => [:something]}, - values: {:score_keys => [:score1, :score2], :subscore_keys => [:value, :int]}, - means: {:score_keys => [:score3, :score4], :subscore_keys => [:mean]} + main: {score_keys: [:score0], subscore_keys: [:something]}, + values: {score_keys: [:score1, :score2], subscore_keys: [:value, :int]}, + means: {score_keys: [:score3, :score4], subscore_keys: [:mean]} } } }) -- GitLab From d1475b477a46c9b3eb3f23e4166eb1685b3aaa3e Mon Sep 17 00:00:00 2001 From: Jorn van de Beek <jornvandebeek@roqua.nl> Date: Tue, 6 Jul 2021 13:49:21 +0200 Subject: [PATCH 2/4] Fix spec --- Gemfile.lock | 22 +++++++++---------- .../compiler/entities/outcome_table_spec.rb | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 5f79fbe..2dc79b4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - quby-compiler (0.3.4) + quby-compiler (0.3.5) actionview (>= 5.0) activemodel (>= 5.0) activesupport (>= 5.0) @@ -21,8 +21,8 @@ GEM erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - active_interaction (3.8.3) - activemodel (>= 4, < 7) + active_interaction (4.0.2) + activemodel (>= 5, < 7) activemodel (6.0.4) activesupport (= 6.0.4) activerecord (6.0.4) @@ -34,7 +34,7 @@ GEM minitest (~> 5.1) tzinfo (~> 1.1) zeitwerk (~> 2.2, >= 2.2.2) - appsignal (2.10.12) + appsignal (3.0.8) rack builder (3.2.4) coderay (1.1.3) @@ -44,13 +44,13 @@ GEM dry-configurable (0.12.1) concurrent-ruby (~> 1.0) dry-core (~> 0.5, >= 0.5.0) - dry-container (0.7.2) + dry-container (0.8.0) concurrent-ruby (~> 1.0) dry-configurable (~> 0.1, >= 0.1.3) - dry-core (0.5.0) + dry-core (0.6.0) concurrent-ruby (~> 1.0) dry-inflector (0.2.0) - dry-logic (1.1.0) + dry-logic (1.2.0) concurrent-ruby (~> 1.0) dry-core (~> 0.5, >= 0.5) dry-struct (1.4.0) @@ -91,10 +91,10 @@ GEM loofah (~> 2.3) rake (12.3.3) redcarpet (3.5.1) - roqua-support (0.3.5) - active_interaction (~> 3.0) - activesupport (>= 5.1, < 6.1) - appsignal (>= 2.9, < 2.11) + roqua-support (0.4.0) + active_interaction (>= 3.0, < 5.0) + activesupport (>= 5.2, < 6.2) + appsignal (>= 2.9, < 3.1) naught (~> 1.0) with_advisory_lock (~> 3.2) rspec (3.9.0) diff --git a/spec/quby/compiler/entities/outcome_table_spec.rb b/spec/quby/compiler/entities/outcome_table_spec.rb index 52b982d..c2ef7e6 100644 --- a/spec/quby/compiler/entities/outcome_table_spec.rb +++ b/spec/quby/compiler/entities/outcome_table_spec.rb @@ -46,7 +46,7 @@ module Quby::Compiler::Entities questionnaire: questionnaire) table.valid? expect(table.errors.full_messages).to \ - eq(["Outcome table associations defined in score schemas should not be combined with explicit outcome tables"]) + eq(["Score schemas Outcome table associations defined in score schemas should not be combined with explicit outcome tables"]) end end end -- GitLab From 3f2199bf7c94f0fec8205147204e2b995c6385ff Mon Sep 17 00:00:00 2001 From: Jorn van de Beek <jornvandebeek@roqua.nl> Date: Tue, 6 Jul 2021 15:40:04 +0200 Subject: [PATCH 3/4] Handle missing subscore labels correctly --- lib/quby/compiler/entities/outcome_table.rb | 2 +- lib/quby/compiler/outputs/roqua_serializer.rb | 7 ++++--- .../quby/compiler/outputs/roqua_serializer_spec.rb | 14 +++++++------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/quby/compiler/entities/outcome_table.rb b/lib/quby/compiler/entities/outcome_table.rb index 1879b6d..82933ec 100644 --- a/lib/quby/compiler/entities/outcome_table.rb +++ b/lib/quby/compiler/entities/outcome_table.rb @@ -39,4 +39,4 @@ module Quby end end end -end \ No newline at end of file +end diff --git a/lib/quby/compiler/outputs/roqua_serializer.rb b/lib/quby/compiler/outputs/roqua_serializer.rb index b5f40cd..4ffc900 100644 --- a/lib/quby/compiler/outputs/roqua_serializer.rb +++ b/lib/quby/compiler/outputs/roqua_serializer.rb @@ -102,12 +102,13 @@ module Quby default_collapsed: table.default_collapsed, score_keys: table.score_keys, subscore_keys: table.subscore_keys}.compact - table.score_keys.each do |score_key| - table.subscore_keys.each do |subscore_key| + + table.subscore_keys.each do |subscore_key| + table.score_keys.find do |score_key| subschema = questionnaire.score_schemas[score_key].subscore_schemas.find do |subschema| subschema.key == subscore_key end - headers[subscore_key] = subschema.label + headers[subscore_key] = subschema&.label end end end diff --git a/spec/quby/compiler/outputs/roqua_serializer_spec.rb b/spec/quby/compiler/outputs/roqua_serializer_spec.rb index f623230..033c88c 100644 --- a/spec/quby/compiler/outputs/roqua_serializer_spec.rb +++ b/spec/quby/compiler/outputs/roqua_serializer_spec.rb @@ -5,15 +5,15 @@ describe Quby::Compiler::Outputs::RoquaSerializer do questionnaire = dsl("test") do title "Test Quest" - score_schema :score0, 'Score 0' do - subscore(:value, 'Nog iets', export_key: :score0) { 'Iets' } - end - score_schema :score1, 'Score 1' do subscore(:value, 'Waarde', export_key: :score1) { 1 } subscore(:int, 'Interpretatie', export_key: :score1_i) { 'Wah' } end + score_schema :score0, 'Score 0' do + subscore(:value, 'Nog iets', export_key: :score0) { 'Iets' } + end + outcome_table name: 'Alleen score 0', key: :only_score0, score_keys: [:score0], @@ -23,20 +23,20 @@ describe Quby::Compiler::Outputs::RoquaSerializer do outcome_table name: 'Scores', key: :scores, score_keys: [:score0, :score1], - subscore_keys: %i[value] + subscore_keys: %i[value int] end serializer = described_class.new(questionnaire) expected = { outcome_tables_schema: - {headers: {value: "Waarde"}, + {headers: {int: "Interpretatie", value: "Nog iets"}, tables: {only_score0: {default_collapsed: true, name: "Alleen score 0", score_keys: [:score0], subscore_keys: [:value]}, scores: {name: "Scores", score_keys: [:score0, :score1], - subscore_keys: [:value]}}} + subscore_keys: [:value, :int]}}} } expect(serializer.as_json).to include(expected) end -- GitLab From dd06274d9f965a71d76f0fd44d2c8de8233ba9a0 Mon Sep 17 00:00:00 2001 From: Jorn van de Beek <jornvandebeek@roqua.nl> Date: Tue, 6 Jul 2021 15:41:16 +0200 Subject: [PATCH 4/4] Reinstate deleted validation --- lib/quby/compiler/entities/outcome_table.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/quby/compiler/entities/outcome_table.rb b/lib/quby/compiler/entities/outcome_table.rb index 82933ec..06654c0 100644 --- a/lib/quby/compiler/entities/outcome_table.rb +++ b/lib/quby/compiler/entities/outcome_table.rb @@ -12,6 +12,7 @@ module Quby include ActiveModel::Model attr_accessor :score_keys, :subscore_keys, :name, :default_collapsed, :questionnaire, :key + validates :score_keys, :subscore_keys, :questionnaire, :key, presence: true validates :name, presence: true, if: proc { |table| table.default_collapsed } validate :references_existing_score_keys validate :no_outcome_tables_defined_in_score_schemas -- GitLab