alembic 0.14.0 → 0.16.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 26fff39c56e3627fa327fc6ae59d02d9d034687db485abf2e7d991e19beac021
4
- data.tar.gz: e8eb409d6bff630da792f4d084138e6c48d7d7b443a659e257a31f19b91e0627
3
+ metadata.gz: f4ad973a4cd7a81bb2d9ff18e31075ca5b4dc32c20b82c86d3cdbf39445ce28d
4
+ data.tar.gz: fdf0002e2cb0c7a559be457f24df5af9d64354f6136d5428a81e6a31c7b4e00b
5
5
  SHA512:
6
- metadata.gz: 45395f01c87606d7a626341112ed4b99c27ba1e4b11b82cb8cc186a8e33f2b3279f9f7542c625f8f879b37327defa4a57ac7bbcfef3846f1b5053d02abf65076
7
- data.tar.gz: 523ec9fda8a088f4843bcb3b5347bca4771a523fd42e7c9314ea128792f1279d97186418bcaf56b8b6c650b4f93b9a31f42f7c20789eb61d537f9b6afa123ae3
6
+ metadata.gz: d0f8baba0a3c8f8b0eef256bae0bf3211a8037216f4ebbf6df5ea09c830de4ed50b23f07f8cf1c754757aa09884216d9fb2402f5d27c871c242f2b88118c2ac5
7
+ data.tar.gz: 546561d85803831584fa1e8aa6b9ce9bcf6503c51277e6a0b36258cd71ceab78ae252acdd6b4c721b2affbf5e5be62eb59dd128480ea7bcfd7f6e417290667bc
@@ -21,6 +21,11 @@ module Alembic
21
21
  Flow::AnswerKey.chosen(step_settings(question.id))
22
22
  end
23
23
 
24
+ def named_right_answer(question)
25
+ accepted = Flow::AnswerKey.accepted(step_settings(question.id))
26
+ accepted.any? ? accepted.to_sentence(two_words_connector: " or ", last_word_connector: ", or ") : super
27
+ end
28
+
24
29
  def shows_answer_values?
25
30
  Flow::Summaries.new(previewed).shows_answer_values?
26
31
  end
@@ -0,0 +1,21 @@
1
+ module Alembic
2
+ module Manage
3
+ class QuizzesController < EasyFlow::Manage::BaseController
4
+ hosted_by FLOW_HOST
5
+
6
+ def new
7
+ @flow = hosted_flows.new
8
+ end
9
+
10
+ def create
11
+ @flow = hosted_flows.new(params.require(:quiz).permit(:title))
12
+
13
+ if Flow::TitledStart.new(@flow).save
14
+ redirect_to easy_flow.manage_flow_path(@flow), notice: "Quiz created."
15
+ else
16
+ render :new, status: :unprocessable_entity
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -10,7 +10,7 @@ module Alembic
10
10
  helper ContentBlocksHelper
11
11
  helper KsBlocks::LayoutHelper
12
12
  after_action :keep_ended_inner_run, only: :step
13
- helper_method :flow_summary, :first_step_path, :summary_values, :intro_values, :start_over_path, :finish_link, :visited_flow_address, :answered_right?, :single_choice?, :drawing_of, :chosen_answer, :step_category, :shown
13
+ helper_method :flow_summary, :first_step_path, :summary_values, :intro_values, :start_over_path, :finish_link, :visited_flow_address, :answered_right?, :single_choice?, :drawing_of, :chosen_answer, :named_right_answer, :step_category, :shown
14
14
  end
15
15
 
16
16
  private
@@ -41,6 +41,11 @@ module Alembic
41
41
 
42
42
  def chosen_answer(_question); end
43
43
 
44
+ def named_right_answer(question)
45
+ chosen = chosen_answer(question)
46
+ @guide.choice_label(question.id, chosen) if chosen.present?
47
+ end
48
+
44
49
  def start_over_path
45
50
  flow_start_path(visited_flow_address)
46
51
  end
@@ -8,6 +8,10 @@ module Alembic
8
8
  else Outputs::WeightedSum.right_answers(step).first
9
9
  end
10
10
  end
11
+
12
+ def self.accepted(step)
13
+ Array(step["accepted_answers"]).filter_map { |answer| answer["value"].presence }
14
+ end
11
15
  end
12
16
  end
13
17
  end
@@ -0,0 +1,46 @@
1
+ module Alembic
2
+ module Flow
3
+ class TitledStart
4
+ FALLBACK_SLUG = "quiz"
5
+ MADE_SLUG_LENGTH = 100
6
+ TRIES_FOR_A_FREE_SLUG = 3
7
+ SLUGS_THE_ROUTES_USE = %w[manage pages runs].freeze
8
+
9
+ def initialize(flow)
10
+ @flow = flow
11
+ end
12
+
13
+ def save
14
+ return refuse_blank_title if @flow.title.blank?
15
+
16
+ tries = 0
17
+ begin
18
+ @flow.slug = free_slug
19
+ @flow.save
20
+ rescue ActiveRecord::RecordNotUnique
21
+ retry if (tries += 1) < TRIES_FOR_A_FREE_SLUG
22
+ raise
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def refuse_blank_title
29
+ @flow.errors.add(:title, :blank)
30
+ false
31
+ end
32
+
33
+ def free_slug
34
+ made = @flow.title.parameterize.first(MADE_SLUG_LENGTH).chomp("-").presence || FALLBACK_SLUG
35
+ numbered = (2..).lazy.map { |number| "#{made}-#{number}" }
36
+ taken = unavailable
37
+
38
+ [ made ].chain(numbered).find { |candidate| taken.exclude?(candidate) }
39
+ end
40
+
41
+ def unavailable
42
+ EasyFlow::Definition.where(host: @flow.host, owner: @flow.owner).pluck(:slug) + SLUGS_THE_ROUTES_USE
43
+ end
44
+ end
45
+ end
46
+ end
@@ -32,8 +32,8 @@
32
32
  <%= render @drawing, step: shown(@question), chosen: chosen_answer(@question) %>
33
33
  <% end %>
34
34
 
35
- <% if (right_answer = chosen_answer(@question)).present? %>
36
- <%= ui_value_list(rows: [ { label: ui_badge(label: "Right answer", variant: :success), value: @guide.choice_label(@question.id, right_answer) } ]) %>
35
+ <% if (right_answer = named_right_answer(@question)).present? %>
36
+ <%= ui_value_list(rows: [ { label: ui_badge(label: "Right answer", variant: :success), value: right_answer } ]) %>
37
37
  <% end %>
38
38
 
39
39
  <div class="mt-8 flex items-center gap-4">
@@ -0,0 +1,11 @@
1
+ <% content_for(:title, "New quiz") %>
2
+
3
+ <%= ui_page(max_width: :md) do %>
4
+ <%= ui_page_header(title: "New quiz") %>
5
+
6
+ <%= ui_form(action: alembic.manage_quizzes_path, method: :post) do %>
7
+ <%= ui_form_field(attribute: "quiz[title]", label: "Title", value: @flow.title, errors: @flow.errors.full_messages_for(:title)) %>
8
+
9
+ <%= ui_button(label: "Create", type: :submit) %>
10
+ <% end %>
11
+ <% end %>
data/config/routes.rb CHANGED
@@ -18,6 +18,8 @@ Alembic::Engine.routes.draw do
18
18
  get :step
19
19
  end
20
20
  end
21
+
22
+ resources :quizzes, only: [ :new, :create ]
21
23
  end
22
24
 
23
25
  constraints(->(request) { request.path_info.match?(%r{\A/manage/flows(/|\z)}) }) do
@@ -0,0 +1,25 @@
1
+ module Alembic
2
+ module AnswerExplanations
3
+ TEXT = {
4
+ "question" => {
5
+ "answers.info" => "Extra detail saved with this answer, which the question page does not show to a player.",
6
+ "answers.hint" => "A smaller line a player sees under this answer's text.",
7
+ "answers.label" => "The text a player sees for this answer in place of its value.",
8
+ "answers.value" => "The text saved when a player picks this answer, which the player also sees when the label is blank or the flow shows answer values.",
9
+ "answers.weight" => "The points a player scores by picking this answer, and any weight above zero makes it a right answer."
10
+ },
11
+ "multiple_select" => {
12
+ "answers.label" => "The text a player sees for this answer in place of its value.",
13
+ "answers.value" => "The text saved when a player ticks this answer, which the player also sees when the label is blank.",
14
+ "answers.weight" => "Any weight above zero makes this a right answer, whatever its size, and the question scores one point only when a player ticks every right answer and no others."
15
+ },
16
+ "fill_in_the_blank" => {
17
+ "accepted_answers.value" => "A typed answer that matches this text, ignoring capitals and the spaces around it, is right and scores one point."
18
+ }
19
+ }.freeze
20
+
21
+ def explanation_for(step_type, setting)
22
+ super || TEXT.dig(step_type.to_s, setting.to_s)
23
+ end
24
+ end
25
+ end
@@ -33,6 +33,10 @@ module Alembic
33
33
  end
34
34
  end
35
35
 
36
+ initializer "alembic.answer_explanations" do |app|
37
+ app.config.to_prepare { Alembic.explain_answer_fields }
38
+ end
39
+
36
40
  initializer "alembic.question_importer" do |app|
37
41
  app.config.to_prepare { require "alembic/question_importer" if defined?(Ixport::Importer) }
38
42
  end
@@ -1,3 +1,3 @@
1
1
  module Alembic
2
- VERSION = "0.14.0"
2
+ VERSION = "0.16.0"
3
3
  end
data/lib/alembic.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "json"
2
2
  require "alembic/version"
3
3
  require "alembic/engine"
4
+ require "alembic/answer_explanations"
4
5
 
5
6
  module Alembic
6
7
  NotPublished = EasyFlow::NotPublished
@@ -37,9 +38,12 @@ module Alembic
37
38
  end
38
39
 
39
40
  def set_up_flow_host
40
- EasyFlow.host(FLOW_HOST) do |host|
41
- FLOW_HOST_SETTINGS.each { |name| host.public_send(:"#{name}=", public_send(name)) }
42
- end
41
+ host = explain_answer_fields
42
+ FLOW_HOST_SETTINGS.each { |name| host.public_send(:"#{name}=", public_send(name)) }
43
+ end
44
+
45
+ def explain_answer_fields
46
+ flow_host.extend(AnswerExplanations)
43
47
  end
44
48
 
45
49
  def lead_partial=(_partial)
@@ -69,6 +73,13 @@ module Alembic
69
73
  def admin_layout
70
74
  @admin_layout || "application"
71
75
  end
76
+
77
+ private
78
+
79
+ def flow_host
80
+ host = EasyFlow.host_named(FLOW_HOST)
81
+ host.set_up? ? host : EasyFlow.host(FLOW_HOST)
82
+ end
72
83
  end
73
84
 
74
85
  set_up_flow_host
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alembic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.14.0
4
+ version: 0.16.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - tylercschneider
@@ -57,20 +57,14 @@ dependencies:
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '0.32'
61
- - - ">="
62
- - !ruby/object:Gem::Version
63
- version: 0.32.1
60
+ version: '0.35'
64
61
  type: :runtime
65
62
  prerelease: false
66
63
  version_requirements: !ruby/object:Gem::Requirement
67
64
  requirements:
68
65
  - - "~>"
69
66
  - !ruby/object:Gem::Version
70
- version: '0.32'
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- version: 0.32.1
67
+ version: '0.35'
74
68
  description: Alembic builds and runs data-driven interactive diagnostics — scored
75
69
  assessments and branching guides — that place a visitor on an outcome and capture
76
70
  the result. A runtime engine plus a UI builder.
@@ -95,6 +89,7 @@ files:
95
89
  - app/controllers/alembic/manage/page_blocks_controller.rb
96
90
  - app/controllers/alembic/manage/pages_controller.rb
97
91
  - app/controllers/alembic/manage/previews_controller.rb
92
+ - app/controllers/alembic/manage/quizzes_controller.rb
98
93
  - app/controllers/alembic/pages_controller.rb
99
94
  - app/controllers/concerns/alembic/manage/authenticates_admin.rb
100
95
  - app/controllers/concerns/alembic/owned_pages.rb
@@ -115,6 +110,7 @@ files:
115
110
  - app/models/alembic/flow/run_summary.rb
116
111
  - app/models/alembic/flow/summaries.rb
117
112
  - app/models/alembic/flow/summary_version.rb
113
+ - app/models/alembic/flow/titled_start.rb
118
114
  - app/models/alembic/flow/uploaded_question.rb
119
115
  - app/models/alembic/flow/uploaded_questions.rb
120
116
  - app/models/alembic/outputs/band.rb
@@ -161,6 +157,7 @@ files:
161
157
  - app/views/alembic/manage/pages/_block_content.html.erb
162
158
  - app/views/alembic/manage/pages/index.html.erb
163
159
  - app/views/alembic/manage/pages/show.html.erb
160
+ - app/views/alembic/manage/quizzes/new.html.erb
164
161
  - app/views/alembic/pages/show.html.erb
165
162
  - app/views/layouts/alembic/application.html.erb
166
163
  - config/routes.rb
@@ -225,6 +222,7 @@ files:
225
222
  - db/migrate/20261020120000_add_kept_result_to_alembic_flow_run_summaries.rb
226
223
  - db/migrate/20261025031225_add_shuffles_answers_to_alembic_flow_definition_summaries.rb
227
224
  - lib/alembic.rb
225
+ - lib/alembic/answer_explanations.rb
228
226
  - lib/alembic/engine.rb
229
227
  - lib/alembic/leftover_stylesheet.rb
230
228
  - lib/alembic/question_importer.rb