quby-compiler 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +13 -0
- data/.gitlab-ci.yml +5 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Dockerfile +11 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +133 -0
- data/LICENSE.txt +21 -0
- data/README.md +44 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/rspec +29 -0
- data/bin/setup +8 -0
- data/config/locales/de.yml +58 -0
- data/config/locales/en.yml +57 -0
- data/config/locales/nl.yml +57 -0
- data/config/locales/rails-i18n/README.md +4 -0
- data/config/locales/rails-i18n/de.yml +223 -0
- data/config/locales/rails-i18n/en.yml +216 -0
- data/config/locales/rails-i18n/nl.yml +214 -0
- data/exe/quby-compile +56 -0
- data/lib/quby/array_attribute_valid_validator.rb +15 -0
- data/lib/quby/attribute_valid_validator.rb +14 -0
- data/lib/quby/compiler.rb +50 -0
- data/lib/quby/compiler/dsl.rb +29 -0
- data/lib/quby/compiler/dsl/base.rb +20 -0
- data/lib/quby/compiler/dsl/calls_custom_methods.rb +29 -0
- data/lib/quby/compiler/dsl/charting/bar_chart_builder.rb +14 -0
- data/lib/quby/compiler/dsl/charting/chart_builder.rb +95 -0
- data/lib/quby/compiler/dsl/charting/line_chart_builder.rb +34 -0
- data/lib/quby/compiler/dsl/charting/overview_chart_builder.rb +31 -0
- data/lib/quby/compiler/dsl/charting/radar_chart_builder.rb +14 -0
- data/lib/quby/compiler/dsl/helpers.rb +53 -0
- data/lib/quby/compiler/dsl/panel_builder.rb +80 -0
- data/lib/quby/compiler/dsl/question_builder.rb +40 -0
- data/lib/quby/compiler/dsl/questionnaire_builder.rb +279 -0
- data/lib/quby/compiler/dsl/questions/base.rb +180 -0
- data/lib/quby/compiler/dsl/questions/checkbox_question_builder.rb +20 -0
- data/lib/quby/compiler/dsl/questions/date_question_builder.rb +18 -0
- data/lib/quby/compiler/dsl/questions/deprecated_question_builder.rb +18 -0
- data/lib/quby/compiler/dsl/questions/float_question_builder.rb +21 -0
- data/lib/quby/compiler/dsl/questions/integer_question_builder.rb +21 -0
- data/lib/quby/compiler/dsl/questions/radio_question_builder.rb +20 -0
- data/lib/quby/compiler/dsl/questions/select_question_builder.rb +18 -0
- data/lib/quby/compiler/dsl/questions/string_question_builder.rb +20 -0
- data/lib/quby/compiler/dsl/questions/text_question_builder.rb +22 -0
- data/lib/quby/compiler/dsl/score_builder.rb +22 -0
- data/lib/quby/compiler/dsl/score_schema_builder.rb +53 -0
- data/lib/quby/compiler/dsl/standardized_panel_generators.rb +33 -0
- data/lib/quby/compiler/dsl/table_builder.rb +48 -0
- data/lib/quby/compiler/entities.rb +38 -0
- data/lib/quby/compiler/entities/charting/bar_chart.rb +17 -0
- data/lib/quby/compiler/entities/charting/chart.rb +101 -0
- data/lib/quby/compiler/entities/charting/charts.rb +42 -0
- data/lib/quby/compiler/entities/charting/line_chart.rb +38 -0
- data/lib/quby/compiler/entities/charting/overview_chart.rb +20 -0
- data/lib/quby/compiler/entities/charting/plottable.rb +20 -0
- data/lib/quby/compiler/entities/charting/radar_chart.rb +17 -0
- data/lib/quby/compiler/entities/definition.rb +26 -0
- data/lib/quby/compiler/entities/fields.rb +119 -0
- data/lib/quby/compiler/entities/flag.rb +55 -0
- data/lib/quby/compiler/entities/item.rb +40 -0
- data/lib/quby/compiler/entities/lookup_tables.rb +71 -0
- data/lib/quby/compiler/entities/outcome_table.rb +31 -0
- data/lib/quby/compiler/entities/panel.rb +82 -0
- data/lib/quby/compiler/entities/question.rb +365 -0
- data/lib/quby/compiler/entities/question_option.rb +96 -0
- data/lib/quby/compiler/entities/questionnaire.rb +440 -0
- data/lib/quby/compiler/entities/questions/checkbox_question.rb +82 -0
- data/lib/quby/compiler/entities/questions/date_question.rb +84 -0
- data/lib/quby/compiler/entities/questions/deprecated_question.rb +19 -0
- data/lib/quby/compiler/entities/questions/float_question.rb +15 -0
- data/lib/quby/compiler/entities/questions/integer_question.rb +15 -0
- data/lib/quby/compiler/entities/questions/radio_question.rb +19 -0
- data/lib/quby/compiler/entities/questions/select_question.rb +19 -0
- data/lib/quby/compiler/entities/questions/string_question.rb +15 -0
- data/lib/quby/compiler/entities/questions/text_question.rb +15 -0
- data/lib/quby/compiler/entities/score_calculation.rb +35 -0
- data/lib/quby/compiler/entities/score_schema.rb +25 -0
- data/lib/quby/compiler/entities/subscore_schema.rb +23 -0
- data/lib/quby/compiler/entities/table.rb +143 -0
- data/lib/quby/compiler/entities/text.rb +71 -0
- data/lib/quby/compiler/entities/textvar.rb +23 -0
- data/lib/quby/compiler/entities/validation.rb +17 -0
- data/lib/quby/compiler/entities/version.rb +23 -0
- data/lib/quby/compiler/entities/visibility_rule.rb +71 -0
- data/lib/quby/compiler/instance.rb +72 -0
- data/lib/quby/compiler/output.rb +13 -0
- data/lib/quby/compiler/outputs.rb +4 -0
- data/lib/quby/compiler/outputs/quby_frontend_v1_serializer.rb +362 -0
- data/lib/quby/compiler/outputs/quby_frontend_v2_serializer.rb +15 -0
- data/lib/quby/compiler/outputs/roqua_serializer.rb +108 -0
- data/lib/quby/compiler/outputs/seed_serializer.rb +34 -0
- data/lib/quby/compiler/services/definition_validator.rb +330 -0
- data/lib/quby/compiler/services/quby_proxy.rb +405 -0
- data/lib/quby/compiler/services/seed_diff.rb +116 -0
- data/lib/quby/compiler/services/text_transformation.rb +30 -0
- data/lib/quby/compiler/version.rb +5 -0
- data/lib/quby/markdown_parser.rb +38 -0
- data/lib/quby/range_categories.rb +38 -0
- data/lib/quby/settings.rb +86 -0
- data/lib/quby/text_transformation.rb +26 -0
- data/lib/quby/type_validator.rb +12 -0
- data/quby-compiler.gemspec +39 -0
- metadata +277 -0
@@ -0,0 +1,180 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quby
|
4
|
+
module Compiler
|
5
|
+
module DSL
|
6
|
+
module Questions
|
7
|
+
class Base < ::Quby::Compiler::DSL::Base
|
8
|
+
attr_reader :key
|
9
|
+
attr_reader :title
|
10
|
+
attr_reader :type
|
11
|
+
attr_reader :questionnaire
|
12
|
+
|
13
|
+
def initialize(key, options = {})
|
14
|
+
@questionnaire = options[:questionnaire]
|
15
|
+
end
|
16
|
+
|
17
|
+
def build
|
18
|
+
@question
|
19
|
+
end
|
20
|
+
|
21
|
+
def title(value)
|
22
|
+
@question.title = value
|
23
|
+
end
|
24
|
+
|
25
|
+
def context_free_title(value)
|
26
|
+
@question.context_free_title = value
|
27
|
+
end
|
28
|
+
|
29
|
+
def description(value)
|
30
|
+
@question.description = value
|
31
|
+
end
|
32
|
+
|
33
|
+
def presentation(value)
|
34
|
+
@question.presentation = value
|
35
|
+
end
|
36
|
+
|
37
|
+
def hidden(value = true)
|
38
|
+
@question.hidden = value
|
39
|
+
end
|
40
|
+
|
41
|
+
def depends_on(keys)
|
42
|
+
@question.set_depends_on(keys)
|
43
|
+
end
|
44
|
+
|
45
|
+
def default_position(value)
|
46
|
+
@question.default_position = value
|
47
|
+
end
|
48
|
+
|
49
|
+
# TODO not referenced in definitions?
|
50
|
+
def validates_presence_of_answer(options = {})
|
51
|
+
@question.validations ||= []
|
52
|
+
@question.validations << {type: :requires_answer}.reverse_merge(options)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module RegexpValidations
|
57
|
+
def validates_format_with(regexp, options = {})
|
58
|
+
@question.validations ||= []
|
59
|
+
@question.validations << {type: :regexp, matcher: regexp}.reverse_merge(options)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
module MinMaxValidations
|
64
|
+
def validates_minimum(value, options = {})
|
65
|
+
subtype = @question.type == :date ? :date : :number
|
66
|
+
@question.validations ||= []
|
67
|
+
@question.validations << {type: :minimum, value: value, subtype: subtype}.reverse_merge(options)
|
68
|
+
end
|
69
|
+
|
70
|
+
def validates_maximum(value, options = {})
|
71
|
+
subtype = @question.type == :date ? :date : :number
|
72
|
+
@question.validations ||= []
|
73
|
+
@question.validations << {type: :maximum, value: value, subtype: subtype}.reverse_merge(options)
|
74
|
+
end
|
75
|
+
|
76
|
+
def validates_in_range(range, options = {})
|
77
|
+
subtype = @question.type == :date ? :date : :number
|
78
|
+
@question.validations ||= []
|
79
|
+
@question.validations << {type: :minimum, value: range.first, subtype: subtype}.reverse_merge(options)
|
80
|
+
@question.validations << {type: :maximum, value: range.last, subtype: subtype}.reverse_merge(options)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
module Labeling
|
85
|
+
def label(value)
|
86
|
+
@question.labels << value
|
87
|
+
end
|
88
|
+
|
89
|
+
# deprecated
|
90
|
+
def left_label(value)
|
91
|
+
@question.labels.unshift(value)
|
92
|
+
end
|
93
|
+
|
94
|
+
# deprecated
|
95
|
+
def right_label(value)
|
96
|
+
@question.labels << value
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
module MultipleChoice
|
101
|
+
def option(key, options = {}, &block)
|
102
|
+
question_option = Entities::QuestionOption.new(key, @question, options)
|
103
|
+
if @questionnaire.key_in_use?(question_option.input_key) || @question.key_in_use?(question_option.input_key)
|
104
|
+
fail "#{questionnaire.key}:#{@question.key}:#{question_option.key}: " \
|
105
|
+
"A question or option with input key #{question_option.input_key} is already defined."
|
106
|
+
end
|
107
|
+
|
108
|
+
@question.options << question_option
|
109
|
+
instance_eval(&block) if block
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
module Subquestions
|
114
|
+
def initialize(key, options = {}, &block)
|
115
|
+
super
|
116
|
+
@default_question_options = options[:default_question_options] || {}
|
117
|
+
@title_question = nil
|
118
|
+
end
|
119
|
+
|
120
|
+
def build
|
121
|
+
if @title_question
|
122
|
+
@question.options.last.questions << @title_question
|
123
|
+
@title_question = nil
|
124
|
+
end
|
125
|
+
|
126
|
+
super
|
127
|
+
end
|
128
|
+
|
129
|
+
def title_question(key, options = {}, &block)
|
130
|
+
options = @default_question_options.merge({depends_on: @question.key,
|
131
|
+
questionnaire: @questionnaire,
|
132
|
+
parent: @question,
|
133
|
+
presentation: :next_to_title,
|
134
|
+
allow_blank_titles: @question.allow_blank_titles}.merge(options))
|
135
|
+
|
136
|
+
check_question_keys_uniqueness key, options, @questionnaire
|
137
|
+
|
138
|
+
question = QuestionBuilder.build(key, options, &block)
|
139
|
+
|
140
|
+
@questionnaire.register_question(question)
|
141
|
+
@title_question = question
|
142
|
+
end
|
143
|
+
|
144
|
+
def question(key, options = {}, &block)
|
145
|
+
options = @default_question_options.merge(options)
|
146
|
+
.merge(questionnaire: @questionnaire,
|
147
|
+
parent: @question,
|
148
|
+
parent_option_key: @question.options.last.key)
|
149
|
+
|
150
|
+
check_question_keys_uniqueness key, options, @questionnaire
|
151
|
+
|
152
|
+
question = QuestionBuilder.build(key, options, &block)
|
153
|
+
|
154
|
+
@questionnaire.register_question(question)
|
155
|
+
@question.options.last.questions << question
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
module InnerTitles
|
160
|
+
def inner_title(value)
|
161
|
+
question_option = Entities::QuestionOption.new(nil, @question, inner_title: true, description: value)
|
162
|
+
@question.options << question_option
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
module Units
|
167
|
+
def unit(value)
|
168
|
+
@question.unit = value
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
module Sizes
|
173
|
+
def size(value)
|
174
|
+
@question.size = value
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quby
|
4
|
+
module Compiler
|
5
|
+
module DSL
|
6
|
+
module Questions
|
7
|
+
class CheckboxQuestionBuilder < Base
|
8
|
+
include MultipleChoice
|
9
|
+
include Subquestions
|
10
|
+
include InnerTitles
|
11
|
+
|
12
|
+
def initialize(key, options = {}, &block)
|
13
|
+
super
|
14
|
+
@question = Entities::Questions::CheckboxQuestion.new(key, options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quby
|
4
|
+
module Compiler
|
5
|
+
module DSL
|
6
|
+
module Questions
|
7
|
+
class DateQuestionBuilder < Base
|
8
|
+
include MinMaxValidations
|
9
|
+
|
10
|
+
def initialize(key, options = {}, &block)
|
11
|
+
super
|
12
|
+
@question = Entities::Questions::DateQuestion.new(key, options)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quby
|
4
|
+
module Compiler
|
5
|
+
module DSL
|
6
|
+
module Questions
|
7
|
+
class DeprecatedQuestionBuilder < Base
|
8
|
+
include MultipleChoice
|
9
|
+
|
10
|
+
def initialize(key, options = {}, &block)
|
11
|
+
super
|
12
|
+
@question = Entities::Questions::DeprecatedQuestion.new(key, options)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quby
|
4
|
+
module Compiler
|
5
|
+
module DSL
|
6
|
+
module Questions
|
7
|
+
class FloatQuestionBuilder < Base
|
8
|
+
include MinMaxValidations
|
9
|
+
include Labeling
|
10
|
+
include Units
|
11
|
+
include Sizes
|
12
|
+
|
13
|
+
def initialize(key, options = {}, &block)
|
14
|
+
super
|
15
|
+
@question = Entities::Questions::FloatQuestion.new(key, options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quby
|
4
|
+
module Compiler
|
5
|
+
module DSL
|
6
|
+
module Questions
|
7
|
+
class IntegerQuestionBuilder < Base
|
8
|
+
include MinMaxValidations
|
9
|
+
include Labeling
|
10
|
+
include Units
|
11
|
+
include Sizes
|
12
|
+
|
13
|
+
def initialize(key, options = {}, &block)
|
14
|
+
super
|
15
|
+
@question = Entities::Questions::IntegerQuestion.new(key, options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quby
|
4
|
+
module Compiler
|
5
|
+
module DSL
|
6
|
+
module Questions
|
7
|
+
class RadioQuestionBuilder < Base
|
8
|
+
include MultipleChoice
|
9
|
+
include Subquestions
|
10
|
+
include InnerTitles
|
11
|
+
|
12
|
+
def initialize(key, options = {}, &block)
|
13
|
+
super
|
14
|
+
@question = Entities::Questions::RadioQuestion.new(key, options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quby
|
4
|
+
module Compiler
|
5
|
+
module DSL
|
6
|
+
module Questions
|
7
|
+
class SelectQuestionBuilder < Base
|
8
|
+
include MultipleChoice
|
9
|
+
|
10
|
+
def initialize(key, options = {}, &block)
|
11
|
+
super
|
12
|
+
@question = Entities::Questions::SelectQuestion.new(key, options)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quby
|
4
|
+
module Compiler
|
5
|
+
module DSL
|
6
|
+
module Questions
|
7
|
+
class StringQuestionBuilder < Base
|
8
|
+
include RegexpValidations
|
9
|
+
include Units
|
10
|
+
include Sizes
|
11
|
+
|
12
|
+
def initialize(key, options = {}, &block)
|
13
|
+
super
|
14
|
+
@question = Entities::Questions::StringQuestion.new(key, options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quby
|
4
|
+
module Compiler
|
5
|
+
module DSL
|
6
|
+
module Questions
|
7
|
+
class TextQuestionBuilder < Base
|
8
|
+
include RegexpValidations
|
9
|
+
|
10
|
+
def initialize(key, options = {}, &block)
|
11
|
+
super
|
12
|
+
@question = Entities::Questions::TextQuestion.new(key, options)
|
13
|
+
end
|
14
|
+
|
15
|
+
def lines(value)
|
16
|
+
@question.lines = value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'quby/compiler/entities'
|
4
|
+
|
5
|
+
module Quby
|
6
|
+
module Compiler
|
7
|
+
module DSL
|
8
|
+
class ScoreBuilder
|
9
|
+
attr_reader :key
|
10
|
+
attr_reader :calculation
|
11
|
+
|
12
|
+
def initialize(key, options = {}, &block)
|
13
|
+
@score = Entities::ScoreCalculation.new(key, options, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def build
|
17
|
+
@score
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'quby/compiler/entities'
|
2
|
+
|
3
|
+
module Quby
|
4
|
+
module Compiler
|
5
|
+
module DSL
|
6
|
+
class ScoreSchemaBuilder < Base
|
7
|
+
def initialize(key:, label:, &block)
|
8
|
+
@score_key = key
|
9
|
+
@score_label = label
|
10
|
+
@subschema_params = []
|
11
|
+
@generated_calculations = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def build
|
15
|
+
score_schema = Entities::ScoreSchema.new key: @score_key,
|
16
|
+
label: @score_label,
|
17
|
+
subscore_schemas: @subschema_params
|
18
|
+
[score_schema, @generated_calculations + [generate_score_calculation(score_schema)]]
|
19
|
+
end
|
20
|
+
|
21
|
+
def subscore(key, label, **options, &block)
|
22
|
+
if block
|
23
|
+
# Generate a key to go with the subscore calculation made from the given block and save it inside the schema
|
24
|
+
calculation_key = :"_#{@score_key}.#{key}"
|
25
|
+
calculation = Entities::ScoreCalculation.new calculation_key,
|
26
|
+
label: "#{@score_label} #{label}",
|
27
|
+
&block
|
28
|
+
@generated_calculations << calculation
|
29
|
+
options.merge!(calculation_key: calculation_key)
|
30
|
+
end
|
31
|
+
@subschema_params << options.merge(key: key, label: label)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def generate_score_calculation(score_schema)
|
37
|
+
inner_hash_string = score_schema.subscore_schemas.map do |subschema|
|
38
|
+
":#{subschema.key} => score(:'#{subschema.calculation_key}')"
|
39
|
+
end.join(",\n ")
|
40
|
+
# method-source can only grab whole lines of implementation. For regular questionnaires
|
41
|
+
# this means calculation.sourcecode includes the surrounding score/attention/completion/etc. call.
|
42
|
+
# This surrounding call will be stripped after reading in the source in quby.
|
43
|
+
# We add a fake `score do` call around this generated implementation so the stripping will work correctly
|
44
|
+
score_code_string = "score do\n {#{inner_hash_string}}\nend"
|
45
|
+
Entities::ScoreCalculation.new score_schema.key,
|
46
|
+
label: score_schema.label,
|
47
|
+
score: true,
|
48
|
+
ruby_string: score_code_string
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|