quby-compiler 0.3.1 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/CHANGELOG.md +21 -0
- data/Gemfile.lock +25 -25
- data/exe/quby-compile +2 -3
- data/lib/quby/compiler/dsl.rb +3 -3
- data/lib/quby/compiler/dsl/base.rb +2 -2
- data/lib/quby/compiler/dsl/calls_custom_methods.rb +1 -2
- data/lib/quby/compiler/dsl/charting/chart_builder.rb +3 -3
- data/lib/quby/compiler/dsl/charting/overview_chart_builder.rb +1 -1
- data/lib/quby/compiler/dsl/helpers.rb +3 -3
- data/lib/quby/compiler/dsl/panel_builder.rb +13 -10
- data/lib/quby/compiler/dsl/question_builder.rb +2 -2
- data/lib/quby/compiler/dsl/questionnaire_builder.rb +24 -24
- data/lib/quby/compiler/dsl/questions/base.rb +7 -7
- data/lib/quby/compiler/dsl/questions/checkbox_question_builder.rb +1 -1
- data/lib/quby/compiler/dsl/questions/date_question_builder.rb +1 -1
- data/lib/quby/compiler/dsl/questions/deprecated_question_builder.rb +1 -1
- data/lib/quby/compiler/dsl/questions/float_question_builder.rb +1 -1
- data/lib/quby/compiler/dsl/questions/integer_question_builder.rb +1 -1
- data/lib/quby/compiler/dsl/questions/radio_question_builder.rb +1 -1
- data/lib/quby/compiler/dsl/questions/select_question_builder.rb +1 -1
- data/lib/quby/compiler/dsl/questions/string_question_builder.rb +1 -1
- data/lib/quby/compiler/dsl/questions/text_question_builder.rb +1 -1
- data/lib/quby/compiler/dsl/score_builder.rb +1 -1
- data/lib/quby/compiler/dsl/table_builder.rb +5 -5
- data/lib/quby/compiler/entities/definition.rb +3 -2
- data/lib/quby/compiler/entities/outcome_table.rb +12 -0
- data/lib/quby/compiler/entities/questionnaire.rb +2 -2
- data/lib/quby/compiler/entities/questions/float_question.rb +9 -0
- data/lib/quby/compiler/entities/questions/integer_question.rb +9 -0
- data/lib/quby/compiler/entities/subscore_schema.rb +2 -1
- data/lib/quby/compiler/instance.rb +2 -2
- data/lib/quby/compiler/outputs/roqua_serializer.rb +39 -2
- data/lib/quby/compiler/services/definition_validator.rb +8 -4
- data/lib/quby/compiler/services/quby_proxy.rb +6 -6
- data/lib/quby/compiler/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a56013c91225af82fd15a27e8195ca88b22dcb3ea94354ab2ef62cef50532bf2
|
|
4
|
+
data.tar.gz: 6412e7e3ef45dd548dc10eea9e2b72da4b7cc64d94d9de2a3ede13db70c5be25
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 67d746a71ccbd1c0780a836579000efdf50e825a10906a10992abaf3612340039e9670320814d6cb7f6baf3eb041e85c3872496e4d95a70ed4195d61632b969a
|
|
7
|
+
data.tar.gz: 51151607042665ecbdd7f4b9448e24a220350cd132ec1e5ef509dfd71b5abca5668686de5231cfd40a27e43ecead4003e1f41ab04e01f952fae95ecc3f96a7cf
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
2.7.
|
|
1
|
+
2.7.2
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
# 0.3.6
|
|
2
|
+
|
|
3
|
+
* `outcome_table` panel dsl method now exports the given outcome table definition to `roqua.json`
|
|
4
|
+
This can't be used in combination with the `outcome_table: ` attibute in score schemas.
|
|
5
|
+
|
|
6
|
+
# 0.3.5
|
|
7
|
+
|
|
8
|
+
* Allow score_schema's outcome_table to be set to nil to hide values from outcome tables
|
|
9
|
+
|
|
10
|
+
# 0.3.4
|
|
11
|
+
|
|
12
|
+
* Added preliminary support for sliders to the v2 output.
|
|
13
|
+
|
|
14
|
+
# 0.3.3
|
|
15
|
+
|
|
16
|
+
* Replace `options={}` with `**options` in the builders to prevent prepare for ruby 3.0
|
|
17
|
+
|
|
18
|
+
# 0.3.2
|
|
19
|
+
|
|
20
|
+
* Fix slashes-after-numbers removal when question does not have a title
|
|
21
|
+
|
|
1
22
|
# 0.3.1
|
|
2
23
|
|
|
3
24
|
* Slashes after numbers are now removed from question titles when making RoQua seeds (quests attribute).
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
quby-compiler (0.3.
|
|
4
|
+
quby-compiler (0.3.5)
|
|
5
5
|
actionview (>= 5.0)
|
|
6
6
|
activemodel (>= 5.0)
|
|
7
7
|
activesupport (>= 5.0)
|
|
@@ -15,42 +15,42 @@ PATH
|
|
|
15
15
|
GEM
|
|
16
16
|
remote: https://rubygems.org/
|
|
17
17
|
specs:
|
|
18
|
-
actionview (6.0.
|
|
19
|
-
activesupport (= 6.0.
|
|
18
|
+
actionview (6.0.4)
|
|
19
|
+
activesupport (= 6.0.4)
|
|
20
20
|
builder (~> 3.1)
|
|
21
21
|
erubi (~> 1.4)
|
|
22
22
|
rails-dom-testing (~> 2.0)
|
|
23
23
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
|
24
|
-
active_interaction (
|
|
25
|
-
activemodel (>=
|
|
26
|
-
activemodel (6.0.
|
|
27
|
-
activesupport (= 6.0.
|
|
28
|
-
activerecord (6.0.
|
|
29
|
-
activemodel (= 6.0.
|
|
30
|
-
activesupport (= 6.0.
|
|
31
|
-
activesupport (6.0.
|
|
24
|
+
active_interaction (4.0.2)
|
|
25
|
+
activemodel (>= 5, < 7)
|
|
26
|
+
activemodel (6.0.4)
|
|
27
|
+
activesupport (= 6.0.4)
|
|
28
|
+
activerecord (6.0.4)
|
|
29
|
+
activemodel (= 6.0.4)
|
|
30
|
+
activesupport (= 6.0.4)
|
|
31
|
+
activesupport (6.0.4)
|
|
32
32
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
33
33
|
i18n (>= 0.7, < 2)
|
|
34
34
|
minitest (~> 5.1)
|
|
35
35
|
tzinfo (~> 1.1)
|
|
36
36
|
zeitwerk (~> 2.2, >= 2.2.2)
|
|
37
|
-
appsignal (
|
|
37
|
+
appsignal (3.0.8)
|
|
38
38
|
rack
|
|
39
39
|
builder (3.2.4)
|
|
40
40
|
coderay (1.1.3)
|
|
41
|
-
concurrent-ruby (1.1.
|
|
41
|
+
concurrent-ruby (1.1.9)
|
|
42
42
|
crass (1.0.6)
|
|
43
43
|
diff-lcs (1.4.4)
|
|
44
44
|
dry-configurable (0.12.1)
|
|
45
45
|
concurrent-ruby (~> 1.0)
|
|
46
46
|
dry-core (~> 0.5, >= 0.5.0)
|
|
47
|
-
dry-container (0.
|
|
47
|
+
dry-container (0.8.0)
|
|
48
48
|
concurrent-ruby (~> 1.0)
|
|
49
49
|
dry-configurable (~> 0.1, >= 0.1.3)
|
|
50
|
-
dry-core (0.
|
|
50
|
+
dry-core (0.6.0)
|
|
51
51
|
concurrent-ruby (~> 1.0)
|
|
52
52
|
dry-inflector (0.2.0)
|
|
53
|
-
dry-logic (1.
|
|
53
|
+
dry-logic (1.2.0)
|
|
54
54
|
concurrent-ruby (~> 1.0)
|
|
55
55
|
dry-core (~> 0.5, >= 0.5)
|
|
56
56
|
dry-struct (1.4.0)
|
|
@@ -64,20 +64,20 @@ GEM
|
|
|
64
64
|
dry-inflector (~> 0.1, >= 0.1.2)
|
|
65
65
|
dry-logic (~> 1.0, >= 1.0.2)
|
|
66
66
|
erubi (1.10.0)
|
|
67
|
-
i18n (1.8.
|
|
67
|
+
i18n (1.8.10)
|
|
68
68
|
concurrent-ruby (~> 1.0)
|
|
69
69
|
ice_nine (0.11.2)
|
|
70
|
-
loofah (2.
|
|
70
|
+
loofah (2.10.0)
|
|
71
71
|
crass (~> 1.0.2)
|
|
72
72
|
nokogiri (>= 1.5.9)
|
|
73
73
|
method_source (1.0.0)
|
|
74
|
-
mini_portile2 (2.5.
|
|
74
|
+
mini_portile2 (2.5.3)
|
|
75
75
|
minitest (5.14.4)
|
|
76
76
|
naught (1.1.0)
|
|
77
|
-
nokogiri (1.11.
|
|
77
|
+
nokogiri (1.11.7)
|
|
78
78
|
mini_portile2 (~> 2.5.0)
|
|
79
79
|
racc (~> 1.4)
|
|
80
|
-
nokogumbo (2.0.
|
|
80
|
+
nokogumbo (2.0.5)
|
|
81
81
|
nokogiri (~> 1.8, >= 1.8.4)
|
|
82
82
|
pry (0.13.1)
|
|
83
83
|
coderay (~> 1.1)
|
|
@@ -91,10 +91,10 @@ GEM
|
|
|
91
91
|
loofah (~> 2.3)
|
|
92
92
|
rake (12.3.3)
|
|
93
93
|
redcarpet (3.5.1)
|
|
94
|
-
roqua-support (0.
|
|
95
|
-
active_interaction (
|
|
96
|
-
activesupport (>= 5.
|
|
97
|
-
appsignal (>= 2.9, <
|
|
94
|
+
roqua-support (0.4.0)
|
|
95
|
+
active_interaction (>= 3.0, < 5.0)
|
|
96
|
+
activesupport (>= 5.2, < 6.2)
|
|
97
|
+
appsignal (>= 2.9, < 3.1)
|
|
98
98
|
naught (~> 1.0)
|
|
99
99
|
with_advisory_lock (~> 3.2)
|
|
100
100
|
rspec (3.9.0)
|
data/exe/quby-compile
CHANGED
|
@@ -21,7 +21,7 @@ OptionParser.new do |opts|
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
opts.on("--seeds=INPUT") do |value|
|
|
24
|
-
|
|
24
|
+
puts '--seeds is a deprecated option, questionnaire definitions should use seed_patches to conserve seed tweaks'
|
|
25
25
|
end
|
|
26
26
|
end.parse!
|
|
27
27
|
|
|
@@ -38,7 +38,7 @@ lookup_tables = Quby::Compiler::Entities::LookupTables.new(lookup_tables_path)
|
|
|
38
38
|
paths.each do |path|
|
|
39
39
|
puts "Compiling #{path}"
|
|
40
40
|
|
|
41
|
-
key = File.basename(
|
|
41
|
+
key = File.basename(File.dirname(path))
|
|
42
42
|
sourcecode = File.read(path)
|
|
43
43
|
last_update = File.mtime(path)
|
|
44
44
|
seed_path = File.join(seeds_path, "#{key}.yml")
|
|
@@ -46,7 +46,6 @@ paths.each do |path|
|
|
|
46
46
|
compiled = Quby::Compiler.compile(key, sourcecode, path: path, seeds: seeds, lookup_tables: lookup_tables, last_update: last_update)
|
|
47
47
|
|
|
48
48
|
FileUtils.mkdir_p(File.join(output_path, key))
|
|
49
|
-
|
|
50
49
|
compiled[:outputs].each do |type, output|
|
|
51
50
|
next unless output
|
|
52
51
|
File.open(File.join(output_path, key, output.filename), 'w') do |file|
|
data/lib/quby/compiler/dsl.rb
CHANGED
|
@@ -10,15 +10,15 @@ module Quby
|
|
|
10
10
|
module DSL
|
|
11
11
|
def self.build_from_definition(definition)
|
|
12
12
|
Entities::Questionnaire.new(definition.key, last_update: definition.timestamp).tap do |questionnaire|
|
|
13
|
-
builder = QuestionnaireBuilder.new(questionnaire)
|
|
13
|
+
builder = QuestionnaireBuilder.new(questionnaire, lookup_tables: definition.lookup_tables)
|
|
14
14
|
builder.instance_eval(definition.sourcecode, definition.path) if definition.sourcecode
|
|
15
15
|
questionnaire.callback_after_dsl_enhance_on_questions
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def self.build(key, sourcecode = nil, path: nil, timestamp: nil, &block)
|
|
19
|
+
def self.build(key, sourcecode = nil, path: nil, timestamp: nil, lookup_tables: {}, &block)
|
|
20
20
|
Entities::Questionnaire.new(key, last_update: timestamp).tap do |questionnaire|
|
|
21
|
-
builder = QuestionnaireBuilder.new(questionnaire)
|
|
21
|
+
builder = QuestionnaireBuilder.new(questionnaire, lookup_tables: lookup_tables)
|
|
22
22
|
builder.instance_eval(sourcecode, path || key) if sourcecode
|
|
23
23
|
builder.instance_eval(&block) if block
|
|
24
24
|
questionnaire.callback_after_dsl_enhance_on_questions
|
|
@@ -16,8 +16,8 @@ module Quby
|
|
|
16
16
|
@chart_class
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
def initialize(questionnaire, key, options
|
|
20
|
-
@chart = self.class.chart_class.new(key, options)
|
|
19
|
+
def initialize(questionnaire, key, **options)
|
|
20
|
+
@chart = self.class.chart_class.new(key, **options)
|
|
21
21
|
@questionnaire = questionnaire
|
|
22
22
|
end
|
|
23
23
|
|
|
@@ -49,7 +49,7 @@ module Quby
|
|
|
49
49
|
@chart.plotlines << {value: value, color: color}
|
|
50
50
|
end
|
|
51
51
|
|
|
52
|
-
def plot(key, options
|
|
52
|
+
def plot(key, **options)
|
|
53
53
|
unless plottable = @questionnaire.find_plottable(key)
|
|
54
54
|
fail "Questionnaire #{@questionnaire.key} chart #{@chart.key} references unknown score or question #{key}"
|
|
55
55
|
end
|
|
@@ -7,7 +7,7 @@ module Quby
|
|
|
7
7
|
class OverviewChartBuilder < ChartBuilder
|
|
8
8
|
set_chart_class(Entities::Charting::OverviewChart)
|
|
9
9
|
|
|
10
|
-
def initialize(questionnaire, options
|
|
10
|
+
def initialize(questionnaire, **options)
|
|
11
11
|
@questionnaire = questionnaire
|
|
12
12
|
@chart = self.class.chart_class.new
|
|
13
13
|
end
|
|
@@ -7,8 +7,8 @@ module Quby
|
|
|
7
7
|
include ActionView::Helpers::TagHelper
|
|
8
8
|
include ActionView::Helpers::OutputSafetyHelper
|
|
9
9
|
|
|
10
|
-
def image_tag(source, options
|
|
11
|
-
tag.img(options.reverse_merge(src: source, alt: image_alt(source)))
|
|
10
|
+
def image_tag(source, **options)
|
|
11
|
+
tag.img(**options.reverse_merge(src: source, alt: image_alt(source)))
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
# Copied from ActionController::Base.helpers.image_alt, because it will be removed from Rails 6.0, but we want
|
|
@@ -18,7 +18,7 @@ module Quby
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def check_question_keys_uniqueness(key, options, questionnaire)
|
|
21
|
-
keys = QuestionBuilder.build(key, options).claimed_keys
|
|
21
|
+
keys = QuestionBuilder.build(key, **options).claimed_keys
|
|
22
22
|
if keys.any? { |k| questionnaire.key_in_use? k }
|
|
23
23
|
fail "#{questionnaire.key}:#{key}: A question or option with input key #{key} is already defined."
|
|
24
24
|
end
|
|
@@ -9,9 +9,9 @@ module Quby
|
|
|
9
9
|
attr_reader :title
|
|
10
10
|
attr_reader :questionnaire
|
|
11
11
|
|
|
12
|
-
def initialize(title,
|
|
13
|
-
@panel = Entities::Panel.new(
|
|
14
|
-
@default_question_options =
|
|
12
|
+
def initialize(title, default_question_options: {}, **options)
|
|
13
|
+
@panel = Entities::Panel.new({title: title, items: [], **options})
|
|
14
|
+
@default_question_options = default_question_options
|
|
15
15
|
@questionnaire = options[:questionnaire]
|
|
16
16
|
@custom_methods = options[:custom_methods] || {}
|
|
17
17
|
end
|
|
@@ -41,25 +41,28 @@ module Quby
|
|
|
41
41
|
@panel.items << Entities::Text.new('', raw_content: video_html)
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
def default_question_options(options
|
|
44
|
+
def default_question_options(**options)
|
|
45
45
|
@default_question_options = @default_question_options.merge(options)
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
def question(key, options
|
|
48
|
+
def question(key, **options, &block)
|
|
49
49
|
options = @default_question_options.merge(options).merge(questionnaire: @panel.questionnaire)
|
|
50
50
|
|
|
51
51
|
check_question_keys_uniqueness key, options, @questionnaire
|
|
52
52
|
|
|
53
|
-
question = QuestionBuilder.build(key, options, &block)
|
|
53
|
+
question = QuestionBuilder.build(key, **options, &block)
|
|
54
54
|
|
|
55
55
|
@questionnaire.register_question(question)
|
|
56
56
|
@panel.items << question
|
|
57
57
|
end
|
|
58
58
|
|
|
59
|
-
def table(options
|
|
60
|
-
table_builder = TableBuilder.new
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
def table(**options, &block)
|
|
60
|
+
table_builder = TableBuilder.new \
|
|
61
|
+
@panel,
|
|
62
|
+
questionnaire: @panel.questionnaire,
|
|
63
|
+
default_question_options: @default_question_options,
|
|
64
|
+
custom_methods: @custom_methods,
|
|
65
|
+
**options
|
|
63
66
|
table_builder.instance_eval(&block) if block
|
|
64
67
|
end
|
|
65
68
|
|
|
@@ -31,8 +31,8 @@ module Quby
|
|
|
31
31
|
'hidden' => Questions::DeprecatedQuestionBuilder
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
def self.build(key, options
|
|
35
|
-
BUILDERS.fetch(options.fetch(:type).to_s).build(key, options, &block)
|
|
34
|
+
def self.build(key, **options, &block)
|
|
35
|
+
BUILDERS.fetch(options.fetch(:type).to_s).build(key, **options, &block)
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
38
|
end
|
|
@@ -19,7 +19,7 @@ module Quby
|
|
|
19
19
|
include StandardizedPanelGenerators
|
|
20
20
|
include Helpers
|
|
21
21
|
|
|
22
|
-
def initialize(target_instance, lookup_tables:
|
|
22
|
+
def initialize(target_instance, lookup_tables:)
|
|
23
23
|
@questionnaire = target_instance
|
|
24
24
|
@lookup_tables = lookup_tables
|
|
25
25
|
@default_question_options = {}
|
|
@@ -148,7 +148,7 @@ module Quby
|
|
|
148
148
|
end
|
|
149
149
|
|
|
150
150
|
def panel(title = nil, options = {}, &block)
|
|
151
|
-
panel = PanelBuilder.build(title, options
|
|
151
|
+
panel = PanelBuilder.build(title, **options, **default_panel_options, &block)
|
|
152
152
|
@questionnaire.add_panel(panel)
|
|
153
153
|
end
|
|
154
154
|
|
|
@@ -167,28 +167,28 @@ module Quby
|
|
|
167
167
|
@questionnaire.lookup_tables[key] = {levels: levels, tree: tree}
|
|
168
168
|
end
|
|
169
169
|
|
|
170
|
-
def default_question_options(options
|
|
170
|
+
def default_question_options(**options)
|
|
171
171
|
@default_question_options.merge!(options)
|
|
172
172
|
end
|
|
173
173
|
|
|
174
174
|
# Short-circuit the question command to perform an implicit panel
|
|
175
|
-
def question(key, options
|
|
175
|
+
def question(key, **options, &block)
|
|
176
176
|
panel(nil, default_panel_options) do
|
|
177
|
-
question(key,
|
|
177
|
+
question(key, questionnaire: @questionnaire, **@default_question_options, **options, &block)
|
|
178
178
|
end
|
|
179
179
|
end
|
|
180
180
|
|
|
181
181
|
# Short-circuit the text command to perform an implicit panel
|
|
182
|
-
def text(value, options
|
|
183
|
-
panel(nil, default_panel_options) do
|
|
184
|
-
text(value, options)
|
|
182
|
+
def text(value, **options)
|
|
183
|
+
panel(nil, **default_panel_options) do
|
|
184
|
+
text(value, **options)
|
|
185
185
|
end
|
|
186
186
|
end
|
|
187
187
|
|
|
188
188
|
# Short-circuit the table command to perform an implicit panel
|
|
189
|
-
def table(options
|
|
190
|
-
panel(nil, default_panel_options) do
|
|
191
|
-
table(options, &block)
|
|
189
|
+
def table(**options, &block)
|
|
190
|
+
panel(nil, **default_panel_options) do
|
|
191
|
+
table(**options, &block)
|
|
192
192
|
end
|
|
193
193
|
end
|
|
194
194
|
|
|
@@ -197,15 +197,15 @@ module Quby
|
|
|
197
197
|
# # variables are private to the score calculation
|
|
198
198
|
# q01 + q02 + q03
|
|
199
199
|
# end
|
|
200
|
-
def variable(key, options
|
|
201
|
-
@questionnaire.add_score_calculation ScoreBuilder.new(key, options, &block).build
|
|
200
|
+
def variable(key, **options, &block)
|
|
201
|
+
@questionnaire.add_score_calculation ScoreBuilder.new(key, **options, &block).build
|
|
202
202
|
end
|
|
203
203
|
|
|
204
|
-
def score(key, options
|
|
204
|
+
def score(key, **options, &block)
|
|
205
205
|
@questionnaire.errors.add "Score #{key}", 'misses label in score call' if options[:label].blank?
|
|
206
206
|
schema = options.delete(:schema)
|
|
207
207
|
score_schema(key, options[:label], schema) if schema.present?
|
|
208
|
-
variable(key,
|
|
208
|
+
variable(key, score: true, **options, &block)
|
|
209
209
|
end
|
|
210
210
|
|
|
211
211
|
def score_schema(key, label, options = nil, &block)
|
|
@@ -222,16 +222,16 @@ module Quby
|
|
|
222
222
|
end
|
|
223
223
|
end
|
|
224
224
|
|
|
225
|
-
def attention(options
|
|
226
|
-
variable(:attention,
|
|
225
|
+
def attention(**options, &block)
|
|
226
|
+
variable(:attention, action: true, **options, &block)
|
|
227
227
|
end
|
|
228
228
|
|
|
229
|
-
def alarm(options
|
|
230
|
-
variable(:alarm,
|
|
229
|
+
def alarm(**options, &block)
|
|
230
|
+
variable(:alarm, action: true, **options, &block)
|
|
231
231
|
end
|
|
232
232
|
|
|
233
|
-
def completion(options
|
|
234
|
-
variable(:completion,
|
|
233
|
+
def completion(**options, &block)
|
|
234
|
+
variable(:completion, completion: true, **options, &block)
|
|
235
235
|
end
|
|
236
236
|
|
|
237
237
|
def overview_chart(*args, &block)
|
|
@@ -255,15 +255,15 @@ module Quby
|
|
|
255
255
|
@questionnaire.add_chart(builder.build(&block))
|
|
256
256
|
end
|
|
257
257
|
|
|
258
|
-
def flag(flag_options)
|
|
258
|
+
def flag(**flag_options)
|
|
259
259
|
@questionnaire.add_flag flag_options
|
|
260
260
|
end
|
|
261
261
|
|
|
262
|
-
def textvar(textvar_options)
|
|
262
|
+
def textvar(**textvar_options)
|
|
263
263
|
@questionnaire.add_textvar textvar_options
|
|
264
264
|
end
|
|
265
265
|
|
|
266
|
-
def outcome_table(table_options)
|
|
266
|
+
def outcome_table(**table_options)
|
|
267
267
|
@questionnaire.add_outcome_table table_options
|
|
268
268
|
end
|
|
269
269
|
|
|
@@ -10,8 +10,8 @@ module Quby
|
|
|
10
10
|
attr_reader :type
|
|
11
11
|
attr_reader :questionnaire
|
|
12
12
|
|
|
13
|
-
def initialize(key, options
|
|
14
|
-
@questionnaire =
|
|
13
|
+
def initialize(key, questionnaire:, **options)
|
|
14
|
+
@questionnaire = questionnaire
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def build
|
|
@@ -111,7 +111,7 @@ module Quby
|
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
module Subquestions
|
|
114
|
-
def initialize(key, options
|
|
114
|
+
def initialize(key, **options, &block)
|
|
115
115
|
super
|
|
116
116
|
@default_question_options = options[:default_question_options] || {}
|
|
117
117
|
@title_question = nil
|
|
@@ -126,7 +126,7 @@ module Quby
|
|
|
126
126
|
super
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
def title_question(key, options
|
|
129
|
+
def title_question(key, **options, &block)
|
|
130
130
|
options = @default_question_options.merge({depends_on: @question.key,
|
|
131
131
|
questionnaire: @questionnaire,
|
|
132
132
|
parent: @question,
|
|
@@ -135,13 +135,13 @@ module Quby
|
|
|
135
135
|
|
|
136
136
|
check_question_keys_uniqueness key, options, @questionnaire
|
|
137
137
|
|
|
138
|
-
question = QuestionBuilder.build(key, options, &block)
|
|
138
|
+
question = QuestionBuilder.build(key, **options, &block)
|
|
139
139
|
|
|
140
140
|
@questionnaire.register_question(question)
|
|
141
141
|
@title_question = question
|
|
142
142
|
end
|
|
143
143
|
|
|
144
|
-
def question(key, options
|
|
144
|
+
def question(key, **options, &block)
|
|
145
145
|
options = @default_question_options.merge(options)
|
|
146
146
|
.merge(questionnaire: @questionnaire,
|
|
147
147
|
parent: @question,
|
|
@@ -149,7 +149,7 @@ module Quby
|
|
|
149
149
|
|
|
150
150
|
check_question_keys_uniqueness key, options, @questionnaire
|
|
151
151
|
|
|
152
|
-
question = QuestionBuilder.build(key, options, &block)
|
|
152
|
+
question = QuestionBuilder.build(key, **options, &block)
|
|
153
153
|
|
|
154
154
|
@questionnaire.register_question(question)
|
|
155
155
|
@question.options.last.questions << question
|
|
@@ -9,10 +9,10 @@ module Quby
|
|
|
9
9
|
prepend CallsCustomMethods
|
|
10
10
|
include Helpers
|
|
11
11
|
|
|
12
|
-
def initialize(panel,
|
|
12
|
+
def initialize(panel, default_question_options: {}, **options)
|
|
13
13
|
@panel = panel
|
|
14
14
|
@table = Entities::Table.new(options)
|
|
15
|
-
@default_question_options =
|
|
15
|
+
@default_question_options = default_question_options
|
|
16
16
|
@panel.items << @table
|
|
17
17
|
end
|
|
18
18
|
|
|
@@ -24,11 +24,11 @@ module Quby
|
|
|
24
24
|
@table.description = value
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
-
def text(value, options
|
|
27
|
+
def text(value, **options)
|
|
28
28
|
@table.items << Entities::Text.new(value.to_s, options)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
def question(key, options
|
|
31
|
+
def question(key, **options, &block)
|
|
32
32
|
options = @default_question_options.merge(options)
|
|
33
33
|
.merge(table: @table,
|
|
34
34
|
questionnaire: @panel.questionnaire)
|
|
@@ -36,7 +36,7 @@ module Quby
|
|
|
36
36
|
check_question_keys_uniqueness key, options, @panel.questionnaire
|
|
37
37
|
fail "You can't create a slider in a table at the moment" if options[:as] == :slider
|
|
38
38
|
|
|
39
|
-
question = QuestionBuilder.build(key, options, &block)
|
|
39
|
+
question = QuestionBuilder.build(key, **options, &block)
|
|
40
40
|
|
|
41
41
|
@panel.questionnaire.register_question(question)
|
|
42
42
|
@table.items << question
|
|
@@ -10,13 +10,14 @@ module Quby
|
|
|
10
10
|
extend ActiveModel::Naming
|
|
11
11
|
include ActiveModel::Validations
|
|
12
12
|
|
|
13
|
-
attr_accessor :key, :sourcecode, :timestamp, :path
|
|
13
|
+
attr_accessor :key, :sourcecode, :timestamp, :path, :lookup_tables
|
|
14
14
|
|
|
15
|
-
def initialize(key:, path:, sourcecode: "", timestamp: nil)
|
|
15
|
+
def initialize(key:, path:, sourcecode: "", timestamp: nil, lookup_tables: {})
|
|
16
16
|
@path = path
|
|
17
17
|
@key = key
|
|
18
18
|
@sourcecode = sourcecode
|
|
19
19
|
@timestamp = timestamp
|
|
20
|
+
@lookup_tables = lookup_tables
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
validates_with Services::DefinitionValidator
|
|
@@ -15,6 +15,7 @@ module Quby
|
|
|
15
15
|
validates :score_keys, :subscore_keys, :questionnaire, :key, presence: true
|
|
16
16
|
validates :name, presence: true, if: proc { |table| table.default_collapsed }
|
|
17
17
|
validate :references_existing_score_keys
|
|
18
|
+
validate :no_outcome_tables_defined_in_score_schemas
|
|
18
19
|
|
|
19
20
|
def references_existing_score_keys
|
|
20
21
|
(score_keys - questionnaire.score_schemas.values.map(&:key)).each do |missing_key|
|
|
@@ -25,6 +26,17 @@ module Quby
|
|
|
25
26
|
errors.add :subscore_keys, "#{missing_key.inspect} not found in subscore schemas"
|
|
26
27
|
end
|
|
27
28
|
end
|
|
29
|
+
|
|
30
|
+
def no_outcome_tables_defined_in_score_schemas
|
|
31
|
+
if questionnaire.score_schemas.values.any? do |schema|
|
|
32
|
+
schema.subscore_schemas.any? do |subscore|
|
|
33
|
+
subscore.outcome_table != :main
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
errors.add :score_schemas,
|
|
37
|
+
"Outcome table associations defined in score schemas should not be combined with explicit outcome tables"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
28
40
|
end
|
|
29
41
|
end
|
|
30
42
|
end
|
|
@@ -283,7 +283,7 @@ module Quby
|
|
|
283
283
|
end
|
|
284
284
|
flag_options[:key] = flag_key
|
|
285
285
|
fail(ArgumentError, "Flag '#{flag_key}' already defined") if flags.key?(flag_key)
|
|
286
|
-
flags[flag_key] = Flag.new(flag_options)
|
|
286
|
+
flags[flag_key] = Flag.new(**flag_options)
|
|
287
287
|
end
|
|
288
288
|
|
|
289
289
|
def filter_flags(given_flags)
|
|
@@ -297,7 +297,7 @@ module Quby
|
|
|
297
297
|
textvar_options[:key] = textvar_key
|
|
298
298
|
validate_textvar_keys_unique(textvar_key)
|
|
299
299
|
validate_depends_on_flag(textvar_key, textvar_options)
|
|
300
|
-
textvars[textvar_key] = Textvar.new(textvar_options)
|
|
300
|
+
textvars[textvar_key] = Textvar.new(**textvar_options)
|
|
301
301
|
end
|
|
302
302
|
|
|
303
303
|
def filter_textvars(given_textvars)
|
|
@@ -5,6 +5,15 @@ module Quby
|
|
|
5
5
|
module Entities
|
|
6
6
|
module Questions
|
|
7
7
|
class FloatQuestion < Question
|
|
8
|
+
def as_json(options = {})
|
|
9
|
+
super.merge(
|
|
10
|
+
minimum: minimum,
|
|
11
|
+
maximum: maximum,
|
|
12
|
+
step: 0.01, # fixed in v1.
|
|
13
|
+
# defaultPosition: default_position # Needs discussion, can be number or string "hidden"
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
|
|
8
17
|
def size
|
|
9
18
|
@size || 30
|
|
10
19
|
end
|
|
@@ -5,6 +5,15 @@ module Quby
|
|
|
5
5
|
module Entities
|
|
6
6
|
module Questions
|
|
7
7
|
class IntegerQuestion < Question
|
|
8
|
+
def as_json(options = {})
|
|
9
|
+
super.merge(
|
|
10
|
+
minimum: minimum,
|
|
11
|
+
maximum: maximum,
|
|
12
|
+
step: 1, # fixed in v1.
|
|
13
|
+
# defaultPosition: default_position # Needs discussion, can be number or string "hidden"
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
|
|
8
17
|
def size
|
|
9
18
|
@size || 30
|
|
10
19
|
end
|
|
@@ -16,7 +16,8 @@ module Quby
|
|
|
16
16
|
attribute :calculation_key?, Types::Symbol
|
|
17
17
|
# [Optional argument] The name of the outcome table where this subscore should be shown. Used for cases where scores
|
|
18
18
|
# differ in subscores too much to be shown as one table. By default, all scores end up in the `:main` table.
|
|
19
|
-
|
|
19
|
+
# When outcome_table is explicitly nil, the value should not be shown in outcome tables
|
|
20
|
+
attribute :outcome_table, Types::Symbol.optional.default(:main)
|
|
20
21
|
end
|
|
21
22
|
end
|
|
22
23
|
end
|
|
@@ -11,7 +11,7 @@ module Quby
|
|
|
11
11
|
if block # defined in block for tests
|
|
12
12
|
questionnaire = DSL.build(key, path: path, &block)
|
|
13
13
|
else # sourcecode given as string
|
|
14
|
-
tempfile = Tempfile.new(key)
|
|
14
|
+
tempfile = Tempfile.new([key, '.rb'])
|
|
15
15
|
questionnaire = Entities::Questionnaire.new(key, last_update: last_update)
|
|
16
16
|
Thread.current["quby-questionnaire-loading"] = Quby::Compiler::DSL::QuestionnaireBuilder.new(questionnaire, lookup_tables: lookup_tables)
|
|
17
17
|
|
|
@@ -63,7 +63,7 @@ module Quby
|
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
def validate(key:, sourcecode:)
|
|
66
|
-
definition = Entities::Definition.new(key: key, sourcecode: sourcecode, path: "validating '#{key}'")
|
|
66
|
+
definition = Entities::Definition.new(key: key, sourcecode: sourcecode, path: "validating '#{key}'", lookup_tables: lookup_tables)
|
|
67
67
|
definition.valid?
|
|
68
68
|
definition
|
|
69
69
|
end
|
|
@@ -84,19 +84,56 @@ module Quby
|
|
|
84
84
|
# <subscore_key:Symbol>: <subscore.label:String> # headers for each subscore key for all tables.
|
|
85
85
|
|
|
86
86
|
def outcome_tables_schema
|
|
87
|
+
if questionnaire.outcome_tables.present?
|
|
88
|
+
outcome_tables_from_definition
|
|
89
|
+
else
|
|
90
|
+
outcome_tables_from_score_schemas
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def outcome_tables_from_definition
|
|
95
|
+
# hash of tables, with the score keys (rows) and subscore keys (columns) used for each
|
|
96
|
+
tables = {}
|
|
97
|
+
# hash of `subscore_key: subscore_label` pairs used in tables
|
|
98
|
+
headers = {}
|
|
99
|
+
|
|
100
|
+
questionnaire.outcome_tables.each do |table|
|
|
101
|
+
tables[table.key] = {name: table.name,
|
|
102
|
+
default_collapsed: table.default_collapsed,
|
|
103
|
+
score_keys: table.score_keys,
|
|
104
|
+
subscore_keys: table.subscore_keys}.compact
|
|
105
|
+
|
|
106
|
+
table.subscore_keys.each do |subscore_key|
|
|
107
|
+
table.score_keys.find do |score_key|
|
|
108
|
+
subschema = questionnaire.score_schemas[score_key].subscore_schemas.find do |subschema|
|
|
109
|
+
subschema.key == subscore_key
|
|
110
|
+
end
|
|
111
|
+
headers[subscore_key] = subschema&.label
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
{
|
|
117
|
+
headers: headers,
|
|
118
|
+
tables: tables,
|
|
119
|
+
}
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def outcome_tables_from_score_schemas
|
|
87
123
|
# hash of tables, with the score keys (rows) and subscore keys (columns) used for each
|
|
88
124
|
tables = Hash.new{ |hash, key| hash[key] = {score_keys: Set.new, subscore_keys: Set.new } }
|
|
89
125
|
# hash of `subscore_key: subscore_label` pairs used in tables
|
|
90
126
|
headers = {}
|
|
91
|
-
|
|
127
|
+
|
|
92
128
|
questionnaire.score_schemas.values.each do |schema|
|
|
93
129
|
schema.subscore_schemas.each do |subschema|
|
|
130
|
+
next if subschema.outcome_table.blank?
|
|
94
131
|
tables[subschema.outcome_table][:subscore_keys] << subschema.key
|
|
95
132
|
tables[subschema.outcome_table][:score_keys] << schema.key
|
|
96
133
|
headers[subschema.key] = subschema.label
|
|
97
134
|
end
|
|
98
135
|
end
|
|
99
|
-
|
|
136
|
+
|
|
100
137
|
{
|
|
101
138
|
headers: headers,
|
|
102
139
|
tables: tables,
|
|
@@ -25,12 +25,11 @@ module Quby
|
|
|
25
25
|
validate_outcome_tables(questionnaire)
|
|
26
26
|
validate_markdown_fields(questionnaire) if questionnaire.validate_html
|
|
27
27
|
validate_raw_content_items(questionnaire) if questionnaire.validate_html
|
|
28
|
-
validate_scores(questionnaire)
|
|
29
28
|
# Some compilation errors are Exceptions (pure syntax errors) and some StandardErrors (NameErrors)
|
|
30
29
|
rescue Exception => exception # rubocop:disable Lint/RescueException
|
|
31
30
|
definition.errors.add(:sourcecode, {message: "Questionnaire error: #{definition.key}\n" \
|
|
32
31
|
"#{exception.message}",
|
|
33
|
-
backtrace: exception.backtrace[0..
|
|
32
|
+
backtrace: exception.backtrace[0..20]})
|
|
34
33
|
end
|
|
35
34
|
|
|
36
35
|
def validate_fields(questionnaire)
|
|
@@ -81,6 +80,13 @@ module Quby
|
|
|
81
80
|
fail "Score #{score.key} does not have a score schema" unless score_schema
|
|
82
81
|
fail "Score label langer dan 100 tekens (geeft problemen oru accare)\n #{score_schema.label}" if score_schema.label&.length > 100
|
|
83
82
|
end
|
|
83
|
+
|
|
84
|
+
export_keys = questionnaire.score_schemas.flat_map { |_key, score_schema|
|
|
85
|
+
score_schema.subscore_schemas.map(&:export_key)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
duplicate_export_keys = export_keys.tally.select { |key, count| count > 1 }.keys
|
|
89
|
+
fail "Score export keys not unique, duplicates: #{duplicate_export_keys}" if duplicate_export_keys.present?
|
|
84
90
|
end
|
|
85
91
|
|
|
86
92
|
def validate_question_options(questionnaire, question)
|
|
@@ -241,8 +247,6 @@ scores_schema tables to the resulting seed."
|
|
|
241
247
|
|
|
242
248
|
def validate_score_label_present(score)
|
|
243
249
|
fail "Score #{score.key} label must be passed in as an option." unless score.label.present?
|
|
244
|
-
|
|
245
|
-
|
|
246
250
|
end
|
|
247
251
|
|
|
248
252
|
def validate_subquestion_absence_in_select(question)
|
|
@@ -292,19 +292,19 @@ module Quby
|
|
|
292
292
|
|
|
293
293
|
def strip_question_number_slashes(quests)
|
|
294
294
|
quests.transform_values! do |value|
|
|
295
|
-
value
|
|
295
|
+
value&.gsub /^(\s*\d+)\\/, '\1'
|
|
296
296
|
end
|
|
297
297
|
end
|
|
298
298
|
|
|
299
299
|
def process_scores
|
|
300
300
|
scores_from_schemas
|
|
301
301
|
end
|
|
302
|
-
|
|
302
|
+
|
|
303
303
|
def scores_from_schemas
|
|
304
304
|
score_headers = [] # headers outcome (humanized name for subscores)
|
|
305
305
|
score_keys = [] # headers data-export (not all of it, just the score_subscore part, shortened)
|
|
306
306
|
score_labels = [] # score names outcome (humanized name for score as a whole)
|
|
307
|
-
|
|
307
|
+
|
|
308
308
|
questionnaire.score_schemas.values.each do |score_schema|
|
|
309
309
|
score_labels << score_schema.label
|
|
310
310
|
score_keys << score_schema.subscore_schemas.map do |subschema|
|
|
@@ -318,18 +318,18 @@ module Quby
|
|
|
318
318
|
hash
|
|
319
319
|
end
|
|
320
320
|
end
|
|
321
|
-
|
|
321
|
+
|
|
322
322
|
headers = score_schema.subscore_schemas.map(&:label)
|
|
323
323
|
score_headers += headers - score_headers
|
|
324
324
|
end
|
|
325
|
-
|
|
325
|
+
|
|
326
326
|
{
|
|
327
327
|
headers: score_headers,
|
|
328
328
|
keys: score_keys,
|
|
329
329
|
labels: score_labels
|
|
330
330
|
}
|
|
331
331
|
end
|
|
332
|
-
|
|
332
|
+
|
|
333
333
|
class ShortenKeysUniq
|
|
334
334
|
def initialize
|
|
335
335
|
@seen_results = []
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: quby-compiler
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Marten Veldthuis
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-
|
|
11
|
+
date: 2021-07-19 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activemodel
|
|
@@ -271,7 +271,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
271
271
|
- !ruby/object:Gem::Version
|
|
272
272
|
version: '0'
|
|
273
273
|
requirements: []
|
|
274
|
-
rubygems_version: 3.1.
|
|
274
|
+
rubygems_version: 3.1.4
|
|
275
275
|
signing_key:
|
|
276
276
|
specification_version: 4
|
|
277
277
|
summary: Quby::Compiler compiles a DSL for questionnaires to JSON
|