sablon 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +32 -7
- data/lib/sablon/operations.rb +3 -2
- data/lib/sablon/parser/mail_merge.rb +17 -11
- data/lib/sablon/processor.rb +24 -10
- data/lib/sablon/template.rb +2 -0
- data/lib/sablon/test.rb +1 -0
- data/lib/sablon/test/assertions.rb +22 -0
- data/lib/sablon/version.rb +1 -1
- data/misc/output.png +0 -0
- data/misc/template.png +0 -0
- data/sablon.gemspec +1 -1
- data/test/fixtures/sablon_sample.docx +0 -0
- data/test/fixtures/sablon_template.docx +0 -0
- data/test/mail_merge_parser_test.rb +100 -7
- data/test/processor_test.rb +123 -96
- data/test/sablon_test.rb +6 -19
- data/test/test_helper.rb +1 -0
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f2bdc7b8b84da3ad1a1893b515d23530fa6f597
|
4
|
+
data.tar.gz: c872738213cbc5ebd926a9287512c40393a27fe2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b12594e4647d2787ed4b8a2020ac44f668d2834f53cf8a16df4ff384fe52587386b8af8004cfdcb2c0da89d7c64481fb33363d1a59b43235cbb19f2b65f3bfa1
|
7
|
+
data.tar.gz: 5a4ea402a07886f1009d24917ec850f7adef2d248511e2d5e93272794d0d49ff632af0554a2cd4cfcd1ddda7535db6f081e117d00b9d333f7e859b0abcaa5076
|
data/README.md
CHANGED
@@ -2,8 +2,9 @@
|
|
2
2
|
|
3
3
|
[![Build Status](https://travis-ci.org/senny/sablon.svg?branch=master)](https://travis-ci.org/senny/sablon)
|
4
4
|
|
5
|
-
Is a document template processor
|
6
|
-
|
5
|
+
Is a document template processor for Word `docx` files. It leverages Word's
|
6
|
+
built-in formatting and layouting capabilities to make it easy to create your
|
7
|
+
templates.
|
7
8
|
|
8
9
|
## Installation
|
9
10
|
|
@@ -33,7 +34,7 @@ Sablon templates are normal word documents (`.docx`) sprinkled with MergeFields
|
|
33
34
|
to perform operations. The following section will use the notation `«=title»` to
|
34
35
|
refer to [Word MailMerge](http://en.wikipedia.org/wiki/Mail_merge) fields.
|
35
36
|
|
36
|
-
####
|
37
|
+
#### Content Insertion
|
37
38
|
|
38
39
|
The most basic operation is to insert content. The contents of a context
|
39
40
|
variable can be inserted using a field like:
|
@@ -61,8 +62,16 @@ context variable. Conditional fields are inserted around the content.
|
|
61
62
|
```
|
62
63
|
|
63
64
|
This will render the enclosed markup only if the expression is truthy.
|
64
|
-
Note that `nil`, `false` and `[]` are considered falsy. Everything else is
|
65
|
+
Note that `nil`, `false` and `[]` are considered falsy. Everything else is
|
66
|
+
truthy.
|
65
67
|
|
68
|
+
For more complex conditionals you can use a predicate like so:
|
69
|
+
|
70
|
+
```
|
71
|
+
«body:if(present?)»
|
72
|
+
... arbitrary document markup ...
|
73
|
+
«body:endIf»
|
74
|
+
```
|
66
75
|
|
67
76
|
#### Loops
|
68
77
|
|
@@ -88,9 +97,24 @@ It is possible to nest loops and conditionals.
|
|
88
97
|
|
89
98
|
### Examples
|
90
99
|
|
91
|
-
[
|
92
|
-
|
93
|
-
|
100
|
+
There is a [sample template](test/fixtures/sablon_template.docx) in the
|
101
|
+
repository, which illustrates the functionality of sablon:
|
102
|
+
|
103
|
+
<p align="center">
|
104
|
+
<img
|
105
|
+
src="https://raw.githubusercontent.com/senny/sablon/master/misc/template.png"
|
106
|
+
alt="Sablon Template"/>
|
107
|
+
</p>
|
108
|
+
|
109
|
+
Processing this template with some sample data yields the following
|
110
|
+
[output document](test/fixtures/sablon_sample.docx).
|
111
|
+
For more details, check out this [test case](test/sablon_test.rb).
|
112
|
+
|
113
|
+
<p align="center">
|
114
|
+
<img
|
115
|
+
src="https://raw.githubusercontent.com/senny/sablon/master/misc/output.png"
|
116
|
+
alt="Sablon Output"/>
|
117
|
+
</p>
|
94
118
|
|
95
119
|
|
96
120
|
## Contributing
|
@@ -101,6 +125,7 @@ the corresponding [output](test/fixtures/sablon_sample.docx).
|
|
101
125
|
4. Push to the branch (`git push origin my-new-feature`)
|
102
126
|
5. Create a new Pull Request
|
103
127
|
|
128
|
+
|
104
129
|
## Inspiration
|
105
130
|
|
106
131
|
The following projects address a similar goal and inspired the work on Sablon:
|
data/lib/sablon/operations.rb
CHANGED
@@ -16,9 +16,10 @@ module Sablon
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
class Condition < Struct.new(:conditon_expr, :block)
|
19
|
+
class Condition < Struct.new(:conditon_expr, :block, :predicate)
|
20
20
|
def evaluate(context)
|
21
|
-
|
21
|
+
value = conditon_expr.evaluate(context)
|
22
|
+
if truthy?(predicate ? value.public_send(predicate) : value)
|
22
23
|
block.replace(block.process(context).reverse)
|
23
24
|
else
|
24
25
|
block.replace([])
|
@@ -10,7 +10,7 @@ module Sablon
|
|
10
10
|
private
|
11
11
|
def replace_field_display(node, text)
|
12
12
|
display_node = node.search(".//w:t").first
|
13
|
-
text.scan(/[^\n]+|\n/).reverse.each do |part|
|
13
|
+
text.to_s.scan(/[^\n]+|\n/).reverse.each do |part|
|
14
14
|
if part == "\n"
|
15
15
|
display_node.add_next_sibling Nokogiri::XML::Node.new "w:br", display_node.document
|
16
16
|
else
|
@@ -67,20 +67,26 @@ module Sablon
|
|
67
67
|
def parse_fields(xml)
|
68
68
|
fields = []
|
69
69
|
xml.traverse do |node|
|
70
|
-
if node.name == "fldSimple"
|
71
|
-
|
72
|
-
elsif node.name == "fldChar" && node
|
73
|
-
|
74
|
-
field_nodes = [possible_field_node]
|
75
|
-
while possible_field_node && possible_field_node.search(".//w:fldChar[@w:fldCharType='end']").empty?
|
76
|
-
possible_field_node = possible_field_node.next_element
|
77
|
-
field_nodes << possible_field_node
|
78
|
-
end
|
79
|
-
fields << ComplexField.new(field_nodes)
|
70
|
+
if node.name == "fldSimple"
|
71
|
+
field = SimpleField.new(node)
|
72
|
+
elsif node.name == "fldChar" && node["w:fldCharType"] == "begin"
|
73
|
+
field = build_complex_field(node)
|
80
74
|
end
|
75
|
+
fields << field if field && field.expression
|
81
76
|
end
|
82
77
|
fields
|
83
78
|
end
|
79
|
+
|
80
|
+
private
|
81
|
+
def build_complex_field(node)
|
82
|
+
possible_field_node = node.parent
|
83
|
+
field_nodes = [possible_field_node]
|
84
|
+
while possible_field_node && possible_field_node.search(".//w:fldChar[@w:fldCharType='end']").empty?
|
85
|
+
possible_field_node = possible_field_node.next_element
|
86
|
+
field_nodes << possible_field_node
|
87
|
+
end
|
88
|
+
ComplexField.new(field_nodes)
|
89
|
+
end
|
84
90
|
end
|
85
91
|
end
|
86
92
|
end
|
data/lib/sablon/processor.rb
CHANGED
@@ -38,16 +38,15 @@ module Sablon
|
|
38
38
|
class Block < Struct.new(:start_field, :end_field)
|
39
39
|
def self.enclosed_by(start_field, end_field)
|
40
40
|
@blocks ||= [RowBlock, ParagraphBlock]
|
41
|
-
block_class = @blocks.detect { |klass| klass.
|
41
|
+
block_class = @blocks.detect { |klass| klass.encloses?(start_field, end_field) }
|
42
42
|
block_class.new start_field, end_field
|
43
43
|
end
|
44
44
|
|
45
45
|
def process(context)
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
46
|
+
replaced_node = Nokogiri::XML::Node.new("tmp", start_node.document)
|
47
|
+
replaced_node.children = Nokogiri::XML::NodeSet.new(start_node.document, body.map(&:dup))
|
48
|
+
Processor.process replaced_node, context
|
49
|
+
replaced_node.children
|
51
50
|
end
|
52
51
|
|
53
52
|
def replace(content)
|
@@ -76,8 +75,8 @@ module Sablon
|
|
76
75
|
@end_node ||= self.class.parent(end_field).first
|
77
76
|
end
|
78
77
|
|
79
|
-
def self.
|
80
|
-
parent(
|
78
|
+
def self.encloses?(start_field, end_field)
|
79
|
+
parent(start_field).any? && parent(end_field).any?
|
81
80
|
end
|
82
81
|
end
|
83
82
|
|
@@ -85,6 +84,12 @@ module Sablon
|
|
85
84
|
def self.parent(node)
|
86
85
|
node.ancestors ".//w:tr"
|
87
86
|
end
|
87
|
+
|
88
|
+
def self.encloses?(start_field, end_field)
|
89
|
+
if super
|
90
|
+
parent(start_field) != parent(end_field)
|
91
|
+
end
|
92
|
+
end
|
88
93
|
end
|
89
94
|
|
90
95
|
class ParagraphBlock < Block
|
@@ -108,6 +113,7 @@ module Sablon
|
|
108
113
|
|
109
114
|
def consume(allow_insertion)
|
110
115
|
@field = @fields.shift
|
116
|
+
return unless @field
|
111
117
|
case @field.expression
|
112
118
|
when /^=/
|
113
119
|
if allow_insertion
|
@@ -116,6 +122,9 @@ module Sablon
|
|
116
122
|
when /([^ ]+):each\(([^ ]+)\)/
|
117
123
|
block = consume_block("#{$1}:endEach")
|
118
124
|
Statement::Loop.new(Expression.parse($1), $2, block)
|
125
|
+
when /([^ ]+):if\(([^)]+)\)/
|
126
|
+
block = consume_block("#{$1}:endIf")
|
127
|
+
Statement::Condition.new(Expression.parse($1), block, $2)
|
119
128
|
when /([^ ]+):if/
|
120
129
|
block = consume_block("#{$1}:endIf")
|
121
130
|
Statement::Condition.new(Expression.parse($1), block)
|
@@ -125,10 +134,15 @@ module Sablon
|
|
125
134
|
def consume_block(end_expression)
|
126
135
|
start_field = end_field = @field
|
127
136
|
while end_field && end_field.expression != end_expression
|
128
|
-
|
137
|
+
consume(false)
|
129
138
|
end_field = @field
|
130
139
|
end
|
131
|
-
|
140
|
+
|
141
|
+
if end_field
|
142
|
+
Block.enclosed_by start_field, end_field
|
143
|
+
else
|
144
|
+
raise "no end field for #{start_field.expression}. Was looking for #{end_expression}"
|
145
|
+
end
|
132
146
|
end
|
133
147
|
end
|
134
148
|
end
|
data/lib/sablon/template.rb
CHANGED
@@ -25,6 +25,8 @@ module Sablon
|
|
25
25
|
content = entry.get_input_stream.read
|
26
26
|
if entry_name == 'word/document.xml'
|
27
27
|
out.write(Processor.process(Nokogiri::XML(content), context, properties).to_xml)
|
28
|
+
elsif entry_name =~ /word\/header\d*\.xml/ || entry_name =~ /word\/footer\d*\.xml/
|
29
|
+
out.write(Processor.process(Nokogiri::XML(content), context).to_xml)
|
28
30
|
else
|
29
31
|
out.write(content)
|
30
32
|
end
|
data/lib/sablon/test.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "sablon/test/assertions"
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Sablon
|
2
|
+
module Test
|
3
|
+
module Assertions
|
4
|
+
def assert_docx_equal(expected_path, actual_path)
|
5
|
+
if get_document_xml(expected_path) != get_document_xml(actual_path)
|
6
|
+
msg = <<-error
|
7
|
+
The generated document does not match the sample. Please investigate.
|
8
|
+
|
9
|
+
If the generated document is correct, the sample needs to be updated:
|
10
|
+
\t cp #{actual_path} #{expected_path}
|
11
|
+
error
|
12
|
+
fail msg
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_document_xml(path)
|
17
|
+
document_xml_entry = Zip::File.open(path).get_entry("word/document.xml")
|
18
|
+
document_xml_entry.get_input_stream.read
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/sablon/version.rb
CHANGED
data/misc/output.png
ADDED
Binary file
|
data/misc/template.png
ADDED
Binary file
|
data/sablon.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_runtime_dependency 'nokogiri'
|
22
|
-
spec.add_runtime_dependency 'rubyzip'
|
22
|
+
spec.add_runtime_dependency 'rubyzip', ">= 1.1"
|
23
23
|
|
24
24
|
spec.add_development_dependency "bundler", ">= 1.6"
|
25
25
|
spec.add_development_dependency "rake", "~> 10.0"
|
Binary file
|
Binary file
|
@@ -10,13 +10,20 @@ module MailMergeParser
|
|
10
10
|
@parser = Sablon::Parser::MailMerge.new
|
11
11
|
end
|
12
12
|
|
13
|
+
def field
|
14
|
+
@field ||= fields.first
|
15
|
+
end
|
16
|
+
|
13
17
|
def fields
|
14
|
-
@document
|
15
|
-
@parser.parse_fields(@document)
|
18
|
+
@parser.parse_fields(document)
|
16
19
|
end
|
17
20
|
|
18
21
|
def body_xml
|
19
|
-
|
22
|
+
document.search(".//w:body").children.map(&:to_xml).join.strip
|
23
|
+
end
|
24
|
+
|
25
|
+
def document
|
26
|
+
@document ||= xml
|
20
27
|
end
|
21
28
|
end
|
22
29
|
|
@@ -28,7 +35,6 @@ module MailMergeParser
|
|
28
35
|
end
|
29
36
|
|
30
37
|
def test_replace
|
31
|
-
field = fields.first
|
32
38
|
field.replace("Hello")
|
33
39
|
assert_equal <<-body_xml.strip, body_xml
|
34
40
|
<w:r w:rsidR=\"004B49F0\">
|
@@ -39,7 +45,6 @@ body_xml
|
|
39
45
|
end
|
40
46
|
|
41
47
|
def test_replace_with_newlines
|
42
|
-
field = fields.first
|
43
48
|
field.replace("First\nSecond\n\nThird")
|
44
49
|
|
45
50
|
assert_equal <<-body_xml.strip, body_xml
|
@@ -50,6 +55,28 @@ body_xml
|
|
50
55
|
body_xml
|
51
56
|
end
|
52
57
|
|
58
|
+
def test_replace_with_nil
|
59
|
+
field.replace(nil)
|
60
|
+
|
61
|
+
assert_equal <<-body_xml.strip, body_xml.gsub(/^\s+$/,'')
|
62
|
+
<w:r w:rsidR=\"004B49F0\">
|
63
|
+
<w:rPr><w:noProof/></w:rPr>
|
64
|
+
|
65
|
+
</w:r>
|
66
|
+
body_xml
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_replace_with_numeric
|
70
|
+
field.replace(45)
|
71
|
+
|
72
|
+
assert_equal <<-body_xml.strip, body_xml.gsub(/^\s+$/,'')
|
73
|
+
<w:r w:rsidR=\"004B49F0\">
|
74
|
+
<w:rPr><w:noProof/></w:rPr>
|
75
|
+
<w:t>45</w:t>
|
76
|
+
</w:r>
|
77
|
+
body_xml
|
78
|
+
end
|
79
|
+
|
53
80
|
private
|
54
81
|
def xml
|
55
82
|
wrap(<<-xml)
|
@@ -71,7 +98,6 @@ body_xml
|
|
71
98
|
end
|
72
99
|
|
73
100
|
def test_replace
|
74
|
-
field = fields.first
|
75
101
|
field.replace("Hello")
|
76
102
|
assert_equal <<-body_xml.strip, body_xml
|
77
103
|
<w:r w:rsidR="004B49F0">
|
@@ -85,7 +111,6 @@ body_xml
|
|
85
111
|
end
|
86
112
|
|
87
113
|
def test_replace_with_newlines
|
88
|
-
field = fields.first
|
89
114
|
field.replace("First\nSecond\n\nThird")
|
90
115
|
|
91
116
|
assert_equal <<-body_xml.strip, body_xml
|
@@ -99,6 +124,20 @@ body_xml
|
|
99
124
|
body_xml
|
100
125
|
end
|
101
126
|
|
127
|
+
def test_replace_with_nil
|
128
|
+
field.replace(nil)
|
129
|
+
|
130
|
+
assert_equal <<-body_xml.strip, body_xml.gsub(/^\s+$/,'')
|
131
|
+
<w:r w:rsidR="004B49F0">
|
132
|
+
<w:rPr>
|
133
|
+
<w:b/>
|
134
|
+
<w:noProof/>
|
135
|
+
</w:rPr>
|
136
|
+
|
137
|
+
</w:r>
|
138
|
+
body_xml
|
139
|
+
end
|
140
|
+
|
102
141
|
private
|
103
142
|
def xml
|
104
143
|
wrap(<<-xml)
|
@@ -128,4 +167,58 @@ body_xml
|
|
128
167
|
xml
|
129
168
|
end
|
130
169
|
end
|
170
|
+
|
171
|
+
class NonSablonFieldTest < Sablon::TestCase
|
172
|
+
include SharedBehavior
|
173
|
+
|
174
|
+
def test_is_ignored
|
175
|
+
assert_equal [], fields.map(&:class)
|
176
|
+
end
|
177
|
+
|
178
|
+
private
|
179
|
+
def xml
|
180
|
+
wrap(<<-xml)
|
181
|
+
<w:p w14:paraId="0CF428D7" w14:textId="77777777" w:rsidR="00043618" w:rsidRDefault="00043618" w:rsidP="00B960C2">
|
182
|
+
<w:pPr>
|
183
|
+
<w:pStyle w:val="Footer" />
|
184
|
+
<w:framePr w:wrap="around" w:vAnchor="text" w:hAnchor="margin" w:xAlign="right" w:y="1" />
|
185
|
+
<w:rPr>
|
186
|
+
<w:rStyle w:val="PageNumber" />
|
187
|
+
</w:rPr>
|
188
|
+
</w:pPr>
|
189
|
+
<w:r>
|
190
|
+
<w:rPr>
|
191
|
+
<w:rStyle w:val="PageNumber" />
|
192
|
+
</w:rPr>
|
193
|
+
<w:fldChar w:fldCharType="begin" />
|
194
|
+
</w:r>
|
195
|
+
<w:r>
|
196
|
+
<w:rPr>
|
197
|
+
<w:rStyle w:val="PageNumber" />
|
198
|
+
</w:rPr>
|
199
|
+
<w:instrText xml:space="preserve">PAGE </w:instrText>
|
200
|
+
</w:r>
|
201
|
+
<w:r>
|
202
|
+
<w:rPr>
|
203
|
+
<w:rStyle w:val="PageNumber" />
|
204
|
+
</w:rPr>
|
205
|
+
<w:fldChar w:fldCharType="separate" />
|
206
|
+
</w:r>
|
207
|
+
<w:r w:rsidR="00326FC5">
|
208
|
+
<w:rPr>
|
209
|
+
<w:rStyle w:val="PageNumber" />
|
210
|
+
<w:noProof />
|
211
|
+
</w:rPr>
|
212
|
+
<w:t>1</w:t>
|
213
|
+
</w:r>
|
214
|
+
<w:r>
|
215
|
+
<w:rPr>
|
216
|
+
<w:rStyle w:val="PageNumber" />
|
217
|
+
</w:rPr>
|
218
|
+
<w:fldChar w:fldCharType="end" />
|
219
|
+
</w:r>
|
220
|
+
</w:p>
|
221
|
+
xml
|
222
|
+
end
|
223
|
+
end
|
131
224
|
end
|
data/test/processor_test.rb
CHANGED
@@ -38,34 +38,23 @@ class ProcessorTest < Sablon::TestCase
|
|
38
38
|
result = process(<<-documentxml, {"last_name" => "Zane"})
|
39
39
|
<w:r><w:t xml:space="preserve">Hello! My Name is </w:t></w:r>
|
40
40
|
<w:r w:rsidR="00BE47B1" w:rsidRPr="00BE47B1">
|
41
|
-
<w:rPr>
|
42
|
-
<w:b/>
|
43
|
-
</w:rPr>
|
41
|
+
<w:rPr><w:b/></w:rPr>
|
44
42
|
<w:fldChar w:fldCharType="begin"/>
|
45
43
|
</w:r>
|
46
44
|
<w:r w:rsidR="00BE47B1" w:rsidRPr="00BE47B1">
|
47
|
-
<w:rPr>
|
48
|
-
<w:b/>
|
49
|
-
</w:rPr>
|
45
|
+
<w:rPr><w:b/></w:rPr>
|
50
46
|
<w:instrText xml:space="preserve"> MERGEFIELD =last_name \\* MERGEFORMAT </w:instrText>
|
51
47
|
</w:r>
|
52
48
|
<w:r w:rsidR="00BE47B1" w:rsidRPr="00BE47B1">
|
53
|
-
<w:rPr>
|
54
|
-
<w:b/>
|
55
|
-
</w:rPr>
|
49
|
+
<w:rPr><w:b/></w:rPr>
|
56
50
|
<w:fldChar w:fldCharType="separate"/>
|
57
51
|
</w:r>
|
58
52
|
<w:r w:rsidR="004B49F0">
|
59
|
-
<w:rPr>
|
60
|
-
<w:b/>
|
61
|
-
<w:noProof/>
|
62
|
-
</w:rPr>
|
53
|
+
<w:rPr><w:b/><w:noProof/></w:rPr>
|
63
54
|
<w:t>«=last_name»</w:t>
|
64
55
|
</w:r>
|
65
56
|
<w:r w:rsidR="00BE47B1" w:rsidRPr="00BE47B1">
|
66
|
-
<w:rPr>
|
67
|
-
<w:b/>
|
68
|
-
</w:rPr>
|
57
|
+
<w:rPr><w:b/></w:rPr>
|
69
58
|
<w:fldChar w:fldCharType="end"/>
|
70
59
|
</w:r>
|
71
60
|
<w:r w:rsidR="00BE47B1"><w:t xml:space="preserve">, nice to meet you.</w:t></w:r>
|
@@ -75,10 +64,7 @@ class ProcessorTest < Sablon::TestCase
|
|
75
64
|
assert_xml_equal <<-document, result
|
76
65
|
<w:r><w:t xml:space="preserve">Hello! My Name is </w:t></w:r>
|
77
66
|
<w:r w:rsidR="004B49F0">
|
78
|
-
<w:rPr>
|
79
|
-
<w:b/>
|
80
|
-
<w:noProof/>
|
81
|
-
</w:rPr>
|
67
|
+
<w:rPr><w:b/><w:noProof/></w:rPr>
|
82
68
|
<w:t>Zane</w:t>
|
83
69
|
</w:r>
|
84
70
|
<w:r w:rsidR="00BE47B1"><w:t xml:space="preserve">, nice to meet you.</w:t></w:r>
|
@@ -106,9 +92,7 @@ class ProcessorTest < Sablon::TestCase
|
|
106
92
|
<w:fldChar w:fldCharType="separate" />
|
107
93
|
</w:r>
|
108
94
|
<w:r w:rsidR="00441382">
|
109
|
-
<w:rPr>
|
110
|
-
<w:noProof />
|
111
|
-
</w:rPr>
|
95
|
+
<w:rPr><w:noProof /></w:rPr>
|
112
96
|
<w:t>«=person.first_name»</w:t>
|
113
97
|
</w:r>
|
114
98
|
<w:r w:rsidR="003C4780">
|
@@ -121,9 +105,7 @@ class ProcessorTest < Sablon::TestCase
|
|
121
105
|
assert_xml_equal <<-document, result
|
122
106
|
<w:r><w:t xml:space="preserve">Hello! My Name is </w:t></w:r>
|
123
107
|
<w:r w:rsidR="00441382">
|
124
|
-
<w:rPr>
|
125
|
-
<w:noProof/>
|
126
|
-
</w:rPr>
|
108
|
+
<w:rPr><w:noProof/></w:rPr>
|
127
109
|
<w:t>Daniel</w:t>
|
128
110
|
</w:r>
|
129
111
|
<w:r w:rsidR="00BE47B1"><w:t xml:space="preserve">, nice to meet you.</w:t></w:r>
|
@@ -131,7 +113,6 @@ class ProcessorTest < Sablon::TestCase
|
|
131
113
|
end
|
132
114
|
|
133
115
|
def test_paragraph_block_replacement
|
134
|
-
item = Struct.new(:index, :label, :rating)
|
135
116
|
result = process(<<-document, {"technologies" => ["Ruby", "Rails"]})
|
136
117
|
<w:p w14:paraId="6CB29D92" w14:textId="164B70F4" w:rsidR="007F5CDE" w:rsidRDefault="007F5CDE" w:rsidP="007F5CDE">
|
137
118
|
<w:pPr>
|
@@ -143,9 +124,7 @@ class ProcessorTest < Sablon::TestCase
|
|
143
124
|
</w:pPr>
|
144
125
|
<w:fldSimple w:instr=" MERGEFIELD technologies:each(technology) \\* MERGEFORMAT ">
|
145
126
|
<w:r>
|
146
|
-
<w:rPr>
|
147
|
-
<w:noProof />
|
148
|
-
</w:rPr>
|
127
|
+
<w:rPr><w:noProof /></w:rPr>
|
149
128
|
<w:t>«technologies:each(technology)»</w:t>
|
150
129
|
</w:r>
|
151
130
|
</w:fldSimple>
|
@@ -174,9 +153,7 @@ class ProcessorTest < Sablon::TestCase
|
|
174
153
|
<w:fldChar w:fldCharType="separate" />
|
175
154
|
</w:r>
|
176
155
|
<w:r w:rsidR="009F01DA">
|
177
|
-
<w:rPr>
|
178
|
-
<w:noProof />
|
179
|
-
</w:rPr>
|
156
|
+
<w:rPr><w:noProof /></w:rPr>
|
180
157
|
<w:t>«=technology»</w:t>
|
181
158
|
</w:r>
|
182
159
|
<w:r>
|
@@ -193,9 +170,7 @@ class ProcessorTest < Sablon::TestCase
|
|
193
170
|
</w:pPr>
|
194
171
|
<w:fldSimple w:instr=" MERGEFIELD technologies:endEach \\* MERGEFORMAT ">
|
195
172
|
<w:r>
|
196
|
-
<w:rPr>
|
197
|
-
<w:noProof />
|
198
|
-
</w:rPr>
|
173
|
+
<w:rPr><w:noProof /></w:rPr>
|
199
174
|
<w:t>«technologies:endEach»</w:t>
|
200
175
|
</w:r>
|
201
176
|
</w:fldSimple>
|
@@ -213,9 +188,7 @@ class ProcessorTest < Sablon::TestCase
|
|
213
188
|
</w:numPr>
|
214
189
|
</w:pPr>
|
215
190
|
<w:r w:rsidR="009F01DA">
|
216
|
-
<w:rPr>
|
217
|
-
<w:noProof/>
|
218
|
-
</w:rPr>
|
191
|
+
<w:rPr><w:noProof/></w:rPr>
|
219
192
|
<w:t>Ruby</w:t>
|
220
193
|
</w:r>
|
221
194
|
</w:p><w:p w14:paraId="1081E316" w14:textId="3EAB5FDC" w:rsidR="00380EE8" w:rsidRDefault="00380EE8" w:rsidP="007F5CDE">
|
@@ -227,15 +200,76 @@ class ProcessorTest < Sablon::TestCase
|
|
227
200
|
</w:numPr>
|
228
201
|
</w:pPr>
|
229
202
|
<w:r w:rsidR="009F01DA">
|
230
|
-
<w:rPr>
|
231
|
-
<w:noProof/>
|
232
|
-
</w:rPr>
|
203
|
+
<w:rPr><w:noProof/></w:rPr>
|
233
204
|
<w:t>Rails</w:t>
|
234
205
|
</w:r>
|
235
206
|
</w:p>
|
236
207
|
document
|
237
208
|
end
|
238
209
|
|
210
|
+
def test_paragraph_block_within_table_cell
|
211
|
+
result = process(<<-document, {"technologies" => ["Puppet", "Chef"]})
|
212
|
+
<w:tbl>
|
213
|
+
<w:tblGrid>
|
214
|
+
<w:gridCol w:w="2202"/>
|
215
|
+
</w:tblGrid>
|
216
|
+
<w:tr w:rsidR="00757DAD">
|
217
|
+
<w:tc>
|
218
|
+
<w:p>
|
219
|
+
<w:fldSimple w:instr=" MERGEFIELD technologies:each(technology) \\* MERGEFORMAT ">
|
220
|
+
<w:r w:rsidR="004B49F0">
|
221
|
+
<w:rPr><w:noProof/></w:rPr>
|
222
|
+
<w:t>«technologies:each(technology)»</w:t>
|
223
|
+
</w:r>
|
224
|
+
</w:fldSimple>
|
225
|
+
</w:p>
|
226
|
+
<w:p>
|
227
|
+
<w:fldSimple w:instr=" MERGEFIELD =technology \\* MERGEFORMAT ">
|
228
|
+
<w:r w:rsidR="004B49F0">
|
229
|
+
<w:rPr><w:noProof/></w:rPr>
|
230
|
+
<w:t>«=technology»</w:t>
|
231
|
+
</w:r>
|
232
|
+
</w:fldSimple>
|
233
|
+
</w:p>
|
234
|
+
<w:p>
|
235
|
+
<w:fldSimple w:instr=" MERGEFIELD technologies:endEach \\* MERGEFORMAT ">
|
236
|
+
<w:r w:rsidR="004B49F0">
|
237
|
+
<w:rPr><w:noProof/></w:rPr>
|
238
|
+
<w:t>«technologies:endEach»</w:t>
|
239
|
+
</w:r>
|
240
|
+
</w:fldSimple>
|
241
|
+
</w:p>
|
242
|
+
</w:tc>
|
243
|
+
</w:tr>
|
244
|
+
</w:tbl>
|
245
|
+
document
|
246
|
+
|
247
|
+
assert_equal "Puppet Chef", text(result)
|
248
|
+
assert_xml_equal <<-document, result
|
249
|
+
<w:tbl>
|
250
|
+
<w:tblGrid>
|
251
|
+
<w:gridCol w:w="2202"/>
|
252
|
+
</w:tblGrid>
|
253
|
+
<w:tr w:rsidR="00757DAD">
|
254
|
+
<w:tc>
|
255
|
+
<w:p>
|
256
|
+
<w:r w:rsidR="004B49F0">
|
257
|
+
<w:rPr><w:noProof/></w:rPr>
|
258
|
+
<w:t>Puppet</w:t>
|
259
|
+
</w:r>
|
260
|
+
</w:p>
|
261
|
+
<w:p>
|
262
|
+
<w:r w:rsidR="004B49F0">
|
263
|
+
<w:rPr><w:noProof/></w:rPr>
|
264
|
+
<w:t>Chef</w:t>
|
265
|
+
</w:r>
|
266
|
+
</w:p>
|
267
|
+
</w:tc>
|
268
|
+
</w:tr>
|
269
|
+
</w:tbl>
|
270
|
+
document
|
271
|
+
end
|
272
|
+
|
239
273
|
def test_single_row_table_loop
|
240
274
|
item = Struct.new(:index, :label, :rating)
|
241
275
|
result = process(<<-document, {"items" => [item.new("1.", "Milk", "***"), item.new("2.", "Sugar", "**")]})
|
@@ -266,9 +300,7 @@ class ProcessorTest < Sablon::TestCase
|
|
266
300
|
<w:fldChar w:fldCharType="separate"/>
|
267
301
|
</w:r>
|
268
302
|
<w:r>
|
269
|
-
<w:rPr>
|
270
|
-
<w:noProof/>
|
271
|
-
</w:rPr>
|
303
|
+
<w:rPr><w:noProof/></w:rPr>
|
272
304
|
<w:t>«items:each(item)»</w:t>
|
273
305
|
</w:r>
|
274
306
|
<w:r>
|
@@ -305,9 +337,7 @@ class ProcessorTest < Sablon::TestCase
|
|
305
337
|
<w:fldChar w:fldCharType="separate"/>
|
306
338
|
</w:r>
|
307
339
|
<w:r>
|
308
|
-
<w:rPr>
|
309
|
-
<w:noProof/>
|
310
|
-
</w:rPr>
|
340
|
+
<w:rPr><w:noProof/></w:rPr>
|
311
341
|
<w:t>«=item.index»</w:t>
|
312
342
|
</w:r>
|
313
343
|
<w:r>
|
@@ -330,9 +360,7 @@ class ProcessorTest < Sablon::TestCase
|
|
330
360
|
<w:fldChar w:fldCharType="separate"/>
|
331
361
|
</w:r>
|
332
362
|
<w:r>
|
333
|
-
<w:rPr>
|
334
|
-
<w:noProof/>
|
335
|
-
</w:rPr>
|
363
|
+
<w:rPr><w:noProof/></w:rPr>
|
336
364
|
<w:t>«=item.label»</w:t>
|
337
365
|
</w:r>
|
338
366
|
<w:r>
|
@@ -355,9 +383,7 @@ class ProcessorTest < Sablon::TestCase
|
|
355
383
|
<w:fldChar w:fldCharType="separate"/>
|
356
384
|
</w:r>
|
357
385
|
<w:r>
|
358
|
-
<w:rPr>
|
359
|
-
<w:noProof/>
|
360
|
-
</w:rPr>
|
386
|
+
<w:rPr><w:noProof/></w:rPr>
|
361
387
|
<w:t>«=item.rating»</w:t>
|
362
388
|
</w:r>
|
363
389
|
<w:r>
|
@@ -382,9 +408,7 @@ class ProcessorTest < Sablon::TestCase
|
|
382
408
|
<w:fldChar w:fldCharType="separate"/>
|
383
409
|
</w:r>
|
384
410
|
<w:r>
|
385
|
-
<w:rPr>
|
386
|
-
<w:noProof/>
|
387
|
-
</w:rPr>
|
411
|
+
<w:rPr><w:noProof/></w:rPr>
|
388
412
|
<w:t>«items:endEach»</w:t>
|
389
413
|
</w:r>
|
390
414
|
<w:r>
|
@@ -427,9 +451,7 @@ class ProcessorTest < Sablon::TestCase
|
|
427
451
|
</w:tcPr>
|
428
452
|
<w:p w14:paraId="41ACB3D9" w14:textId="77777777" w:rsidR="00757DAD" w:rsidRDefault="00757DAD" w:rsidP="006333C3">
|
429
453
|
<w:r>
|
430
|
-
<w:rPr>
|
431
|
-
<w:noProof/>
|
432
|
-
</w:rPr>
|
454
|
+
<w:rPr><w:noProof/></w:rPr>
|
433
455
|
<w:t>1.</w:t>
|
434
456
|
</w:r>
|
435
457
|
</w:p>
|
@@ -440,9 +462,7 @@ class ProcessorTest < Sablon::TestCase
|
|
440
462
|
</w:tcPr>
|
441
463
|
<w:p w14:paraId="197C6F31" w14:textId="77777777" w:rsidR="00757DAD" w:rsidRDefault="00757DAD" w:rsidP="006333C3">
|
442
464
|
<w:r>
|
443
|
-
<w:rPr>
|
444
|
-
<w:noProof/>
|
445
|
-
</w:rPr>
|
465
|
+
<w:rPr><w:noProof/></w:rPr>
|
446
466
|
<w:t>Milk</w:t>
|
447
467
|
</w:r>
|
448
468
|
</w:p>
|
@@ -453,9 +473,7 @@ class ProcessorTest < Sablon::TestCase
|
|
453
473
|
</w:tcPr>
|
454
474
|
<w:p w14:paraId="55C258BB" w14:textId="77777777" w:rsidR="00757DAD" w:rsidRDefault="00757DAD" w:rsidP="006333C3">
|
455
475
|
<w:r>
|
456
|
-
<w:rPr>
|
457
|
-
<w:noProof/>
|
458
|
-
</w:rPr>
|
476
|
+
<w:rPr><w:noProof/></w:rPr>
|
459
477
|
<w:t>***</w:t>
|
460
478
|
</w:r>
|
461
479
|
</w:p>
|
@@ -467,9 +485,7 @@ class ProcessorTest < Sablon::TestCase
|
|
467
485
|
</w:tcPr>
|
468
486
|
<w:p w14:paraId="41ACB3D9" w14:textId="77777777" w:rsidR="00757DAD" w:rsidRDefault="00757DAD" w:rsidP="006333C3">
|
469
487
|
<w:r>
|
470
|
-
<w:rPr>
|
471
|
-
<w:noProof/>
|
472
|
-
</w:rPr>
|
488
|
+
<w:rPr><w:noProof/></w:rPr>
|
473
489
|
<w:t>2.</w:t>
|
474
490
|
</w:r>
|
475
491
|
</w:p>
|
@@ -480,9 +496,7 @@ class ProcessorTest < Sablon::TestCase
|
|
480
496
|
</w:tcPr>
|
481
497
|
<w:p w14:paraId="197C6F31" w14:textId="77777777" w:rsidR="00757DAD" w:rsidRDefault="00757DAD" w:rsidP="006333C3">
|
482
498
|
<w:r>
|
483
|
-
<w:rPr>
|
484
|
-
<w:noProof/>
|
485
|
-
</w:rPr>
|
499
|
+
<w:rPr><w:noProof/></w:rPr>
|
486
500
|
<w:t>Sugar</w:t>
|
487
501
|
</w:r>
|
488
502
|
</w:p>
|
@@ -493,9 +507,7 @@ class ProcessorTest < Sablon::TestCase
|
|
493
507
|
</w:tcPr>
|
494
508
|
<w:p w14:paraId="55C258BB" w14:textId="77777777" w:rsidR="00757DAD" w:rsidRDefault="00757DAD" w:rsidP="006333C3">
|
495
509
|
<w:r>
|
496
|
-
<w:rPr>
|
497
|
-
<w:noProof/>
|
498
|
-
</w:rPr>
|
510
|
+
<w:rPr><w:noProof/></w:rPr>
|
499
511
|
<w:t>**</w:t>
|
500
512
|
</w:r>
|
501
513
|
</w:p>
|
@@ -521,9 +533,7 @@ class ProcessorTest < Sablon::TestCase
|
|
521
533
|
<w:p w14:paraId="7630A6C6" w14:textId="699D0C71" w:rsidR="00F23752" w:rsidRDefault="00F23752" w:rsidP="003F16E3">
|
522
534
|
<w:fldSimple w:instr=" MERGEFIELD foods:each(food) \\* MERGEFORMAT ">
|
523
535
|
<w:r w:rsidR="00213ACD">
|
524
|
-
<w:rPr>
|
525
|
-
<w:noProof />
|
526
|
-
</w:rPr>
|
536
|
+
<w:rPr><w:noProof /></w:rPr>
|
527
537
|
<w:t>«foods:each(food)»</w:t>
|
528
538
|
</w:r>
|
529
539
|
</w:fldSimple>
|
@@ -546,9 +556,7 @@ class ProcessorTest < Sablon::TestCase
|
|
546
556
|
<w:p w14:paraId="3FCF3855" w14:textId="38FA7F3B" w:rsidR="00F23752" w:rsidRDefault="00F23752" w:rsidP="00F23752">
|
547
557
|
<w:fldSimple w:instr=" MERGEFIELD =food.index \\* MERGEFORMAT ">
|
548
558
|
<w:r w:rsidR="00213ACD">
|
549
|
-
<w:rPr>
|
550
|
-
<w:noProof />
|
551
|
-
</w:rPr>
|
559
|
+
<w:rPr><w:noProof /></w:rPr>
|
552
560
|
<w:t>«=food.index»</w:t>
|
553
561
|
</w:r>
|
554
562
|
</w:fldSimple>
|
@@ -598,9 +606,7 @@ class ProcessorTest < Sablon::TestCase
|
|
598
606
|
<w:p w14:paraId="3E9FF163" w14:textId="0F37CDFB" w:rsidR="00213ACD" w:rsidRDefault="00213ACD" w:rsidP="003F16E3">
|
599
607
|
<w:fldSimple w:instr=" MERGEFIELD =food.body \\* MERGEFORMAT ">
|
600
608
|
<w:r>
|
601
|
-
<w:rPr>
|
602
|
-
<w:noProof />
|
603
|
-
</w:rPr>
|
609
|
+
<w:rPr><w:noProof /></w:rPr>
|
604
610
|
<w:t>«=food.body»</w:t>
|
605
611
|
</w:r>
|
606
612
|
</w:fldSimple>
|
@@ -624,9 +630,7 @@ class ProcessorTest < Sablon::TestCase
|
|
624
630
|
<w:fldChar w:fldCharType="separate" />
|
625
631
|
</w:r>
|
626
632
|
<w:r>
|
627
|
-
<w:rPr>
|
628
|
-
<w:noProof />
|
629
|
-
</w:rPr>
|
633
|
+
<w:rPr><w:noProof /></w:rPr>
|
630
634
|
<w:t>«foods:endEach»</w:t>
|
631
635
|
</w:r>
|
632
636
|
<w:r>
|
@@ -654,9 +658,7 @@ class ProcessorTest < Sablon::TestCase
|
|
654
658
|
<w:p>
|
655
659
|
<w:fldSimple w:instr=" MERGEFIELD middle_name:if \\* MERGEFORMAT ">
|
656
660
|
<w:r>
|
657
|
-
<w:rPr>
|
658
|
-
<w:noProof/>
|
659
|
-
</w:rPr>
|
661
|
+
<w:rPr><w:noProof/></w:rPr>
|
660
662
|
<w:t>«middle_name:if»</w:t>
|
661
663
|
</w:r>
|
662
664
|
</w:fldSimple>
|
@@ -664,9 +666,7 @@ class ProcessorTest < Sablon::TestCase
|
|
664
666
|
<w:p>
|
665
667
|
<w:fldSimple w:instr=" MERGEFIELD =middle_name \\* MERGEFORMAT ">
|
666
668
|
<w:r>
|
667
|
-
<w:rPr>
|
668
|
-
<w:noProof/>
|
669
|
-
</w:rPr>
|
669
|
+
<w:rPr><w:noProof/></w:rPr>
|
670
670
|
<w:t>«=middle_name»</w:t>
|
671
671
|
</w:r>
|
672
672
|
</w:fldSimple>
|
@@ -674,9 +674,7 @@ class ProcessorTest < Sablon::TestCase
|
|
674
674
|
<w:p>
|
675
675
|
<w:fldSimple w:instr=" MERGEFIELD middle_name:endIf \\* MERGEFORMAT ">
|
676
676
|
<w:r>
|
677
|
-
<w:rPr>
|
678
|
-
<w:noProof/>
|
679
|
-
</w:rPr>
|
677
|
+
<w:rPr><w:noProof/></w:rPr>
|
680
678
|
<w:t>«middle_name:endIf»</w:t>
|
681
679
|
</w:r>
|
682
680
|
</w:fldSimple>
|
@@ -690,6 +688,35 @@ class ProcessorTest < Sablon::TestCase
|
|
690
688
|
assert_equal "Anthony Hall", text(result)
|
691
689
|
end
|
692
690
|
|
691
|
+
def test_conditional_with_predicate
|
692
|
+
document = <<-documentxml
|
693
|
+
<w:p>
|
694
|
+
<w:fldSimple w:instr=" MERGEFIELD body:if(empty?) \\* MERGEFORMAT ">
|
695
|
+
<w:r>
|
696
|
+
<w:rPr><w:noProof/></w:rPr>
|
697
|
+
<w:t>«body:if(empty?)»</w:t>
|
698
|
+
</w:r>
|
699
|
+
</w:fldSimple>
|
700
|
+
</w:p>
|
701
|
+
<w:p>
|
702
|
+
<w:t>some content</w:t>
|
703
|
+
</w:p>
|
704
|
+
<w:p>
|
705
|
+
<w:fldSimple w:instr=" MERGEFIELD body:endIf \\* MERGEFORMAT ">
|
706
|
+
<w:r>
|
707
|
+
<w:rPr><w:noProof/></w:rPr>
|
708
|
+
<w:t>«body:endIf»</w:t>
|
709
|
+
</w:r>
|
710
|
+
</w:fldSimple>
|
711
|
+
</w:p>
|
712
|
+
documentxml
|
713
|
+
result = process(document, {"body" => ""})
|
714
|
+
assert_equal "some content", text(result)
|
715
|
+
|
716
|
+
result = process(document, {"body" => "not empty"})
|
717
|
+
assert_equal "", text(result)
|
718
|
+
end
|
719
|
+
|
693
720
|
private
|
694
721
|
def process(document, context)
|
695
722
|
@processor.process(wrap(document), context).to_xml
|
data/test/sablon_test.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
require "test_helper"
|
3
3
|
|
4
4
|
class SablonTest < Sablon::TestCase
|
5
|
+
include Sablon::Test::Assertions
|
6
|
+
|
5
7
|
def setup
|
6
8
|
super
|
7
9
|
@base_path = Pathname.new(File.expand_path("../", __FILE__))
|
@@ -15,11 +17,14 @@ class SablonTest < Sablon::TestCase
|
|
15
17
|
position = Struct.new(:duration, :label, :description)
|
16
18
|
language = Struct.new(:name, :skill)
|
17
19
|
context = {
|
20
|
+
"current_time" => Time.now.strftime("%d.%m.%Y %H:%M"),
|
21
|
+
"author" => "Yves Senn",
|
18
22
|
"title" => "Letter of application",
|
19
23
|
"person" => person,
|
20
24
|
"items" => [item.new("1.", "Ruby", "★" * 5), item.new("2.", "Java", "★" * 1), item.new("3.", "Python", "★" * 3)],
|
21
25
|
"career" => [position.new("1999 - 2006", "Junior Java Engineer", "Lorem ipsum dolor\nsit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."),
|
22
|
-
position.new("2006 - 2013", "Senior Ruby Developer", "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.")
|
26
|
+
position.new("2006 - 2013", "Senior Ruby Developer", "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo."),
|
27
|
+
position.new("2013 - today", "Sales...", nil)],
|
23
28
|
"technologies" => ["HTML", "CSS", "SASS", "LESS", "JavaScript"],
|
24
29
|
"languages" => [language.new("German", "native speaker"), language.new("English", "fluent")],
|
25
30
|
"training" => "At vero eos et accusam et justo duo dolores et ea rebum.\n\nStet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet."
|
@@ -31,22 +36,4 @@ class SablonTest < Sablon::TestCase
|
|
31
36
|
|
32
37
|
assert_docx_equal @base_path + "fixtures/sablon_sample.docx", @output_path
|
33
38
|
end
|
34
|
-
|
35
|
-
private
|
36
|
-
def assert_docx_equal(expected_path, actual_path)
|
37
|
-
if get_document_xml(expected_path) != get_document_xml(actual_path)
|
38
|
-
msg = <<-error
|
39
|
-
The generated document does not match the sample. Please investigate.
|
40
|
-
|
41
|
-
If the generated document is correct, the sample needs to be updated:
|
42
|
-
\t cp #{actual_path} #{expected_path}
|
43
|
-
error
|
44
|
-
fail msg
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def get_document_xml(path)
|
49
|
-
document_xml_entry = Zip::File.open(path).get_entry("word/document.xml")
|
50
|
-
document_xml_entry.get_input_stream.read
|
51
|
-
end
|
52
39
|
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sablon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yves Senn
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-11-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '1.1'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '1.1'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: bundler
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,7 +114,11 @@ files:
|
|
114
114
|
- lib/sablon/processor.rb
|
115
115
|
- lib/sablon/processor/section_properties.rb
|
116
116
|
- lib/sablon/template.rb
|
117
|
+
- lib/sablon/test.rb
|
118
|
+
- lib/sablon/test/assertions.rb
|
117
119
|
- lib/sablon/version.rb
|
120
|
+
- misc/output.png
|
121
|
+
- misc/template.png
|
118
122
|
- sablon.gemspec
|
119
123
|
- test/expression_test.rb
|
120
124
|
- test/fixtures/sablon_sample.docx
|