quby-compiler 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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