smartdown 0.6.0 → 0.7.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.
Files changed (41) hide show
  1. data/README.md +26 -54
  2. data/lib/smartdown/api/flow.rb +5 -0
  3. data/lib/smartdown/api/previous_question.rb +6 -6
  4. data/lib/smartdown/api/previous_question_page.rb +5 -1
  5. data/lib/smartdown/api/question.rb +4 -0
  6. data/lib/smartdown/api/state.rb +18 -6
  7. data/lib/smartdown/model/answer/base.rb +1 -1
  8. data/lib/smartdown/model/answer/multiple_choice.rb +4 -0
  9. data/lib/smartdown/model/answer/salary.rb +15 -0
  10. data/lib/smartdown/model/scenarios/question.rb +7 -0
  11. data/lib/smartdown/model/scenarios/scenario.rb +7 -0
  12. data/lib/smartdown/model/scenarios/scenario_set.rb +7 -0
  13. data/lib/smartdown/parser/directory_input.rb +2 -2
  14. data/lib/smartdown/parser/input_set.rb +2 -2
  15. data/lib/smartdown/parser/scenario_sets_interpreter.rb +68 -0
  16. data/lib/smartdown/parser/snippet_pre_parser.rb +1 -1
  17. data/lib/smartdown/version.rb +1 -1
  18. data/spec/acceptance/flow_spec.rb +67 -0
  19. data/spec/api/previous_question_spec.rb +25 -0
  20. data/spec/api/state_spec.rb +23 -0
  21. data/spec/fixtures/acceptance/animal-example-multiple/animal-example-multiple.txt +25 -0
  22. data/spec/fixtures/acceptance/animal-example-multiple/outcomes/outcome_safe_pet.txt +69 -0
  23. data/spec/fixtures/acceptance/animal-example-multiple/outcomes/outcome_tigers_are_fine.txt +9 -0
  24. data/spec/fixtures/acceptance/animal-example-multiple/outcomes/outcome_trained_with_lions.txt +3 -0
  25. data/spec/fixtures/acceptance/animal-example-multiple/outcomes/outcome_trained_with_tigers.txt +3 -0
  26. data/spec/fixtures/acceptance/animal-example-multiple/outcomes/outcome_untrained_with_lions.txt +3 -0
  27. data/spec/fixtures/acceptance/animal-example-multiple/questions/question_1.txt +15 -0
  28. data/spec/fixtures/acceptance/animal-example-multiple/questions/question_2.txt +25 -0
  29. data/spec/fixtures/acceptance/animal-example-multiple/questions/question_3.txt +12 -0
  30. data/spec/fixtures/acceptance/animal-example-multiple/scenarios/lions.txt +23 -0
  31. data/spec/fixtures/acceptance/animal-example-multiple/scenarios/tigers_and_cats.txt +3 -0
  32. data/spec/fixtures/acceptance/animal-example-simple/outcomes/outcome_can_outrun_a_lion.txt +3 -0
  33. data/spec/fixtures/acceptance/animal-example-simple/questions/question_2.txt +1 -1
  34. data/spec/fixtures/acceptance/animal-example-simple/questions/question_3.txt +7 -0
  35. data/spec/fixtures/acceptance/animal-example-simple/scenarios/lions.txt +16 -0
  36. data/spec/fixtures/acceptance/animal-example-simple/scenarios/tigers_and_cats.txt +3 -0
  37. data/spec/model/answer/multiple_choice_spec.rb +18 -0
  38. data/spec/model/answer/salary_spec.rb +35 -0
  39. data/spec/parser/directory_input_spec.rb +4 -4
  40. data/spec/support/flow_input_interface.rb +1 -1
  41. metadata +53 -11
data/README.md CHANGED
@@ -10,8 +10,6 @@ The language is designed to look like
10
10
  to allow expression of logical rules, questions and conditional blocks of
11
11
  text.
12
12
 
13
- It's a work-in-progress so some of the features described in this readme haven't been implemented yet. These are indicated with (tbd).
14
-
15
13
  ## Overview
16
14
 
17
15
  A single smartdown flow has a cover sheet, a set of questions, a set of
@@ -34,9 +32,9 @@ flow:
34
32
  | |-- medical_y.txt
35
33
  | `-- ...
36
34
  |-- scenarios
37
- | |-- 1.test
38
- | |-- 2.test
39
- | `-- 3.test
35
+ | |-- 1.txt
36
+ | |-- 2.txt
37
+ | `-- 3.txt
40
38
  |-- questions
41
39
  | |-- planning_to_leave_airport.txt
42
40
  | |-- purpose_of_visit.txt
@@ -108,30 +106,6 @@ to your outbound flight.
108
106
  * no: No
109
107
  ```
110
108
 
111
- ### Country (tbd)
112
-
113
- ```markdown
114
- ## What passport do you have?
115
-
116
- [country: passport_country]
117
- ```
118
-
119
- Presents a drop-down list of countries from the built-in list.
120
-
121
- Use front matter to exclude/include countries
122
-
123
- ```markdown
124
- ---
125
- passport_country:
126
- exclude_countries: country1, country2
127
- include_countries: {country3: "Country 3", country4: "Country 4"}
128
- ---
129
-
130
- ## What passport do you have?
131
-
132
- [country: passport_country]
133
- ```
134
-
135
109
  ### Date
136
110
 
137
111
  ```markdown
@@ -148,30 +122,12 @@ passport_country:
148
122
 
149
123
  Asks for an arbitrary text input.
150
124
 
151
- ### Money (tbd)
152
-
153
- ```markdown
154
- [money]
155
- ```
156
-
157
- Asks for a numerical input which can have decimals and optional thousand-separating commas.
158
-
159
125
  ### Salary
160
126
 
161
127
  ```markdown
162
128
  [salary: salary_value]
163
129
  ```
164
130
 
165
- ### Checkbox (tbd)
166
-
167
- ```markdown
168
- ## Will you pass through UK Border Control?
169
-
170
- [checkbox: uk_border_control]
171
- * [ ] yes: Yes
172
- * [ ] no: No
173
- ```
174
-
175
131
  ## Next steps
176
132
 
177
133
  Markdown to be displayed as part of an outcome to direct the users to other information of potential interest to them.
@@ -305,20 +261,36 @@ More copy...
305
261
  Where `snippet_name` is in a `snippets/` directory in the flow root with a `.txt`
306
262
  extension, eg `my-flow-name/snippets/my_snippet.txt`.
307
263
 
308
- The contents of `my_snippet` will be inseted into the outcome/question.
264
+ The contents of `my_snippet` will be inserted into the outcome/question.
265
+
266
+ ## Scenarios
267
+
268
+ Scenarios are meant to be run as test to check that a Smartdown flow behaves
269
+ in a certain way given some input data.
309
270
 
310
- ## Named predicates (tbd)
271
+ ###Scenario files
311
272
 
312
- Named predicates
273
+ There can be as many scenario files as one wishes, with no restriction on name. Each
274
+ scenario file should contain scenarios written as documented below.
313
275
 
314
- ## Plugin API (tbd)
276
+ ###Format
315
277
 
316
- A plugin API will be provided to allow more complex calculations to be defined
317
- in an external ruby class.
278
+ Each scenario is made of:
279
+ * a description (optional)
280
+ * list of questions pages (each question page starts with a -), inside which questions to answers are defined
281
+ * name of the outcome
282
+
283
+ ```
284
+ # Description
285
+ - name_of_q1_p1: answer_to_q1_p1
286
+ - name_of_q1_p2: answer_to_q1_p2
287
+ name_of_q2_p2: answer_to_q2_p2
288
+ outcome_the_result
289
+ ```
318
290
 
319
291
  ## Software design
320
292
 
321
- The software design can be seen in this diagram:
293
+ The initial plan for software design can be seen in this diagram:
322
294
 
323
295
  ![Software design](https://raw.githubusercontent.com/alphagov/smartdown/master/doc/design.png)
324
296
 
@@ -4,13 +4,18 @@ require 'smartdown/api/state'
4
4
  require 'smartdown/api/coversheet'
5
5
  require 'smartdown/api/question_page'
6
6
  require 'smartdown/api/outcome'
7
+ require 'smartdown/parser/scenario_sets_interpreter'
7
8
 
8
9
  module Smartdown
9
10
  module Api
10
11
  class Flow
12
+
13
+ attr_reader :scenario_sets
14
+
11
15
  def initialize(smartdown_input, initial_state = {})
12
16
  @smartdown_flow = Smartdown::Parser::FlowInterpreter.new(smartdown_input).interpret
13
17
  @engine = Smartdown::Engine.new(@smartdown_flow, initial_state)
18
+ @scenario_sets = Smartdown::Parser::ScenarioSetsInterpreter.new(smartdown_input).interpret
14
19
  end
15
20
 
16
21
  def state(started, responses)
@@ -5,19 +5,19 @@ module Smartdown
5
5
 
6
6
  def_delegators :@question, :title, :options
7
7
 
8
- attr_reader :response, :question
8
+ attr_reader :answer, :question
9
9
 
10
10
  def initialize(elements, response)
11
- @response = response
12
- if elements.find{|element| element.is_a? Smartdown::Model::Element::Question::MultipleChoice}
11
+ if element = elements.find{|element| element.is_a? Smartdown::Model::Element::Question::MultipleChoice}
13
12
  @question = MultipleChoice.new(elements)
14
- elsif elements.find{|element| element.is_a? Smartdown::Model::Element::Question::Date}
13
+ elsif element = elements.find{|element| element.is_a? Smartdown::Model::Element::Question::Date}
15
14
  @question = DateQuestion.new(elements)
16
- elsif elements.find{|element| element.is_a? Smartdown::Model::Element::Question::Salary}
15
+ elsif element = elements.find{|element| element.is_a? Smartdown::Model::Element::Question::Salary}
17
16
  @question = SalaryQuestion.new(elements)
18
- elsif elements.find{|element| element.is_a? Smartdown::Model::Element::Question::Text}
17
+ elsif element = elements.find{|element| element.is_a? Smartdown::Model::Element::Question::Text}
19
18
  @question = TextQuestion.new(elements)
20
19
  end
20
+ @answer = element.answer_type.new(response, element) if element
21
21
  end
22
22
 
23
23
  end
@@ -22,8 +22,12 @@ module Smartdown
22
22
  @responses = responses
23
23
  end
24
24
 
25
+ def answers
26
+ questions.map(&:answer)
27
+ end
28
+
25
29
  def questions
26
- elements.slice_before do |element|
30
+ @questions ||= elements.slice_before do |element|
27
31
  element.is_a? Smartdown::Model::Element::MarkdownHeading
28
32
  end.each_with_index.map do |question_element_group, index|
29
33
  Smartdown::Api::PreviousQuestion.new(question_element_group, responses[index])
@@ -10,6 +10,10 @@ module Smartdown
10
10
  elements.first.content
11
11
  end
12
12
 
13
+ def name
14
+ elements.find{ |element| element.class.to_s.include?("Smartdown::Model::Element::Question") }.name
15
+ end
16
+
13
17
  def body
14
18
  elements_before_smartdown = elements[1..-1].take_while{|element| !smartdown_element?(element)}
15
19
  build_govspeak(elements_before_smartdown)
@@ -12,6 +12,16 @@ module Smartdown
12
12
  @responses = responses
13
13
  end
14
14
 
15
+ def answers
16
+ previous_question_pages(responses).map { |previous_question_page|
17
+ previous_question_page.answers
18
+ }.flatten
19
+ end
20
+
21
+ def previous_question_pages(responses)
22
+ @previous_question_pages ||= build_question_pages(responses)
23
+ end
24
+
15
25
  def started?
16
26
  !current_node.is_a? Smartdown::Api::Coversheet
17
27
  end
@@ -20,12 +30,6 @@ module Smartdown
20
30
  current_node.is_a? Smartdown::Api::Outcome
21
31
  end
22
32
 
23
- def previous_question_pages(responses)
24
- previous_questionpage_smartdown_nodes.map do |smartdown_questionpage_node|
25
- Smartdown::Api::PreviousQuestionPage.new(smartdown_questionpage_node, responses)
26
- end
27
- end
28
-
29
33
  def current_question_number
30
34
  responses.count + 1
31
35
  end
@@ -34,6 +38,14 @@ module Smartdown
34
38
 
35
39
  attr_reader :smartdown_state, :previous_questionpage_smartdown_nodes
36
40
 
41
+ def build_question_pages(responses)
42
+ resp = responses.dup
43
+ previous_questionpage_smartdown_nodes.map do |smartdown_questionpage_node|
44
+ page_questions = resp.take(smartdown_questionpage_node.questions.count)
45
+ resp = resp.drop(smartdown_questionpage_node.questions.count)
46
+ Smartdown::Api::PreviousQuestionPage.new(smartdown_questionpage_node, page_questions)
47
+ end
48
+ end
37
49
  end
38
50
  end
39
51
  end
@@ -5,7 +5,7 @@ module Smartdown
5
5
  extend Forwardable
6
6
  include Comparable
7
7
 
8
- def_delegators :value, :to_s, :to_i, :to_f, :+, :-, :*, :/
8
+ def_delegators :value, :to_s, :humanize, :to_i, :to_f, :+, :-, :*, :/
9
9
 
10
10
  def value_type
11
11
  ::String
@@ -7,6 +7,10 @@ module Smartdown
7
7
  def value_type
8
8
  ::String
9
9
  end
10
+
11
+ def humanize
12
+ question.choices.fetch(value)
13
+ end
10
14
  end
11
15
  end
12
16
  end
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  require_relative "base"
2
3
 
3
4
  module Smartdown
@@ -14,6 +15,11 @@ module Smartdown
14
15
  "#{'%.2f' % amount_per_period} per #{period}"
15
16
  end
16
17
 
18
+ def humanize
19
+ whole, decimal = separate_by_comma(amount_per_period)
20
+ "£#{whole}.#{decimal} per #{period}"
21
+ end
22
+
17
23
  private
18
24
  def parse_value(value)
19
25
  @amount_per_period, @period = value.split(/-|\W*per\W*/)
@@ -31,6 +37,15 @@ module Smartdown
31
37
  amount_per_period
32
38
  end
33
39
  end
40
+
41
+ def separate_by_comma(number)
42
+ left, right = ('%.2f' % number).split('.')
43
+ left.gsub!(/(\d)(?=(\d\d\d)+(?!\d))/) do |digit_to_delimit|
44
+ "#{digit_to_delimit},"
45
+ end
46
+ right = "%02d" % right.to_i
47
+ [left, right]
48
+ end
34
49
  end
35
50
  end
36
51
  end
@@ -0,0 +1,7 @@
1
+ module Smartdown
2
+ module Model
3
+ module Scenarios
4
+ Question = Struct.new(:name, :answer)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Smartdown
2
+ module Model
3
+ module Scenarios
4
+ Scenario = Struct.new(:description, :question_groups, :outcome)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Smartdown
2
+ module Model
3
+ module Scenarios
4
+ ScenarioSet = Struct.new(:name, :scenarios)
5
+ end
6
+ end
7
+ end
@@ -19,7 +19,7 @@ module Smartdown
19
19
  read_dir("outcomes")
20
20
  end
21
21
 
22
- def scenarios
22
+ def scenario_sets
23
23
  read_dir("scenarios")
24
24
  end
25
25
 
@@ -32,7 +32,7 @@ module Smartdown
32
32
  coversheet: coversheet.to_s,
33
33
  questions: questions.map(&:to_s),
34
34
  outcomes: outcomes.map(&:to_s),
35
- scenarios: scenarios.map(&:to_s)
35
+ scenario_sets: scenario_sets.map(&:to_s)
36
36
  }
37
37
  end
38
38
 
@@ -1,14 +1,14 @@
1
1
  module Smartdown
2
2
  module Parser
3
3
  class InputSet
4
- attr_reader :coversheet, :questions, :outcomes, :snippets, :scenarios
4
+ attr_reader :coversheet, :questions, :outcomes, :snippets, :scenario_sets
5
5
 
6
6
  def initialize(params = {})
7
7
  @coversheet = params[:coversheet]
8
8
  @questions = params[:questions]
9
9
  @outcomes = params[:outcomes]
10
10
  @snippets = params[:snippets]
11
- @scenarios = params[:scenarios]
11
+ @scenario_sets = params[:scenario_sets]
12
12
  end
13
13
  end
14
14
 
@@ -0,0 +1,68 @@
1
+ require "smartdown/model/scenarios/scenario_set"
2
+ require "smartdown/model/scenarios/scenario"
3
+ require "smartdown/model/scenarios/question"
4
+
5
+ module Smartdown
6
+ module Parser
7
+ class ScenarioSetsInterpreter
8
+
9
+ def initialize(smartdown_input)
10
+ @smartdown_input = smartdown_input
11
+ end
12
+
13
+ def interpret
14
+ @smartdown_input.scenario_sets.map { |scenario_set| interpret_scenario_set(scenario_set) }
15
+ end
16
+
17
+ private
18
+ def interpret_scenario_set(scenario_set)
19
+ Smartdown::Model::Scenarios::ScenarioSet.new(
20
+ scenario_set.name,
21
+ scenario_set.read.split("\n\n").map { |scenario_string| interpret_scenario(scenario_string) }
22
+ )
23
+ end
24
+
25
+ def interpret_scenario(scenario_string)
26
+ scenario_lines = scenario_string.split("\n")
27
+ if scenario_lines.first.start_with?("#")
28
+ description = scenario_lines.first[1..-1].strip
29
+ scenario_lines = scenario_lines[1..-1]
30
+ end
31
+ outcome = scenario_lines.last
32
+ question_pages = group_questions_by_page(scenario_lines[0..-2])
33
+ question_groups = question_pages.map { |question_page| interpret_question_page(question_page) }
34
+ Smartdown::Model::Scenarios::Scenario.new(
35
+ description,
36
+ question_groups,
37
+ outcome,
38
+ )
39
+ end
40
+
41
+ def group_questions_by_page(scenario_lines)
42
+ result = []
43
+ scenario_lines.each do |scenario_line|
44
+ if scenario_line.start_with?("-")
45
+ result << [scenario_line[1..-1]]
46
+ else
47
+ result.last << scenario_line
48
+ end
49
+ end
50
+ result
51
+ end
52
+
53
+ def interpret_question_page(question_page)
54
+ question_page.map { |question|
55
+ interpret_question(question)
56
+ }
57
+ end
58
+
59
+ def interpret_question(question_string)
60
+ name, answer = question_string.split(":").map(&:strip)
61
+ Smartdown::Model::Scenarios::Question.new(
62
+ name,
63
+ answer,
64
+ )
65
+ end
66
+ end
67
+ end
68
+ end
@@ -17,7 +17,7 @@ module Smartdown
17
17
  questions: input_data.questions.map { |question_data| parse_node_input(question_data) },
18
18
  outcomes: input_data.outcomes.map { |outcome_data| parse_node_input(outcome_data) },
19
19
  snippets: input_data.snippets,
20
- scenarios: input_data.scenarios,
20
+ scenario_sets: input_data.scenario_sets,
21
21
  })
22
22
  end
23
23
 
@@ -1,3 +1,3 @@
1
1
  module Smartdown
2
- VERSION = "0.6.0"
2
+ VERSION = "0.7.0"
3
3
  end
@@ -0,0 +1,67 @@
1
+ require 'smartdown/api/flow'
2
+
3
+ describe Smartdown::Api::Flow do
4
+
5
+ def fixture(name)
6
+ File.dirname(__FILE__) + "/../fixtures/acceptance/#{name}/#{name}.txt"
7
+ end
8
+
9
+ let(:input) { Smartdown::Parser::DirectoryInput.new(fixture("animal-example-simple")) }
10
+ subject(:flow) { Smartdown::Api::Flow.new(input) }
11
+
12
+ context "flow with one question per page" do
13
+ it "has two scenario_sets" do
14
+ expect(flow.scenario_sets.size).to eq(2)
15
+ end
16
+
17
+ it "has scenario_set names" do
18
+ expect(flow.scenario_sets.map(&:name)).to match_array(["lions", "tigers_and_cats"])
19
+ end
20
+
21
+ it "has scenarios with description, questions and outcome" do
22
+ tigers_and_cats_scenario_set = flow.scenario_sets.find { |scenario_set| scenario_set.name == "tigers_and_cats" }
23
+ expect(tigers_and_cats_scenario_set.scenarios.size).to eq(1)
24
+ expect(tigers_and_cats_scenario_set.scenarios.first.description).to eq("User has a cat")
25
+ expect(tigers_and_cats_scenario_set.scenarios.first.question_groups.size).to eq(1)
26
+ expect(tigers_and_cats_scenario_set.scenarios.first.outcome).to eq("outcome_safe_pet")
27
+ end
28
+
29
+ it "has scenario questions with name and answer" do
30
+ tigers_and_cats_scenario_set = flow.scenario_sets.find { |scenario_set| scenario_set.name == "tigers_and_cats" }
31
+ tigers_and_cats_scenario = tigers_and_cats_scenario_set.scenarios.first
32
+ expect(tigers_and_cats_scenario.question_groups.first.first.name).to eq("question_1")
33
+ expect(tigers_and_cats_scenario.question_groups.first.first.answer).to eq("cat")
34
+ end
35
+ end
36
+
37
+ context "flow with two questions per page" do
38
+ let(:input) { Smartdown::Parser::DirectoryInput.new(fixture("animal-example-multiple")) }
39
+ it "has two scenario_sets" do
40
+ expect(flow.scenario_sets.size).to eq(2)
41
+ end
42
+
43
+ it "has scenario_set names" do
44
+ expect(flow.scenario_sets.map(&:name)).to match_array(["lions", "tigers_and_cats"])
45
+ end
46
+
47
+ it "has scenarios with description, questions and outcome" do
48
+ tigers_and_cats_scenario_set = flow.scenario_sets.find { |scenario_set| scenario_set.name == "lions" }
49
+ expect(tigers_and_cats_scenario_set.scenarios.size).to eq(4)
50
+ expect(tigers_and_cats_scenario_set.scenarios.first.description).to eq("User has trained with lions, not with tigers")
51
+ expect(tigers_and_cats_scenario_set.scenarios.first.question_groups.size).to eq(2)
52
+ expect(tigers_and_cats_scenario_set.scenarios.first.outcome).to eq("outcome_trained_with_lions")
53
+ end
54
+
55
+ it "has scenario questions with name and answer" do
56
+ tigers_and_cats_scenario_set = flow.scenario_sets.find { |scenario_set| scenario_set.name == "lions" }
57
+ tigers_and_cats_scenario = tigers_and_cats_scenario_set.scenarios.first
58
+ expect(tigers_and_cats_scenario.question_groups[1][0].name).to eq("trained_for_lions")
59
+ expect(tigers_and_cats_scenario.question_groups[1][0].answer).to eq("yes")
60
+ expect(tigers_and_cats_scenario.question_groups[1][1].name).to eq("trained_for_tigers")
61
+ expect(tigers_and_cats_scenario.question_groups[1][1].answer).to eq("no")
62
+ end
63
+ end
64
+
65
+ end
66
+
67
+
@@ -0,0 +1,25 @@
1
+ require 'smartdown/api/previous_question'
2
+ require 'smartdown/api/multiple_choice'
3
+
4
+ describe Smartdown::Api::PreviousQuestion do
5
+
6
+ subject(:previous_question) { Smartdown::Api::PreviousQuestion.new(elements, response)}
7
+ let(:elements) { [ multiple_choice_element ] }
8
+ let(:multiple_choice_element) { Smartdown::Model::Element::Question::MultipleChoice.new }
9
+ let(:response) { double(:response) }
10
+ let(:multiple_choice_class) { double(:multiple_choice_class, :new => nil) }
11
+ let(:answer_type) { double(:answer_type) }
12
+
13
+ describe "#question" do
14
+ it "is of the correct type" do
15
+ expect(previous_question.question).to be_instance_of(Smartdown::Api::MultipleChoice)
16
+ end
17
+ end
18
+
19
+ describe "#answer" do
20
+ it "is of the correct type" do
21
+ expect(previous_question.answer).to be_instance_of(Smartdown::Model::Answer::MultipleChoice)
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,23 @@
1
+ require 'smartdown/api/state'
2
+
3
+ describe Smartdown::Api::State do
4
+
5
+ subject(:state) { Smartdown::Api::State.new(current_node, previous_questionpage_smartdown_nodes, responses)}
6
+ let(:current_node) { double(:current_node) }
7
+ let(:previous_questionpage_smartdown_nodes) { [question_page_node_1, question_page_node_2] }
8
+ let(:question_page_node_1) { double(:question_page_node_1, :questions => [double, double]) }
9
+ let(:question_page_node_2) { double(:question_page_node_2, :questions => [double]) }
10
+ let(:responses) { ["a", "b", "c"] }
11
+ let(:previous_question_page_class) { double(:previous_question_page_class, :new => nil)}
12
+
13
+ describe "#previous_question_pages" do
14
+ it "creates question pages with their corresponding responses" do
15
+ stub_const("Smartdown::Api::PreviousQuestionPage", previous_question_page_class)
16
+ state.previous_question_pages(responses)
17
+ expect(Smartdown::Api::PreviousQuestionPage).to have_received(:new)
18
+ .with(question_page_node_1, ["a", "b"])
19
+ expect(Smartdown::Api::PreviousQuestionPage).to have_received(:new)
20
+ .with(question_page_node_2, ["c"])
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ meta_description: Animals eh?
2
+ satisfies_need: 100982
3
+ status: draft
4
+
5
+ # A simple example of smartdown
6
+
7
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
8
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
9
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
10
+ consequat.
11
+
12
+ Duis aute irure dolor in reprehenderit in voluptate velit esse
13
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
14
+ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
15
+
16
+ ## Before you start, you will need
17
+
18
+ * To know the kind of feline you have
19
+ * Any animal training certification documents
20
+
21
+ [start: question_1]
22
+
23
+ ## Devolved body
24
+
25
+ Which is really just body content after the start button
@@ -0,0 +1,69 @@
1
+ # You picked a safe pet
2
+
3
+ Good call.
4
+
5
+ # Markdown/Govspeak examples
6
+
7
+ ## H2 example
8
+
9
+ With answers, that are smart. Down with that?
10
+
11
+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
12
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
13
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
14
+
15
+ ### H3 example
16
+
17
+ consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
18
+ cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
19
+ proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
20
+
21
+ ## List
22
+
23
+ * one
24
+ * two
25
+ * three
26
+
27
+ ## List 2
28
+
29
+ - A
30
+ - B
31
+ - C
32
+
33
+ ## List 3
34
+
35
+ + Up
36
+ + Down
37
+ + Left
38
+ + Right
39
+
40
+ ^This is an information callout.^
41
+
42
+ %This is a warning callout - use it when there’s a risk of getting a fine or going to prison.%
43
+
44
+ $E
45
+ **Example**
46
+ Your income for the last tax year was £30,000. You think your income will drop to £20,000 this tax year. Enter £22,500 into the calculator.
47
+ $E
48
+
49
+ {::highlight-answer}
50
+ The VAT rate is *20%*
51
+ {:/highlight-answer}
52
+
53
+
54
+ $C
55
+ **Student Finance England**
56
+ Telephone: 0845 300 5090
57
+ Minicom: 0845 604 4434
58
+ [Find out about call charges](http://www.gov.uk/call-charges)
59
+ $C
60
+
61
+ $A
62
+ Hercules House
63
+ Hercules Road
64
+ London SE1 7DU
65
+ $A
66
+
67
+ $D
68
+ [Download the 'Example application form' (PDF, 35KB)](http://example.com/ "Example form")
69
+ $D
@@ -0,0 +1,9 @@
1
+ # Tigers are fine
2
+
3
+ You haven't trained with tigers, but you'll be alright, probably.
4
+
5
+ [next_steps]
6
+ ###You bought a tiger? Seriously?
7
+
8
+ [Your nearest hospital](https://gov.uk/hospital)
9
+ [end_next_steps]
@@ -0,0 +1,3 @@
1
+ # You've trained with lions
2
+
3
+ You'll be alright, you won't forget your training for another %{years_until_training_forgotten(training_date)} years.
@@ -0,0 +1,3 @@
1
+ # You've trained with tigers
2
+
3
+ Grrrrreat!
@@ -0,0 +1,3 @@
1
+ # You're not trained with lions
2
+
3
+ Nice to know you.
@@ -0,0 +1,15 @@
1
+ # What type of feline do you have?
2
+
3
+ # Check the serial number by the tail.
4
+
5
+ Text before the options.
6
+
7
+ [choice: question_1]
8
+ * lion: Lion
9
+ * tiger: Tiger
10
+ * cat: Cat
11
+
12
+ This is an optional note after question.
13
+
14
+ * question_1 in {lion tiger} => question_2
15
+ * otherwise => outcome_safe_pet
@@ -0,0 +1,25 @@
1
+ # How good is your big cat training?
2
+
3
+ # Are you trained for lions?
4
+
5
+ Think very carefully.
6
+
7
+ [choice: trained_for_lions]
8
+ * yes: Yes
9
+ * no: No
10
+
11
+ # Are you trained for tigers?
12
+
13
+ Think very carefully again.
14
+
15
+ [choice: trained_for_tigers]
16
+ * yes: Yes
17
+ * maybe: I've been to a zoo once
18
+ * no: No
19
+
20
+ * question_1 is 'lion'
21
+ * trained_for_lions is 'yes' => question_3
22
+ * otherwise => outcome_untrained_with_lions
23
+ * otherwise
24
+ * trained_for_tigers is 'yes' => question_3
25
+ * otherwise => outcome_tigers_are_fine
@@ -0,0 +1,12 @@
1
+ # Training date?
2
+
3
+ When did you do your %{question_1} training?
4
+
5
+ [date: training_date]
6
+
7
+ * question_1 is 'lion'
8
+ * trained_for_lions is 'yes' => outcome_trained_with_lions
9
+ * otherwise => outcome_untrained_with_lions
10
+ * otherwise
11
+ * trained_for_tigers is 'yes' => outcome_trained_with_tigers
12
+ * otherwise => outcome_tigers_are_fine
@@ -0,0 +1,23 @@
1
+ #User has trained with lions, not with tigers
2
+ - question_1: lion
3
+ - trained_for_lions: yes
4
+ trained_for_tigers: no
5
+ outcome_trained_with_lions
6
+
7
+ #User has trained with lions and tigers
8
+ - question_1: lion
9
+ - trained_for_lions: yes
10
+ trained_for_lions: yes
11
+ outcome_can_outrun_a_lion
12
+
13
+ #User has trained neither with lions, nor with tigers
14
+ - question_1: lion
15
+ - trained_for_lions: no
16
+ trained_for_tigers: no
17
+ outcome_untrained_with_lions
18
+
19
+ #User has trained with tigers, not with lions
20
+ - question_1: lion
21
+ - trained_for_lions: no
22
+ trained_for_tigers: yes
23
+ outcome_untrained_with_lions
@@ -0,0 +1,3 @@
1
+ #User has a cat
2
+ - question_1: cat
3
+ outcome_safe_pet
@@ -0,0 +1,3 @@
1
+ # You can outrun a lion
2
+
3
+ You'll be alright, I think.
@@ -6,5 +6,5 @@
6
6
 
7
7
  * question_1 is 'lion'
8
8
  * trained_for_lions is 'yes' => outcome_trained_with_lions
9
- * otherwise => outcome_untrained_with_lions
9
+ * otherwise => question_3
10
10
  * otherwise => outcome_tigers_are_fine
@@ -0,0 +1,7 @@
1
+ # How fast can you run?
2
+
3
+ [text: how_fast]
4
+
5
+ * how_fast is 'fast' => outcome_can_outrun_a_lion
6
+ * otherwise => outcome_untrained_with_lions
7
+
@@ -0,0 +1,16 @@
1
+ # User has trained with lions
2
+ - question_1: lion
3
+ - trained_for_lions: yes
4
+ outcome_trained_with_lions
5
+
6
+ # User has not trained with lions but can run fast
7
+ - question_1: lion
8
+ - trained_for_lions: no
9
+ - how_fast: fast
10
+ outcome_can_outrun_a_lion
11
+
12
+ # User has not trained with lions and runs very slowly
13
+ - question_1: lion
14
+ - trained_for_lions: no
15
+ - how_fast: very slowly
16
+ outcome_untrained_with_lions
@@ -0,0 +1,3 @@
1
+ # User has a cat
2
+ - question_1: cat
3
+ outcome_safe_pet
@@ -0,0 +1,18 @@
1
+ # encoding: utf-8
2
+ require 'smartdown/model/answer/multiple_choice'
3
+
4
+ describe Smartdown::Model::Answer::MultipleChoice do
5
+
6
+ subject(:answer) { described_class.new("answer", multiple_choice_question) }
7
+ let(:multiple_choice_question) {
8
+ Smartdown::Model::Element::Question::MultipleChoice.new("question",
9
+ {"answer" => "Beautiful answer"}
10
+ )
11
+ }
12
+
13
+ describe "#humanize" do
14
+ it "returns the humanized answer" do
15
+ expect(answer.humanize).to eq "Beautiful answer"
16
+ end
17
+ end
18
+ end
@@ -1,3 +1,4 @@
1
+ # encoding: utf-8
1
2
  require 'smartdown/model/answer/date'
2
3
  require 'smartdown/model/element/question/date'
3
4
 
@@ -13,6 +14,40 @@ describe Smartdown::Model::Answer::Salary do
13
14
  expect(instance.to_s).to eql("500.00 per week")
14
15
  end
15
16
 
17
+ describe "#humanize" do
18
+ it "declares itself in the initial format provided" do
19
+ expect(instance.humanize).to eql("£500.00 per week")
20
+ end
21
+
22
+ context "amounts over 999" do
23
+ let(:salary_string) { "15000-week" }
24
+ it "adds commas" do
25
+ expect(instance.humanize).to eql("£15,000.00 per week")
26
+ end
27
+ end
28
+
29
+ context "amounts with .525 decimal part" do
30
+ let(:salary_string) { "15000.525-week" }
31
+ it "adds commas" do
32
+ expect(instance.humanize).to eql("£15,000.52 per week")
33
+ end
34
+ end
35
+
36
+ context "amounts with .555 decimal part" do
37
+ let(:salary_string) { "15000.555-week" }
38
+ it "adds commas" do
39
+ expect(instance.humanize).to eql("£15,000.56 per week")
40
+ end
41
+ end
42
+
43
+ context "amounts with .556 decimal part" do
44
+ let(:salary_string) { "15000.556-week" }
45
+ it "adds commas" do
46
+ expect(instance.humanize).to eql("£15,000.56 per week")
47
+ end
48
+ end
49
+ end
50
+
16
51
  context "declared by week" do
17
52
  let(:salary_string) { "500-week" }
18
53
  specify { expect(instance.value).to eql 500.0 * 52 }
@@ -40,11 +40,11 @@ describe Smartdown::Parser::DirectoryInput do
40
40
  end
41
41
  end
42
42
 
43
- describe "#scenarios" do
43
+ describe "#scenario_sets" do
44
44
  it "returns an InputFile for every file in the scenarios folder" do
45
- expect(input.scenarios).to match([instance_of(Smartdown::Parser::InputFile)])
46
- expect(input.scenarios.first.name).to eq("s1")
47
- expect(input.scenarios.first.read).to eq("scenario one\n")
45
+ expect(input.scenario_sets).to match([instance_of(Smartdown::Parser::InputFile)])
46
+ expect(input.scenario_sets.first.name).to eq("s1")
47
+ expect(input.scenario_sets.first.read).to eq("scenario one\n")
48
48
  end
49
49
  end
50
50
 
@@ -2,6 +2,6 @@ shared_examples "flow input interface" do
2
2
  it { should respond_to(:coversheet) }
3
3
  it { should respond_to(:questions) }
4
4
  it { should respond_to(:outcomes) }
5
- it { should respond_to(:scenarios) }
5
+ it { should respond_to(:scenario_sets) }
6
6
  it { should respond_to(:snippets) }
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smartdown
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2014-07-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: parslet
16
- requirement: &18240820 !ruby/object:Gem::Requirement
16
+ requirement: &14489700 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 1.6.1
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *18240820
24
+ version_requirements: *14489700
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &18238780 !ruby/object:Gem::Requirement
27
+ requirement: &14488200 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 3.0.0
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *18238780
35
+ version_requirements: *14488200
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rake
38
- requirement: &18237320 !ruby/object:Gem::Requirement
38
+ requirement: &14504920 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *18237320
46
+ version_requirements: *14504920
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: gem_publisher
49
- requirement: &18235860 !ruby/object:Gem::Requirement
49
+ requirement: &14504180 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,7 +54,7 @@ dependencies:
54
54
  version: '0'
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *18235860
57
+ version_requirements: *14504180
58
58
  description:
59
59
  email: david.heath@digital.cabinet-office.gov.uk
60
60
  executables:
@@ -73,6 +73,7 @@ files:
73
73
  - lib/smartdown/parser/directory_input.rb
74
74
  - lib/smartdown/parser/rules.rb
75
75
  - lib/smartdown/parser/node_parser.rb
76
+ - lib/smartdown/parser/scenario_sets_interpreter.rb
76
77
  - lib/smartdown/parser/element/date_question.rb
77
78
  - lib/smartdown/parser/element/salary_question.rb
78
79
  - lib/smartdown/parser/element/conditional.rb
@@ -105,6 +106,9 @@ files:
105
106
  - lib/smartdown/engine/transition.rb
106
107
  - lib/smartdown/engine/interpolator.rb
107
108
  - lib/smartdown/engine/errors.rb
109
+ - lib/smartdown/model/scenarios/question.rb
110
+ - lib/smartdown/model/scenarios/scenario_set.rb
111
+ - lib/smartdown/model/scenarios/scenario.rb
108
112
  - lib/smartdown/model/flow.rb
109
113
  - lib/smartdown/model/predicate/named.rb
110
114
  - lib/smartdown/model/predicate/set_membership.rb
@@ -142,6 +146,7 @@ files:
142
146
  - README.md
143
147
  - spec/acceptance/parsing_spec.rb
144
148
  - spec/acceptance/smartdown_cli_spec.rb
149
+ - spec/acceptance/flow_spec.rb
145
150
  - spec/parser/directory_input_spec.rb
146
151
  - spec/parser/integration/cover_sheet_spec.rb
147
152
  - spec/parser/base_spec.rb
@@ -162,6 +167,8 @@ files:
162
167
  - spec/parser/snippet_pre_parser_spec.rb
163
168
  - spec/support/flow_input_interface.rb
164
169
  - spec/support/model_builder.rb
170
+ - spec/api/state_spec.rb
171
+ - spec/api/previous_question_spec.rb
165
172
  - spec/spec_helper.rb
166
173
  - spec/engine/state_spec.rb
167
174
  - spec/engine/interpolator_spec.rb
@@ -175,13 +182,28 @@ files:
175
182
  - spec/fixtures/acceptance/question-and-outcome/question-and-outcome.txt
176
183
  - spec/fixtures/acceptance/question-and-outcome/outcomes/o1.txt
177
184
  - spec/fixtures/acceptance/question-and-outcome/questions/q1.txt
185
+ - spec/fixtures/acceptance/animal-example-simple/scenarios/tigers_and_cats.txt
186
+ - spec/fixtures/acceptance/animal-example-simple/scenarios/lions.txt
178
187
  - spec/fixtures/acceptance/animal-example-simple/outcomes/outcome_untrained_with_lions.txt
179
188
  - spec/fixtures/acceptance/animal-example-simple/outcomes/outcome_tigers_are_fine.txt
189
+ - spec/fixtures/acceptance/animal-example-simple/outcomes/outcome_can_outrun_a_lion.txt
180
190
  - spec/fixtures/acceptance/animal-example-simple/outcomes/outcome_safe_pet.txt
181
191
  - spec/fixtures/acceptance/animal-example-simple/outcomes/outcome_trained_with_lions.txt
182
192
  - spec/fixtures/acceptance/animal-example-simple/animal-example-simple.txt
193
+ - spec/fixtures/acceptance/animal-example-simple/questions/question_3.txt
183
194
  - spec/fixtures/acceptance/animal-example-simple/questions/question_1.txt
184
195
  - spec/fixtures/acceptance/animal-example-simple/questions/question_2.txt
196
+ - spec/fixtures/acceptance/animal-example-multiple/scenarios/tigers_and_cats.txt
197
+ - spec/fixtures/acceptance/animal-example-multiple/scenarios/lions.txt
198
+ - spec/fixtures/acceptance/animal-example-multiple/outcomes/outcome_trained_with_tigers.txt
199
+ - spec/fixtures/acceptance/animal-example-multiple/outcomes/outcome_untrained_with_lions.txt
200
+ - spec/fixtures/acceptance/animal-example-multiple/outcomes/outcome_tigers_are_fine.txt
201
+ - spec/fixtures/acceptance/animal-example-multiple/outcomes/outcome_safe_pet.txt
202
+ - spec/fixtures/acceptance/animal-example-multiple/outcomes/outcome_trained_with_lions.txt
203
+ - spec/fixtures/acceptance/animal-example-multiple/animal-example-multiple.txt
204
+ - spec/fixtures/acceptance/animal-example-multiple/questions/question_3.txt
205
+ - spec/fixtures/acceptance/animal-example-multiple/questions/question_1.txt
206
+ - spec/fixtures/acceptance/animal-example-multiple/questions/question_2.txt
185
207
  - spec/fixtures/acceptance/cover-sheet/cover-sheet.txt
186
208
  - spec/fixtures/acceptance/one-question/one-question.txt
187
209
  - spec/fixtures/acceptance/one-question/questions/q1.txt
@@ -193,6 +215,7 @@ files:
193
215
  - spec/model/node_spec.rb
194
216
  - spec/model/flow_spec.rb
195
217
  - spec/model/answer/money_spec.rb
218
+ - spec/model/answer/multiple_choice_spec.rb
196
219
  - spec/model/answer/text_spec.rb
197
220
  - spec/model/answer/base_spec.rb
198
221
  - spec/model/answer/salary_spec.rb
@@ -218,7 +241,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
218
241
  version: '0'
219
242
  segments:
220
243
  - 0
221
- hash: -4119241983513724352
244
+ hash: -1023483134513177718
222
245
  required_rubygems_version: !ruby/object:Gem::Requirement
223
246
  none: false
224
247
  requirements:
@@ -227,7 +250,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
227
250
  version: '0'
228
251
  segments:
229
252
  - 0
230
- hash: -4119241983513724352
253
+ hash: -1023483134513177718
231
254
  requirements: []
232
255
  rubyforge_project:
233
256
  rubygems_version: 1.8.11
@@ -237,6 +260,7 @@ summary: Interactive question-answer flows using markdown-like external DSL
237
260
  test_files:
238
261
  - spec/acceptance/parsing_spec.rb
239
262
  - spec/acceptance/smartdown_cli_spec.rb
263
+ - spec/acceptance/flow_spec.rb
240
264
  - spec/parser/directory_input_spec.rb
241
265
  - spec/parser/integration/cover_sheet_spec.rb
242
266
  - spec/parser/base_spec.rb
@@ -257,6 +281,8 @@ test_files:
257
281
  - spec/parser/snippet_pre_parser_spec.rb
258
282
  - spec/support/flow_input_interface.rb
259
283
  - spec/support/model_builder.rb
284
+ - spec/api/state_spec.rb
285
+ - spec/api/previous_question_spec.rb
260
286
  - spec/spec_helper.rb
261
287
  - spec/engine/state_spec.rb
262
288
  - spec/engine/interpolator_spec.rb
@@ -270,13 +296,28 @@ test_files:
270
296
  - spec/fixtures/acceptance/question-and-outcome/question-and-outcome.txt
271
297
  - spec/fixtures/acceptance/question-and-outcome/outcomes/o1.txt
272
298
  - spec/fixtures/acceptance/question-and-outcome/questions/q1.txt
299
+ - spec/fixtures/acceptance/animal-example-simple/scenarios/tigers_and_cats.txt
300
+ - spec/fixtures/acceptance/animal-example-simple/scenarios/lions.txt
273
301
  - spec/fixtures/acceptance/animal-example-simple/outcomes/outcome_untrained_with_lions.txt
274
302
  - spec/fixtures/acceptance/animal-example-simple/outcomes/outcome_tigers_are_fine.txt
303
+ - spec/fixtures/acceptance/animal-example-simple/outcomes/outcome_can_outrun_a_lion.txt
275
304
  - spec/fixtures/acceptance/animal-example-simple/outcomes/outcome_safe_pet.txt
276
305
  - spec/fixtures/acceptance/animal-example-simple/outcomes/outcome_trained_with_lions.txt
277
306
  - spec/fixtures/acceptance/animal-example-simple/animal-example-simple.txt
307
+ - spec/fixtures/acceptance/animal-example-simple/questions/question_3.txt
278
308
  - spec/fixtures/acceptance/animal-example-simple/questions/question_1.txt
279
309
  - spec/fixtures/acceptance/animal-example-simple/questions/question_2.txt
310
+ - spec/fixtures/acceptance/animal-example-multiple/scenarios/tigers_and_cats.txt
311
+ - spec/fixtures/acceptance/animal-example-multiple/scenarios/lions.txt
312
+ - spec/fixtures/acceptance/animal-example-multiple/outcomes/outcome_trained_with_tigers.txt
313
+ - spec/fixtures/acceptance/animal-example-multiple/outcomes/outcome_untrained_with_lions.txt
314
+ - spec/fixtures/acceptance/animal-example-multiple/outcomes/outcome_tigers_are_fine.txt
315
+ - spec/fixtures/acceptance/animal-example-multiple/outcomes/outcome_safe_pet.txt
316
+ - spec/fixtures/acceptance/animal-example-multiple/outcomes/outcome_trained_with_lions.txt
317
+ - spec/fixtures/acceptance/animal-example-multiple/animal-example-multiple.txt
318
+ - spec/fixtures/acceptance/animal-example-multiple/questions/question_3.txt
319
+ - spec/fixtures/acceptance/animal-example-multiple/questions/question_1.txt
320
+ - spec/fixtures/acceptance/animal-example-multiple/questions/question_2.txt
280
321
  - spec/fixtures/acceptance/cover-sheet/cover-sheet.txt
281
322
  - spec/fixtures/acceptance/one-question/one-question.txt
282
323
  - spec/fixtures/acceptance/one-question/questions/q1.txt
@@ -288,6 +329,7 @@ test_files:
288
329
  - spec/model/node_spec.rb
289
330
  - spec/model/flow_spec.rb
290
331
  - spec/model/answer/money_spec.rb
332
+ - spec/model/answer/multiple_choice_spec.rb
291
333
  - spec/model/answer/text_spec.rb
292
334
  - spec/model/answer/base_spec.rb
293
335
  - spec/model/answer/salary_spec.rb