quby 4.0.3 → 5.0.0.pre1

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/lib/quby/questionnaires.rb +1 -0
  3. data/lib/quby/questionnaires/api.rb +5 -1
  4. data/lib/quby/questionnaires/deserializer.rb +433 -0
  5. data/lib/quby/questionnaires/dsl.rb +10 -15
  6. data/lib/quby/questionnaires/entities.rb +1 -0
  7. data/lib/quby/questionnaires/entities/charting/line_chart.rb +23 -0
  8. data/lib/quby/questionnaires/entities/charting/overview_chart.rb +3 -1
  9. data/lib/quby/questionnaires/entities/definition.rb +3 -5
  10. data/lib/quby/questionnaires/entities/fields.rb +0 -15
  11. data/lib/quby/questionnaires/entities/question.rb +9 -32
  12. data/lib/quby/questionnaires/entities/questionnaire.rb +4 -15
  13. data/lib/quby/questionnaires/entities/questions/checkbox_question.rb +0 -24
  14. data/lib/quby/questionnaires/entities/questions/date_question.rb +0 -8
  15. data/lib/quby/questionnaires/entities/score_calculation.rb +36 -3
  16. data/lib/quby/questionnaires/repos.rb +1 -0
  17. data/lib/quby/questionnaires/repos/bundle_disk_repo.rb +51 -0
  18. data/lib/quby/version.rb +1 -1
  19. data/spec/internal/log/test-events.log +166 -0
  20. data/spec/internal/log/test.log +6170 -0
  21. data/spec/internal/tmp/capybara/screenshot_2020-10-27-14-25-21.063.html +207 -0
  22. data/spec/internal/tmp/capybara/screenshot_2020-10-27-14-25-21.063.png +0 -0
  23. data/spec/quby/answers/services/answer_validations_spec.rb +8 -8
  24. data/spec/quby/questionnaires/deserializer/questionnaire_spec.rb +237 -0
  25. data/spec/quby/questionnaires/dsl_spec.rb +0 -9
  26. data/spec/quby/questionnaires/entities/fields_spec.rb +3 -3
  27. data/spec/quby/questionnaires/entities/question_spec.rb +0 -8
  28. data/spec/quby/questionnaires/entities/questionnaire_spec.rb +2 -26
  29. data/spec/quby/table_backend/range_tree_spec.rb +7 -0
  30. data/spec/spec_helper.rb +1 -0
  31. metadata +25 -46
  32. data/lib/quby/questionnaires/dsl/base.rb +0 -20
  33. data/lib/quby/questionnaires/dsl/calls_custom_methods.rb +0 -29
  34. data/lib/quby/questionnaires/dsl/charting/bar_chart_builder.rb +0 -18
  35. data/lib/quby/questionnaires/dsl/charting/chart_builder.rb +0 -91
  36. data/lib/quby/questionnaires/dsl/charting/line_chart_builder.rb +0 -57
  37. data/lib/quby/questionnaires/dsl/charting/overview_chart_builder.rb +0 -31
  38. data/lib/quby/questionnaires/dsl/charting/radar_chart_builder.rb +0 -18
  39. data/lib/quby/questionnaires/dsl/helpers.rb +0 -51
  40. data/lib/quby/questionnaires/dsl/panel_builder.rb +0 -80
  41. data/lib/quby/questionnaires/dsl/question_builder.rb +0 -40
  42. data/lib/quby/questionnaires/dsl/questionnaire_builder.rb +0 -252
  43. data/lib/quby/questionnaires/dsl/questions/base.rb +0 -179
  44. data/lib/quby/questionnaires/dsl/questions/checkbox_question_builder.rb +0 -20
  45. data/lib/quby/questionnaires/dsl/questions/date_question_builder.rb +0 -18
  46. data/lib/quby/questionnaires/dsl/questions/deprecated_question_builder.rb +0 -18
  47. data/lib/quby/questionnaires/dsl/questions/float_question_builder.rb +0 -21
  48. data/lib/quby/questionnaires/dsl/questions/integer_question_builder.rb +0 -21
  49. data/lib/quby/questionnaires/dsl/questions/radio_question_builder.rb +0 -20
  50. data/lib/quby/questionnaires/dsl/questions/select_question_builder.rb +0 -18
  51. data/lib/quby/questionnaires/dsl/questions/string_question_builder.rb +0 -20
  52. data/lib/quby/questionnaires/dsl/questions/text_question_builder.rb +0 -22
  53. data/lib/quby/questionnaires/dsl/score_builder.rb +0 -22
  54. data/lib/quby/questionnaires/dsl/standardized_panel_generators.rb +0 -33
  55. data/lib/quby/questionnaires/dsl/table_builder.rb +0 -48
  56. data/lib/quby/questionnaires/services/definition_validator.rb +0 -298
  57. data/spec/quby/questionnaires/dsl/calls_custom_methods_spec.rb +0 -38
  58. data/spec/quby/questionnaires/dsl/charting/bar_chart_builder_spec.rb +0 -41
  59. data/spec/quby/questionnaires/dsl/charting/chart_builder_spec.rb +0 -127
  60. data/spec/quby/questionnaires/dsl/charting/line_chart_builder_spec.rb +0 -66
  61. data/spec/quby/questionnaires/dsl/charting/radar_chart_builder_spec.rb +0 -41
  62. data/spec/quby/questionnaires/dsl/helpers_spec.rb +0 -80
  63. data/spec/quby/questionnaires/dsl/questionnaire_builder_spec.rb +0 -480
  64. data/spec/quby/questionnaires/services/definition_validator_spec.rb +0 -793
  65. data/spec/support/examples_for_chart_builders.rb +0 -59
@@ -1,31 +0,0 @@
1
- require 'quby/questionnaires/entities/charting/overview_chart'
2
- require_relative 'chart_builder'
3
-
4
- module Quby
5
- module Questionnaires
6
- module DSL
7
- class OverviewChartBuilder < ChartBuilder
8
- set_chart_class(Entities::Charting::OverviewChart)
9
-
10
- def initialize(questionnaire, options = {})
11
- @questionnaire = questionnaire
12
- @chart = self.class.chart_class.new
13
- end
14
-
15
- def subscore(key)
16
- @chart.subscore = key
17
- end
18
-
19
- def y_max(value)
20
- @chart.y_max = value
21
- end
22
-
23
- def validate!
24
- fail ArgumentError, "subscore not specified" unless @chart.subscore.present?
25
- fail ArgumentError, "y_max not specified" unless @chart.y_max.present?
26
- true
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'quby/questionnaires/entities/charting/radar_chart'
4
- require_relative 'chart_builder'
5
-
6
- module Quby
7
- module Questionnaires
8
- module DSL
9
- class RadarChartBuilder < ChartBuilder
10
- set_chart_class(Entities::Charting::RadarChart)
11
-
12
- def plotline(value, color)
13
- @chart.plotlines << {value: value, color: color, width: 1, zIndex: 3}
14
- end
15
- end
16
- end
17
- end
18
- end
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Quby
4
- module Questionnaires
5
- module DSL
6
- module Helpers
7
- def image_tag(*args)
8
- options = args.extract_options!
9
-
10
- ActionController::Base.helpers.image_tag(
11
- *args, options.reverse_merge(alt: image_alt(args.first))
12
- )
13
- end
14
-
15
- # Copied from ActionController::Base.helpers.image_alt, because it will be removed from Rails 6.0, but we want
16
- # to keep using this functionality
17
- def image_alt(source)
18
- File.basename(source, ".*").sub(/-[[:xdigit:]]{32,64}\z/, "").tr("-_", " ").capitalize
19
- end
20
-
21
- def check_question_keys_uniqueness(key, options, questionnaire)
22
- keys = QuestionBuilder.build(key, options).claimed_keys
23
- if keys.any? { |k| questionnaire.key_in_use? k }
24
- fail "#{questionnaire.key}:#{key}: A question or option with input key #{key} is already defined."
25
- end
26
- end
27
-
28
- def video_tag(*urls, poster: nil, autoplay: false, loop: false)
29
- # assume the file extension is the video format
30
- # otherwise, the host's declared mime type is used to figure out compatibility
31
- # which is usually wrong
32
- sources = urls.map { |url| [url, url.match(/[^\.]*\z/)&.[](0).downcase] }
33
- sources.each { |_url, ext| raise 'unknown video url file extension' unless %w[mp4 webm].include?(ext) }
34
-
35
- ActionController::Base.helpers.tag.video\
36
- width: '100%',
37
- preload: 'none',
38
- poster: poster,
39
- loop: loop,
40
- autoplay: autoplay,
41
- muted: autoplay,
42
- controls: '' do |tag|
43
- sources.map { |url, ext| tag.source src: url, type: "video/#{ext}" }
44
- .append(I18n.t('video_not_supported'))
45
- .yield_self(&tag.method(:safe_join))
46
- end
47
- end
48
- end
49
- end
50
- end
51
- end
@@ -1,80 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'quby/questionnaires/entities'
4
-
5
- module Quby
6
- module Questionnaires
7
- module DSL
8
- class PanelBuilder < Base
9
- attr_reader :title
10
- attr_reader :questionnaire
11
-
12
- def initialize(title, options = {})
13
- @panel = Entities::Panel.new(options.merge(title: title, items: []))
14
- @default_question_options = options[:default_question_options] || {}
15
- @questionnaire = options[:questionnaire]
16
- @custom_methods = options[:custom_methods] || {}
17
- end
18
-
19
- def build
20
- @panel
21
- end
22
-
23
- def title(value)
24
- @panel.title = value
25
- end
26
-
27
- def text(value, options = {})
28
- @panel.items << Entities::Text.new(value.to_s, options)
29
- end
30
-
31
- def html(value)
32
- @panel.items << Entities::Text.new('', html_content: value.to_s)
33
- end
34
-
35
- def raw_html(value)
36
- @panel.items << Entities::Text.new('', raw_content: value.to_s)
37
- end
38
-
39
- def video(*urls, **options)
40
- video_html = video_tag *urls, **options
41
- @panel.items << Entities::Text.new('', raw_content: video_html)
42
- end
43
-
44
- def default_question_options(options = {})
45
- @default_question_options = @default_question_options.merge(options)
46
- end
47
-
48
- def question(key, options = {}, &block)
49
- options = @default_question_options.merge(options).merge(questionnaire: @panel.questionnaire)
50
-
51
- check_question_keys_uniqueness key, options, @questionnaire
52
-
53
- question = QuestionBuilder.build(key, options, &block)
54
-
55
- @questionnaire.register_question(question)
56
- @panel.items << question
57
- end
58
-
59
- def table(options = {}, &block)
60
- table_builder = TableBuilder.new(@panel, options.merge(questionnaire: @panel.questionnaire,
61
- default_question_options: @default_question_options,
62
- custom_methods: @custom_methods))
63
- table_builder.instance_eval(&block) if block
64
- end
65
-
66
- def method_missing(method_sym, *args, &block)
67
- if @custom_methods.key? method_sym
68
- instance_exec(*args, &@custom_methods[method_sym])
69
- else
70
- super
71
- end
72
- end
73
-
74
- def respond_to_missing?(method_name, include_private = false)
75
- @custom_methods.key?(method_name) || super
76
- end
77
- end
78
- end
79
- end
80
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'quby/questionnaires/entities'
4
-
5
- require 'quby/questionnaires/dsl/questions/base'
6
- require 'quby/questionnaires/dsl/questions/checkbox_question_builder'
7
- require 'quby/questionnaires/dsl/questions/date_question_builder'
8
- require 'quby/questionnaires/dsl/questions/deprecated_question_builder'
9
- require 'quby/questionnaires/dsl/questions/float_question_builder'
10
- require 'quby/questionnaires/dsl/questions/integer_question_builder'
11
- require 'quby/questionnaires/dsl/questions/radio_question_builder'
12
- require 'quby/questionnaires/dsl/questions/select_question_builder'
13
- require 'quby/questionnaires/dsl/questions/string_question_builder'
14
- require 'quby/questionnaires/dsl/questions/text_question_builder'
15
-
16
- module Quby
17
- module Questionnaires
18
- module DSL
19
- module QuestionBuilder
20
- include Helpers
21
- BUILDERS = {
22
- 'string' => Questions::StringQuestionBuilder,
23
- 'textarea' => Questions::TextQuestionBuilder,
24
- 'integer' => Questions::IntegerQuestionBuilder,
25
- 'float' => Questions::FloatQuestionBuilder,
26
- 'radio' => Questions::RadioQuestionBuilder,
27
- 'scale' => Questions::RadioQuestionBuilder,
28
- 'select' => Questions::SelectQuestionBuilder,
29
- 'check_box' => Questions::CheckboxQuestionBuilder,
30
- 'date' => Questions::DateQuestionBuilder,
31
- 'hidden' => Questions::DeprecatedQuestionBuilder
32
- }
33
-
34
- def self.build(key, options = {}, &block)
35
- BUILDERS.fetch(options.fetch(:type).to_s).build(key, options, &block)
36
- end
37
- end
38
- end
39
- end
40
- end
@@ -1,252 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'quby/questionnaires/dsl/panel_builder'
4
- require 'quby/questionnaires/dsl/table_builder'
5
- require 'quby/questionnaires/dsl/question_builder'
6
- require 'quby/questionnaires/dsl/score_builder'
7
- require 'quby/questionnaires/dsl/charting/line_chart_builder'
8
- require 'quby/questionnaires/dsl/charting/radar_chart_builder'
9
- require 'quby/questionnaires/dsl/charting/bar_chart_builder'
10
- require 'quby/questionnaires/dsl/charting/overview_chart_builder'
11
-
12
- require_relative 'standardized_panel_generators'
13
-
14
- module Quby
15
- module Questionnaires
16
- module DSL
17
- class QuestionnaireBuilder
18
- prepend CallsCustomMethods
19
- include StandardizedPanelGenerators
20
- include Helpers
21
-
22
- def initialize(target_instance)
23
- @questionnaire = target_instance
24
- @default_question_options = {}
25
- @custom_methods = {}
26
- end
27
-
28
- def leave_page_alert(text)
29
- @questionnaire.leave_page_alert = text
30
- end
31
-
32
- def key(key)
33
- # no-op, key is now passed in to Questionnaire constructor
34
- end
35
-
36
- def roqua_keys(*keys)
37
- @questionnaire.roqua_keys = keys
38
- end
39
-
40
- def do_not_check_key_clashes
41
- @questionnaire.check_key_clashes = false
42
- end
43
-
44
- def do_not_check_score_keys_consistency
45
- @questionnaire.check_score_keys_consistency = false
46
- end
47
-
48
- def do_not_validate_html
49
- @questionnaire.validate_html = false
50
- end
51
-
52
- def title(title)
53
- @questionnaire.title = title
54
- end
55
-
56
- def description(description)
57
- @questionnaire.description = description
58
- end
59
-
60
- def outcome_description(description)
61
- @questionnaire.outcome_description = description
62
- end
63
-
64
- def short_description(description)
65
- @questionnaire.short_description = description
66
- end
67
-
68
- def sbg_key(sbg_key)
69
- @questionnaire.sbg_key = sbg_key
70
- end
71
-
72
- def sbg_domain(sbg_code, outcome:, from: nil, till: nil, sbg_key: nil, primary: false)
73
- @questionnaire.sbg_domains << {
74
- sbg_code: sbg_code,
75
- from: from,
76
- till: till,
77
- outcome: outcome,
78
- sbg_key: sbg_key || @questionnaire.sbg_key,
79
- primary: primary
80
- }
81
- end
82
-
83
- def abortable
84
- @questionnaire.abortable = true
85
- end
86
-
87
- def allow_hotkeys(type = :all)
88
- @questionnaire.allow_hotkeys = type
89
- end
90
-
91
- def license(type, licensor: nil)
92
- @questionnaire.license = type
93
- @questionnaire.licensor = licensor
94
- end
95
-
96
- def language(language)
97
- @questionnaire.language = language
98
- end
99
-
100
- def respondent_types(*respondent_types)
101
- @questionnaire.respondent_types = respondent_types
102
- end
103
-
104
- def tags(*tags)
105
- @questionnaire.tags = tags
106
- end
107
-
108
- def outcome_regeneration_requested_at(timestamp)
109
- @questionnaire.outcome_regeneration_requested_at = timestamp
110
- end
111
-
112
- def deactivate_answers_requested_at(timestamp)
113
- @questionnaire.deactivate_answers_requested_at = timestamp
114
- end
115
-
116
- def enable_previous_questionnaire_button
117
- @questionnaire.enable_previous_questionnaire_button = true
118
- end
119
-
120
- def renderer_version(version)
121
- @questionnaire.renderer_version = version
122
- end
123
-
124
- def css(value)
125
- @questionnaire.extra_css += value
126
- end
127
-
128
- def allow_switch_to_bulk(value=true)
129
- @questionnaire.allow_switch_to_bulk = value
130
- end
131
-
132
- def default_answer_value(value)
133
- @questionnaire.default_answer_value = value
134
- end
135
-
136
- def panel(title = nil, options = {}, &block)
137
- panel = PanelBuilder.build(title, options.merge(default_panel_options), &block)
138
- @questionnaire.add_panel(panel)
139
- end
140
-
141
- def custom_method(key, &block)
142
- if PanelBuilder.new(nil, custom_methods: @custom_methods).respond_to? key
143
- fail 'Custom method trying to override existing method'
144
- end
145
- @custom_methods[key] = block
146
- end
147
-
148
- def add_lookup_tree(key, levels:, tree:)
149
- @questionnaire.lookup_tables[key] = Quby::TableBackend::RangeTree.new(levels: levels, tree: tree)
150
- end
151
-
152
- def default_question_options(options = {})
153
- @default_question_options.merge!(options)
154
- end
155
-
156
- # Short-circuit the question command to perform an implicit panel
157
- def question(key, options = {}, &block)
158
- panel(nil, default_panel_options) do
159
- question(key, @default_question_options.merge(options).merge(questionnaire: @questionnaire), &block)
160
- end
161
- end
162
-
163
- # Short-circuit the text command to perform an implicit panel
164
- def text(value, options = {})
165
- panel(nil, default_panel_options) do
166
- text(value, options)
167
- end
168
- end
169
-
170
- # Short-circuit the table command to perform an implicit panel
171
- def table(options = {}, &block)
172
- panel(nil, default_panel_options) do
173
- table(options, &block)
174
- end
175
- end
176
-
177
- # variable :totaal do
178
- # # Plain old Ruby code here, executed in the scope of the answer
179
- # # variables are private to the score calculation
180
- # q01 + q02 + q03
181
- # end
182
- def variable(key, options = {}, &block)
183
- s = ScoreBuilder.new(key, options, &block)
184
- @questionnaire.add_score_calculation s.build
185
- end
186
-
187
- def score(key, options = {}, &block)
188
- @questionnaire.errors.add "Score #{key}", 'misses label in score call' if options[:label].blank?
189
- schema = options.delete(:schema)
190
- @questionnaire.add_score_schema(key, options[:label], schema) if schema.present?
191
- variable(key, options.reverse_merge(score: true), &block)
192
- end
193
-
194
- def score_schema(key, label, options)
195
- @questionnaire.add_score_schema(key, label, options)
196
- end
197
-
198
- def attention(options = {}, &block)
199
- variable(:attention, options.reverse_merge(action: true), &block)
200
- end
201
-
202
- def alarm(options = {}, &block)
203
- variable(:alarm, options.reverse_merge(action: true), &block)
204
- end
205
-
206
- def completion(options = {}, &block)
207
- variable(:completion, options.reverse_merge(completion: true), &block)
208
- end
209
-
210
- def overview_chart(*args, &block)
211
- raise "Cannot define more than one overview chart" if @questionnaire.charts.overview.present?
212
- builder = OverviewChartBuilder.new(@questionnaire, *args)
213
- @questionnaire.charts.overview = builder.build(&block)
214
- end
215
-
216
- def line_chart(*args, &block)
217
- builder = LineChartBuilder.new(@questionnaire, *args)
218
- @questionnaire.add_chart(builder.build(&block))
219
- end
220
-
221
- def bar_chart(*args, &block)
222
- builder = BarChartBuilder.new(@questionnaire, *args)
223
- @questionnaire.add_chart(builder.build(&block))
224
- end
225
-
226
- def radar_chart(*args, &block)
227
- builder = RadarChartBuilder.new(@questionnaire, *args)
228
- @questionnaire.add_chart(builder.build(&block))
229
- end
230
-
231
- def flag(flag_options)
232
- @questionnaire.add_flag flag_options
233
- end
234
-
235
- def textvar(textvar_options)
236
- @questionnaire.add_textvar textvar_options
237
- end
238
-
239
- def outcome_table(table_options)
240
- @questionnaire.add_outcome_table table_options
241
- end
242
-
243
- private
244
-
245
- def default_panel_options
246
- {questionnaire: @questionnaire, default_question_options: @default_question_options,
247
- custom_methods: @custom_methods}
248
- end
249
- end
250
- end
251
- end
252
- end