smartdown 0.1.0 → 0.1.1
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.
- data/lib/smartdown/api/coversheet.rb +7 -0
- data/lib/smartdown/api/directory_input.rb +11 -0
- data/lib/smartdown/api/flow.rb +119 -0
- data/lib/smartdown/api/multiple_choice.rb +25 -0
- data/lib/smartdown/api/node.rb +67 -0
- data/lib/smartdown/api/outcome.rb +16 -0
- data/lib/smartdown/api/previous_question.rb +31 -0
- data/lib/smartdown/api/question.rb +76 -0
- data/lib/smartdown/api/question_page.rb +15 -0
- data/lib/smartdown/api/state.rb +58 -0
- data/lib/smartdown/version.rb +1 -1
- metadata +21 -11
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'smartdown'
|
2
|
+
require 'smartdown/engine'
|
3
|
+
require 'smartdown/api/state'
|
4
|
+
require 'smartdown/api/coversheet'
|
5
|
+
require 'smartdown/api/question_page'
|
6
|
+
require 'smartdown/api/outcome'
|
7
|
+
|
8
|
+
module Smartdown
|
9
|
+
module Api
|
10
|
+
class Flow
|
11
|
+
|
12
|
+
def initialize(smartdown_input)
|
13
|
+
@smartdown_flow = Smartdown::Parser::FlowInterpreter.new(smartdown_input).interpret
|
14
|
+
@engine = Smartdown::Engine.new(@smartdown_flow)
|
15
|
+
end
|
16
|
+
|
17
|
+
def state(started, responses)
|
18
|
+
state = smartdown_state(started, responses)
|
19
|
+
State.new(transform_node(node_by_name(state.get(:current_node))),
|
20
|
+
previous_question_nodes_for(state),
|
21
|
+
responses
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def name
|
26
|
+
@smartdown_flow.name
|
27
|
+
end
|
28
|
+
|
29
|
+
def title
|
30
|
+
coversheet.title
|
31
|
+
end
|
32
|
+
|
33
|
+
def meta_description
|
34
|
+
front_matter.meta_description
|
35
|
+
end
|
36
|
+
|
37
|
+
def need_id
|
38
|
+
front_matter.satisfies_need
|
39
|
+
end
|
40
|
+
|
41
|
+
def status
|
42
|
+
front_matter.status
|
43
|
+
end
|
44
|
+
|
45
|
+
def draft?
|
46
|
+
status == 'draft'
|
47
|
+
end
|
48
|
+
|
49
|
+
def transition?
|
50
|
+
status == 'transition'
|
51
|
+
end
|
52
|
+
|
53
|
+
def published?
|
54
|
+
status == 'published'
|
55
|
+
end
|
56
|
+
|
57
|
+
def nodes
|
58
|
+
@smartdown_flow.nodes.map{ |node| transform_node(node) }
|
59
|
+
.select{ |node| (node.is_a? Smartdown::Api::QuestionPage) ||
|
60
|
+
(node.is_a? Smartdown::Api::Outcome)
|
61
|
+
}
|
62
|
+
end
|
63
|
+
|
64
|
+
def question_pages
|
65
|
+
nodes.select{ |node| node.is_a? Smartdown::Api::QuestionPage }
|
66
|
+
end
|
67
|
+
|
68
|
+
def outcomes
|
69
|
+
nodes.select{ |node| node.is_a? Smartdown::Api::Outcome}
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def transform_node(node)
|
75
|
+
if node.elements.any?{|element| element.is_a? Smartdown::Model::Element::StartButton}
|
76
|
+
Smartdown::Api::Coversheet.new(node)
|
77
|
+
elsif node.elements.any?{|element| element.is_a? Smartdown::Model::NextNodeRules}
|
78
|
+
if node.elements.any?{|element| element.is_a? Smartdown::Model::Element::MultipleChoice}
|
79
|
+
Smartdown::Api::QuestionPage.new(node)
|
80
|
+
else
|
81
|
+
#TODO: support other types of questions
|
82
|
+
end
|
83
|
+
else
|
84
|
+
Smartdown::Api::Outcome.new(node)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def coversheet
|
89
|
+
@coversheet ||= Smartdown::Api::Coversheet.new(@smartdown_flow.coversheet)
|
90
|
+
end
|
91
|
+
|
92
|
+
def front_matter
|
93
|
+
@front_matter ||= coversheet.front_matter
|
94
|
+
end
|
95
|
+
|
96
|
+
def smartdown_state(started, responses)
|
97
|
+
smartdown_responses = responses.clone
|
98
|
+
if started
|
99
|
+
smartdown_responses.unshift('y')
|
100
|
+
end
|
101
|
+
@engine.process(smartdown_responses)
|
102
|
+
end
|
103
|
+
|
104
|
+
def node_by_name(node_name)
|
105
|
+
@smartdown_flow.node(node_name)
|
106
|
+
end
|
107
|
+
|
108
|
+
def previous_question_nodes_for(state)
|
109
|
+
node_path = state.get('path')
|
110
|
+
return [] if node_path.empty?
|
111
|
+
|
112
|
+
node_path[1..-1].map do |node_name|
|
113
|
+
node_by_name(node_name)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'smartdown/api/question'
|
2
|
+
|
3
|
+
module Smartdown
|
4
|
+
module Api
|
5
|
+
class MultipleChoice < Question
|
6
|
+
def options
|
7
|
+
question = elements.find{|element| element.is_a? Smartdown::Model::Element::MultipleChoice}
|
8
|
+
question.choices.map do |choice|
|
9
|
+
OpenStruct.new(:label => choice[1], :value => choice[0])
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
question = elements.find{|element| element.is_a? Smartdown::Model::Element::MultipleChoice}
|
15
|
+
question.name
|
16
|
+
end
|
17
|
+
|
18
|
+
#TODO: move to presenters in smart-answer app
|
19
|
+
def partial_template_name
|
20
|
+
"multiple_choice_question"
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Smartdown
|
2
|
+
module Api
|
3
|
+
class Node
|
4
|
+
|
5
|
+
attr_reader :title ,:elements, :front_matter, :name
|
6
|
+
|
7
|
+
def initialize(node)
|
8
|
+
node_elements = node.elements.clone
|
9
|
+
headings = node_elements.select {
|
10
|
+
|element| element.is_a? Smartdown::Model::Element::MarkdownHeading
|
11
|
+
}
|
12
|
+
@title = headings.first.content.to_s if headings.first
|
13
|
+
node_elements.delete(headings.first) #Remove page title
|
14
|
+
@elements = node_elements
|
15
|
+
@front_matter = node.front_matter
|
16
|
+
@name = node.name
|
17
|
+
end
|
18
|
+
|
19
|
+
def has_title?
|
20
|
+
!!title
|
21
|
+
end
|
22
|
+
|
23
|
+
def body
|
24
|
+
elements_before_smartdown = elements.take_while{|element| !smartdown_element?(element)}
|
25
|
+
build_govspeak(elements_before_smartdown)
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_body?
|
29
|
+
!!body
|
30
|
+
end
|
31
|
+
|
32
|
+
def has_devolved_body?
|
33
|
+
!!devolved_body
|
34
|
+
end
|
35
|
+
|
36
|
+
def devolved_body
|
37
|
+
elements_after_smartdown = elements.drop_while{|element| !smartdown_element?(element)}
|
38
|
+
build_govspeak(elements_after_smartdown)
|
39
|
+
end
|
40
|
+
|
41
|
+
def next_nodes
|
42
|
+
elements.select{ |element| element.is_a? Smartdown::Model::NextNodeRules }
|
43
|
+
end
|
44
|
+
|
45
|
+
def permitted_next_nodes
|
46
|
+
next_nodes
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def markdown_element?(element)
|
52
|
+
(element.is_a? Smartdown::Model::Element::MarkdownParagraph) || (element.is_a? Smartdown::Model::Element::MarkdownHeading)
|
53
|
+
end
|
54
|
+
|
55
|
+
def smartdown_element?(element)
|
56
|
+
!markdown_element?(element)
|
57
|
+
end
|
58
|
+
|
59
|
+
def build_govspeak(elements)
|
60
|
+
markdown_elements = elements.select do |element|
|
61
|
+
markdown_element?(element)
|
62
|
+
end
|
63
|
+
GovspeakPresenter.new(markdown_elements.map(&:content).join("\n")).html
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Smartdown
|
2
|
+
module Api
|
3
|
+
class Outcome < Node
|
4
|
+
|
5
|
+
def has_next_steps?
|
6
|
+
!!next_steps
|
7
|
+
end
|
8
|
+
|
9
|
+
def next_steps
|
10
|
+
next_step_element = elements.find{|element| element.is_a? Smartdown::Model::Element::NextSteps}
|
11
|
+
GovspeakPresenter.new(next_step_element.content).html if next_step_element
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Smartdown
|
2
|
+
module Api
|
3
|
+
class PreviousQuestion
|
4
|
+
|
5
|
+
attr_reader :response, :title
|
6
|
+
|
7
|
+
def initialize(title, question_element, response, modifiable)
|
8
|
+
@title = title
|
9
|
+
@question_element = question_element
|
10
|
+
@response = response
|
11
|
+
@modifiable = modifiable
|
12
|
+
end
|
13
|
+
|
14
|
+
#TODO: remove need for this method by impleemnting modification properly
|
15
|
+
def modifiable?
|
16
|
+
@modifiable
|
17
|
+
end
|
18
|
+
|
19
|
+
#TODO: to be moved to presenter
|
20
|
+
def multiple_responses?
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
#TODO: move to presenter, this object API should only expose question_element.choices
|
25
|
+
def response_label(value=response)
|
26
|
+
@question_element.choices.fetch(value)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Smartdown
|
2
|
+
module Api
|
3
|
+
class Question
|
4
|
+
|
5
|
+
attr_reader :number
|
6
|
+
|
7
|
+
def initialize(elements, number=nil)
|
8
|
+
@elements = elements
|
9
|
+
@number = number
|
10
|
+
end
|
11
|
+
|
12
|
+
#TODO: this assumes the title is the first element
|
13
|
+
def title
|
14
|
+
elements.first.content
|
15
|
+
end
|
16
|
+
|
17
|
+
def has_body?
|
18
|
+
!!body
|
19
|
+
end
|
20
|
+
|
21
|
+
def body
|
22
|
+
elements_before_smartdown = elements[1..-1].take_while{|element| !smartdown_element?(element)}
|
23
|
+
build_govspeak(elements_before_smartdown)
|
24
|
+
end
|
25
|
+
|
26
|
+
def has_hint?
|
27
|
+
!!hint
|
28
|
+
end
|
29
|
+
|
30
|
+
#TODO: confirm we can delete this
|
31
|
+
# Usage TBC, most hints should actually be `body`s, semi-deprecated
|
32
|
+
# As we transition content we should better define it, or remove it
|
33
|
+
def hint
|
34
|
+
end
|
35
|
+
|
36
|
+
def prefix
|
37
|
+
"todo prefix"
|
38
|
+
end
|
39
|
+
|
40
|
+
def suffix
|
41
|
+
"todo suffix"
|
42
|
+
end
|
43
|
+
|
44
|
+
def subtitle
|
45
|
+
"todo subtitle"
|
46
|
+
end
|
47
|
+
|
48
|
+
#TODO
|
49
|
+
def error
|
50
|
+
end
|
51
|
+
|
52
|
+
#TODO: should not be needed
|
53
|
+
def responses
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
attr_reader :elements
|
59
|
+
|
60
|
+
def markdown_element?(element)
|
61
|
+
(element.is_a? Smartdown::Model::Element::MarkdownParagraph) || (element.is_a? Smartdown::Model::Element::MarkdownHeading)
|
62
|
+
end
|
63
|
+
|
64
|
+
def smartdown_element?(element)
|
65
|
+
!markdown_element?(element)
|
66
|
+
end
|
67
|
+
|
68
|
+
def build_govspeak(elements)
|
69
|
+
markdown_elements = elements.select do |element|
|
70
|
+
markdown_element?(element)
|
71
|
+
end
|
72
|
+
GovspeakPresenter.new(markdown_elements.map(&:content).join("\n")).html
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'smartdown/api/multiple_choice'
|
2
|
+
|
3
|
+
module Smartdown
|
4
|
+
module Api
|
5
|
+
class QuestionPage < Node
|
6
|
+
def questions
|
7
|
+
elements.slice_before do |element|
|
8
|
+
element.is_a? Smartdown::Model::Element::MarkdownHeading
|
9
|
+
end.each_with_index.map do |question_element_group, index|
|
10
|
+
Smartdown::Api::MultipleChoice.new(question_element_group, index+1)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'smartdown/api/previous_question'
|
2
|
+
|
3
|
+
module Smartdown
|
4
|
+
module Api
|
5
|
+
class State
|
6
|
+
|
7
|
+
attr_reader :responses, :current_node
|
8
|
+
|
9
|
+
def initialize(current_node, previous_questionpage_smartdown_nodes, responses)
|
10
|
+
@current_node = current_node
|
11
|
+
@previous_question_page_nodes = previous_questionpage_smartdown_nodes
|
12
|
+
@responses = responses
|
13
|
+
end
|
14
|
+
|
15
|
+
def started?
|
16
|
+
!current_node.is_a? Smartdown::Api::Coversheet
|
17
|
+
end
|
18
|
+
|
19
|
+
def finished?
|
20
|
+
current_node.is_a? Smartdown::Api::Outcome
|
21
|
+
end
|
22
|
+
|
23
|
+
#TODO: refactor this :-O
|
24
|
+
def previous_questions
|
25
|
+
response_index = 0
|
26
|
+
previous_question_nodes.map.each_with_index do |previous_questions, node_index|
|
27
|
+
previous_questions.map.each_with_index do |previous_question, index|
|
28
|
+
previous_question = Smartdown::Api::PreviousQuestion.new(
|
29
|
+
previous_question_title_nodes[node_index][index].content,
|
30
|
+
previous_question,
|
31
|
+
responses[response_index],
|
32
|
+
index == 0
|
33
|
+
)
|
34
|
+
response_index+=1
|
35
|
+
previous_question
|
36
|
+
end
|
37
|
+
end.flatten
|
38
|
+
end
|
39
|
+
|
40
|
+
def previous_question_nodes
|
41
|
+
@previous_question_page_nodes.map(&:questions)
|
42
|
+
end
|
43
|
+
|
44
|
+
def previous_question_title_nodes
|
45
|
+
@previous_question_page_nodes.map(&:question_titles)
|
46
|
+
end
|
47
|
+
|
48
|
+
def current_question_number
|
49
|
+
responses.count + 1
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
attr_reader :smartdown_state, :previous_question_page_nodes
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/smartdown/version.rb
CHANGED
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.1.
|
4
|
+
version: 0.1.1
|
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: &
|
16
|
+
requirement: &20994400 !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: *
|
24
|
+
version_requirements: *20994400
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
requirement: &
|
27
|
+
requirement: &20993600 !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: *
|
35
|
+
version_requirements: *20993600
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rake
|
38
|
-
requirement: &
|
38
|
+
requirement: &20993000 !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: *
|
46
|
+
version_requirements: *20993000
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: gem_publisher
|
49
|
-
requirement: &
|
49
|
+
requirement: &20992380 !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: *
|
57
|
+
version_requirements: *20992380
|
58
58
|
description:
|
59
59
|
email: david.heath@digital.cabinet-office.gov.uk
|
60
60
|
executables:
|
@@ -79,6 +79,16 @@ files:
|
|
79
79
|
- lib/smartdown/parser/element/next_steps.rb
|
80
80
|
- lib/smartdown/parser/element/markdown_heading.rb
|
81
81
|
- lib/smartdown/parser/flow_interpreter.rb
|
82
|
+
- lib/smartdown/api/coversheet.rb
|
83
|
+
- lib/smartdown/api/question.rb
|
84
|
+
- lib/smartdown/api/flow.rb
|
85
|
+
- lib/smartdown/api/question_page.rb
|
86
|
+
- lib/smartdown/api/state.rb
|
87
|
+
- lib/smartdown/api/node.rb
|
88
|
+
- lib/smartdown/api/directory_input.rb
|
89
|
+
- lib/smartdown/api/previous_question.rb
|
90
|
+
- lib/smartdown/api/outcome.rb
|
91
|
+
- lib/smartdown/api/multiple_choice.rb
|
82
92
|
- lib/smartdown/version.rb
|
83
93
|
- lib/smartdown/engine/node_presenter.rb
|
84
94
|
- lib/smartdown/engine/state.rb
|
@@ -157,7 +167,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
157
167
|
version: '0'
|
158
168
|
segments:
|
159
169
|
- 0
|
160
|
-
hash:
|
170
|
+
hash: 3595553799676610551
|
161
171
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
162
172
|
none: false
|
163
173
|
requirements:
|
@@ -166,7 +176,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
166
176
|
version: '0'
|
167
177
|
segments:
|
168
178
|
- 0
|
169
|
-
hash:
|
179
|
+
hash: 3595553799676610551
|
170
180
|
requirements: []
|
171
181
|
rubyforge_project:
|
172
182
|
rubygems_version: 1.8.11
|