easy_flow 0.9.0 → 0.10.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: cf8a8dbfd774f223e6a43af475f4815a3fa9d94c9ce36d58ac546c803e299232
4
- data.tar.gz: b773f634332cb61f248bbfb03879a322be6baaaacec6d7cf0220a70eb743b72e
3
+ metadata.gz: e32261c0899102541cff5f5da1bfd7e7bf34e520a03fe87bc177dbb021509184
4
+ data.tar.gz: 6ccd6013266e9909dd243093c5efe452cd67df0e5c1258d94ee5c8c640f03414
5
5
  SHA512:
6
- metadata.gz: 6b5de21e4e9c7074abe01b61fab6c3305f34d407dc19584e54c649e046bb138a92067cebaa1774cc15d3f55e2aaa67eb1a6fa73ed0dcec219881f7df31807e4b
7
- data.tar.gz: e833348051900594e25dc04ffc7a90214544deac6b9f5965e9f3ee79cd1152672253f0679122f3503239552fb8a696285d6c51ff66fefaf955d3e958db91d8c8
6
+ metadata.gz: 7c93882cd862430530ae5580ed937270cfc3a930203087ed63b6f137c733afe73858ebe00dcbe403c72e1e9c86d616954614a8ad846b23336baa7f5e0145c4c9
7
+ data.tar.gz: 79e4297428d1a89f364b94b98c816c5b26ac526c7752072e544bd2c505d083da98ba0d2c3ef93707f5e691bb3494d0c4cdc172f59c3e1b81495a5590a4914d56
@@ -67,6 +67,13 @@ module EasyFlow
67
67
  walk(state).last
68
68
  end
69
69
 
70
+ def output(state)
71
+ ended = nil
72
+ walk(state) { |cursor| ended = cursor }
73
+
74
+ ended.config["output"].presence if step_type(ended)&.ends_here?
75
+ end
76
+
70
77
  def state_on_path(state)
71
78
  state.slice(*walk(state).first)
72
79
  end
@@ -94,6 +101,7 @@ module EasyFlow
94
101
  while cursor
95
102
  return [ recorded, nil ] if visits[cursor.id].positive? && answers_at_visit[cursor.id] == answered
96
103
 
104
+ yield cursor if block_given?
97
105
  visits[cursor.id] += 1
98
106
  answers_at_visit[cursor.id] = answered
99
107
  key = visit_key(cursor.id, visits[cursor.id])
@@ -30,6 +30,10 @@ module EasyFlow
30
30
  digest.next_step(state.transform_keys(&:to_s))
31
31
  end
32
32
 
33
+ def output
34
+ digest.output(recorded.transform_keys(&:to_s))
35
+ end
36
+
33
37
  def walked(state)
34
38
  digest.state_on_path(state.transform_keys(&:to_s))
35
39
  end
@@ -6,6 +6,8 @@ module EasyFlow
6
6
 
7
7
  ends_here
8
8
 
9
+ setting :output, type: :string
10
+
9
11
  names_by { |_node| "End" }
10
12
  end
11
13
  end
@@ -1,3 +1,3 @@
1
1
  module EasyFlow
2
- VERSION = "0.9.0"
2
+ VERSION = "0.10.0"
3
3
  end
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: easy_flow-develop
3
- description: Use PROACTIVELY for adding a step type to easy_flow flows (a step that asks the visitor something, takes several answers at once, computes a value from earlier answers, picks the next branch, or holds the visitor until something outside the flow has happened), showing a step differently depending on the visitor's stored run, branching on what a visitor ticked on a checklist, moving a paused run on once what it waits for has happened, refusing a blank or invalid answer to a step with a message, offering an admin a step setting whose options are read from the app's own records, letting an admin edit a value stored on one of the app's own records from a step's settings on the canvas, serving a host's flows from the app's own controller and routes, acting when a visitor finishes a flow, and reading a run's recorded answers and question labels, including every answer ticked on a checklist and every visit's answer when a flow loops back to a question already asked — MUST BE USED instead of hand-rolling questionnaire steps, checkbox lists, branching logic, number comparisons, hard-coded setting options, copying a record's value into a flow and back, answer validation, polling or "come back later" pages, flow controllers or answer lookups.
3
+ description: Use PROACTIVELY for adding a step type to easy_flow flows (a step that asks the visitor something, takes several answers at once, computes a value from earlier answers, picks the next branch, or holds the visitor until something outside the flow has happened), showing a step differently depending on the visitor's stored run, branching on what a visitor ticked on a checklist, moving a paused run on once what it waits for has happened, refusing a blank or invalid answer to a step with a message, offering an admin a step setting whose options are read from the app's own records, letting an admin edit a value stored on one of the app's own records from a step's settings on the canvas, serving a host's flows from the app's own controller and routes, acting when a visitor finishes a flow, acting on the output a visitor's flow ended with, and reading a run's recorded answers and question labels, including every answer ticked on a checklist and every visit's answer when a flow loops back to a question already asked — MUST BE USED instead of hand-rolling questionnaire steps, checkbox lists, branching logic, number comparisons, hard-coded setting options, copying a record's value into a flow and back, answer validation, polling or "come back later" pages, flow controllers or answer lookups.
4
4
  tools: Read, Write, Edit, Grep
5
5
  scope: guided flows — versioned documents of steps and the connections between them, drawn on a canvas by an admin and run by a visitor one step at a time, with step types the host registers
6
6
  ---
@@ -9,7 +9,7 @@ This local follows the steps below exactly and invents none. Where a step names
9
9
 
10
10
  ## What easy_flow is
11
11
 
12
- A Rails engine for flows an admin draws on a canvas and a visitor runs one step at a time. Each step is an instance of a step type. The engine ships seven: start (`:start`), end (`:terminal`), question (`:question`, a question with a list of answers of which the visitor picks one, which the admin can mark required so a blank answer is refused), checklist (`:checklist`, a question with a list of answers of which the visitor ticks any number, which the admin can mark required so a visitor who ticks nothing is refused), and three that pick a branch from an earlier answer with no code — condition (`:condition`, is or is not a chosen value), switch (`:switch`, follows the connection labelled with the answer) and compare (`:compare`, reads the answer as a number and checks it by more than, less than, at least or at most against an amount). On a question and on a checklist the admin can give each answer info, a longer explanation the visitor opens with an info button beside that answer. An admin may connect a step back to an earlier one, so a flow can ask the same question more than once, and each visit's answer is kept. Before writing a step type to ask for one answer or several, or to branch on an answer or a number, ask the developer whether an admin placing one of the built-in types on the canvas is enough. None of condition, switch or compare reads a checklist's answer, so branching on what a visitor ticked takes a step type of the app's own that defines `route`. Use this local when the app needs a step type of its own, needs a host's flows on its own pages with its own behaviour when a visitor finishes, or needs to read what a visitor answered. It assumes easy_flow is already installed and a host is declared; if not, hand off to `easy_flow-install` first.
12
+ A Rails engine for flows an admin draws on a canvas and a visitor runs one step at a time. Each step is an instance of a step type. The engine ships seven: start (`:start`), end (`:terminal`, whose one setting is the output an admin writes for a flow that ends there), question (`:question`, a question with a list of answers of which the visitor picks one, which the admin can mark required so a blank answer is refused), checklist (`:checklist`, a question with a list of answers of which the visitor ticks any number, which the admin can mark required so a visitor who ticks nothing is refused), and three that pick a branch from an earlier answer with no code — condition (`:condition`, is or is not a chosen value), switch (`:switch`, follows the connection labelled with the answer) and compare (`:compare`, reads the answer as a number and checks it by more than, less than, at least or at most against an amount). On a question and on a checklist the admin can give each answer info, a longer explanation the visitor opens with an info button beside that answer. An admin may connect a step back to an earlier one, so a flow can ask the same question more than once, and each visit's answer is kept. Before writing a step type to ask for one answer or several, or to branch on an answer or a number, ask the developer whether an admin placing one of the built-in types on the canvas is enough. None of condition, switch or compare reads a checklist's answer, so branching on what a visitor ticked takes a step type of the app's own that defines `route`. Use this local when the app needs a step type of its own, needs a host's flows on its own pages with its own behaviour when a visitor finishes, or needs to read what a visitor answered. It assumes easy_flow is already installed and a host is declared; if not, hand off to `easy_flow-install` first.
13
13
 
14
14
  ## Interface
15
15
 
@@ -18,7 +18,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
18
18
  - `EasyFlow::FlowsController` — the visitor controller; the app subclasses it to serve one host's flows from its own routes and to change what happens at the start, on each step and at the finish.
19
19
  - `hosted_by` — class method on a `FlowsController` subclass naming the host whose flows it serves.
20
20
  - `routed_by` — class method on a `FlowsController` subclass naming the prefix of the app's own route names that the controller redirects and links to.
21
- - `EasyFlow::Run` — the stored record of one visitor's pass through a flow, pinned to the version that was live when it started, and moved on past a waiting step with `advance`.
21
+ - `EasyFlow::Run` — the stored record of one visitor's pass through a flow, pinned to the version that was live when it started, moved on past a waiting step with `advance`, and read for the output its flow ended with by `output`.
22
22
  - `EasyFlow::QuestionRunner` — reads a flow document: its steps, the next step for a set of answers, the answers on the path taken, and a question's text and an answer's label.
23
23
 
24
24
  ## How to use it
@@ -82,7 +82,7 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
82
82
  - `awaits_input` — the visitor is shown this step and submits an answer to it.
83
83
  - `waits_until { |node, state| ... }` — the run stops at this step until the block returns a truthy value. See step 8.
84
84
  - `answer_check { |node, value| ... }` — checks a submitted answer before it is recorded. `value` is the submitted string, an array of strings when the input submits several values, or `nil` or `""` when the input sent nothing. An array may hold blank strings. Return a message to refuse the answer, or `nil` to accept it. Without it every answer is accepted, including a blank one.
85
- - `ends_here` / `begins_here` — marks the type as an end or a start of a flow.
85
+ - `ends_here` / `begins_here` — marks the type as an end or a start of a flow. A run that ends on a step of an `ends_here` type gives that step's `output` setting as `run.output`, so a type of the app's own that ends a flow declares `setting :output, type: :string` for the admin to fill in, or gives no output.
86
86
  - `displays_by { |node| ... }` or `displays_by { |node, run| ... }` — builds the object handed to the step's partial as the local `step`. Without it the partial receives the node itself. A block that takes two arguments is also given the visitor's stored `EasyFlow::Run`, which is `nil` when the flow keeps no stored run at this point and in an admin's preview, so the block must handle `nil`. The block is also called with a `nil` run once for each step already answered every time a step page is shown, to count progress, so it must not be slow and must not change anything.
87
87
  - `drawn_by "<partial>"` — the partial that draws this type for a visitor. Without it the host's default drawing is used, which draws one answer to pick and expects `step.id`, `step.text` and `step.choices`, each choice answering `value`, `label`, `hint` and `info`, so a type with its own display shape needs its own partial.
88
88
  6. For a type that computes or routes, define instance methods on the class (or `process { |node, state| ... }` / `route { |node, state| ... }` in the block form):
@@ -221,7 +221,7 @@ Use this when an admin should edit a value that belongs to one of the app's own
221
221
 
222
222
  The controller inherits from the base controller set at install, uses the host's layout, visitor authorization and refusal methods, and only finds flows that belong to the named host. Pages it does not override use the engine's own views.
223
223
  4. Override only the private methods the developer's answers call for:
224
- - `finished(answers, run)` — called when the visitor reaches the end. `answers` is the answers on the path taken, keyed by step id as symbols, each a string or, for a checklist, an array of strings. `run` is the stored `EasyFlow::Run`, or `nil` when the admin set the flow to save nothing. A flow the admin set to save on finish gets its run created at this point. It must render or redirect. Default: the engine's completion page, which lists each answer on the path taken by its label, a checklist's answer as the labels of everything ticked joined into one sentence.
224
+ - `finished(answers, run)` — called when the visitor reaches the end. `answers` is the answers on the path taken, keyed by step id as symbols, each a string or, for a checklist, an array of strings. `run` is the stored `EasyFlow::Run`, or `nil` when the admin set the flow to save nothing. A flow the admin set to save on finish gets its run created at this point. To act on which way the flow ended, read `run.output`; when `run` is `nil` there is no output to read. It must render or redirect. Default: the engine's completion page, which lists each answer on the path taken by its label, a checklist's answer as the labels of everything ticked joined into one sentence.
225
225
  - `start_run(flow)` — creates the run when a visitor starts a flow the admin set to save each step. Call `super` and change the run it returns, for example to set its `owner` or `label`.
226
226
  - `runner_for(definition)` — returns the runner used for each step. Return a subclass of `EasyFlow::QuestionRunner` to change what the step and completion pages read from it.
227
227
  5. Visit `/<path>/<slug>` for a published flow and walk it to the end.
@@ -235,6 +235,7 @@ Use this when an admin should edit a value that belongs to one of the app's own
235
235
  - `run.owner` — the optional record the run belongs to, polymorphic, set by the app. `run.label` and `run.status` are free string columns for the app's own use.
236
236
  - `run.pinned_definition` — the flow document of the version the run started on.
237
237
  - `run.next_step(answers)` and `run.walked(answers)` — the next step, and the answers on the path taken, for a set of answers against that pinned version.
238
+ - `run.output` — the text the admin wrote into the output setting of the End step the run ended on, read from the run's pinned version. It is `nil` when the run has not reached an End step, or ended on one whose output was left blank. A flow may have several End steps with a different output on each, so the output says which way the flow ended. Ask the developer what the app does with each output, and what it does when there is none.
238
239
  - `run.advance` — moves the run past every waiting step whose `waits_until` block now returns a truthy value, and past every step that computes a value, and records each result on the run. It stops at the next step that asks the visitor for input, the next waiting step that is not ready, or the end. It does not call `finished`; that is called the next time the visitor loads the run's page.
239
240
  3. To show answers with their question text and answer labels, build a runner from the run's pinned document:
240
241
 
@@ -276,5 +277,7 @@ Use this when an admin should edit a value that belongs to one of the app's own
276
277
  - A `waits_until` block is given only the step and the answers recorded so far, so what it waits for must be findable from those.
277
278
  - A type that waits never also declares `awaits_input`.
278
279
  - `run.advance` only moves a stored run, and never finishes it; the visitor's next page load does.
280
+ - A flow's output is free text an admin writes on each End step, so code that acts on it handles `nil` and any value it does not expect.
281
+ - A flow's output is read from a stored run only, so a flow the admin set to save nothing gives none.
279
282
  - A `FlowsController` subclass needs all four named routes for its prefix; a missing one raises when the visitor is linked or redirected to it.
280
283
  - The engine installs, mounts and configures hosts, the step types each host offers, layouts, the default drawing and checks through `easy_flow-install`, not here.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: easy_flow-info
3
- description: Use to learn what easy_flow offers — guided flows an admin draws on a canvas and a visitor runs one step at a time, versioned documents of steps and connections, flows that loop back to ask a step again, hosts and the step types each offers its admins, runs, the built-in step types including questions and checklists that can require an answer and explain each answer behind an info button, and branching on an answer or comparing a number, step types the host app registers, the checks they make on an answer, what a step shows a visitor and how that can depend on the visitor's run, and steps that hold a run until something outside the flow has happened, and the settings an admin fills in, including picks whose options come from the app's data and settings kept on one of the app's own records.
3
+ description: Use to learn what easy_flow offers — guided flows an admin draws on a canvas and a visitor runs one step at a time, versioned documents of steps and connections, flows that loop back to ask a step again, hosts and the step types each offers its admins, runs and the output a flow gives when it ends, the built-in step types including questions and checklists that can require an answer and explain each answer behind an info button, and branching on an answer or comparing a number, step types the host app registers, the checks they make on an answer, what a step shows a visitor and how that can depend on the visitor's run, and steps that hold a run until something outside the flow has happened, and the settings an admin fills in, including picks whose options come from the app's data and settings kept on one of the app's own records.
4
4
  tools: Read
5
5
  scope: guided flows — versioned documents of steps and the connections between them, drawn on a canvas by an admin and run by a visitor one step at a time, with step types the host registers
6
6
  ---
@@ -18,12 +18,13 @@ Reach for it when an app needs a questionnaire, an intake form, or any decision
18
18
  easy_flow declares no commands of its own for this local. Its surface is split between the other two:
19
19
 
20
20
  - **easy_flow-install** owns putting the engine into an app: its migrations, mounting it, choosing the controller it inherits from, naming hosts and the step types each one offers, choosing the default step drawing, the flow checks, and the admin pages.
21
- - **easy_flow-develop** owns building on it: declaring and registering step types, including ones that wait and ones with settings kept on the app's own records, moving a run on once what it waits for has happened, serving a host's flows from the app's own controllers and routes, and reading a visitor's run and answers.
21
+ - **easy_flow-develop** owns building on it: declaring and registering step types, including ones that wait and ones with settings kept on the app's own records, moving a run on once what it waits for has happened, serving a host's flows from the app's own controllers and routes, and reading a visitor's run, its answers and the output its flow ended with.
22
22
 
23
23
  ## How to use it
24
24
 
25
25
  - To get easy_flow running in an app, or to change how it is configured, including which step types a host's admins can add, use **easy_flow-install**.
26
- - To add a step type, give a step type its own rule for refusing an answer, make what a step shows depend on the visitor's run, hold a run until something outside the flow has happened, keep a step's setting on one of the app's own records, put a flow on the app's own pages, or act on what a visitor answered, use **easy_flow-develop**.
26
+ - To add a step type, give a step type its own rule for refusing an answer, make what a step shows depend on the visitor's run, hold a run until something outside the flow has happened, keep a step's setting on one of the app's own records, put a flow on the app's own pages, act on what a visitor answered, or act on the output a visitor's flow ended with, use **easy_flow-develop**.
27
+ - To give a flow a different output for each way it can end, no code is needed: an admin fills in the output on each End step on the canvas.
27
28
  - To branch a flow on an answer or on a number the visitor gave, no code is needed: an admin places one of the built-in branching steps on the canvas.
28
29
  - To make a visitor answer a question or tick something on a checklist before going on, no code is needed: an admin marks that step as required on the canvas.
29
30
  - To let a visitor tick several answers on one step, no code is needed: an admin places a checklist step on the canvas.
@@ -45,7 +46,8 @@ easy_flow declares no commands of its own for this local. Its surface is split b
45
46
  - **Options** — the values a pick-from-a-list setting offers. They are either a fixed list written into the step type, or a lookup the app provides that is read each time the canvas or a save asks for them, so they can come from the app's own data. A saved value that is not among the options is refused.
46
47
  - **Kept setting** — a setting whose value lives on one of the app's own records rather than in the flow. The step type says how to find that record from the step's other settings and which of its attributes holds the value. The canvas shows the value read from the record, and saving the step's settings writes it straight to the record, so the flow's document and its versions never hold it and undo or publishing does not change it. When no record is found, nothing is written. When the record refuses a value, the save is refused with the record's own error and none of the step's kept settings are written.
47
48
  - **Output** — a value a step records into the run, with a type and a label. Later steps read outputs, and a setting that points at an earlier step offers that step's known values on the canvas.
48
- - **Start** and **End** — the built-in step types that begin and finish a flow.
49
+ - **Start** and **End** — the built-in step types that begin and finish a flow. An End step has one setting, its output.
50
+ - **Flow output** — the text an admin writes into the output setting of an End step, given as the result of a stored run that has reached that step. A flow may hold several End steps with a different output on each, so the output says which way the flow ended. A run that has not reached an End step, or that ended on one whose output was left blank, gives no output.
49
51
  - **Question** — the built-in step type that asks the visitor: a question text, an optional category, a yes-or-no required setting, and a list of answers, each with a value, a label, a weight, a hint and an info. The visitor picks one answer, and that answer's value is recorded.
50
52
  - **Checklist** — the built-in step type that asks the visitor to tick any number of answers: a question text, a yes-or-no required setting, and a list of answers, each with a value, a label and an info. The list of ticked values is recorded, and a checklist left with nothing ticked records an empty list.
51
53
  - **Hint** — a short line of text shown under an answer's label on a question step.
@@ -84,10 +84,11 @@ A Rails engine for flows an admin draws on a canvas and a visitor runs one step
84
84
  - After install, check that `<mount path>/manage/flows` shows the flow list and that a new flow opens on the canvas. If the canvas is blank, check that the admin layout calls `yield :head`.
85
85
  - After publishing a flow, check that `<mount path>/<slug>` shows it to a visitor who passes the host's visitor authorization method.
86
86
  - After publishing a flow with a question or a checklist whose answer has info text, check that the visitor's page shows an info button on that answer. If it does not, compare the app's `keystone_ui` version with the one in step 2.
87
+ - After install, check that an End step selected on the canvas shows an output setting. An admin fills it in on each End step, and it needs no migration and no setting in the initializer.
87
88
  - After publishing a flow with a checklist, check that a visitor can tick several answers and go on, and that a checklist marked required refuses to go on with nothing ticked.
88
89
  - After upgrading easy_flow, run `bin/rails easy_flow:install:migrations` again and then `bin/rails db:migrate`. Only migrations the app does not already have are copied.
89
90
  - After setting a host's `owner_method`, check that two different owners each see only their own flows on `<mount path>/manage/flows`.
90
91
  - After setting a host's `offers`, check that the canvas palette on that host's `<mount path>/manage/flows` lists only those step types and End.
91
92
  - Taking a step type off a host's `offers` removes it from the palette only. Steps of that type already in the host's flows stay in them and keep running.
92
93
  - The initializer runs once at boot, so a change to it needs a server restart.
93
- - Declaring step types, including settings kept on the app's own records, serving a host's flows from the app's own controllers and routes, and reading runs and answers are out of scope here. They belong to the `easy_flow-develop` local.
94
+ - Declaring step types, including settings kept on the app's own records, serving a host's flows from the app's own controllers and routes, and reading runs, answers and the output a flow ended with are out of scope here. They belong to the `easy_flow-develop` local.
@@ -32,6 +32,7 @@ sources:
32
32
  - app/models/easy_flow/settings.rb
33
33
  - app/models/easy_flow/canvas.rb
34
34
  - app/controllers/easy_flow/manage/canvas_controller.rb
35
+ - app/models/easy_flow/terminal.rb
35
36
  - app/models/easy_flow/steps/question.rb
36
37
  - app/models/easy_flow/steps/checklist.rb
37
38
  - app/models/easy_flow/step_type.rb
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easy_flow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - tylercschneider