sablon 0.0.15 → 0.0.16
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 +2 -2
- data/lib/sablon/parser/mail_merge.rb +21 -0
- data/lib/sablon/processor.rb +33 -4
- data/lib/sablon/version.rb +1 -1
- data/test/fixtures/conditionals_sample.docx +0 -0
- data/test/fixtures/conditionals_template.docx +0 -0
- data/test/fixtures/xml/complex_field_inline_conditional.xml +71 -0
- data/test/fixtures/xml/conditional_inline.xml +25 -0
- data/test/processor_test.rb +13 -0
- data/test/sablon_test.rb +20 -0
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e21664d93631483d0c03a94ef0e459c386487e0d
|
4
|
+
data.tar.gz: ea8c86cb3c1b325c88ea696d622fed0286f1c068
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f64f332f7cd6c2831cae719fce8eb4bced5ce6c71e427e7a0fb316d21a361aedc95bb8fca9ca7920da0147ad17f4d0f5cfa8b29b8651a16d4b4ee0004b82eeb
|
7
|
+
data.tar.gz: 52c537c73248d4c9bb578864786e42849389ed90785645d72ebb848f205b950bdf1159fec73f58583f1578715c86680bb0a6e2e04e1a848038b9bff3158b647a
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
sablon (0.0.
|
4
|
+
sablon (0.0.16)
|
5
5
|
nokogiri (>= 1.6.0)
|
6
6
|
redcarpet (>= 3.2)
|
7
7
|
rubyzip (>= 1.1)
|
@@ -10,7 +10,7 @@ GEM
|
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
12
|
mini_portile (0.6.2)
|
13
|
-
minitest (5.
|
13
|
+
minitest (5.8.0)
|
14
14
|
nokogiri (1.6.6.2)
|
15
15
|
mini_portile (~> 0.6.0)
|
16
16
|
rake (10.4.2)
|
@@ -36,10 +36,22 @@ module Sablon
|
|
36
36
|
(@nodes - [pattern_node]).each(&:remove)
|
37
37
|
end
|
38
38
|
|
39
|
+
def remove
|
40
|
+
@nodes.each(&:remove)
|
41
|
+
end
|
42
|
+
|
39
43
|
def ancestors(*args)
|
40
44
|
@nodes.first.ancestors(*args)
|
41
45
|
end
|
42
46
|
|
47
|
+
def start_node
|
48
|
+
@nodes.first
|
49
|
+
end
|
50
|
+
|
51
|
+
def end_node
|
52
|
+
@nodes.last
|
53
|
+
end
|
54
|
+
|
43
55
|
private
|
44
56
|
def pattern_node
|
45
57
|
separate_node.next_element
|
@@ -61,9 +73,18 @@ module Sablon
|
|
61
73
|
@node.replace(@node.children)
|
62
74
|
end
|
63
75
|
|
76
|
+
def remove
|
77
|
+
@node.remove
|
78
|
+
end
|
79
|
+
|
64
80
|
def ancestors(*args)
|
65
81
|
@node.ancestors(*args)
|
66
82
|
end
|
83
|
+
|
84
|
+
def start_node
|
85
|
+
@node
|
86
|
+
end
|
87
|
+
alias_method :end_node, :start_node
|
67
88
|
end
|
68
89
|
|
69
90
|
def parse_fields(xml)
|
data/lib/sablon/processor.rb
CHANGED
@@ -50,7 +50,7 @@ module Sablon
|
|
50
50
|
|
51
51
|
class Block < Struct.new(:start_field, :end_field)
|
52
52
|
def self.enclosed_by(start_field, end_field)
|
53
|
-
@blocks ||= [RowBlock, ParagraphBlock]
|
53
|
+
@blocks ||= [RowBlock, ParagraphBlock, InlineParagraphBlock]
|
54
54
|
block_class = @blocks.detect { |klass| klass.encloses?(start_field, end_field) }
|
55
55
|
block_class.new start_field, end_field
|
56
56
|
end
|
@@ -64,7 +64,10 @@ module Sablon
|
|
64
64
|
|
65
65
|
def replace(content)
|
66
66
|
content.each { |n| start_node.add_next_sibling n }
|
67
|
+
remove_control_elements
|
68
|
+
end
|
67
69
|
|
70
|
+
def remove_control_elements
|
68
71
|
body.each &:remove
|
69
72
|
start_node.remove
|
70
73
|
end_node.remove
|
@@ -99,9 +102,7 @@ module Sablon
|
|
99
102
|
end
|
100
103
|
|
101
104
|
def self.encloses?(start_field, end_field)
|
102
|
-
|
103
|
-
parent(start_field) != parent(end_field)
|
104
|
-
end
|
105
|
+
super && parent(start_field) != parent(end_field)
|
105
106
|
end
|
106
107
|
end
|
107
108
|
|
@@ -109,6 +110,34 @@ module Sablon
|
|
109
110
|
def self.parent(node)
|
110
111
|
node.ancestors ".//w:p"
|
111
112
|
end
|
113
|
+
|
114
|
+
def self.encloses?(start_field, end_field)
|
115
|
+
super && parent(start_field) != parent(end_field)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class InlineParagraphBlock < Block
|
120
|
+
def self.parent(node)
|
121
|
+
node.ancestors ".//w:p"
|
122
|
+
end
|
123
|
+
|
124
|
+
def remove_control_elements
|
125
|
+
body.each &:remove
|
126
|
+
start_field.remove
|
127
|
+
end_field.remove
|
128
|
+
end
|
129
|
+
|
130
|
+
def start_node
|
131
|
+
@start_node ||= start_field.end_node
|
132
|
+
end
|
133
|
+
|
134
|
+
def end_node
|
135
|
+
@end_node ||= end_field.start_node
|
136
|
+
end
|
137
|
+
|
138
|
+
def self.encloses?(start_field, end_field)
|
139
|
+
super && parent(start_field) == parent(end_field)
|
140
|
+
end
|
112
141
|
end
|
113
142
|
|
114
143
|
class OperationConstruction
|
data/lib/sablon/version.rb
CHANGED
Binary file
|
Binary file
|
@@ -0,0 +1,71 @@
|
|
1
|
+
<w:p w14:paraId="2CDA5882" w14:textId="37B2B395" w:rsidR="00F16EA4" w:rsidRDefault="00F16EA4">
|
2
|
+
<w:r>
|
3
|
+
<w:t>ParagraphBefore</w:t>
|
4
|
+
</w:r>
|
5
|
+
</w:p>
|
6
|
+
<w:p w14:paraId="7FA396E2" w14:textId="74DBBC79" w:rsidR="00045676" w:rsidRDefault="00F16EA4">
|
7
|
+
<w:r>
|
8
|
+
<w:t>Before</w:t>
|
9
|
+
</w:r>
|
10
|
+
<w:r w:rsidR="00357C82">
|
11
|
+
<w:fldChar w:fldCharType="begin" />
|
12
|
+
</w:r>
|
13
|
+
<w:r w:rsidR="00357C82">
|
14
|
+
<w:instrText xml:space="preserve"> </w:instrText>
|
15
|
+
</w:r>
|
16
|
+
<w:r w:rsidR="00357C82">
|
17
|
+
<w:instrText>MERGEFIELD boolean:if</w:instrText>
|
18
|
+
</w:r>
|
19
|
+
<w:r w:rsidR="00357C82">
|
20
|
+
<w:instrText xml:space="preserve"> \* MERGEFORMAT </w:instrText>
|
21
|
+
</w:r>
|
22
|
+
<w:r w:rsidR="00357C82">
|
23
|
+
<w:fldChar w:fldCharType="separate" />
|
24
|
+
</w:r>
|
25
|
+
<w:r w:rsidR="00936258">
|
26
|
+
<w:rPr>
|
27
|
+
<w:noProof />
|
28
|
+
</w:rPr>
|
29
|
+
<w:t>«boolean:if»</w:t>
|
30
|
+
</w:r>
|
31
|
+
<w:r w:rsidR="00357C82">
|
32
|
+
<w:fldChar w:fldCharType="end" />
|
33
|
+
</w:r>
|
34
|
+
<w:r>
|
35
|
+
<w:t>Content</w:t>
|
36
|
+
</w:r>
|
37
|
+
<w:r w:rsidR="00357C82">
|
38
|
+
<w:fldChar w:fldCharType="begin" />
|
39
|
+
</w:r>
|
40
|
+
<w:r w:rsidR="00357C82">
|
41
|
+
<w:instrText xml:space="preserve"> MERGEFIELD </w:instrText>
|
42
|
+
</w:r>
|
43
|
+
<w:r w:rsidR="00357C82">
|
44
|
+
<w:instrText>boolean:endIf</w:instrText>
|
45
|
+
</w:r>
|
46
|
+
<w:r w:rsidR="00357C82">
|
47
|
+
<w:instrText xml:space="preserve"> \* MERGEFORMAT </w:instrText>
|
48
|
+
</w:r>
|
49
|
+
<w:r w:rsidR="00357C82">
|
50
|
+
<w:fldChar w:fldCharType="separate" />
|
51
|
+
</w:r>
|
52
|
+
<w:r w:rsidR="00427F41">
|
53
|
+
<w:rPr>
|
54
|
+
<w:noProof />
|
55
|
+
</w:rPr>
|
56
|
+
<w:t>«boolean:endIf»</w:t>
|
57
|
+
</w:r>
|
58
|
+
<w:r w:rsidR="00357C82">
|
59
|
+
<w:fldChar w:fldCharType="end" />
|
60
|
+
</w:r>
|
61
|
+
<w:r>
|
62
|
+
<w:t>After</w:t>
|
63
|
+
</w:r>
|
64
|
+
</w:p>
|
65
|
+
<w:p w14:paraId="5DA03BEF" w14:textId="672833BC" w:rsidR="00F16EA4" w:rsidRDefault="00F16EA4">
|
66
|
+
<w:r>
|
67
|
+
<w:t>ParagraphAfter</w:t>
|
68
|
+
</w:r>
|
69
|
+
<w:bookmarkStart w:id="0" w:name="_GoBack" />
|
70
|
+
<w:bookmarkEnd w:id="0" />
|
71
|
+
</w:p>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<w:p>
|
2
|
+
<w:r><w:t>Anthony</w:t></w:r>
|
3
|
+
<w:r><w:t xml:space="preserve"> </w:t></w:r>
|
4
|
+
<w:fldSimple w:instr=" MERGEFIELD middle_name:if \* MERGEFORMAT ">
|
5
|
+
<w:r>
|
6
|
+
<w:rPr><w:noProof/></w:rPr>
|
7
|
+
<w:t>«middle_name:if»</w:t>
|
8
|
+
</w:r>
|
9
|
+
</w:fldSimple>
|
10
|
+
<w:r>
|
11
|
+
<w:t>Michael</w:t>
|
12
|
+
</w:r>
|
13
|
+
<w:r>
|
14
|
+
<w:t xml:space="preserve"> </w:t>
|
15
|
+
</w:r>
|
16
|
+
<w:fldSimple w:instr=" MERGEFIELD middle_name:endIf \* MERGEFORMAT ">
|
17
|
+
<w:r>
|
18
|
+
<w:rPr><w:noProof/></w:rPr>
|
19
|
+
<w:t>«middle_name:endIf»</w:t>
|
20
|
+
</w:r>
|
21
|
+
</w:fldSimple>
|
22
|
+
<w:r>
|
23
|
+
<w:t>Hall</w:t>
|
24
|
+
</w:r>
|
25
|
+
</w:p>
|
data/test/processor_test.rb
CHANGED
@@ -341,6 +341,19 @@ class ProcessorTest < Sablon::TestCase
|
|
341
341
|
assert_equal "Anthony Hall", text(result)
|
342
342
|
end
|
343
343
|
|
344
|
+
def test_simple_field_conditional_inline
|
345
|
+
result = process(snippet("conditional_inline"), {"middle_name" => true})
|
346
|
+
assert_equal "Anthony Michael Hall", text(result)
|
347
|
+
end
|
348
|
+
|
349
|
+
def test_complex_field_conditional_inline
|
350
|
+
with_false = process(snippet("complex_field_inline_conditional"), {"boolean" => false})
|
351
|
+
assert_equal "ParagraphBefore Before After ParagraphAfter", text(with_false)
|
352
|
+
|
353
|
+
with_true = process(snippet("complex_field_inline_conditional"), {"boolean" => true})
|
354
|
+
assert_equal "ParagraphBefore Before Content After ParagraphAfter", text(with_true)
|
355
|
+
end
|
356
|
+
|
344
357
|
def test_conditional_with_predicate
|
345
358
|
result = process(snippet("conditional_with_predicate"), {"body" => ""})
|
346
359
|
assert_equal "some content", text(result)
|
data/test/sablon_test.rb
CHANGED
@@ -84,3 +84,23 @@ class SablonTest < Sablon::TestCase
|
|
84
84
|
assert_docx_equal @sample_path, @output_path
|
85
85
|
end
|
86
86
|
end
|
87
|
+
|
88
|
+
class SablonTest < Sablon::TestCase
|
89
|
+
include Sablon::Test::Assertions
|
90
|
+
include XMLSnippets
|
91
|
+
|
92
|
+
def setup
|
93
|
+
super
|
94
|
+
@base_path = Pathname.new(File.expand_path("../", __FILE__))
|
95
|
+
@template_path = @base_path + "fixtures/conditionals_template.docx"
|
96
|
+
@output_path = @base_path + "sandbox/conditionals.docx"
|
97
|
+
@sample_path = @base_path + "fixtures/conditionals_sample.docx"
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_generate_document_from_template
|
101
|
+
template = Sablon.template @template_path
|
102
|
+
context = {paragraph: true, inline: true, table: true, table_inline: true, content: "Some Content"}
|
103
|
+
template.render_to_file @output_path, context
|
104
|
+
assert_docx_equal @sample_path, @output_path
|
105
|
+
end
|
106
|
+
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.0.
|
4
|
+
version: 0.0.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yves Senn
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-08-
|
11
|
+
date: 2015-08-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -147,13 +147,17 @@ files:
|
|
147
147
|
- test/context_test.rb
|
148
148
|
- test/executable_test.rb
|
149
149
|
- test/expression_test.rb
|
150
|
+
- test/fixtures/conditionals_sample.docx
|
151
|
+
- test/fixtures/conditionals_template.docx
|
150
152
|
- test/fixtures/cv_sample.docx
|
151
153
|
- test/fixtures/cv_template.docx
|
152
154
|
- test/fixtures/recipe_context.json
|
153
155
|
- test/fixtures/recipe_sample.docx
|
154
156
|
- test/fixtures/recipe_template.docx
|
155
157
|
- test/fixtures/xml/complex_field.xml
|
158
|
+
- test/fixtures/xml/complex_field_inline_conditional.xml
|
156
159
|
- test/fixtures/xml/conditional.xml
|
160
|
+
- test/fixtures/xml/conditional_inline.xml
|
157
161
|
- test/fixtures/xml/conditional_with_predicate.xml
|
158
162
|
- test/fixtures/xml/conditional_without_ending.xml
|
159
163
|
- test/fixtures/xml/corrupt_table.xml
|
@@ -203,13 +207,17 @@ test_files:
|
|
203
207
|
- test/context_test.rb
|
204
208
|
- test/executable_test.rb
|
205
209
|
- test/expression_test.rb
|
210
|
+
- test/fixtures/conditionals_sample.docx
|
211
|
+
- test/fixtures/conditionals_template.docx
|
206
212
|
- test/fixtures/cv_sample.docx
|
207
213
|
- test/fixtures/cv_template.docx
|
208
214
|
- test/fixtures/recipe_context.json
|
209
215
|
- test/fixtures/recipe_sample.docx
|
210
216
|
- test/fixtures/recipe_template.docx
|
211
217
|
- test/fixtures/xml/complex_field.xml
|
218
|
+
- test/fixtures/xml/complex_field_inline_conditional.xml
|
212
219
|
- test/fixtures/xml/conditional.xml
|
220
|
+
- test/fixtures/xml/conditional_inline.xml
|
213
221
|
- test/fixtures/xml/conditional_with_predicate.xml
|
214
222
|
- test/fixtures/xml/conditional_without_ending.xml
|
215
223
|
- test/fixtures/xml/corrupt_table.xml
|