smartdown 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/LICENSE.md +21 -0
  2. data/README.md +204 -0
  3. data/bin/smartdown +41 -0
  4. data/lib/smartdown/engine/errors.rb +5 -0
  5. data/lib/smartdown/engine/predicate_evaluator.rb +23 -0
  6. data/lib/smartdown/engine/state.rb +63 -0
  7. data/lib/smartdown/engine/transition.rb +65 -0
  8. data/lib/smartdown/engine.rb +33 -0
  9. data/lib/smartdown/model/element/markdown_heading.rb +7 -0
  10. data/lib/smartdown/model/element/markdown_paragraph.rb +7 -0
  11. data/lib/smartdown/model/element/multiple_choice.rb +7 -0
  12. data/lib/smartdown/model/element/start_button.rb +7 -0
  13. data/lib/smartdown/model/flow.rb +24 -0
  14. data/lib/smartdown/model/front_matter.rb +37 -0
  15. data/lib/smartdown/model/nested_rule.rb +5 -0
  16. data/lib/smartdown/model/next_node_rules.rb +5 -0
  17. data/lib/smartdown/model/node.rb +47 -0
  18. data/lib/smartdown/model/predicate/equality.rb +7 -0
  19. data/lib/smartdown/model/predicate/named.rb +7 -0
  20. data/lib/smartdown/model/predicate/set_membership.rb +7 -0
  21. data/lib/smartdown/model/rule.rb +5 -0
  22. data/lib/smartdown/parser/base.rb +35 -0
  23. data/lib/smartdown/parser/directory_input.rb +61 -0
  24. data/lib/smartdown/parser/element/front_matter.rb +17 -0
  25. data/lib/smartdown/parser/element/markdown_heading.rb +14 -0
  26. data/lib/smartdown/parser/element/markdown_paragraph.rb +19 -0
  27. data/lib/smartdown/parser/element/multiple_choice_question.rb +24 -0
  28. data/lib/smartdown/parser/element/start_button.rb +15 -0
  29. data/lib/smartdown/parser/flow_interpreter.rb +50 -0
  30. data/lib/smartdown/parser/node_interpreter.rb +29 -0
  31. data/lib/smartdown/parser/node_parser.rb +37 -0
  32. data/lib/smartdown/parser/node_transform.rb +83 -0
  33. data/lib/smartdown/parser/predicates.rb +36 -0
  34. data/lib/smartdown/parser/rules.rb +51 -0
  35. data/lib/smartdown/version.rb +3 -0
  36. data/lib/smartdown.rb +9 -0
  37. data/spec/acceptance/parsing_spec.rb +109 -0
  38. data/spec/acceptance/smartdown_cli_spec.rb +16 -0
  39. data/spec/engine/predicate_evaluator_spec.rb +98 -0
  40. data/spec/engine/state_spec.rb +106 -0
  41. data/spec/engine/transition_spec.rb +150 -0
  42. data/spec/engine_spec.rb +79 -0
  43. data/spec/fixtures/acceptance/cover-sheet/cover-sheet.txt +14 -0
  44. data/spec/fixtures/acceptance/one-question/one-question.txt +3 -0
  45. data/spec/fixtures/acceptance/one-question/questions/q1.txt +9 -0
  46. data/spec/fixtures/acceptance/question-and-outcome/outcomes/o1.txt +3 -0
  47. data/spec/fixtures/acceptance/question-and-outcome/question-and-outcome.txt +3 -0
  48. data/spec/fixtures/acceptance/question-and-outcome/questions/q1.txt +9 -0
  49. data/spec/fixtures/directory_input/cover-sheet.txt +1 -0
  50. data/spec/fixtures/directory_input/outcomes/o1.txt +1 -0
  51. data/spec/fixtures/directory_input/questions/q1.txt +1 -0
  52. data/spec/fixtures/directory_input/scenarios/s1.txt +1 -0
  53. data/spec/fixtures/example.sd +17 -0
  54. data/spec/model/flow_spec.rb +42 -0
  55. data/spec/model/node_spec.rb +32 -0
  56. data/spec/parser/base_spec.rb +49 -0
  57. data/spec/parser/directory_input_spec.rb +56 -0
  58. data/spec/parser/element/front_matter_spec.rb +21 -0
  59. data/spec/parser/element/markdown_heading_spec.rb +24 -0
  60. data/spec/parser/element/markdown_paragraph_spec.rb +28 -0
  61. data/spec/parser/element/multiple_choice_question_spec.rb +31 -0
  62. data/spec/parser/element/start_button_parser_spec.rb +30 -0
  63. data/spec/parser/integration/cover_sheet_spec.rb +30 -0
  64. data/spec/parser/node_parser_spec.rb +133 -0
  65. data/spec/parser/predicates_spec.rb +65 -0
  66. data/spec/parser/rules_spec.rb +244 -0
  67. data/spec/spec_helper.rb +27 -0
  68. data/spec/support/model_builder.rb +83 -0
  69. data/spec/support_specs/model_builder_spec.rb +90 -0
  70. metadata +218 -0
@@ -0,0 +1,106 @@
1
+ require 'smartdown/engine/state'
2
+
3
+ describe Smartdown::Engine::State do
4
+ subject {
5
+ described_class.new(current_node: :start_state)
6
+ }
7
+
8
+ it "raises if current_node not given to constructor" do
9
+ expect { described_class.new() }.to raise_error(ArgumentError)
10
+ end
11
+
12
+ it "initializes path and responses" do
13
+ expect(subject.get(:responses)).to eq []
14
+ expect(subject.get(:path)).to eq []
15
+ end
16
+
17
+ describe "#get" do
18
+ it "raises if a value is undefined" do
19
+ expect { subject.get(:a) }.to raise_error(Smartdown::Engine::UndefinedValue)
20
+ end
21
+
22
+ it "by string or symbol" do
23
+ expect(subject.get(:current_node)).to eq(:start_state)
24
+ expect(subject.get("current_node")).to eq(:start_state)
25
+ end
26
+ end
27
+
28
+ describe "#keys" do
29
+ it "returns a set of all keys in the state" do
30
+ expect(subject.keys).to eq(Set.new(["current_node", "path", "responses"]))
31
+ end
32
+ end
33
+
34
+ describe "#put" do
35
+ it "returns a copy of state and leaves orignal unchanged" do
36
+ new_state = subject.put(:a, 1)
37
+ expect { subject.get(:a) }.to raise_error
38
+ expect(new_state.get(:a)).to eq 1
39
+ end
40
+
41
+ it "by string or symbol" do
42
+ s2 = subject.put(:b, 1)
43
+ expect(s2.get(:b)).to eq(1)
44
+ expect(s2.get("b")).to eq(1)
45
+ s3 = subject.put("b", 2)
46
+ expect(s3.get(:b)).to eq(2)
47
+ expect(s3.get("b")).to eq(2)
48
+ end
49
+ end
50
+
51
+ context "lambda values" do
52
+ let(:predicate) { double("predicate", call: true) }
53
+ subject(:state) {
54
+ described_class.new(current_node: :start_state, predicate?: predicate)
55
+ }
56
+
57
+ describe "#get" do
58
+ it "evaluates lambda with state" do
59
+ expect(predicate).to receive(:call).with(state).and_return(true)
60
+ expect(state.get(:predicate?)).to eq(true)
61
+ end
62
+
63
+ it "caches the result of evaluating the lambda" do
64
+ expect(predicate).to receive(:call).once
65
+ state.get(:predicate?)
66
+ state.get(:predicate?)
67
+ end
68
+ end
69
+
70
+ describe "#==" do
71
+ let(:l1) { ->(state) { true } }
72
+ let(:l2) { ->(state) { true } }
73
+
74
+ let(:state_with_l1a) { described_class.new(current_node: "red", pred: l1)}
75
+ let(:state_with_l1b) { described_class.new(current_node: "red", pred: l1)}
76
+ let(:state_with_l2) { described_class.new(current_node: "red", pred: l2)}
77
+
78
+ it "is equal if identical lambdas" do
79
+ expect(state_with_l1a).to eq(state_with_l1b)
80
+ end
81
+
82
+ it "is not equal if different lambdas" do
83
+ expect(state_with_l1a).not_to eq(state_with_l2)
84
+ end
85
+ end
86
+ end
87
+
88
+ describe "#==" do
89
+ let(:s1) { described_class.new(current_node: "red") }
90
+ let(:s2) { described_class.new(current_node: "red") }
91
+ let(:s3) { described_class.new(current_node: "green") }
92
+ let(:s4) { described_class.new(current_node: "red", a: 1) }
93
+
94
+ it "is true if two states have the same keys and values" do
95
+ expect(s1).to eq(s2)
96
+ end
97
+
98
+ it "is false if two states have the same keys with different values" do
99
+ expect(s1).not_to eq(s3)
100
+ end
101
+
102
+ it "is false if one state is a subset of the other" do
103
+ expect(s1).not_to eq(s4)
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,150 @@
1
+ require 'smartdown/engine/transition'
2
+ require 'smartdown/engine/state'
3
+ require 'smartdown/model/rule'
4
+ require 'smartdown/model/nested_rule'
5
+
6
+ describe Smartdown::Engine::Transition do
7
+ let(:current_node_name) { "q1" }
8
+ let(:start_state) { Smartdown::Engine::State.new(current_node: current_node_name) }
9
+ let(:input) { "yes" }
10
+ subject(:transition) { described_class.new(start_state, current_node, input, predicate_evaluator: predicate_evaluator) }
11
+ let(:predicate_evaluator) { instance_double("Smartdown::Engine::PredicateEvaluator") }
12
+ let(:state_including_input) {
13
+ start_state.put(current_node.name, input)
14
+ }
15
+
16
+ context "no next node rules" do
17
+ let(:current_node) {
18
+ Smartdown::Model::Node.new(current_node_name, [])
19
+ }
20
+
21
+ describe "#next_node" do
22
+ it "raises IndeterminateNextNode" do
23
+ expect { transition.next_node }.to raise_error(Smartdown::Engine::IndeterminateNextNode)
24
+ end
25
+ end
26
+ end
27
+
28
+ context "next node rules defined with a simple rule" do
29
+ let(:predicate1) { double("predicate1") }
30
+ let(:outcome_name1) { "o1" }
31
+ let(:predicate2) { double("predicate2") }
32
+ let(:outcome_name2) { "o2" }
33
+
34
+ let(:current_node) {
35
+ Smartdown::Model::Node.new(
36
+ current_node_name,
37
+ [
38
+ Smartdown::Model::NextNodeRules.new(
39
+ [
40
+ Smartdown::Model::Rule.new(
41
+ predicate1, outcome_name1
42
+ ),
43
+ Smartdown::Model::Rule.new(
44
+ predicate2, outcome_name2
45
+ )
46
+ ]
47
+ )
48
+ ]
49
+ )
50
+ }
51
+
52
+ describe "#next_node" do
53
+ it "invokes the predicate evaluator with the predicate and state including the input value" do
54
+ expect(predicate_evaluator).to receive(:evaluate).with(predicate1, state_including_input).and_return(true)
55
+
56
+ transition.next_node
57
+ end
58
+
59
+ it "invokes the predicate evaluator for each rule in turn" do
60
+ allow(predicate_evaluator).to receive(:evaluate).with(predicate1, state_including_input).and_return(false)
61
+ expect(predicate_evaluator).to receive(:evaluate).with(predicate2, state_including_input).and_return(true)
62
+
63
+ transition.next_node
64
+ end
65
+
66
+ it "returns the name of the next node" do
67
+ allow(predicate_evaluator).to receive(:evaluate).with(predicate1, state_including_input).and_return(false)
68
+ allow(predicate_evaluator).to receive(:evaluate).with(predicate2, state_including_input).and_return(true)
69
+
70
+ expect(transition.next_node).to eq(outcome_name2)
71
+ end
72
+ end
73
+
74
+ describe "#next_state" do
75
+ before(:each) do
76
+ allow(predicate_evaluator).to receive(:evaluate).and_return(true)
77
+ end
78
+
79
+ it "returns a state including a record of responses, path, and new current_node" do
80
+ expected_state = start_state
81
+ .put(:responses, [input])
82
+ .put(:path, [current_node_name])
83
+ .put(:current_node, outcome_name1)
84
+ .put(current_node.name, input)
85
+
86
+ expect(transition.next_state).to eq(expected_state)
87
+ end
88
+ end
89
+ end
90
+
91
+ context "next node rules defined with nested rule" do
92
+ let(:predicate1) { double("predicate1") }
93
+ let(:predicate2) { double("predicate2") }
94
+ let(:predicate3) { double("predicate3") }
95
+ let(:outcome_name1) { "o1" }
96
+ let(:outcome_name2) { "o2" }
97
+
98
+ let(:current_node) {
99
+ Smartdown::Model::Node.new(
100
+ current_node_name,
101
+ [
102
+ Smartdown::Model::NextNodeRules.new(
103
+ [
104
+ Smartdown::Model::NestedRule.new(
105
+ predicate1, [
106
+ Smartdown::Model::Rule.new(
107
+ predicate2, outcome_name1
108
+ ),
109
+ Smartdown::Model::Rule.new(
110
+ predicate3, outcome_name2
111
+ )
112
+ ]
113
+ )
114
+ ]
115
+ )
116
+ ]
117
+ )
118
+ }
119
+
120
+ describe "#next_node" do
121
+ context "p1 false" do
122
+ it "invokes the predicate evaluator with each predicate in turn" do
123
+ expect(predicate_evaluator).to receive(:evaluate).with(predicate1, state_including_input).and_return(false)
124
+
125
+ expect { transition.next_node }.to raise_error(Smartdown::Engine::IndeterminateNextNode)
126
+ end
127
+ end
128
+
129
+ context "p1 and p2 true" do
130
+ it "invokes the predicate evaluator with each predicate in turn" do
131
+ allow(predicate_evaluator).to receive(:evaluate).with(predicate1, state_including_input).and_return(true)
132
+ expect(predicate_evaluator).to receive(:evaluate).with(predicate2, state_including_input).and_return(true)
133
+
134
+ expect(transition.next_node).to eq(outcome_name1)
135
+ end
136
+ end
137
+
138
+ context "p1 true, p2 false, p3 true" do
139
+ it "invokes the predicate evaluator with each predicate in turn" do
140
+ allow(predicate_evaluator).to receive(:evaluate).with(predicate1, state_including_input).and_return(true)
141
+ allow(predicate_evaluator).to receive(:evaluate).with(predicate2, state_including_input).and_return(false)
142
+ expect(predicate_evaluator).to receive(:evaluate).with(predicate3, state_including_input).and_return(true)
143
+
144
+ expect(transition.next_node).to eq(outcome_name2)
145
+ end
146
+ end
147
+ end
148
+ end
149
+
150
+ end
@@ -0,0 +1,79 @@
1
+ require 'smartdown/engine'
2
+
3
+ describe Smartdown::Engine do
4
+ let(:flow) {
5
+ build_flow("check-uk-visa") do
6
+ node("check-uk-visa") do
7
+ heading("Check uk visa")
8
+ paragraph("This is the paragraph")
9
+ start_button("what_passport_do_you_have?")
10
+ next_node_rules do
11
+ rule do
12
+ named_predicate("otherwise")
13
+ outcome("what_passport_do_you_have?")
14
+ end
15
+ end
16
+ end
17
+
18
+ node("what_passport_do_you_have?") do
19
+ heading("What passport do you have?")
20
+ multiple_choice(
21
+ greek: "Greek",
22
+ british: "British",
23
+ usa: "USA"
24
+ )
25
+ next_node_rules do
26
+ rule do
27
+ named_predicate("eea_passport?")
28
+ outcome("outcome_no_visa_needed")
29
+ end
30
+ end
31
+ end
32
+ end
33
+ }
34
+
35
+ subject(:engine) { Smartdown::Engine.new(flow) }
36
+ let(:start_state) {
37
+ engine.default_start_state
38
+ .put(:eea_passport?, ->(state) {
39
+ %w{greek british}.include?(state.get(:what_passport_do_you_have?))
40
+ })
41
+ .put(:otherwise, true)
42
+ }
43
+
44
+ describe "#process" do
45
+ subject { engine.process(responses, start_state) }
46
+
47
+ context "start button response only" do
48
+ let(:responses) { %w{yes} }
49
+
50
+ it "is on what_passport_do_you_have?" do
51
+ expect(subject.get(:current_node)).to eq("what_passport_do_you_have?")
52
+ end
53
+
54
+ it "has recorded input" do
55
+ expect(subject.get("check-uk-visa")).to eq("yes")
56
+ end
57
+ end
58
+
59
+ context "greek passport" do
60
+ let(:responses) { %w{yes greek} }
61
+
62
+ it "is on what_passport_do_you_have?" do
63
+ expect(subject.get(:current_node)).to eq("outcome_no_visa_needed")
64
+ end
65
+
66
+ it "has recorded input" do
67
+ expect(subject.get("what_passport_do_you_have?")).to eq("greek")
68
+ end
69
+ end
70
+
71
+ context "USA passport" do
72
+ let(:responses) { %w{yes usa} }
73
+
74
+ it "raises IndeterminateNextNode error" do
75
+ expect { subject }.to raise_error(Smartdown::Engine::IndeterminateNextNode)
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,14 @@
1
+ satisfies_need: 1234
2
+ meta_description: Blah blah
3
+
4
+ # My coversheet
5
+
6
+ This is the body markdown.
7
+
8
+ It has many paragraphs
9
+ of text.
10
+
11
+ * it
12
+ * can
13
+ * have
14
+ * lists
@@ -0,0 +1,3 @@
1
+ # My coversheet
2
+
3
+ Blah
@@ -0,0 +1,9 @@
1
+ # Question one
2
+
3
+ Body text line 1.
4
+
5
+ Body text
6
+ para 2.
7
+
8
+ * yes: Yes
9
+ * no: No
@@ -0,0 +1,3 @@
1
+ # Outcome one
2
+
3
+ body
@@ -0,0 +1,9 @@
1
+ # Question one
2
+
3
+ Body text line 1.
4
+
5
+ Body text
6
+ para 2.
7
+
8
+ * yes: Yes
9
+ * no: No
@@ -0,0 +1 @@
1
+ cover sheet
@@ -0,0 +1 @@
1
+ outcome one
@@ -0,0 +1 @@
1
+ question one
@@ -0,0 +1 @@
1
+ scenario one
@@ -0,0 +1,17 @@
1
+ name: border_control?
2
+
3
+ # Will you pass through UK Border Control?
4
+
5
+ You might pass through UK Border Control even if you don't leave the airport -
6
+ eg your bags aren't checked through and you need to collect them before transferring
7
+ to your outbound flight.
8
+
9
+ * yes: Yes
10
+ * no: No
11
+
12
+ -----------
13
+
14
+ # Next node
15
+
16
+ * border_control is 'yes' => transit
17
+ * border_control is 'no' => outcome_visa
@@ -0,0 +1,42 @@
1
+ require 'smartdown/model/flow'
2
+ require 'smartdown/model/node'
3
+
4
+ describe Smartdown::Model::Flow do
5
+ let(:flow_name) { "my_name" }
6
+ let(:nodes) { [] }
7
+ subject(:flow) { Smartdown::Model::Flow.new(flow_name, nodes) }
8
+
9
+ it "has a name" do
10
+ expect(subject.name).to eq(flow_name)
11
+ end
12
+
13
+ context "no nodes" do
14
+ it "has no nodes" do
15
+ expect(flow.nodes).to eq([])
16
+ end
17
+ end
18
+
19
+ context "one node" do
20
+ let(:node_name) { "chocolate?" }
21
+ let(:node) {
22
+ instance_double("Smartdown::Model::Node", name: node_name)
23
+ }
24
+ let(:nodes) { [node] }
25
+
26
+ describe "#nodes" do
27
+ it "returns a list with the node" do
28
+ expect(flow.nodes).to eq([node])
29
+ end
30
+ end
31
+
32
+ describe "#node" do
33
+ it "fetches the named node" do
34
+ expect(subject.node(node_name)).to eq(node)
35
+ end
36
+
37
+ it "raises if node not found" do
38
+ expect { subject.node("undefined node") }.to raise_error
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,32 @@
1
+ require 'smartdown/model/node'
2
+
3
+ describe Smartdown::Model::Node do
4
+ let(:name) { "my node" }
5
+ let(:elements) { [] }
6
+
7
+ describe "#new" do
8
+ subject(:node) { described_class.new(name, elements) }
9
+
10
+ it "accepts name and list of body blocks" do
11
+ expect(node.name).to eq(name)
12
+ expect(node.elements).to eq(elements)
13
+ end
14
+
15
+ context "no front matter" do
16
+ let(:empty_front_matter) { Smartdown::Model::FrontMatter.new({}) }
17
+
18
+ it "defaults to empty" do
19
+ expect(node.front_matter).to eq(empty_front_matter)
20
+ end
21
+ end
22
+
23
+ context "front matter" do
24
+ let(:front_matter) { Smartdown::Model::FrontMatter.new({a: "1"}) }
25
+ subject(:node) { described_class.new(name, elements, front_matter) }
26
+
27
+ it "uses it" do
28
+ expect(node.front_matter).to eq(front_matter)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,49 @@
1
+ require 'smartdown/parser/element/front_matter'
2
+
3
+ describe Smartdown::Parser::Base do
4
+
5
+ subject(:parser) { described_class.new }
6
+
7
+ describe "#ws" do
8
+ subject { parser.ws }
9
+ it { should parse("\n") }
10
+ it { should parse(" ") }
11
+ it { should parse(" ") }
12
+ end
13
+
14
+ describe "#eof" do
15
+ subject { parser.eof }
16
+
17
+ it { should parse("") }
18
+ it { should_not parse(" ") }
19
+ end
20
+
21
+ describe "#newline" do
22
+ subject { parser.newline }
23
+
24
+ # Only one newline
25
+ it { should parse("\r") }
26
+ it { should parse("\r\n") }
27
+ it { should parse("\n\r") }
28
+ it { should parse("\n") }
29
+
30
+ # Not multiple
31
+ it { should_not parse("\n\n") }
32
+ end
33
+
34
+ describe "#whitespace_terminated_string" do
35
+ subject { parser.whitespace_terminated_string }
36
+
37
+ it { should parse("a b c") }
38
+ it { should_not parse(" a") }
39
+ it { should_not parse("a ") }
40
+ end
41
+
42
+ describe "identifier" do
43
+ subject { parser.identifier }
44
+
45
+ it { should parse("abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ-123") }
46
+ it { should_not parse("abc_ABC-123?") }
47
+ end
48
+ end
49
+
@@ -0,0 +1,56 @@
1
+ require 'smartdown/parser/directory_input'
2
+
3
+ shared_examples "flow input interface" do
4
+ it { should respond_to(:coversheet) }
5
+ it { should respond_to(:questions) }
6
+ it { should respond_to(:outcomes) }
7
+ it { should respond_to(:scenarios) }
8
+ end
9
+
10
+ describe Smartdown::Parser::DirectoryInput do
11
+ it_should_behave_like "flow input interface"
12
+
13
+ let(:coversheet_file) {
14
+ Pathname.new("../../fixtures/directory_input/cover-sheet.txt").expand_path(__FILE__)
15
+ }
16
+
17
+ subject(:input) { described_class.new(coversheet_file) }
18
+
19
+ describe "#coversheet" do
20
+ subject { input.coversheet }
21
+
22
+ it { should be_a(Smartdown::Parser::InputFile) }
23
+
24
+ it "has name" do
25
+ expect(input.coversheet.name).to eq("cover-sheet")
26
+ end
27
+
28
+ it "reads the file contents" do
29
+ expect(input.coversheet.read).to eq("cover sheet\n")
30
+ end
31
+ end
32
+
33
+ describe "#questions" do
34
+ it "returns an InputFile for every file in the questions folder" do
35
+ expect(input.questions).to match([instance_of(Smartdown::Parser::InputFile)])
36
+ expect(input.questions.first.name).to eq("q1")
37
+ expect(input.questions.first.read).to eq("question one\n")
38
+ end
39
+ end
40
+
41
+ describe "#outcomes" do
42
+ it "returns an InputFile for every file in the outcomes folder" do
43
+ expect(input.outcomes).to match([instance_of(Smartdown::Parser::InputFile)])
44
+ expect(input.outcomes.first.name).to eq("o1")
45
+ expect(input.outcomes.first.read).to eq("outcome one\n")
46
+ end
47
+ end
48
+
49
+ describe "#scenarios" do
50
+ it "returns an InputFile for every file in the scenarios folder" do
51
+ expect(input.scenarios).to match([instance_of(Smartdown::Parser::InputFile)])
52
+ expect(input.scenarios.first.name).to eq("s1")
53
+ expect(input.scenarios.first.read).to eq("scenario one\n")
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,21 @@
1
+ require 'smartdown/parser/element/front_matter'
2
+ require 'smartdown/parser/node_interpreter'
3
+
4
+ describe Smartdown::Parser::Element::FrontMatter do
5
+
6
+ subject(:parser) { described_class.new }
7
+
8
+ it { should parse("a: 1\n").as(front_matter: [{name: "a", value: "1"}]) }
9
+ it { should parse("a: 1\nb: 2\n").as(front_matter: [{name: "a", value: "1"}, {name: "b", value: "2"}]) }
10
+
11
+ describe "transformed" do
12
+ let(:node_name) { "my_node" }
13
+ let(:source) { "a: 1\n" }
14
+ subject(:transformed) {
15
+ Smartdown::Parser::NodeInterpreter.new(node_name, source, parser: parser).interpret
16
+ }
17
+
18
+ it { should eq([Smartdown::Model::FrontMatter.new("a"=>"1")]) }
19
+ end
20
+ end
21
+
@@ -0,0 +1,24 @@
1
+ require 'smartdown/parser/element/markdown_heading'
2
+ require 'smartdown/parser/node_interpreter'
3
+
4
+ describe Smartdown::Parser::Element::MarkdownHeading do
5
+
6
+ subject(:parser) { described_class.new }
7
+ let(:node_name) { "my_node" }
8
+ let(:heading_content) { "My heading"}
9
+ let(:source) { "# #{heading_content}" }
10
+
11
+ it { should parse(source).as(h1: heading_content) }
12
+ it { should parse("# heading\n").as(h1: "heading") }
13
+ it { should parse("# heading \n").as(h1: "heading") }
14
+ it { should parse("# heading ").as(h1: "heading") }
15
+
16
+ describe "transformed" do
17
+ subject(:transformed) {
18
+ Smartdown::Parser::NodeInterpreter.new(node_name, source, parser: parser).interpret
19
+ }
20
+
21
+ it { should eq(Smartdown::Model::Element::MarkdownHeading.new(heading_content)) }
22
+ end
23
+ end
24
+
@@ -0,0 +1,28 @@
1
+ require 'smartdown/parser/element/markdown_paragraph'
2
+ require 'smartdown/parser/node_interpreter'
3
+
4
+ describe Smartdown::Parser::Element::MarkdownParagraph do
5
+
6
+ subject(:parser) { described_class.new }
7
+ let(:node_name) { "my_node" }
8
+
9
+ it { should parse("My para").as(p: "My para") }
10
+ it { should parse("My para\n").as(p: "My para\n") }
11
+ it { should parse(" My para").as(p: " My para") }
12
+ it { should parse(" My para\nsecond line").as(p: " My para\nsecond line") }
13
+ it { should parse(" My para\nsecond line\n").as(p: " My para\nsecond line\n") }
14
+ it { should parse(" My para\nsecond line \n").as(p: " My para\nsecond line \n") }
15
+ it { should_not parse("Para1\n\nPara2") }
16
+
17
+ it { should parse("a b") }
18
+
19
+ describe "transformed" do
20
+ let(:content) { "My para" }
21
+ subject(:transformed) {
22
+ Smartdown::Parser::NodeInterpreter.new(node_name, content, parser: parser).interpret
23
+ }
24
+
25
+ it { should eq(Smartdown::Model::Element::MarkdownParagraph.new(content)) }
26
+ end
27
+ end
28
+