sablon 0.2.1 → 0.3.0
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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +12 -0
- data/lib/sablon/document_object_model/relationships.rb +4 -1
- data/lib/sablon/operations.rb +50 -8
- data/lib/sablon/parser/mail_merge.rb +33 -2
- data/lib/sablon/processor/document.rb +67 -191
- data/lib/sablon/processor/document/blocks.rb +134 -0
- data/lib/sablon/processor/document/field_handlers.rb +117 -0
- data/lib/sablon/processor/document/operation_construction.rb +71 -0
- data/lib/sablon/version.rb +1 -1
- data/test/custom_field_handler_test.rb +106 -0
- data/test/fixtures/conditionals_sample.docx +0 -0
- data/test/fixtures/conditionals_template.docx +0 -0
- data/test/fixtures/custom_field_handlers_sample.docx +0 -0
- data/test/fixtures/custom_field_handlers_template.docx +0 -0
- data/test/fixtures/xml/conditional_inline_with_elsif_else_clauses.xml +40 -0
- data/test/fixtures/xml/conditional_with_elsif_else_clauses.xml +41 -0
- data/test/processor/document_test.rb +174 -0
- data/test/sablon_test.rb +13 -3
- metadata +16 -3
@@ -0,0 +1,41 @@
|
|
1
|
+
<w:p>
|
2
|
+
<w:fldSimple w:instr=" MERGEFIELD object:if(method_a) \* MERGEFORMAT ">
|
3
|
+
<w:r>
|
4
|
+
<w:rPr><w:noProof/></w:rPr>
|
5
|
+
<w:t>object:if(method_a)»</w:t>
|
6
|
+
</w:r>
|
7
|
+
</w:fldSimple>
|
8
|
+
</w:p>
|
9
|
+
<w:p>
|
10
|
+
<w:t>Method A was true</w:t>
|
11
|
+
</w:p>
|
12
|
+
<w:p>
|
13
|
+
<w:fldSimple w:instr=" MERGEFIELD object:elsif(method_b) \* MERGEFORMAT ">
|
14
|
+
<w:r>
|
15
|
+
<w:rPr><w:noProof/></w:rPr>
|
16
|
+
<w:t>object:elsif(method_b)»</w:t>
|
17
|
+
</w:r>
|
18
|
+
</w:fldSimple>
|
19
|
+
</w:p>
|
20
|
+
<w:p>
|
21
|
+
<w:t>Method B was true</w:t>
|
22
|
+
</w:p>
|
23
|
+
<w:p>
|
24
|
+
<w:fldSimple w:instr=" MERGEFIELD object:else \* MERGEFORMAT ">
|
25
|
+
<w:r>
|
26
|
+
<w:rPr><w:noProof/></w:rPr>
|
27
|
+
<w:t>object:else»</w:t>
|
28
|
+
</w:r>
|
29
|
+
</w:fldSimple>
|
30
|
+
</w:p>
|
31
|
+
<w:p>
|
32
|
+
<w:t>Method A and B were false</w:t>
|
33
|
+
</w:p>
|
34
|
+
<w:p>
|
35
|
+
<w:fldSimple w:instr=" MERGEFIELD object:endIf \* MERGEFORMAT ">
|
36
|
+
<w:r>
|
37
|
+
<w:rPr><w:noProof/></w:rPr>
|
38
|
+
<w:t>object:endIf»</w:t>
|
39
|
+
</w:r>
|
40
|
+
</w:fldSimple>
|
41
|
+
</w:p>
|
@@ -7,11 +7,118 @@ class ProcessorDocumentTest < Sablon::TestCase
|
|
7
7
|
include DocumentXMLHelper
|
8
8
|
include XMLSnippets
|
9
9
|
|
10
|
+
TestHandler = Struct.new(:handles, :statement) do
|
11
|
+
def handles?(*)
|
12
|
+
handles
|
13
|
+
end
|
14
|
+
|
15
|
+
def build_statement(*)
|
16
|
+
statement
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
10
20
|
def setup
|
11
21
|
super
|
12
22
|
@processor = Sablon::Processor::Document
|
23
|
+
@processor.instance_variable_set(:@default_field_handler, nil)
|
24
|
+
end
|
25
|
+
|
26
|
+
def teardown
|
27
|
+
super
|
28
|
+
@processor.instance_variable_set(:@default_field_handler, nil)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_register_field_handler
|
32
|
+
test_handlers = {}
|
33
|
+
handler = TestHandler.new(nil, nil)
|
34
|
+
#
|
35
|
+
@processor.stub(:field_handlers, test_handlers) do
|
36
|
+
@processor.register_field_handler 'test', handler
|
37
|
+
#
|
38
|
+
assert @processor.field_handlers.keys.include?(:test), 'handler was not added to handlers hash'
|
39
|
+
assert_equal handler, @processor.field_handlers[:test]
|
40
|
+
#
|
41
|
+
# try and re-register a handler
|
42
|
+
handler2 = 'test'
|
43
|
+
e = assert_raises(ArgumentError, 'Should not have been able to overwrite a handler using this method') do
|
44
|
+
@processor.register_field_handler 'test', handler2
|
45
|
+
end
|
46
|
+
#
|
47
|
+
assert_equal "Handler named: 'test' already exists. Use `replace_field_handler` instead.", e.message
|
48
|
+
assert_equal handler, @processor.field_handlers[:test], 'pre-existing handler should not have been changed'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_register_default_field_handler
|
53
|
+
handler = TestHandler.new(nil, nil)
|
54
|
+
@processor.register_field_handler :default, handler
|
55
|
+
#
|
56
|
+
assert !@processor.field_handlers.keys.include?(:default), 'default handler should not get added to the handlers hash'
|
57
|
+
assert_equal handler, @processor.default_field_handler
|
58
|
+
#
|
59
|
+
# try and re-register a handler
|
60
|
+
handler2 = 'test'
|
61
|
+
e = assert_raises(ArgumentError, 'Should not have been able to overwrite a handler using this method') do
|
62
|
+
@processor.register_field_handler 'default', handler2
|
63
|
+
end
|
64
|
+
#
|
65
|
+
assert_equal "Handler named: 'default' already exists. Use `replace_field_handler` instead.", e.message
|
66
|
+
assert_equal handler, @processor.default_field_handler, 'pre-existing default handler should not have been changed'
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_remove_field_handler
|
70
|
+
handler = TestHandler.new(nil, nil)
|
71
|
+
test_handlers = { test: handler }
|
72
|
+
#
|
73
|
+
@processor.stub(:field_handlers, test_handlers) do
|
74
|
+
removed = @processor.remove_field_handler 'test'
|
75
|
+
#
|
76
|
+
assert !@processor.field_handlers.keys.include?(:test), 'handler was not removed from handlers hash'
|
77
|
+
assert_equal handler, removed, 'handler should have been returned after removal'
|
78
|
+
#
|
79
|
+
# try and remove a non-existant handler
|
80
|
+
removed = @processor.remove_field_handler '_i_do_not_exist_'
|
81
|
+
assert_nil removed, 'Removing a non-existant handler should just return nil'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_remove_default_field_handler
|
86
|
+
handler = TestHandler.new(nil, nil)
|
87
|
+
@processor.instance_variable_set(:@default_field_handler, handler)
|
88
|
+
#
|
89
|
+
removed = @processor.remove_field_handler :default
|
90
|
+
assert_equal handler, removed, 'default handler should have been returned after removal'
|
91
|
+
#
|
92
|
+
# try and remove the default handler again
|
93
|
+
removed = @processor.remove_field_handler :default
|
94
|
+
assert_nil removed, 'Removing a non-existant default handler should just return nil'
|
95
|
+
end
|
96
|
+
|
97
|
+
|
98
|
+
def test_replace_field_handler
|
99
|
+
handler = TestHandler.new(nil, nil)
|
100
|
+
handler2 = TestHandler.new(false, nil)
|
101
|
+
test_handlers = { test: handler }
|
102
|
+
#
|
103
|
+
@processor.stub(:field_handlers, test_handlers) do
|
104
|
+
assert @processor.field_handlers.keys.include?(:test), 'the test key has to already exist for this test to be meaningful'
|
105
|
+
@processor.replace_field_handler :test, handler2
|
106
|
+
#
|
107
|
+
assert @processor.field_handlers.keys.include?(:test), 'The test key remains in the hash'
|
108
|
+
assert_equal handler2, @processor.field_handlers[:test], 'The handler was not replaced'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def test_replace_default_field_handler
|
113
|
+
handler = TestHandler.new(nil, nil)
|
114
|
+
handler2 = TestHandler.new(false, nil)
|
115
|
+
@processor.instance_variable_set(:@default_field_handler, handler)
|
116
|
+
#
|
117
|
+
@processor.replace_field_handler 'default', handler2
|
118
|
+
assert_equal handler2, @processor.default_field_handler, 'The default handler was not replaced'
|
13
119
|
end
|
14
120
|
|
121
|
+
|
15
122
|
def test_simple_field_replacement
|
16
123
|
result = process(snippet("simple_field"), {"first_name" => "Jack"})
|
17
124
|
|
@@ -450,6 +557,73 @@ class ProcessorDocumentTest < Sablon::TestCase
|
|
450
557
|
assert_equal "", text(result)
|
451
558
|
end
|
452
559
|
|
560
|
+
def test_conditional_with_elsif_else_clauses
|
561
|
+
result = process(snippet("conditional_with_elsif_else_clauses"), {'object' => OpenStruct.new(method_a: true, method_b: true)})
|
562
|
+
assert_xml_equal <<-document, result
|
563
|
+
<w:p>
|
564
|
+
<w:t>Method A was true</w:t>
|
565
|
+
</w:p>
|
566
|
+
document
|
567
|
+
|
568
|
+
result = process(snippet("conditional_with_elsif_else_clauses"), {'object' => OpenStruct.new(method_a: false, method_b: true)})
|
569
|
+
assert_xml_equal <<-document, result
|
570
|
+
<w:p>
|
571
|
+
<w:t>Method B was true</w:t>
|
572
|
+
</w:p>
|
573
|
+
document
|
574
|
+
|
575
|
+
result = process(snippet("conditional_with_elsif_else_clauses"), {'object' => OpenStruct.new(method_a: false, method_b: false)})
|
576
|
+
assert_xml_equal <<-document, result
|
577
|
+
<w:p>
|
578
|
+
<w:t>Method A and B were false</w:t>
|
579
|
+
</w:p>
|
580
|
+
document
|
581
|
+
end
|
582
|
+
|
583
|
+
def test_inline_conditional_with_elsif_else_clauses
|
584
|
+
result = process(snippet("conditional_inline_with_elsif_else_clauses"), {'object' => OpenStruct.new(method_a: true, method_b: true)})
|
585
|
+
assert_xml_equal <<-document, result
|
586
|
+
<w:p>
|
587
|
+
<w:r><w:t>Before</w:t></w:r>
|
588
|
+
<w:r><w:t xml:space="preserve"> </w:t></w:r>
|
589
|
+
<w:r>
|
590
|
+
<w:t>Method A was true</w:t>
|
591
|
+
</w:r>
|
592
|
+
<w:r>
|
593
|
+
<w:t>After</w:t>
|
594
|
+
</w:r>
|
595
|
+
</w:p>
|
596
|
+
document
|
597
|
+
|
598
|
+
result = process(snippet("conditional_inline_with_elsif_else_clauses"), {'object' => OpenStruct.new(method_a: false, method_b: true)})
|
599
|
+
assert_xml_equal <<-document, result
|
600
|
+
<w:p>
|
601
|
+
<w:r><w:t>Before</w:t></w:r>
|
602
|
+
<w:r><w:t xml:space="preserve"> </w:t></w:r>
|
603
|
+
<w:r>
|
604
|
+
<w:t>Method B was true</w:t>
|
605
|
+
</w:r>
|
606
|
+
<w:r>
|
607
|
+
<w:t>After</w:t>
|
608
|
+
</w:r>
|
609
|
+
</w:p>
|
610
|
+
document
|
611
|
+
|
612
|
+
result = process(snippet("conditional_inline_with_elsif_else_clauses"), {'object' => OpenStruct.new(method_a: false, method_b: false)})
|
613
|
+
assert_xml_equal <<-document, result
|
614
|
+
<w:p>
|
615
|
+
<w:r><w:t>Before</w:t></w:r>
|
616
|
+
<w:r><w:t xml:space="preserve"> </w:t></w:r>
|
617
|
+
<w:r>
|
618
|
+
<w:t>Method A and B were false</w:t>
|
619
|
+
</w:r>
|
620
|
+
<w:r>
|
621
|
+
<w:t>After</w:t>
|
622
|
+
</w:r>
|
623
|
+
</w:p>
|
624
|
+
document
|
625
|
+
end
|
626
|
+
|
453
627
|
def test_comment
|
454
628
|
result = process(snippet("comment"), {})
|
455
629
|
assert_equal "Before After", text(result)
|
data/test/sablon_test.rb
CHANGED
@@ -102,10 +102,12 @@ class SablonConditionalsTest < Sablon::TestCase
|
|
102
102
|
inline: true,
|
103
103
|
table: true,
|
104
104
|
table_inline: true,
|
105
|
-
|
105
|
+
object: OpenStruct.new(true_method: true, false_method: false),
|
106
|
+
success_content: '✓',
|
107
|
+
fail_content: '✗',
|
108
|
+
content: 'Some Content'
|
106
109
|
}
|
107
110
|
#
|
108
|
-
context = { paragraph: true, inline: true, table: true, table_inline: true, content: "Some Content" }
|
109
111
|
template.render_to_file @output_path, context
|
110
112
|
assert_docx_equal @sample_path, @output_path
|
111
113
|
end
|
@@ -159,7 +161,7 @@ class SablonImagesTest < Sablon::TestCase
|
|
159
161
|
# only a single file added to media. R2D2 should get duplicated in the
|
160
162
|
# media folder because it is used in two different context keys as
|
161
163
|
# separate instances. Darth Vader should not be duplicated because
|
162
|
-
# the
|
164
|
+
# the key "unused_darth" doesn't appear in the template
|
163
165
|
context = {
|
164
166
|
items: [
|
165
167
|
{ title: 'C-3PO', image: c3po },
|
@@ -174,5 +176,13 @@ class SablonImagesTest < Sablon::TestCase
|
|
174
176
|
|
175
177
|
template.render_to_file @output_path, context
|
176
178
|
assert_docx_equal @sample_path, @output_path
|
179
|
+
|
180
|
+
# try to render a document with an image that has no extension
|
181
|
+
trooper = Sablon.content(:image, im_data, filename: 'clone')
|
182
|
+
context = { items: [], trooper: trooper }
|
183
|
+
e = assert_raises ArgumentError do
|
184
|
+
template.render_to_file @output_path, context
|
185
|
+
end
|
186
|
+
assert_equal "Filename: 'clone' has no discernable extension", e.message
|
177
187
|
end
|
178
188
|
end
|
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.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yves Senn
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-04-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -131,6 +131,9 @@ files:
|
|
131
131
|
- lib/sablon/operations.rb
|
132
132
|
- lib/sablon/parser/mail_merge.rb
|
133
133
|
- lib/sablon/processor/document.rb
|
134
|
+
- lib/sablon/processor/document/blocks.rb
|
135
|
+
- lib/sablon/processor/document/field_handlers.rb
|
136
|
+
- lib/sablon/processor/document/operation_construction.rb
|
134
137
|
- lib/sablon/processor/section_properties.rb
|
135
138
|
- lib/sablon/template.rb
|
136
139
|
- lib/sablon/test.rb
|
@@ -155,11 +158,14 @@ files:
|
|
155
158
|
- test/configuration_test.rb
|
156
159
|
- test/content_test.rb
|
157
160
|
- test/context_test.rb
|
161
|
+
- test/custom_field_handler_test.rb
|
158
162
|
- test/environment_test.rb
|
159
163
|
- test/executable_test.rb
|
160
164
|
- test/expression_test.rb
|
161
165
|
- test/fixtures/conditionals_sample.docx
|
162
166
|
- test/fixtures/conditionals_template.docx
|
167
|
+
- test/fixtures/custom_field_handlers_sample.docx
|
168
|
+
- test/fixtures/custom_field_handlers_template.docx
|
163
169
|
- test/fixtures/cv_sample.docx
|
164
170
|
- test/fixtures/cv_template.docx
|
165
171
|
- test/fixtures/html/html_test_content.html
|
@@ -184,6 +190,8 @@ files:
|
|
184
190
|
- test/fixtures/xml/complex_field_inline_conditional.xml
|
185
191
|
- test/fixtures/xml/conditional.xml
|
186
192
|
- test/fixtures/xml/conditional_inline.xml
|
193
|
+
- test/fixtures/xml/conditional_inline_with_elsif_else_clauses.xml
|
194
|
+
- test/fixtures/xml/conditional_with_elsif_else_clauses.xml
|
187
195
|
- test/fixtures/xml/conditional_with_predicate.xml
|
188
196
|
- test/fixtures/xml/conditional_without_ending.xml
|
189
197
|
- test/fixtures/xml/corrupt_table.xml
|
@@ -235,7 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
235
243
|
version: '0'
|
236
244
|
requirements: []
|
237
245
|
rubyforge_project:
|
238
|
-
rubygems_version: 2.
|
246
|
+
rubygems_version: 2.6.8
|
239
247
|
signing_key:
|
240
248
|
specification_version: 4
|
241
249
|
summary: docx template processor
|
@@ -243,11 +251,14 @@ test_files:
|
|
243
251
|
- test/configuration_test.rb
|
244
252
|
- test/content_test.rb
|
245
253
|
- test/context_test.rb
|
254
|
+
- test/custom_field_handler_test.rb
|
246
255
|
- test/environment_test.rb
|
247
256
|
- test/executable_test.rb
|
248
257
|
- test/expression_test.rb
|
249
258
|
- test/fixtures/conditionals_sample.docx
|
250
259
|
- test/fixtures/conditionals_template.docx
|
260
|
+
- test/fixtures/custom_field_handlers_sample.docx
|
261
|
+
- test/fixtures/custom_field_handlers_template.docx
|
251
262
|
- test/fixtures/cv_sample.docx
|
252
263
|
- test/fixtures/cv_template.docx
|
253
264
|
- test/fixtures/html/html_test_content.html
|
@@ -272,6 +283,8 @@ test_files:
|
|
272
283
|
- test/fixtures/xml/complex_field_inline_conditional.xml
|
273
284
|
- test/fixtures/xml/conditional.xml
|
274
285
|
- test/fixtures/xml/conditional_inline.xml
|
286
|
+
- test/fixtures/xml/conditional_inline_with_elsif_else_clauses.xml
|
287
|
+
- test/fixtures/xml/conditional_with_elsif_else_clauses.xml
|
275
288
|
- test/fixtures/xml/conditional_with_predicate.xml
|
276
289
|
- test/fixtures/xml/conditional_without_ending.xml
|
277
290
|
- test/fixtures/xml/corrupt_table.xml
|