docx-templater 0.0.6
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 +15 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +38 -0
- data/Rakefile +1 -0
- data/lib/docx.rb +6 -0
- data/lib/docx/docx_handler.rb +49 -0
- data/lib/docx/template_handler.rb +161 -0
- data/lib/docx/version.rb +3 -0
- data/lib/example/document.xml +2 -0
- data/lib/example/example.rb +14 -0
- data/lib/example/template.docx +0 -0
- metadata +122 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
YjFlNTJkZDEzOTQyZWViMDJmMzVjNTljMjdkYmM0ODgxZDYxMjlkZQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZTZjYTAwODdmMGM1ZGQzMGFmYTA3M2VjODAxYjQ2YjM2ODcxNTUxMQ==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
M2M0ZWUyMzI4ZWEwNGYzMjFmMThmY2ExNDRlMmIxODRkOGU4NmNkYWU1MDYw
|
10
|
+
OWI1ZGZjNmQ1NjQxZTljODAxYjc1Mzk2M2JlZDVlMDdlOTdmZDQxNzc3MTVl
|
11
|
+
NGNiMjBhOTZmYzcxZTg1YTFlNDQxNjI3OWY4M2ZhY2FjOTdjZWY=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MjU1OWNjOTkzNDMxNWNiYTY4MmQxM2NiMzFkMDBmNTk4ZWY5NDhjZGFjZWRk
|
14
|
+
ODcyYjYxMGQ3M2ZiNGQ4NTFlNGYxYWE0NGYzNTAzOTc3ZjI2Y2M0YWJhYTYz
|
15
|
+
MmMzNTgzNzRkMzQ5ZmEyZjJhODBiZDMwYjQwOTJiOTg1ODM0ZWQ=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 DmitryKa
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# DocxTemplater
|
2
|
+
|
3
|
+
PURE RUBY GEM (works on Windows)! I tried use ready solutions, but some of them hasn't neccessary functions, other one didn't work in Win.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'docx-templater2'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle install
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install docx_templater
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Can work with:
|
22
|
+
- $SOME_VALUE$ : replace template stub (if value for replacing will be provided);
|
23
|
+
- $REPEAT:SOME_COLLECTION$
|
24
|
+
(at least, one new row)
|
25
|
+
$EACH:SOME_VALUE_OF_COLLECTION_ITEM$
|
26
|
+
(at least, one new row)
|
27
|
+
$UNREPEAT:SOME_COLLECTION$;
|
28
|
+
|
29
|
+
Repeating commands must be at the separate paragraphs.
|
30
|
+
Note, that created template may look good but have bad structure for templater, so you should open docx as a zip archive, open "word/document.xml" and edit it
|
31
|
+
|
32
|
+
## Contributing
|
33
|
+
|
34
|
+
1. Fork it
|
35
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
36
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
37
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
38
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/docx.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'zip'
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'docx/template_handler'
|
4
|
+
|
5
|
+
module Docx
|
6
|
+
class DocxHandler
|
7
|
+
include TemplateHandler
|
8
|
+
|
9
|
+
DOC_XML_ARCHIVE_PATH = 'word/document.xml'
|
10
|
+
|
11
|
+
def self.open(path, &block)
|
12
|
+
self.new(path, &block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(path, &block)
|
16
|
+
@replace = {}
|
17
|
+
if block_given?
|
18
|
+
@zip = Zip::File.open(path)
|
19
|
+
yield(self)
|
20
|
+
@zip.close
|
21
|
+
else
|
22
|
+
@zip = Zip::File.open(path)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def insert(arg_hash)
|
27
|
+
raise TypeError unless arg_hash.kind_of? Hash
|
28
|
+
xml = @zip.read(DOC_XML_ARCHIVE_PATH)
|
29
|
+
into_doc = Nokogiri::XML(xml) { |x| x.noent } #TODO what is noent?
|
30
|
+
TemplateHandler::insert arg_hash, into_doc
|
31
|
+
@replace[DOC_XML_ARCHIVE_PATH] = into_doc.serialize save_with: 0
|
32
|
+
end
|
33
|
+
|
34
|
+
def save(path)
|
35
|
+
Zip::File.open(path, Zip::File::CREATE) do |out|
|
36
|
+
@zip.each do |entry|
|
37
|
+
out.get_output_stream(entry.name) do |o|
|
38
|
+
if @replace[entry.name]
|
39
|
+
o.write(@replace[entry.name])
|
40
|
+
else
|
41
|
+
o.write(@zip.read(entry.name))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
@zip.close
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
module Docx
|
2
|
+
module TemplateHandler
|
3
|
+
|
4
|
+
START = 'REPEAT:'
|
5
|
+
FINISH = 'UNREPEAT:'
|
6
|
+
EACH = 'EACH:'
|
7
|
+
PARAGRAPH_XPATH = '//w:p'
|
8
|
+
TEXT_NODE_XPATH = './/w:t'
|
9
|
+
BUX = '$'
|
10
|
+
COLON = ':'
|
11
|
+
|
12
|
+
PR = 'Pr'
|
13
|
+
P = 'p'
|
14
|
+
W = 'w'
|
15
|
+
|
16
|
+
# Now supported only one-depth cycles and cycle begin/end must be in the separate rows
|
17
|
+
def self.insert(hash, doc)
|
18
|
+
paragraphs = doc.xpath(PARAGRAPH_XPATH)
|
19
|
+
paragraphs.each do |paragraph|
|
20
|
+
text_nodes = paragraph.xpath(TEXT_NODE_XPATH)
|
21
|
+
text_nodes.each do |text_node|
|
22
|
+
value = text_node.content
|
23
|
+
next unless value[0] == BUX && value[-1] == BUX
|
24
|
+
key = value[1..-2]
|
25
|
+
if key.include? COLON
|
26
|
+
if key.start_with? START
|
27
|
+
key.sub! START, FINISH
|
28
|
+
fin_value = value.sub START, FINISH
|
29
|
+
paragraph, repeat = bound_repeatable_piece(text_node, fin_value)
|
30
|
+
elems_for_repeating = key.sub FINISH, ''
|
31
|
+
if hash[elems_for_repeating] && (hash[elems_for_repeating].kind_of? Enumerable)
|
32
|
+
hash[elems_for_repeating].each do |repeated_elem|
|
33
|
+
repeat.each do |repeatable_paragraph|
|
34
|
+
dup_par = repeatable_paragraph.dup
|
35
|
+
handle_paragraph dup_par, repeated_elem
|
36
|
+
paragraph.add_next_sibling dup_par
|
37
|
+
paragraph = dup_par
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
repeat.each do |par|
|
42
|
+
par.remove
|
43
|
+
end
|
44
|
+
break
|
45
|
+
else
|
46
|
+
vars = key.split COLON
|
47
|
+
obj = hash[vars[0]]
|
48
|
+
text_node.content = if obj.is_a? Hash
|
49
|
+
obj[vars[1]]
|
50
|
+
else
|
51
|
+
begin
|
52
|
+
obj.send vars[1]
|
53
|
+
rescue NoMethodError => e
|
54
|
+
value
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
else
|
59
|
+
text_node.content = hash[key] || value
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
|
68
|
+
def self.handle_paragraph(paragraph, hash)
|
69
|
+
paragraph.xpath(TEXT_NODE_XPATH).each do |text_node|
|
70
|
+
value = text_node.content
|
71
|
+
next unless value[0] == BUX && value[-1] == BUX
|
72
|
+
key = value[1..-2]
|
73
|
+
if key.include? COLON
|
74
|
+
if key.start_with? EACH
|
75
|
+
key.sub! EACH, ''
|
76
|
+
text_node.content = hash[key] || value
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.bound_repeatable_piece(node, fin_value)
|
83
|
+
# Tag name consists from prefix (usually, 'w') and name (i.e. 'r', 'rPr' and so on)
|
84
|
+
temp_key = paragraph_containing node
|
85
|
+
paragraph = temp_key.next_sibling
|
86
|
+
temp_key.remove
|
87
|
+
#next unless paragraph
|
88
|
+
repeat = []
|
89
|
+
while true
|
90
|
+
result = find_finish paragraph, fin_value
|
91
|
+
#if result.kind_of? Array
|
92
|
+
# new_children = Nokogiri::XML::NodeSet.new paragraph.document
|
93
|
+
# result.each do |node|
|
94
|
+
# new_children.push node
|
95
|
+
# end
|
96
|
+
# paragraph.children = new_children
|
97
|
+
# repeat.push paragraph
|
98
|
+
# break
|
99
|
+
#end
|
100
|
+
unless result
|
101
|
+
# Move 'paragraph' back and remove ending delimiter
|
102
|
+
temp_key = paragraph
|
103
|
+
paragraph = paragraph.previous_sibling
|
104
|
+
temp_key.remove
|
105
|
+
break
|
106
|
+
end
|
107
|
+
#paragraph.xpath('.//w:t')
|
108
|
+
repeat.push result
|
109
|
+
paragraph = paragraph.next_sibling
|
110
|
+
break unless paragraph
|
111
|
+
end
|
112
|
+
return paragraph, repeat
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.find_finish(node, finish_str)
|
116
|
+
|
117
|
+
# Now think that repeating will be bounded by paragraphs
|
118
|
+
|
119
|
+
return node if node.name.end_with? PR
|
120
|
+
children = []
|
121
|
+
node.children.each do |child|
|
122
|
+
## Be careful, result = nil in the case, when we found finish_str
|
123
|
+
#result = find_finish child, finish_str
|
124
|
+
#unless result # '$FINISH:...$' returns nil
|
125
|
+
# return nil if children.empty? # <w:t>$...$</w:t> returns nil here
|
126
|
+
# return nil if children.size == 1 && node.name+PR == children.first.name # <w:p><w:pPr>...</w:pPr><w:t>...</w:t> returns nil here
|
127
|
+
# return children
|
128
|
+
#else
|
129
|
+
# # If node is returned, then... If array, then...
|
130
|
+
# if result.kind_of? Nokogiri::XML::Node
|
131
|
+
# children.push child
|
132
|
+
# elsif result.kind_of? Array
|
133
|
+
# new_children = Nokogiri::XML::NodeSet.new child.document
|
134
|
+
# result.each do |res_node|
|
135
|
+
# new_children.push res_node
|
136
|
+
# end
|
137
|
+
# child.children = new_children
|
138
|
+
# children.push child
|
139
|
+
# return children
|
140
|
+
# end
|
141
|
+
#end
|
142
|
+
end
|
143
|
+
|
144
|
+
# WARNING: It seems, situation exists, when finish_str willn't contain in the children but will be in the node
|
145
|
+
if node.content == finish_str
|
146
|
+
return nil
|
147
|
+
else
|
148
|
+
return node
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
|
153
|
+
def self.paragraph_containing node
|
154
|
+
return nil unless node.namespace.prefix == W
|
155
|
+
return node if node.name == P
|
156
|
+
while (node = node.parent).name != P
|
157
|
+
end
|
158
|
+
node
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
data/lib/docx/version.rb
ADDED
@@ -0,0 +1,2 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
2
|
+
<w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 wp14"><w:body><w:p w:rsidR="003E7B44" w:rsidRDefault="00F622F5"><w:pPr><w:rPr><w:lang w:val="en-US"/></w:rPr></w:pPr><w:r><w:rPr><w:lang w:val="en-US"/></w:rPr><w:t xml:space="preserve">Dear </w:t></w:r><w:r><w:rPr><w:lang w:val="en-US"/></w:rPr><w:t>$NAME$</w:t></w:r><w:r><w:rPr><w:lang w:val="en-US"/></w:rPr><w:t>!</w:t></w:r></w:p><w:p w:rsidR="00F622F5" w:rsidRDefault="00F622F5"><w:pPr><w:rPr><w:lang w:val="en-US"/></w:rPr></w:pPr><w:r><w:rPr><w:lang w:val="en-US"/></w:rPr><w:t>You want to know my progress, so:</w:t></w:r></w:p><w:p w:rsidR="00F622F5" w:rsidRDefault="00F622F5"><w:pPr><w:rPr><w:lang w:val="en-US"/></w:rPr></w:pPr><w:r><w:rPr><w:lang w:val="en-US"/></w:rPr><w:t>$REPEAT:ELEMENTS$</w:t></w:r></w:p><w:p w:rsidR="00F622F5" w:rsidRDefault="00F622F5"><w:pPr><w:rPr><w:lang w:val="en-US"/></w:rPr></w:pPr><w:r><w:rPr><w:lang w:val="en-US"/></w:rPr><w:t>$EACH:INDEX$</w:t></w:r><w:r><w:rPr><w:lang w:val="en-US"/></w:rPr><w:t xml:space="preserve">. </w:t></w:r><w:r><w:rPr><w:lang w:val="en-US"/></w:rPr><w:t>$EACH:NAME$</w:t></w:r><w:r><w:rPr><w:lang w:val="en-US"/></w:rPr><w:t xml:space="preserve"> - </w:t></w:r><w:r><w:rPr><w:lang w:val="en-US"/></w:rPr><w:t>$EACH:NUMBER$</w:t></w:r></w:p><w:p w:rsidR="00F622F5" w:rsidRDefault="00F622F5"><w:pPr><w:rPr><w:lang w:val="en-US"/></w:rPr></w:pPr><w:r><w:rPr><w:lang w:val="en-US"/></w:rPr><w:t>$EACH:COMMENTS$</w:t></w:r></w:p><w:p w:rsidR="00F622F5" w:rsidRPr="00F622F5" w:rsidRDefault="00F622F5" w:rsidP="00F622F5"><w:pPr><w:rPr><w:lang w:val="en-US"/></w:rPr></w:pPr><w:r><w:rPr><w:lang w:val="en-US"/></w:rPr><w:t>$UNREPEAT:ELEMENTS$</w:t></w:r></w:p><w:p w:rsidR="00F622F5" w:rsidRPr="00F622F5" w:rsidRDefault="00F622F5"><w:pPr><w:rPr><w:lang w:val="en-US"/></w:rPr></w:pPr><w:r><w:rPr><w:lang w:val="en-US"/></w:rPr><w:t>Good luck!</w:t></w:r></w:p><w:sectPr w:rsidR="00F622F5" w:rsidRPr="00F622F5"><w:pgSz w:w="11906" w:h="16838"/><w:pgMar w:top="1134" w:right="850" w:bottom="1134" w:left="1701" w:header="708" w:footer="708" w:gutter="0"/><w:cols w:space="708"/><w:docGrid w:linePitch="360"/></w:sectPr></w:body></w:document>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'docx'
|
2
|
+
|
3
|
+
SRC_FILE = 'template.docx'
|
4
|
+
DST_FILE = 'ready.docx'
|
5
|
+
|
6
|
+
# Note, in second element 'COMMENTS' is absent. Original stub in template file will be remainded
|
7
|
+
hash = {'NAME' => 'Ann', 'ELEMENTS' => [
|
8
|
+
{ 'NAME' => 'World history', 'INDEX' => '1','NUMBER' => '3', 'COMMENTS' => "Yeah, I'm so stupid in it"},
|
9
|
+
{'INDEX' => '2', 'NAME' => 'Russian language', 'NUMBER' => '5'}
|
10
|
+
]}
|
11
|
+
|
12
|
+
w = Docx::DocxHandler.open(SRC_FILE)
|
13
|
+
w.insert(hash)
|
14
|
+
w.save(DST_FILE)
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: docx-templater
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- DmitryKa
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-10-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: nokogiri
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ! '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.6.0
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.6.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubyzip
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.0.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.0.0
|
69
|
+
description: ! 'PURE RUBY GEM (works on Windows)! Can work with:
|
70
|
+
|
71
|
+
- $SOME_VALUE$;
|
72
|
+
|
73
|
+
- $REPEAT:SOME_COLLECTION$ (at least, new row) $EACH:SOME_VALUE_OF_COLLECTION_ITEM$
|
74
|
+
(at least, new row) $UNREPEAT:SOME_COLLECTION$;
|
75
|
+
|
76
|
+
Repeating commands must be at the separate paragraphs.
|
77
|
+
|
78
|
+
Note, that created template may look good but have bad structure for templater,
|
79
|
+
so you should open docx as a zip archive, open "word/document.xml" and edit it'
|
80
|
+
email:
|
81
|
+
- mail.of.dima.ka@gmail.com
|
82
|
+
executables: []
|
83
|
+
extensions: []
|
84
|
+
extra_rdoc_files: []
|
85
|
+
files:
|
86
|
+
- .gitignore
|
87
|
+
- Gemfile
|
88
|
+
- LICENSE.txt
|
89
|
+
- README.md
|
90
|
+
- Rakefile
|
91
|
+
- lib/docx.rb
|
92
|
+
- lib/docx/docx_handler.rb
|
93
|
+
- lib/docx/template_handler.rb
|
94
|
+
- lib/docx/version.rb
|
95
|
+
- lib/example/document.xml
|
96
|
+
- lib/example/example.rb
|
97
|
+
- lib/example/template.docx
|
98
|
+
homepage: ''
|
99
|
+
licenses:
|
100
|
+
- MIT
|
101
|
+
metadata: {}
|
102
|
+
post_install_message:
|
103
|
+
rdoc_options: []
|
104
|
+
require_paths:
|
105
|
+
- lib
|
106
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ! '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
requirements: []
|
117
|
+
rubyforge_project:
|
118
|
+
rubygems_version: 2.0.7
|
119
|
+
signing_key:
|
120
|
+
specification_version: 4
|
121
|
+
summary: Simple docx templater
|
122
|
+
test_files: []
|