smartdown 0.11.1 → 0.11.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -84,9 +84,9 @@ module Smartdown
84
84
  private
85
85
 
86
86
  def transform_node(node)
87
- if node.elements.any?{|element| element.is_a? Smartdown::Model::Element::StartButton}
87
+ if node.is_start_page_node?
88
88
  Smartdown::Api::Coversheet.new(node)
89
- elsif node.elements.any?{|element| element.is_a? Smartdown::Model::NextNodeRules}
89
+ elsif node.is_question_node?
90
90
  if node.elements.any?{|element| element.class.to_s.include?("Smartdown::Model::Element::Question")}
91
91
  Smartdown::Api::QuestionPage.new(node)
92
92
  else
@@ -27,12 +27,15 @@ module Smartdown
27
27
  end
28
28
 
29
29
  def post_body
30
- elements_after_smartdown = elements.drop_while{|element| !smartdown_element?(element)}
30
+ elements_after_smartdown = elements.select{ |element| !next_node_element?(element) }
31
+ .reverse
32
+ .take_while{|element| !smartdown_element?(element)}
33
+ .reverse
31
34
  build_govspeak(elements_after_smartdown)
32
35
  end
33
36
 
34
37
  def next_nodes
35
- elements.select{ |element| element.is_a? Smartdown::Model::NextNodeRules }
38
+ elements.select{ |element| next_node_element? element }
36
39
  end
37
40
 
38
41
  def permitted_next_nodes
@@ -45,12 +48,18 @@ module Smartdown
45
48
  (element.is_a? Smartdown::Model::Element::MarkdownParagraph) || (element.is_a? Smartdown::Model::Element::MarkdownHeading)
46
49
  end
47
50
 
51
+ def next_node_element?(element)
52
+ (element.is_a? Smartdown::Model::NextNodeRules)
53
+ end
54
+
48
55
  def smartdown_element?(element)
49
56
  !markdown_element?(element)
50
57
  end
51
58
 
52
59
  def build_govspeak(elements)
53
- elements.select { |element| markdown_element?(element) }.map(&:content).join("\n")
60
+ elements.select { |element| markdown_element?(element) }
61
+ return nil if elements.empty?
62
+ elements.map(&:content).join("\n")
54
63
  end
55
64
  end
56
65
  end
@@ -1,3 +1,7 @@
1
+ require 'parslet'
2
+ require 'smartdown/parser/node_transform'
3
+ require 'smartdown/parser/predicates'
4
+
1
5
  module Smartdown
2
6
  class Engine
3
7
  class Interpolator
@@ -24,28 +24,28 @@ module Smartdown
24
24
  {}.merge(@initial_state)
25
25
  end
26
26
 
27
- def process(raw_responses, test_start_state = nil)
28
- #TODO: change interface to match started, raw_responses like API state...no need for shifting etc...
29
- state = test_start_state || build_start_state
30
- unprocessed_responses = raw_responses
27
+ def process(unprocessed_responses, test_start_state = nil)
28
+ state = test_start_state || build_start_state
29
+
31
30
  while !unprocessed_responses.empty? do
32
31
  current_node = flow.node(state.get(:current_node))
33
-
32
+ break if current_node.is_outcome_page_node?
33
+
34
34
  if current_node.is_start_page_node?
35
35
  # If it's a start page node, we've got to do something different because of the preceeding 'y' answer
36
- transition = Transition.new(state, current_node, unprocessed_responses.shift(1))
36
+ answers = unprocessed_responses.shift(1)
37
37
  else
38
38
  answers = current_node.questions.map do |question|
39
39
  question.answer_type.new(unprocessed_responses.shift, question)
40
40
  end
41
-
42
- unless answers.all?(&:valid?)
41
+ if answers.any?(&:invalid?)
43
42
  state = state.put(:current_answers, answers)
44
43
  break
45
44
  end
46
- transition = Transition.new(state, current_node, answers)
47
45
  end
48
- state = transition.next_state
46
+
47
+ transition = Transition.new(state, current_node, answers)
48
+ state = transition.next_state
49
49
  end
50
50
  state
51
51
  end
@@ -43,6 +43,10 @@ module Smartdown
43
43
  @error.nil?
44
44
  end
45
45
 
46
+ def invalid?
47
+ !valid?
48
+ end
49
+
46
50
  private
47
51
  def parse_other_object(comparison_object)
48
52
  if comparison_object.is_a? Base
@@ -37,6 +37,14 @@ module Smartdown
37
37
  @is_start_page_node ||= !!start_button
38
38
  end
39
39
 
40
+ def is_question_node?
41
+ @is_question_node ||= elements.any?{|element| element.is_a? Smartdown::Model::NextNodeRules}
42
+ end
43
+
44
+ def is_outcome_page_node?
45
+ @is_outcome_page_node ||= !is_start_page_node? && !is_question_node?
46
+ end
47
+
40
48
  private
41
49
 
42
50
  def markdown_blocks_before_question
@@ -1,3 +1,3 @@
1
1
  module Smartdown
2
- VERSION = "0.11.1"
2
+ VERSION = "0.11.2"
3
3
  end
@@ -0,0 +1,148 @@
1
+ require 'smartdown/api/node'
2
+ require 'smartdown/api/question'
3
+ require 'smartdown/api/date_question'
4
+ require 'smartdown/model/node'
5
+ require 'smartdown/model/front_matter'
6
+ require 'smartdown/model/next_node_rules'
7
+ require 'smartdown/model/element/question/date'
8
+ require 'smartdown/model/element/markdown_heading'
9
+ require 'smartdown/model/element/markdown_paragraph'
10
+
11
+ describe Smartdown::Api::Node do
12
+
13
+ subject(:node) { Smartdown::Api::Node.new(node_model) }
14
+
15
+ let(:node_name) { "New Oxford Dictionary of English" }
16
+ let(:front_matter) { Smartdown::Model::FrontMatter.new({}) }
17
+ let(:node_model) { Smartdown::Model::Node.new(node_name, elements, front_matter) }
18
+
19
+ let(:next_node_rules_content) {
20
+ %{ Rule 1: Do not talk about Fight Club.
21
+ Rule 2: Do not talk about Fight Club.
22
+ Rule 3: If someone says "stop" or goes limp, taps out the fight is over.
23
+ Rule 4: Only two guys to a fight.
24
+ Rule 5: One fight at a time.
25
+ Rule 6: No shirts, no shoes.
26
+ Rule 7: Fights will go on as long as they have to.
27
+ Rule 8: If this is your first night at Fight Club, you have to fight.} }
28
+ let(:next_node_rules) { Smartdown::Model::NextNodeRules.new(next_node_rules_content) }
29
+
30
+ let(:question_element) {
31
+ Smartdown::Model::Element::Question::Date.new(name, *args)
32
+ }
33
+ let(:aliaz) { nil }
34
+ let(:args) { [start_year, end_year, aliaz] }
35
+ let(:name) { "a question" }
36
+ let(:start_year) { nil }
37
+ let(:end_year) { nil }
38
+
39
+ let(:node_heading_content) { "hehehe" }
40
+ let(:node_heading) { Smartdown::Model::Element::MarkdownHeading.new(node_heading_content) }
41
+
42
+ let(:question_heading_content) { "Do you feel lucky?" }
43
+ let(:question_heading) { Smartdown::Model::Element::MarkdownHeading.new(question_heading_content) }
44
+
45
+ let(:body_content) { "I <3 bodyshopping" }
46
+ let(:body_element) {
47
+ Smartdown::Model::Element::MarkdownParagraph.new(body_content)
48
+ }
49
+
50
+ let(:post_body_content) { "hur hur such content" }
51
+ let(:post_body_element) {
52
+ Smartdown::Model::Element::MarkdownParagraph.new(post_body_content)
53
+ }
54
+
55
+ let(:other_post_body_content) { "Postman Pat and his black and white cat" }
56
+ let(:other_post_body_element) {
57
+ Smartdown::Model::Element::MarkdownParagraph.new(other_post_body_content)
58
+ }
59
+
60
+
61
+ context "with a body and post_body (and next node rules)" do
62
+ let(:elements) { [node_heading, body_element, question_heading, question_element, post_body_element, other_post_body_element, next_node_rules] }
63
+
64
+ describe "#body" do
65
+ it 'returns the content before the question element' do
66
+ body = [body_content, question_heading_content].join("\n")
67
+ expect(node.body).to eq(body)
68
+ end
69
+ end
70
+
71
+ describe '#post_body' do
72
+ it 'returns the content after the question element' do
73
+ post_body = [post_body_content, other_post_body_content].join("\n")
74
+ expect(node.post_body).to eq(post_body)
75
+ end
76
+ end
77
+ end
78
+
79
+ context "missing a body" do
80
+ let(:elements) { [question_element, post_body_element] }
81
+
82
+ describe "#body" do
83
+ it 'returns nil' do
84
+ expect(node.body).to eq(nil)
85
+ end
86
+ end
87
+
88
+ describe '#post_body' do
89
+ it 'returns the content after the question element' do
90
+ expect(node.post_body).to eq(post_body_content)
91
+ end
92
+ end
93
+ end
94
+
95
+ context "missing a post body" do
96
+ let(:elements) { [node_heading, body_element, question_heading, question_element] }
97
+
98
+ describe "#body" do
99
+ it 'returns the content before the question element' do
100
+ body = [body_content, question_heading_content].join("\n")
101
+ expect(node.body).to eq(body)
102
+ end
103
+ end
104
+
105
+ describe '#post_body' do
106
+ it 'returns nil' do
107
+ expect(node.post_body).to eq(nil)
108
+ end
109
+ end
110
+ end
111
+
112
+ context "missing a body and post body" do
113
+ let(:elements) { [question_element] }
114
+
115
+ describe "#body" do
116
+ it 'returns nil' do
117
+ expect(node.body).to eq(nil)
118
+ end
119
+ end
120
+
121
+ describe '#post_body' do
122
+ it 'returns nil' do
123
+ expect(node.post_body).to eq(nil)
124
+ end
125
+ end
126
+ end
127
+
128
+ context "without next node rules" do
129
+ let(:elements) { [node_heading, question_heading, question_element] }
130
+
131
+ describe "#next_nodes" do
132
+ it 'returns an empty list' do
133
+ expect(node.next_nodes).to eq([])
134
+ end
135
+ end
136
+ end
137
+
138
+ context "with next node rules" do
139
+ let(:elements) { [node_heading, question_heading, question_element, next_node_rules] }
140
+
141
+ describe "#next_nodes" do
142
+ it 'returns the next node rules in a list' do
143
+ expect(node.next_nodes).to eq([next_node_rules])
144
+ end
145
+ end
146
+ end
147
+
148
+ end
@@ -0,0 +1,38 @@
1
+ require 'smartdown/api/outcome'
2
+ require 'smartdown/model/node'
3
+ require 'smartdown/model/front_matter'
4
+ require 'smartdown/model/element/next_steps'
5
+
6
+ describe Smartdown::Api::Outcome do
7
+
8
+ subject(:outcome) { Smartdown::Api::Outcome.new(node) }
9
+
10
+ let(:node_name) { 'node.js' }
11
+ let(:front_matter) { Smartdown::Model::FrontMatter.new({}) }
12
+ let(:node) { Smartdown::Model::Node.new(node_name, elements, front_matter) }
13
+
14
+ let(:next_steps_content) { "discontentment" }
15
+ let(:next_steps) { Smartdown::Model::Element::NextSteps.new(next_steps_content) }
16
+
17
+
18
+ context "with next steps" do
19
+ let(:elements) { [next_steps] }
20
+
21
+ describe "#next_steps" do
22
+ it "returns the content for next steps" do
23
+ expect(outcome.next_steps).to eq(next_steps_content)
24
+ end
25
+ end
26
+ end
27
+
28
+ context "without next steps" do
29
+ let(:elements) { [] }
30
+
31
+ describe "#next_steps" do
32
+ it "returns nil" do
33
+ expect(outcome.next_steps).to eq(nil)
34
+ end
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,99 @@
1
+ require 'smartdown/api/question'
2
+ require 'smartdown/api/date_question'
3
+ require 'smartdown/model/element/question/date'
4
+ require 'smartdown/model/element/markdown_heading'
5
+ require 'smartdown/model/element/markdown_paragraph'
6
+
7
+ describe Smartdown::Api::Question do
8
+
9
+ subject(:question) { Smartdown::Api::Question.new(elements) }
10
+
11
+ let(:question_element) {
12
+ Smartdown::Model::Element::Question::Date.new(name, *args)
13
+ }
14
+ let(:aliaz) { nil }
15
+ let(:args) { [start_year, end_year, aliaz] }
16
+ let(:name) { "a question" }
17
+ let(:start_year) { nil }
18
+ let(:end_year) { nil }
19
+
20
+ let(:heading_content) { "hehehe" }
21
+ let(:heading) { Smartdown::Model::Element::MarkdownHeading}
22
+
23
+ let(:body_content) { 'I <3 bodyshopping' }
24
+ let(:body_element) {
25
+ Smartdown::Model::Element::MarkdownParagraph.new(body_content)
26
+ }
27
+
28
+ let(:post_body_content) { 'hur hur such content' }
29
+ let(:post_body_element) {
30
+ Smartdown::Model::Element::MarkdownParagraph.new(post_body_content)
31
+ }
32
+
33
+
34
+
35
+ context "with a body and post_body" do
36
+ let(:elements) { [heading, body_element, question_element, post_body_element] }
37
+
38
+ describe "#body" do
39
+ it 'returns the content before the question element' do
40
+ expect(question.body).to eq(body_content)
41
+ end
42
+ end
43
+
44
+ describe '#post_body' do
45
+ it 'returns the content after the question element' do
46
+ expect(question.post_body).to eq(post_body_content)
47
+ end
48
+ end
49
+ end
50
+
51
+ context "missing a body" do
52
+ let(:elements) { [heading, question_element, post_body_element] }
53
+
54
+ describe "#body" do
55
+ it 'returns nil' do
56
+ expect(question.body).to eq(nil)
57
+ end
58
+ end
59
+
60
+ describe '#post_body' do
61
+ it 'returns the content after the question element' do
62
+ expect(question.post_body).to eq(post_body_content)
63
+ end
64
+ end
65
+ end
66
+
67
+ context "missing a post body" do
68
+ let(:elements) { [heading, body_element, question_element] }
69
+
70
+ describe "#body" do
71
+ it 'returns the content before the question element' do
72
+ expect(question.body).to eq(body_content)
73
+ end
74
+ end
75
+
76
+ describe '#post_body' do
77
+ it 'returns nil' do
78
+ expect(question.post_body).to eq(nil)
79
+ end
80
+ end
81
+ end
82
+
83
+ context "missing a body and post body" do
84
+ let(:elements) { [heading, question_element] }
85
+
86
+ describe "#body" do
87
+ it 'returns nil' do
88
+ expect(question.body).to eq(nil)
89
+ end
90
+ end
91
+
92
+ describe '#post_body' do
93
+ it 'returns nil' do
94
+ expect(question.post_body).to eq(nil)
95
+ end
96
+ end
97
+ end
98
+
99
+ end
data/spec/engine_spec.rb CHANGED
@@ -186,6 +186,13 @@ describe Smartdown::Engine do
186
186
  it "recorded input is accessiable via question alias" do
187
187
  expect(subject.get("passport_type?")).to eq("greek")
188
188
  end
189
+
190
+ context "extra answers passed" do
191
+ let(:responses) { %w{yes greek I wanna be the very best like no one ever was} }
192
+ it "return current_node as outcome and ignores extra responses" do
193
+ expect(subject.get(:current_node)).to eq("outcome_no_visa_needed")
194
+ end
195
+ end
189
196
  end
190
197
 
191
198
  context "USA passport" do
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.11.1
4
+ version: 0.11.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-12-02 00:00:00.000000000 Z
12
+ date: 2014-12-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: parslet
16
- requirement: &10521380 !ruby/object:Gem::Requirement
16
+ requirement: &22904640 !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: *10521380
24
+ version_requirements: *22904640
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &10520820 !ruby/object:Gem::Requirement
27
+ requirement: &22903900 !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: *10520820
35
+ version_requirements: *22903900
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rake
38
- requirement: &10520420 !ruby/object:Gem::Requirement
38
+ requirement: &22903440 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,21 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *10520420
46
+ version_requirements: *22903440
47
+ - !ruby/object:Gem::Dependency
48
+ name: pry
49
+ requirement: &22902800 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *22902800
47
58
  - !ruby/object:Gem::Dependency
48
59
  name: gem_publisher
49
- requirement: &10519900 !ruby/object:Gem::Requirement
60
+ requirement: &22902180 !ruby/object:Gem::Requirement
50
61
  none: false
51
62
  requirements:
52
63
  - - ! '>='
@@ -54,10 +65,10 @@ dependencies:
54
65
  version: '0'
55
66
  type: :development
56
67
  prerelease: false
57
- version_requirements: *10519900
68
+ version_requirements: *22902180
58
69
  - !ruby/object:Gem::Dependency
59
70
  name: timecop
60
- requirement: &10519480 !ruby/object:Gem::Requirement
71
+ requirement: &22901520 !ruby/object:Gem::Requirement
61
72
  none: false
62
73
  requirements:
63
74
  - - ! '>='
@@ -65,7 +76,7 @@ dependencies:
65
76
  version: '0'
66
77
  type: :development
67
78
  prerelease: false
68
- version_requirements: *10519480
79
+ version_requirements: *22901520
69
80
  description:
70
81
  email: david.heath@digital.cabinet-office.gov.uk
71
82
  executables:
@@ -188,7 +199,10 @@ files:
188
199
  - spec/parser/snippet_pre_parser_spec.rb
189
200
  - spec/support/flow_input_interface.rb
190
201
  - spec/support/model_builder.rb
202
+ - spec/api/outcome_spec.rb
191
203
  - spec/api/state_spec.rb
204
+ - spec/api/node_spec.rb
205
+ - spec/api/question_spec.rb
192
206
  - spec/api/date_question_spec.rb
193
207
  - spec/api/previous_question_spec.rb
194
208
  - spec/spec_helper.rb
@@ -269,7 +283,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
269
283
  version: '0'
270
284
  segments:
271
285
  - 0
272
- hash: -3693296040115547194
286
+ hash: 3333648473832850396
273
287
  required_rubygems_version: !ruby/object:Gem::Requirement
274
288
  none: false
275
289
  requirements:
@@ -278,7 +292,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
278
292
  version: '0'
279
293
  segments:
280
294
  - 0
281
- hash: -3693296040115547194
295
+ hash: 3333648473832850396
282
296
  requirements: []
283
297
  rubyforge_project:
284
298
  rubygems_version: 1.8.11
@@ -311,7 +325,10 @@ test_files:
311
325
  - spec/parser/snippet_pre_parser_spec.rb
312
326
  - spec/support/flow_input_interface.rb
313
327
  - spec/support/model_builder.rb
328
+ - spec/api/outcome_spec.rb
314
329
  - spec/api/state_spec.rb
330
+ - spec/api/node_spec.rb
331
+ - spec/api/question_spec.rb
315
332
  - spec/api/date_question_spec.rb
316
333
  - spec/api/previous_question_spec.rb
317
334
  - spec/spec_helper.rb