quby-compiler 0.2.1

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.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.gitlab-ci.yml +5 -0
  4. data/.rspec +3 -0
  5. data/.ruby-version +1 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Dockerfile +11 -0
  8. data/Gemfile +8 -0
  9. data/Gemfile.lock +133 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +44 -0
  12. data/Rakefile +6 -0
  13. data/bin/console +14 -0
  14. data/bin/rspec +29 -0
  15. data/bin/setup +8 -0
  16. data/config/locales/de.yml +58 -0
  17. data/config/locales/en.yml +57 -0
  18. data/config/locales/nl.yml +57 -0
  19. data/config/locales/rails-i18n/README.md +4 -0
  20. data/config/locales/rails-i18n/de.yml +223 -0
  21. data/config/locales/rails-i18n/en.yml +216 -0
  22. data/config/locales/rails-i18n/nl.yml +214 -0
  23. data/exe/quby-compile +56 -0
  24. data/lib/quby/array_attribute_valid_validator.rb +15 -0
  25. data/lib/quby/attribute_valid_validator.rb +14 -0
  26. data/lib/quby/compiler.rb +50 -0
  27. data/lib/quby/compiler/dsl.rb +29 -0
  28. data/lib/quby/compiler/dsl/base.rb +20 -0
  29. data/lib/quby/compiler/dsl/calls_custom_methods.rb +29 -0
  30. data/lib/quby/compiler/dsl/charting/bar_chart_builder.rb +14 -0
  31. data/lib/quby/compiler/dsl/charting/chart_builder.rb +95 -0
  32. data/lib/quby/compiler/dsl/charting/line_chart_builder.rb +34 -0
  33. data/lib/quby/compiler/dsl/charting/overview_chart_builder.rb +31 -0
  34. data/lib/quby/compiler/dsl/charting/radar_chart_builder.rb +14 -0
  35. data/lib/quby/compiler/dsl/helpers.rb +53 -0
  36. data/lib/quby/compiler/dsl/panel_builder.rb +80 -0
  37. data/lib/quby/compiler/dsl/question_builder.rb +40 -0
  38. data/lib/quby/compiler/dsl/questionnaire_builder.rb +279 -0
  39. data/lib/quby/compiler/dsl/questions/base.rb +180 -0
  40. data/lib/quby/compiler/dsl/questions/checkbox_question_builder.rb +20 -0
  41. data/lib/quby/compiler/dsl/questions/date_question_builder.rb +18 -0
  42. data/lib/quby/compiler/dsl/questions/deprecated_question_builder.rb +18 -0
  43. data/lib/quby/compiler/dsl/questions/float_question_builder.rb +21 -0
  44. data/lib/quby/compiler/dsl/questions/integer_question_builder.rb +21 -0
  45. data/lib/quby/compiler/dsl/questions/radio_question_builder.rb +20 -0
  46. data/lib/quby/compiler/dsl/questions/select_question_builder.rb +18 -0
  47. data/lib/quby/compiler/dsl/questions/string_question_builder.rb +20 -0
  48. data/lib/quby/compiler/dsl/questions/text_question_builder.rb +22 -0
  49. data/lib/quby/compiler/dsl/score_builder.rb +22 -0
  50. data/lib/quby/compiler/dsl/score_schema_builder.rb +53 -0
  51. data/lib/quby/compiler/dsl/standardized_panel_generators.rb +33 -0
  52. data/lib/quby/compiler/dsl/table_builder.rb +48 -0
  53. data/lib/quby/compiler/entities.rb +38 -0
  54. data/lib/quby/compiler/entities/charting/bar_chart.rb +17 -0
  55. data/lib/quby/compiler/entities/charting/chart.rb +101 -0
  56. data/lib/quby/compiler/entities/charting/charts.rb +42 -0
  57. data/lib/quby/compiler/entities/charting/line_chart.rb +38 -0
  58. data/lib/quby/compiler/entities/charting/overview_chart.rb +20 -0
  59. data/lib/quby/compiler/entities/charting/plottable.rb +20 -0
  60. data/lib/quby/compiler/entities/charting/radar_chart.rb +17 -0
  61. data/lib/quby/compiler/entities/definition.rb +26 -0
  62. data/lib/quby/compiler/entities/fields.rb +119 -0
  63. data/lib/quby/compiler/entities/flag.rb +55 -0
  64. data/lib/quby/compiler/entities/item.rb +40 -0
  65. data/lib/quby/compiler/entities/lookup_tables.rb +71 -0
  66. data/lib/quby/compiler/entities/outcome_table.rb +31 -0
  67. data/lib/quby/compiler/entities/panel.rb +82 -0
  68. data/lib/quby/compiler/entities/question.rb +365 -0
  69. data/lib/quby/compiler/entities/question_option.rb +96 -0
  70. data/lib/quby/compiler/entities/questionnaire.rb +440 -0
  71. data/lib/quby/compiler/entities/questions/checkbox_question.rb +82 -0
  72. data/lib/quby/compiler/entities/questions/date_question.rb +84 -0
  73. data/lib/quby/compiler/entities/questions/deprecated_question.rb +19 -0
  74. data/lib/quby/compiler/entities/questions/float_question.rb +15 -0
  75. data/lib/quby/compiler/entities/questions/integer_question.rb +15 -0
  76. data/lib/quby/compiler/entities/questions/radio_question.rb +19 -0
  77. data/lib/quby/compiler/entities/questions/select_question.rb +19 -0
  78. data/lib/quby/compiler/entities/questions/string_question.rb +15 -0
  79. data/lib/quby/compiler/entities/questions/text_question.rb +15 -0
  80. data/lib/quby/compiler/entities/score_calculation.rb +35 -0
  81. data/lib/quby/compiler/entities/score_schema.rb +25 -0
  82. data/lib/quby/compiler/entities/subscore_schema.rb +23 -0
  83. data/lib/quby/compiler/entities/table.rb +143 -0
  84. data/lib/quby/compiler/entities/text.rb +71 -0
  85. data/lib/quby/compiler/entities/textvar.rb +23 -0
  86. data/lib/quby/compiler/entities/validation.rb +17 -0
  87. data/lib/quby/compiler/entities/version.rb +23 -0
  88. data/lib/quby/compiler/entities/visibility_rule.rb +71 -0
  89. data/lib/quby/compiler/instance.rb +72 -0
  90. data/lib/quby/compiler/output.rb +13 -0
  91. data/lib/quby/compiler/outputs.rb +4 -0
  92. data/lib/quby/compiler/outputs/quby_frontend_v1_serializer.rb +362 -0
  93. data/lib/quby/compiler/outputs/quby_frontend_v2_serializer.rb +15 -0
  94. data/lib/quby/compiler/outputs/roqua_serializer.rb +108 -0
  95. data/lib/quby/compiler/outputs/seed_serializer.rb +34 -0
  96. data/lib/quby/compiler/services/definition_validator.rb +330 -0
  97. data/lib/quby/compiler/services/quby_proxy.rb +405 -0
  98. data/lib/quby/compiler/services/seed_diff.rb +116 -0
  99. data/lib/quby/compiler/services/text_transformation.rb +30 -0
  100. data/lib/quby/compiler/version.rb +5 -0
  101. data/lib/quby/markdown_parser.rb +38 -0
  102. data/lib/quby/range_categories.rb +38 -0
  103. data/lib/quby/settings.rb +86 -0
  104. data/lib/quby/text_transformation.rb +26 -0
  105. data/lib/quby/type_validator.rb +12 -0
  106. data/quby-compiler.gemspec +39 -0
  107. 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