quby-compiler 0.5.19 → 0.5.20
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/CHANGELOG.md +5 -0
- data/lib/quby/compiler/dsl/helpers.rb +6 -0
- data/lib/quby/compiler/dsl/info_block_builder.rb +44 -0
- data/lib/quby/compiler/dsl/panel_builder.rb +9 -0
- data/lib/quby/compiler/dsl/questionnaire_builder.rb +1 -0
- data/lib/quby/compiler/entities/fields.rb +4 -1
- data/lib/quby/compiler/entities/info_block.rb +28 -0
- data/lib/quby/compiler/entities/question.rb +4 -0
- data/lib/quby/compiler/entities/question_option.rb +4 -0
- data/lib/quby/compiler/entities.rb +1 -0
- data/lib/quby/compiler/outputs/quby_frontend_v1_serializer.rb +3 -1
- data/lib/quby/compiler/outputs/quby_frontend_v2_serializer.rb +12 -0
- data/lib/quby/compiler/services/definition_validator.rb +19 -11
- data/lib/quby/compiler/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58538613874bd655f416eba086f07ba45321bab1306a6bd710df279e3a9cead0
|
4
|
+
data.tar.gz: 1a0c1ea24a9c0fd6e8387f6b1760e14d387e1ed41061d66c8176bf642e72f64e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68251dfd41c4d5054e0d23c7cfa202f6acced87251d2f16b9373c5494d2cbea52955d241479d807e11af8617ced647b49769204b38907bb3728d045a254431cb
|
7
|
+
data.tar.gz: 6f34cd861fec8ae281c6fffb8dea442054d5500f5e90fb5ff3594cf1d41e3dd28200e601edc29f05e68e7be32653e084f2e5c5c02ea92cbdac87c64c6581e438
|
data/CHANGELOG.md
CHANGED
@@ -24,6 +24,12 @@ module Quby
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
def check_key_uniqueness(key, questionnaire:)
|
28
|
+
if questionnaire.key_in_use? key
|
29
|
+
fail "#{questionnaire.key}:#{key}: is already used."
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
27
33
|
def video_tag(*urls, poster: nil, autoplay: false, loop: false)
|
28
34
|
# assume the file extension is the video format
|
29
35
|
# otherwise, the host's declared mime type is used to figure out compatibility
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'quby/compiler/entities'
|
4
|
+
|
5
|
+
module Quby
|
6
|
+
module Compiler
|
7
|
+
module DSL
|
8
|
+
class InfoBlockBuilder < Base
|
9
|
+
attr_reader :info_block, :default_question_options
|
10
|
+
|
11
|
+
delegate :panel, to: :info_block
|
12
|
+
delegate :questionnaire, to: :panel
|
13
|
+
|
14
|
+
def initialize(key, start_open: true, panel:, default_question_options:)
|
15
|
+
@info_block = Entities::InfoBlock.new(key: , panel:, start_open:)
|
16
|
+
@default_question_options = default_question_options
|
17
|
+
check_key_uniqueness(key, questionnaire:)
|
18
|
+
questionnaire.fields.info_block_keys << key
|
19
|
+
panel.items << @info_block
|
20
|
+
end
|
21
|
+
|
22
|
+
def info_html(value)
|
23
|
+
raise "Can only add one info_html item per info_block" if info_block.html.present?
|
24
|
+
info_block.html = value
|
25
|
+
end
|
26
|
+
|
27
|
+
def html(value)
|
28
|
+
info_block.items << Entities::Text.new('', html_content: value.to_s)
|
29
|
+
end
|
30
|
+
|
31
|
+
def question(key, **options, &block)
|
32
|
+
options = default_question_options.merge(options).merge(questionnaire:)
|
33
|
+
|
34
|
+
check_question_keys_uniqueness key, options, questionnaire
|
35
|
+
|
36
|
+
question = QuestionBuilder.build(key, **options, &block)
|
37
|
+
|
38
|
+
questionnaire.register_question(question)
|
39
|
+
info_block.items << question
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -65,6 +65,15 @@ module Quby
|
|
65
65
|
table_builder.instance_eval(&block) if block
|
66
66
|
end
|
67
67
|
|
68
|
+
def info_block(key, **options, &block)
|
69
|
+
info_block_builder = DSL::InfoBlockBuilder.new \
|
70
|
+
key,
|
71
|
+
panel: @panel,
|
72
|
+
default_question_options: @default_question_options,
|
73
|
+
**options
|
74
|
+
info_block_builder.instance_eval(&block)
|
75
|
+
end
|
76
|
+
|
68
77
|
def method_missing(method_sym, *args, **kwargs, &block)
|
69
78
|
if @custom_methods.key? method_sym
|
70
79
|
instance_exec(*args, **kwargs, &@custom_methods[method_sym])
|
@@ -9,6 +9,7 @@ require 'quby/compiler/dsl/charting/radar_chart_builder'
|
|
9
9
|
require 'quby/compiler/dsl/charting/bar_chart_builder'
|
10
10
|
require 'quby/compiler/dsl/charting/overview_chart_builder'
|
11
11
|
require 'quby/compiler/dsl/sexp_variable_builder'
|
12
|
+
require 'quby/compiler/dsl/info_block_builder'
|
12
13
|
|
13
14
|
require_relative 'standardized_panel_generators'
|
14
15
|
|
@@ -23,11 +23,14 @@ module Quby
|
|
23
23
|
# targeted by :depends_on relations.
|
24
24
|
attr_reader :input_keys
|
25
25
|
|
26
|
+
attr_reader :info_block_keys
|
27
|
+
|
26
28
|
def initialize(questionnaire)
|
27
29
|
@question_hash = HashWithIndifferentAccess.new
|
28
30
|
@option_hash = HashWithIndifferentAccess.new
|
29
31
|
@answer_keys = Set.new
|
30
32
|
@input_keys = Set.new
|
33
|
+
@info_block_keys = Set.new
|
31
34
|
@questionnaire = questionnaire
|
32
35
|
end
|
33
36
|
|
@@ -59,7 +62,7 @@ module Quby
|
|
59
62
|
end
|
60
63
|
|
61
64
|
def key_in_use?(key)
|
62
|
-
@question_hash.key?(key) || input_keys.include?(key.to_sym)
|
65
|
+
@question_hash.key?(key) || input_keys.include?(key.to_sym) || info_block_keys.include?(key)
|
63
66
|
end
|
64
67
|
|
65
68
|
# Given a list of question and option keys returns a list of input-keys. If a given key is a question-key,
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Quby
|
2
|
+
module Compiler
|
3
|
+
module Entities
|
4
|
+
class InfoBlock < Item
|
5
|
+
attr_reader :key, :items, :start_open, :panel
|
6
|
+
attr_accessor :html
|
7
|
+
|
8
|
+
validates :key, presence: true, 'quby/compiler/type': {is_a: Symbol}
|
9
|
+
validates :html, presence: true
|
10
|
+
|
11
|
+
def initialize(key:, panel:, start_open: true)
|
12
|
+
@panel = panel
|
13
|
+
@key = key
|
14
|
+
@start_open = start_open
|
15
|
+
@items = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def index
|
19
|
+
panel.items.index(self)
|
20
|
+
end
|
21
|
+
|
22
|
+
def path_str
|
23
|
+
"#{panel.questionnaire.key}:InfoBlock:#{key}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -24,6 +24,7 @@ require 'quby/compiler/entities/charting/plottable'
|
|
24
24
|
require 'quby/compiler/entities/panel'
|
25
25
|
require 'quby/compiler/entities/text'
|
26
26
|
require 'quby/compiler/entities/table'
|
27
|
+
require 'quby/compiler/entities/info_block'
|
27
28
|
|
28
29
|
require 'quby/compiler/entities/outcome_table'
|
29
30
|
|
@@ -15,7 +15,7 @@ module Quby
|
|
15
15
|
{
|
16
16
|
key: panel.key,
|
17
17
|
title: panel.title,
|
18
|
-
items: panel.items.reject { |item| item.respond_to?(:table) && item.table }.
|
18
|
+
items: panel.items.reject { |item| item.respond_to?(:table) && item.table }.flat_map { |item| item_as_json(item) }
|
19
19
|
}
|
20
20
|
end
|
21
21
|
end
|
@@ -28,6 +28,8 @@ module Quby
|
|
28
28
|
question_as_json(item)
|
29
29
|
when Quby::Compiler::Entities::Table
|
30
30
|
table_as_json(item)
|
31
|
+
when Quby::Compiler::Entities::InfoBlock
|
32
|
+
item.items.map { item_as_json(_1) }
|
31
33
|
end
|
32
34
|
end
|
33
35
|
|
@@ -44,11 +44,23 @@ module Quby
|
|
44
44
|
when Quby::Compiler::Entities::Question
|
45
45
|
return if item.table # things inside a table are added to the table, AND ALSO to the panel. skip them.
|
46
46
|
{ type: 'question', key: item.key }
|
47
|
+
when Quby::Compiler::Entities::InfoBlock
|
48
|
+
info_block_item(item)
|
47
49
|
when Quby::Compiler::Entities::Table
|
48
50
|
{ type: "table" }
|
49
51
|
end
|
50
52
|
end
|
51
53
|
|
54
|
+
def info_block_item(info_block)
|
55
|
+
{
|
56
|
+
type: 'info',
|
57
|
+
key: info_block.key,
|
58
|
+
html: handle_html(info_block.html, type: :question_description, v1_markdown: false),
|
59
|
+
startOpen: info_block.start_open,
|
60
|
+
items: info_block.items.map { panel_item(_1) }.compact
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
52
64
|
def questions
|
53
65
|
fields.question_hash \
|
54
66
|
.to_h { |k, question| [k, question(question)] } \
|
@@ -27,6 +27,7 @@ module Quby
|
|
27
27
|
validate_markdown_fields(questionnaire) if questionnaire.validate_html
|
28
28
|
validate_raw_content_items(questionnaire) if questionnaire.validate_html
|
29
29
|
validate_sexp_variables(questionnaire)
|
30
|
+
validate_info_blocks(questionnaire)
|
30
31
|
# Some compilation errors are Exceptions (pure syntax errors) and some StandardErrors (NameErrors)
|
31
32
|
rescue Exception => exception # rubocop:disable Lint/RescueException
|
32
33
|
definition.errors.add(:sourcecode, message: "Questionnaire error: #{definition.key}\n" \
|
@@ -67,7 +68,7 @@ module Quby
|
|
67
68
|
end
|
68
69
|
|
69
70
|
questionnaire.question_hash.each_value do |question|
|
70
|
-
|
71
|
+
validate_item(question)
|
71
72
|
subquestions_cant_have_default_invisible question
|
72
73
|
validate_subquestion_absence_in_select question
|
73
74
|
validate_placeholder_options_nil_values question
|
@@ -79,10 +80,10 @@ module Quby
|
|
79
80
|
end
|
80
81
|
end
|
81
82
|
|
82
|
-
def
|
83
|
-
|
84
|
-
|
85
|
-
|
83
|
+
def validate_item(item)
|
84
|
+
return if item.valid?
|
85
|
+
|
86
|
+
fail "#{item.path_str} is invalid: #{item.errors.full_messages.join(', ')}"
|
86
87
|
end
|
87
88
|
|
88
89
|
def validate_scores(questionnaire)
|
@@ -105,12 +106,9 @@ module Quby
|
|
105
106
|
|
106
107
|
def validate_question_options(questionnaire, question)
|
107
108
|
question.options.each do |option|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
end
|
112
|
-
to_be_hidden_questions_exist_and_not_subquestion?(questionnaire, option, msg_base: msg_base)
|
113
|
-
to_be_shown_questions_exist_and_not_subquestion?(questionnaire, option, msg_base: msg_base)
|
109
|
+
validate_item(option)
|
110
|
+
to_be_hidden_questions_exist_and_not_subquestion?(questionnaire, option, msg_base: option.path_str)
|
111
|
+
to_be_shown_questions_exist_and_not_subquestion?(questionnaire, option, msg_base: option.path_str)
|
114
112
|
end
|
115
113
|
end
|
116
114
|
|
@@ -140,6 +138,16 @@ module Quby
|
|
140
138
|
end
|
141
139
|
end
|
142
140
|
|
141
|
+
def validate_info_blocks(questionnaire)
|
142
|
+
questionnaire.panels.each do |panel|
|
143
|
+
panel.items.each do |item|
|
144
|
+
next unless item.is_a?(Entities::InfoBlock)
|
145
|
+
|
146
|
+
validate_item(item)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
143
151
|
def ensure_valid_descriptions(questionnaire, flag)
|
144
152
|
unless (flag.description_false.present? && flag.description_true.present?) || flag.description.present?
|
145
153
|
fail ArgumentError, "Flag '#{flag.key}' Requires at least either both description_true and description_false or a description"
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quby-compiler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.20
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marten Veldthuis
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-05-
|
10
|
+
date: 2025-05-22 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: activemodel
|
@@ -150,6 +150,7 @@ files:
|
|
150
150
|
- lib/quby/compiler/dsl/charting/overview_chart_builder.rb
|
151
151
|
- lib/quby/compiler/dsl/charting/radar_chart_builder.rb
|
152
152
|
- lib/quby/compiler/dsl/helpers.rb
|
153
|
+
- lib/quby/compiler/dsl/info_block_builder.rb
|
153
154
|
- lib/quby/compiler/dsl/panel_builder.rb
|
154
155
|
- lib/quby/compiler/dsl/question_builder.rb
|
155
156
|
- lib/quby/compiler/dsl/questionnaire_builder.rb
|
@@ -180,6 +181,7 @@ files:
|
|
180
181
|
- lib/quby/compiler/entities/definition.rb
|
181
182
|
- lib/quby/compiler/entities/fields.rb
|
182
183
|
- lib/quby/compiler/entities/flag.rb
|
184
|
+
- lib/quby/compiler/entities/info_block.rb
|
183
185
|
- lib/quby/compiler/entities/item.rb
|
184
186
|
- lib/quby/compiler/entities/lookup_tables.rb
|
185
187
|
- lib/quby/compiler/entities/outcome_table.rb
|