sheng 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitattributes +1 -0
- data/.gitignore +18 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/.watchr +99 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +62 -0
- data/Rakefile +10 -0
- data/docs/creating_templates.docx +0 -0
- data/docs/creating_templates.md +392 -0
- data/lib/sheng/block.rb +59 -0
- data/lib/sheng/check_box.rb +43 -0
- data/lib/sheng/conditional_block.rb +30 -0
- data/lib/sheng/data_set.rb +45 -0
- data/lib/sheng/docx.rb +75 -0
- data/lib/sheng/merge_field.rb +208 -0
- data/lib/sheng/merge_field_set.rb +90 -0
- data/lib/sheng/path_helpers.rb +15 -0
- data/lib/sheng/sequence.rb +66 -0
- data/lib/sheng/support.rb +57 -0
- data/lib/sheng/version.rb +3 -0
- data/lib/sheng/wml_file.rb +47 -0
- data/lib/sheng.rb +21 -0
- data/sheng.gemspec +31 -0
- data/spec/fixtures/bad_docx_files/with_field_not_in_dataset.docx +0 -0
- data/spec/fixtures/bad_docx_files/with_missing_sequence_start.docx +0 -0
- data/spec/fixtures/bad_docx_files/with_old_mergefields.docx +0 -0
- data/spec/fixtures/bad_docx_files/with_poorly_nested_sequences.docx +0 -0
- data/spec/fixtures/bad_docx_files/with_unended_sequence.docx +0 -0
- data/spec/fixtures/docx_files/input_document.docx +0 -0
- data/spec/fixtures/docx_files/old_style/input_document.docx +0 -0
- data/spec/fixtures/docx_files/old_style/output_document.docx +0 -0
- data/spec/fixtures/docx_files/output_document.docx +0 -0
- data/spec/fixtures/inputs/complete.json +61 -0
- data/spec/fixtures/inputs/incomplete.json +52 -0
- data/spec/fixtures/trees/embedded_sequence.yml +13 -0
- data/spec/fixtures/trees/merge_field_set.yml +16 -0
- data/spec/fixtures/xml_fragments/input/check_box/check_box.xml +11 -0
- data/spec/fixtures/xml_fragments/input/conditional_block/bad/badly_nested_conditional.xml +105 -0
- data/spec/fixtures/xml_fragments/input/conditional_block/bad/unclosed_conditional.xml +35 -0
- data/spec/fixtures/xml_fragments/input/conditional_block/conditional_block_if.xml +84 -0
- data/spec/fixtures/xml_fragments/input/conditional_block/conditional_block_inline.xml +59 -0
- data/spec/fixtures/xml_fragments/input/conditional_block/conditional_block_unless.xml +51 -0
- data/spec/fixtures/xml_fragments/input/conditional_block/conditional_in_table.xml +176 -0
- data/spec/fixtures/xml_fragments/input/conditional_block/embedded_conditional.xml +79 -0
- data/spec/fixtures/xml_fragments/input/merge_field/bad/not_a_real_mergefield_new.xml +19 -0
- data/spec/fixtures/xml_fragments/input/merge_field/bad/not_a_real_mergefield_old.xml +9 -0
- data/spec/fixtures/xml_fragments/input/merge_field/bad/unclosed_merge_field.xml +25 -0
- data/spec/fixtures/xml_fragments/input/merge_field/inline_merge_field.xml +26 -0
- data/spec/fixtures/xml_fragments/input/merge_field/merge_field.xml +14 -0
- data/spec/fixtures/xml_fragments/input/merge_field/new_merge_field.xml +28 -0
- data/spec/fixtures/xml_fragments/input/merge_field/split_merge_field.xml +33 -0
- data/spec/fixtures/xml_fragments/input/merge_field_set/complex_nesting_and_reuse.xml +231 -0
- data/spec/fixtures/xml_fragments/input/merge_field_set/merge_field_set.xml +89 -0
- data/spec/fixtures/xml_fragments/input/merge_field_set/with_non_mergefield_fields.xml +43 -0
- data/spec/fixtures/xml_fragments/input/sequence/array_sequence.xml +23 -0
- data/spec/fixtures/xml_fragments/input/sequence/bad/badly_nested_sequence.xml +62 -0
- data/spec/fixtures/xml_fragments/input/sequence/bad/unclosed_sequence.xml +32 -0
- data/spec/fixtures/xml_fragments/input/sequence/embedded_sequence.xml +68 -0
- data/spec/fixtures/xml_fragments/input/sequence/inline_sequence.xml +24 -0
- data/spec/fixtures/xml_fragments/input/sequence/overridden_iterator_array_sequence.xml +23 -0
- data/spec/fixtures/xml_fragments/input/sequence/sequence.xml +39 -0
- data/spec/fixtures/xml_fragments/input/sequence/sequence_in_table.xml +125 -0
- data/spec/fixtures/xml_fragments/input/sequence/sequence_with_section_formatting.xml +41 -0
- data/spec/fixtures/xml_fragments/input/sequence/series_with_commas.xml +73 -0
- data/spec/fixtures/xml_fragments/output/check_box/check_box.xml +11 -0
- data/spec/fixtures/xml_fragments/output/conditional_block/conditional_in_table_does_not_exist.xml +52 -0
- data/spec/fixtures/xml_fragments/output/conditional_block/conditional_in_table_exists.xml +84 -0
- data/spec/fixtures/xml_fragments/output/conditional_block/embedded_conditional_both.xml +11 -0
- data/spec/fixtures/xml_fragments/output/conditional_block/embedded_conditional_inside.xml +5 -0
- data/spec/fixtures/xml_fragments/output/conditional_block/embedded_conditional_outside.xml +8 -0
- data/spec/fixtures/xml_fragments/output/conditional_block/if_does_not_exist.xml +5 -0
- data/spec/fixtures/xml_fragments/output/conditional_block/if_exists.xml +19 -0
- data/spec/fixtures/xml_fragments/output/conditional_block/inline_does_not_exist.xml +10 -0
- data/spec/fixtures/xml_fragments/output/conditional_block/inline_exists.xml +13 -0
- data/spec/fixtures/xml_fragments/output/conditional_block/unless_does_not_exist.xml +11 -0
- data/spec/fixtures/xml_fragments/output/conditional_block/unless_exists.xml +5 -0
- data/spec/fixtures/xml_fragments/output/merge_field/inline_merge_field.xml +11 -0
- data/spec/fixtures/xml_fragments/output/merge_field/merge_field.xml +12 -0
- data/spec/fixtures/xml_fragments/output/merge_field/split_merge_field.xml +10 -0
- data/spec/fixtures/xml_fragments/output/merge_field_set/complex_nesting_and_reuse.xml +190 -0
- data/spec/fixtures/xml_fragments/output/merge_field_set/merge_field_set.xml +75 -0
- data/spec/fixtures/xml_fragments/output/merge_field_set/with_non_mergefield_fields.xml +31 -0
- data/spec/fixtures/xml_fragments/output/sequence/array_sequence.xml +17 -0
- data/spec/fixtures/xml_fragments/output/sequence/embedded_sequence.xml +56 -0
- data/spec/fixtures/xml_fragments/output/sequence/inline_sequence.xml +16 -0
- data/spec/fixtures/xml_fragments/output/sequence/overridden_iterator_array_sequence.xml +12 -0
- data/spec/fixtures/xml_fragments/output/sequence/sequence.xml +28 -0
- data/spec/fixtures/xml_fragments/output/sequence/sequence_in_table.xml +120 -0
- data/spec/fixtures/xml_fragments/output/sequence/sequence_with_section_formatting.xml +46 -0
- data/spec/fixtures/xml_fragments/output/sequence/series_with_commas.xml +43 -0
- data/spec/fixtures/xml_fragments/output/sequence/series_with_commas_two_items.xml +31 -0
- data/spec/lib/sheng/check_box_spec.rb +87 -0
- data/spec/lib/sheng/conditional_block_spec.rb +151 -0
- data/spec/lib/sheng/data_set_spec.rb +65 -0
- data/spec/lib/sheng/docx_spec.rb +146 -0
- data/spec/lib/sheng/merge_field_set_spec.rb +165 -0
- data/spec/lib/sheng/merge_field_spec.rb +276 -0
- data/spec/lib/sheng/sequence_spec.rb +201 -0
- data/spec/lib/sheng/wml_file_spec.rb +38 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/support/path_helper.rb +15 -0
- data/spec/support/xml_helper.rb +28 -0
- metadata +355 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
2
|
+
<w:p>
|
3
|
+
<w:r>
|
4
|
+
<w:t>A Radish Summer</w:t>
|
5
|
+
</w:r>
|
6
|
+
</w:p>
|
7
|
+
<w:p>
|
8
|
+
<w:r>
|
9
|
+
<w:rPr>
|
10
|
+
<w:noProof/>
|
11
|
+
</w:rPr>
|
12
|
+
<w:t>totally rad</w:t>
|
13
|
+
</w:r>
|
14
|
+
</w:p>
|
15
|
+
<w:p>
|
16
|
+
<w:r>
|
17
|
+
<w:t>Elephants Are Not Your Friend</w:t>
|
18
|
+
</w:r>
|
19
|
+
</w:p>
|
20
|
+
<w:p>
|
21
|
+
<w:r>
|
22
|
+
<w:rPr>
|
23
|
+
<w:noProof/>
|
24
|
+
</w:rPr>
|
25
|
+
<w:t>stinky</w:t>
|
26
|
+
</w:r>
|
27
|
+
</w:p>
|
28
|
+
</w:document>
|
@@ -0,0 +1,120 @@
|
|
1
|
+
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
2
|
+
<w:tbl>
|
3
|
+
<w:tr>
|
4
|
+
<w:tc>
|
5
|
+
<w:p>
|
6
|
+
<w:r>
|
7
|
+
<w:t>Meal</w:t>
|
8
|
+
</w:r>
|
9
|
+
</w:p>
|
10
|
+
</w:tc>
|
11
|
+
<w:tc>
|
12
|
+
<w:p>
|
13
|
+
<w:r>
|
14
|
+
<w:t>Drink</w:t>
|
15
|
+
</w:r>
|
16
|
+
</w:p>
|
17
|
+
</w:tc>
|
18
|
+
<w:tc>
|
19
|
+
<w:p>
|
20
|
+
<w:r>
|
21
|
+
<w:t>Appetizer</w:t>
|
22
|
+
</w:r>
|
23
|
+
</w:p>
|
24
|
+
</w:tc>
|
25
|
+
<w:tc>
|
26
|
+
<w:p>
|
27
|
+
<w:r>
|
28
|
+
<w:t>Dessert</w:t>
|
29
|
+
</w:r>
|
30
|
+
</w:p>
|
31
|
+
</w:tc>
|
32
|
+
</w:tr>
|
33
|
+
<w:tr>
|
34
|
+
<w:tc>
|
35
|
+
<w:p>
|
36
|
+
<w:r>
|
37
|
+
<w:t>Gravel Noodles</w:t>
|
38
|
+
</w:r>
|
39
|
+
</w:p>
|
40
|
+
</w:tc>
|
41
|
+
<w:tc>
|
42
|
+
</w:tc>
|
43
|
+
<w:tc>
|
44
|
+
<w:p>
|
45
|
+
<w:r>
|
46
|
+
<w:t>Asphalt Rollups</w:t>
|
47
|
+
</w:r>
|
48
|
+
</w:p>
|
49
|
+
</w:tc>
|
50
|
+
<w:tc>
|
51
|
+
<w:p>
|
52
|
+
<w:r>
|
53
|
+
<w:t>Concrete Cream</w:t>
|
54
|
+
</w:r>
|
55
|
+
</w:p>
|
56
|
+
</w:tc>
|
57
|
+
</w:tr>
|
58
|
+
<w:tr>
|
59
|
+
<w:tc>
|
60
|
+
<w:p>
|
61
|
+
<w:r>
|
62
|
+
<w:rPr>
|
63
|
+
<w:noProof/>
|
64
|
+
</w:rPr>
|
65
|
+
<w:t>Steamed Water</w:t>
|
66
|
+
</w:r>
|
67
|
+
</w:p>
|
68
|
+
</w:tc>
|
69
|
+
<w:tc>
|
70
|
+
</w:tc>
|
71
|
+
<w:tc>
|
72
|
+
</w:tc>
|
73
|
+
<w:tc>
|
74
|
+
</w:tc>
|
75
|
+
</w:tr>
|
76
|
+
<w:tr>
|
77
|
+
<w:tc>
|
78
|
+
<w:p>
|
79
|
+
<w:r>
|
80
|
+
<w:t>A Single Olive</w:t>
|
81
|
+
</w:r>
|
82
|
+
</w:p>
|
83
|
+
</w:tc>
|
84
|
+
<w:tc>
|
85
|
+
</w:tc>
|
86
|
+
<w:tc>
|
87
|
+
<w:p>
|
88
|
+
<w:r>
|
89
|
+
<w:t>A Strand of Hair</w:t>
|
90
|
+
</w:r>
|
91
|
+
</w:p>
|
92
|
+
</w:tc>
|
93
|
+
<w:tc>
|
94
|
+
<w:p>
|
95
|
+
<w:r>
|
96
|
+
<w:t>Wishes and Hopes</w:t>
|
97
|
+
</w:r>
|
98
|
+
</w:p>
|
99
|
+
</w:tc>
|
100
|
+
</w:tr>
|
101
|
+
<w:tr>
|
102
|
+
<w:tc>
|
103
|
+
<w:p>
|
104
|
+
<w:r>
|
105
|
+
<w:rPr>
|
106
|
+
<w:noProof/>
|
107
|
+
</w:rPr>
|
108
|
+
<w:t>The Memory of Soda</w:t>
|
109
|
+
</w:r>
|
110
|
+
</w:p>
|
111
|
+
</w:tc>
|
112
|
+
<w:tc>
|
113
|
+
</w:tc>
|
114
|
+
<w:tc>
|
115
|
+
</w:tc>
|
116
|
+
<w:tc>
|
117
|
+
</w:tc>
|
118
|
+
</w:tr>
|
119
|
+
</w:tbl>
|
120
|
+
</w:document>
|
@@ -0,0 +1,46 @@
|
|
1
|
+
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
2
|
+
<w:p>
|
3
|
+
<w:pPr>
|
4
|
+
<w:pStyle w:val="fancy"/>
|
5
|
+
<w:sectPr>
|
6
|
+
<w:cols w:num="1" w:space="10"/>
|
7
|
+
</w:sectPr>
|
8
|
+
</w:pPr>
|
9
|
+
<w:r>
|
10
|
+
<w:t>Tumbiblia</w:t>
|
11
|
+
</w:r>
|
12
|
+
</w:p>
|
13
|
+
<w:p>
|
14
|
+
<w:pPr>
|
15
|
+
<w:pStyle w:val="fancy"/>
|
16
|
+
<w:sectPr>
|
17
|
+
<w:cols w:num="2" w:space="20"/>
|
18
|
+
</w:sectPr>
|
19
|
+
</w:pPr>
|
20
|
+
<w:r>
|
21
|
+
<w:t>Rofronco</w:t>
|
22
|
+
</w:r>
|
23
|
+
</w:p>
|
24
|
+
<w:p>
|
25
|
+
<w:pPr>
|
26
|
+
<w:pStyle w:val="fancy"/>
|
27
|
+
<w:sectPr>
|
28
|
+
<w:cols w:num="2" w:space="20"/>
|
29
|
+
</w:sectPr>
|
30
|
+
</w:pPr>
|
31
|
+
<w:r>
|
32
|
+
<w:t>Beanipops</w:t>
|
33
|
+
</w:r>
|
34
|
+
</w:p>
|
35
|
+
<w:p>
|
36
|
+
<w:pPr>
|
37
|
+
<w:pStyle w:val="dumb"/>
|
38
|
+
<w:sectPr>
|
39
|
+
<w:cols w:num="3" w:space="30"/>
|
40
|
+
</w:sectPr>
|
41
|
+
</w:pPr>
|
42
|
+
<w:r>
|
43
|
+
<w:t>Baab</w:t>
|
44
|
+
</w:r>
|
45
|
+
</w:p>
|
46
|
+
</w:document>
|
@@ -0,0 +1,43 @@
|
|
1
|
+
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
2
|
+
<w:p>
|
3
|
+
<w:r>
|
4
|
+
<w:t xml:space="preserve">Here's a list of buffoons: </w:t>
|
5
|
+
</w:r>
|
6
|
+
<w:r>
|
7
|
+
<w:t>Snookers</w:t>
|
8
|
+
</w:r>
|
9
|
+
<w:r>
|
10
|
+
<w:t xml:space="preserve"> </w:t>
|
11
|
+
</w:r>
|
12
|
+
<w:r>
|
13
|
+
<w:t>Fumpleton</w:t>
|
14
|
+
</w:r>
|
15
|
+
<w:r>
|
16
|
+
<w:t xml:space="preserve">, </w:t>
|
17
|
+
</w:r>
|
18
|
+
<w:r>
|
19
|
+
<w:t>Francis</w:t>
|
20
|
+
</w:r>
|
21
|
+
<w:r>
|
22
|
+
<w:t xml:space="preserve"> </w:t>
|
23
|
+
</w:r>
|
24
|
+
<w:r>
|
25
|
+
<w:t>Oldgark</w:t>
|
26
|
+
</w:r>
|
27
|
+
<w:r>
|
28
|
+
<w:t xml:space="preserve">, and </w:t>
|
29
|
+
</w:r>
|
30
|
+
<w:r>
|
31
|
+
<w:t>Spanky</w:t>
|
32
|
+
</w:r>
|
33
|
+
<w:r>
|
34
|
+
<w:t xml:space="preserve"> </w:t>
|
35
|
+
</w:r>
|
36
|
+
<w:r>
|
37
|
+
<w:t>McThanks</w:t>
|
38
|
+
</w:r>
|
39
|
+
<w:r>
|
40
|
+
<w:t xml:space="preserve">. Phew. What a list.</w:t>
|
41
|
+
</w:r>
|
42
|
+
</w:p>
|
43
|
+
</w:document>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
2
|
+
<w:p>
|
3
|
+
<w:r>
|
4
|
+
<w:t xml:space="preserve">Here's a list of buffoons: </w:t>
|
5
|
+
</w:r>
|
6
|
+
<w:r>
|
7
|
+
<w:t>Snookers</w:t>
|
8
|
+
</w:r>
|
9
|
+
<w:r>
|
10
|
+
<w:t xml:space="preserve"> </w:t>
|
11
|
+
</w:r>
|
12
|
+
<w:r>
|
13
|
+
<w:t>Fumpleton</w:t>
|
14
|
+
</w:r>
|
15
|
+
<w:r>
|
16
|
+
<w:t xml:space="preserve"> and </w:t>
|
17
|
+
</w:r>
|
18
|
+
<w:r>
|
19
|
+
<w:t>Spanky</w:t>
|
20
|
+
</w:r>
|
21
|
+
<w:r>
|
22
|
+
<w:t xml:space="preserve"> </w:t>
|
23
|
+
</w:r>
|
24
|
+
<w:r>
|
25
|
+
<w:t>McThanks</w:t>
|
26
|
+
</w:r>
|
27
|
+
<w:r>
|
28
|
+
<w:t xml:space="preserve">. Phew. What a list.</w:t>
|
29
|
+
</w:r>
|
30
|
+
</w:p>
|
31
|
+
</w:document>
|
@@ -0,0 +1,87 @@
|
|
1
|
+
describe Sheng::CheckBox do
|
2
|
+
let(:fragment) { xml_fragment('input/check_box/check_box') }
|
3
|
+
let(:element) { fragment.at_xpath(".//w:checkBox/..") }
|
4
|
+
subject { described_class.new(element) }
|
5
|
+
|
6
|
+
describe ".from_element" do
|
7
|
+
it "returns a new instance with the given element" do
|
8
|
+
expect(described_class.from_element(element)).to eq(subject)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#key' do
|
13
|
+
it 'returns w:val attribute of w:name node in xml fragment' do
|
14
|
+
expect(subject.key).to eq 'goats'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#raw_key' do
|
19
|
+
it 'returns key' do
|
20
|
+
expect(subject.raw_key).to eq subject.key
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#value_is_truthy?' do
|
25
|
+
context 'given truthy values' do
|
26
|
+
['true', 'TRuE', true, 1, '1', 'yes'].each do |truthy|
|
27
|
+
given_key = truthy.is_a?(String) ? "'#{truthy}' (as string)" : truthy
|
28
|
+
it "returns true if key is #{given_key} in dataset" do
|
29
|
+
expect(subject.value_is_truthy?(truthy)).to be_truthy
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'given falsy values' do
|
35
|
+
['false', 'FaLSE', false, 0, '0', 'no', '', nil].each do |falsy|
|
36
|
+
given_key = falsy.is_a?(String) ? "'#{falsy}' (as string)" : falsy
|
37
|
+
given_key = 'nil' if falsy.nil?
|
38
|
+
it "returns false if key is #{given_key} in dataset" do
|
39
|
+
expect(subject.value_is_truthy?(falsy)).to be_falsy
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#interpolate' do
|
46
|
+
let(:dataset) { Sheng::DataSet.new('goats' => 'foofle') }
|
47
|
+
|
48
|
+
it "checks the checkbox if key is truthy in dataset" do
|
49
|
+
allow(subject).to receive(:value_is_truthy?).with('foofle').and_return(true)
|
50
|
+
subject.interpolate(dataset)
|
51
|
+
expect(subject.xml_document).to be_equivalent_to xml_fragment('output/check_box/check_box')
|
52
|
+
end
|
53
|
+
|
54
|
+
it "does not check the checkbox if key is falsy in dataset" do
|
55
|
+
allow(subject).to receive(:value_is_truthy?).with('foofle').and_return(false)
|
56
|
+
subject.interpolate(dataset)
|
57
|
+
expect(subject.xml_document).to be_equivalent_to fragment_with_unchecked_box(subject.xml_document)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "does not uncheck a default checked checkbox if key is truthy in dataset" do
|
61
|
+
default_checked = described_class.new(fragment_with_checked_box(subject.xml_document))
|
62
|
+
allow(default_checked).to receive(:value_is_truthy?).with('foofle').and_return(true)
|
63
|
+
default_checked.interpolate(dataset)
|
64
|
+
expect(default_checked.xml_document).to be_equivalent_to xml_fragment('output/check_box/check_box')
|
65
|
+
end
|
66
|
+
|
67
|
+
it "unchecks a default checked checkbox if key is falsy in dataset" do
|
68
|
+
default_checked = described_class.new(fragment_with_checked_box(subject.xml_document))
|
69
|
+
allow(default_checked).to receive(:value_is_truthy?).with('foofle').and_return(false)
|
70
|
+
default_checked.interpolate(dataset)
|
71
|
+
expect(default_checked.xml_document).to be_equivalent_to fragment_with_unchecked_box(default_checked.xml_document)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "does not check the checkbox if key is not found in dataset" do
|
75
|
+
dataset = Sheng::DataSet.new({})
|
76
|
+
subject.interpolate(dataset)
|
77
|
+
expect(subject.xml_document).to be_equivalent_to fragment_with_unchecked_box(subject.xml_document)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "does not uncheck a checked checkbox if key is not found in dataset" do
|
81
|
+
dataset = Sheng::DataSet.new({})
|
82
|
+
default_checked = described_class.new(fragment_with_checked_box(subject.xml_document))
|
83
|
+
default_checked.interpolate(dataset)
|
84
|
+
expect(default_checked.xml_document).to be_equivalent_to xml_fragment('output/check_box/check_box')
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
describe Sheng::ConditionalBlock do
|
2
|
+
let(:fragment) { xml_fragment('input/conditional_block/conditional_block_if') }
|
3
|
+
let(:element) { fragment.xpath("//w:fldChar[contains(@w:fldCharType, 'begin')]").first }
|
4
|
+
let(:merge_field) { Sheng::MergeField.new(element) }
|
5
|
+
subject { described_class.new(merge_field) }
|
6
|
+
|
7
|
+
describe "#raw_key" do
|
8
|
+
it "returns key from start_field" do
|
9
|
+
expect(subject.raw_key).to eq(merge_field.raw_key)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe '#interpolate' do
|
14
|
+
let(:fragment) { xml_fragment('input/conditional_block/conditional_block_inline') }
|
15
|
+
|
16
|
+
context "inline" do
|
17
|
+
it 'includes if sections when variable truthy' do
|
18
|
+
dataset = Sheng::DataSet.new({
|
19
|
+
:alicorns => 'so tasties'
|
20
|
+
})
|
21
|
+
|
22
|
+
subject.interpolate(dataset)
|
23
|
+
expect(subject.xml_document).to be_equivalent_to xml_fragment('output/conditional_block/inline_exists')
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'removes entire section if variable falsy' do
|
27
|
+
dataset = Sheng::DataSet.new({})
|
28
|
+
|
29
|
+
subject.interpolate(dataset)
|
30
|
+
expect(subject.xml_document).to be_equivalent_to xml_fragment('output/conditional_block/inline_does_not_exist')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "with if block" do
|
35
|
+
let(:fragment) { xml_fragment('input/conditional_block/conditional_block_if') }
|
36
|
+
|
37
|
+
it 'includes sections when variable truthy' do
|
38
|
+
dataset = Sheng::DataSet.new({
|
39
|
+
:alicorns => 'so tasties'
|
40
|
+
})
|
41
|
+
|
42
|
+
subject.interpolate(dataset)
|
43
|
+
expect(subject.xml_document).to be_equivalent_to xml_fragment('output/conditional_block/if_exists')
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'removes entire section if variable falsy' do
|
47
|
+
dataset = Sheng::DataSet.new({})
|
48
|
+
|
49
|
+
subject.interpolate(dataset)
|
50
|
+
expect(subject.xml_document).to be_equivalent_to xml_fragment('output/conditional_block/if_does_not_exist')
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "with unless block" do
|
55
|
+
let(:fragment) { xml_fragment('input/conditional_block/conditional_block_unless') }
|
56
|
+
|
57
|
+
it 'includes sections when variable falsy' do
|
58
|
+
dataset = Sheng::DataSet.new({})
|
59
|
+
|
60
|
+
subject.interpolate(dataset)
|
61
|
+
expect(subject.xml_document).to be_equivalent_to xml_fragment('output/conditional_block/unless_does_not_exist')
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'removes entire section if variable truthy' do
|
65
|
+
dataset = Sheng::DataSet.new({
|
66
|
+
:alicorns => 'so tasties'
|
67
|
+
})
|
68
|
+
|
69
|
+
subject.interpolate(dataset)
|
70
|
+
expect(subject.xml_document).to be_equivalent_to xml_fragment('output/conditional_block/unless_exists')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "within a table" do
|
75
|
+
let(:fragment) { xml_fragment('input/conditional_block/conditional_in_table') }
|
76
|
+
let(:dataset_hash) {
|
77
|
+
{
|
78
|
+
:include_dogs => true,
|
79
|
+
:dog_favorites => [
|
80
|
+
{ :name => "Fluffy the Android", :megaphone => "YellTheBest" },
|
81
|
+
{ :name => "Derek Dog", :megaphone => "Super Primo Loudkins" }
|
82
|
+
]
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
it "includes if rows when variable truthy" do
|
87
|
+
dataset = Sheng::DataSet.new(dataset_hash)
|
88
|
+
|
89
|
+
subject.interpolate(dataset)
|
90
|
+
expect(subject.xml_document).to be_equivalent_to xml_fragment('output/conditional_block/conditional_in_table_exists')
|
91
|
+
end
|
92
|
+
|
93
|
+
it "removes entire section when variable falsy" do
|
94
|
+
dataset = Sheng::DataSet.new(dataset_hash.merge(:include_dogs => false))
|
95
|
+
|
96
|
+
subject.interpolate(dataset)
|
97
|
+
expect(subject.xml_document).to be_equivalent_to xml_fragment('output/conditional_block/conditional_in_table_does_not_exist')
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context "with an embedded conditional" do
|
102
|
+
let(:fragment) { xml_fragment('input/conditional_block/embedded_conditional') }
|
103
|
+
let(:dataset_hash) {
|
104
|
+
{ :alicorns => true, :scubas => true }
|
105
|
+
}
|
106
|
+
|
107
|
+
it "includes both sections when both are truthy" do
|
108
|
+
dataset = Sheng::DataSet.new(dataset_hash)
|
109
|
+
|
110
|
+
subject.interpolate(dataset)
|
111
|
+
expect(subject.xml_document).to be_equivalent_to xml_fragment('output/conditional_block/embedded_conditional_both')
|
112
|
+
end
|
113
|
+
|
114
|
+
it "includes only outside section if inside falsy" do
|
115
|
+
dataset = Sheng::DataSet.new(dataset_hash.merge(:scubas => false))
|
116
|
+
|
117
|
+
subject.interpolate(dataset)
|
118
|
+
expect(subject.xml_document).to be_equivalent_to xml_fragment('output/conditional_block/embedded_conditional_outside')
|
119
|
+
end
|
120
|
+
|
121
|
+
it "ignores truthy inside section if outside section is falsy" do
|
122
|
+
dataset = Sheng::DataSet.new(dataset_hash.merge(:alicorns => false))
|
123
|
+
|
124
|
+
subject.interpolate(dataset)
|
125
|
+
expect(subject.xml_document).to be_equivalent_to xml_fragment('output/conditional_block/embedded_conditional_inside')
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '#new' do
|
131
|
+
context "with unclosed conditional" do
|
132
|
+
let(:fragment) { xml_fragment('input/conditional_block/bad/unclosed_conditional') }
|
133
|
+
it 'raises an exception indicating the missing end tag' do
|
134
|
+
dataset = Sheng::DataSet.new({})
|
135
|
+
expect {
|
136
|
+
subject
|
137
|
+
}.to raise_error(described_class::MissingEndTag, "no end tag for if:alicorns")
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context "with badly nested conditional" do
|
142
|
+
let(:fragment) { xml_fragment('input/conditional_block/bad/badly_nested_conditional') }
|
143
|
+
it 'raises an exception indicating the nesting issue' do
|
144
|
+
dataset = Sheng::DataSet.new({})
|
145
|
+
expect {
|
146
|
+
subject
|
147
|
+
}.to raise_error(described_class::ImproperNesting, "expected end tag for unless:pumpkins, got end_if:alicorns")
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
describe Sheng::DataSet do
|
2
|
+
describe '#new' do
|
3
|
+
it 'raises an argument error if not given a Hash' do
|
4
|
+
not_a_hash = double('Not a Hash')
|
5
|
+
allow(not_a_hash).to receive(:is_a?).with(Hash).and_return(false)
|
6
|
+
expect {
|
7
|
+
described_class.new(not_a_hash)
|
8
|
+
}.to raise_error(ArgumentError, "must be initialized with a Hash")
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'deep symbolizes the given hash and assigns it to #raw_hash' do
|
12
|
+
a_hash = double(Hash, :deep_symbolize_keys => :an_awesome_symbolized_hash)
|
13
|
+
allow(a_hash).to receive(:is_a?).with(Hash).and_return(true)
|
14
|
+
subject = described_class.new(a_hash)
|
15
|
+
expect(subject.raw_hash).to eq :an_awesome_symbolized_hash
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#fetch' do
|
20
|
+
let(:raw_hash) {
|
21
|
+
{
|
22
|
+
:rabbits => {
|
23
|
+
:streamlined => [:super_rabbit, :dr_slinky],
|
24
|
+
:slow => :mr_molasses
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
subject { described_class.new(raw_hash) }
|
29
|
+
|
30
|
+
it 'returns a non-hash object found at key' do
|
31
|
+
expect(subject.fetch('rabbits.slow')).to eq :mr_molasses
|
32
|
+
expect(subject.fetch('rabbits.streamlined')).to eq [:super_rabbit, :dr_slinky]
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'raises an error if not given a string' do
|
36
|
+
not_a_string = double('Not a String')
|
37
|
+
allow(not_a_string).to receive(:is_a?).with(String).and_return(false)
|
38
|
+
expect {
|
39
|
+
subject.fetch(not_a_string)
|
40
|
+
}.to raise_error(ArgumentError, "must provide a string")
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'raises a KeyNotFound error if key not found' do
|
44
|
+
expect {
|
45
|
+
subject.fetch('rabbits.funky')
|
46
|
+
}.to raise_error(described_class::KeyNotFound, "did not find in dataset: rabbits.funky (funky not found)")
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'does not raise error on key not found if default given' do
|
50
|
+
expect(subject.fetch('rabbits.funky', :default => "horse")).to eq("horse")
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'raises an error if Hash found at key' do
|
54
|
+
expect {
|
55
|
+
subject.fetch('rabbits')
|
56
|
+
}.to raise_error(described_class::KeyNotFound, "result at rabbits is a Hash")
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'raises an error if key is too long' do
|
60
|
+
expect {
|
61
|
+
subject.fetch('rabbits.slow.but_steady')
|
62
|
+
}.to raise_error(described_class::KeyNotFound, "in rabbits.slow.but_steady, slow did not return a Hash")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|