docxtor 0.1.1 → 0.2.1
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.
- data/.ruby-version +1 -1
- data/Gemfile +1 -0
- data/README.md +88 -44
- data/lib/docxtor.rb +3 -0
- data/lib/docxtor/document/builder.rb +18 -3
- data/lib/docxtor/document/element.rb +9 -2
- data/lib/docxtor/generator.rb +7 -2
- data/lib/docxtor/package/builder.rb +2 -11
- data/lib/docxtor/reference_builder.rb +29 -0
- data/lib/docxtor/running_element.rb +69 -0
- data/lib/docxtor/running_elements_builder.rb +18 -0
- data/lib/docxtor/template_parser.rb +3 -10
- data/lib/docxtor/version.rb +1 -1
- data/spec/docxtor/document/builder_spec.rb +2 -4
- data/spec/docxtor/document/paragraph_spec.rb +8 -8
- data/spec/docxtor/document/root_spec.rb +21 -5
- data/spec/docxtor/document/table_of_contents_spec.rb +1 -5
- data/spec/docxtor/docxtor_spec.rb +6 -6
- data/spec/docxtor/package/builder_spec.rb +51 -11
- data/spec/docxtor/reference_builder_spec.rb +27 -0
- data/spec/docxtor/running_element_spec.rb +38 -0
- data/spec/docxtor/running_elements_builder_spec.rb +25 -0
- data/spec/docxtor/support/contexts/xml_builder_context.rb +0 -2
- data/spec/docxtor/template_parser_spec.rb +3 -3
- data/templates/default/[Content_Types].xml +1 -5
- data/templates/default/_rels/.rels +1 -4
- data/templates/default/docProps/app.xml +1 -0
- data/templates/default/docProps/core.xml +1 -0
- metadata +150 -154
- data/spec/docxtor/support/examples/.gitkeep +0 -0
- data/spec/docxtor/support/matchers/wordprocessingml_matchers.rb +0 -42
- data/spec/docxtor/support/matchers/xpath_matchers.rb +0 -46
- data/templates/default/word/_rels/document.xml.rels +0 -13
- data/templates/default/word/endnotes.xml +0 -17
- data/templates/default/word/fontTable.xml +0 -31
- data/templates/default/word/footer1.xml +0 -35
- data/templates/default/word/footer2.xml +0 -48
- data/templates/default/word/footnotes.xml +0 -17
- data/templates/default/word/numbering.xml +0 -212
- data/templates/default/word/settings.xml +0 -107
- data/templates/default/word/styles.xml +0 -368
- data/templates/default/word/theme/theme1.xml +0 -2
- data/templates/default/word/websettings.xml +0 -4
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
1.9.3-p448
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -9,12 +9,14 @@ docxtor
|
|
9
9
|
## Summary
|
10
10
|
|
11
11
|
Ruby docx generator.
|
12
|
-
|
12
|
+
**Docxtor** is built to work with Ruby 1.8 as well as 1.9
|
13
13
|
|
14
14
|
## Features
|
15
15
|
|
16
|
-
|
17
|
-
|
16
|
+
- Paragraphs and headings markup.
|
17
|
+
- Bold, underline & italic font styles.
|
18
|
+
- Document table of contents.
|
19
|
+
- Document headers & footers, page numbers.
|
18
20
|
|
19
21
|
More to come, stay tuned!
|
20
22
|
|
@@ -34,7 +36,9 @@ Or install it yourself as:
|
|
34
36
|
|
35
37
|
## Usage
|
36
38
|
|
37
|
-
|
39
|
+
Here's the taste of what **Docxtor's** "markup language" may look like.
|
40
|
+
|
41
|
+
```ruby
|
38
42
|
package = Docxtor.generate do
|
39
43
|
table_of_contents "Contents"
|
40
44
|
h 1, "heading1"
|
@@ -63,51 +67,91 @@ end
|
|
63
67
|
package.save('test.docx')
|
64
68
|
```
|
65
69
|
|
66
|
-
|
70
|
+
### Entry point
|
67
71
|
|
72
|
+
```ruby
|
73
|
+
Docxtor.generate do
|
74
|
+
...
|
75
|
+
end
|
68
76
|
```
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
:filename => 'yourfilename.docx',
|
106
|
-
:type =>'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
|
107
|
-
)
|
77
|
+
|
78
|
+
### Paragraphs
|
79
|
+
|
80
|
+
The main building block of `docx` document is a paragraph. There're couple of ways of defining a paragraph.
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
p "Hi there!", :bold => true
|
84
|
+
```
|
85
|
+
|
86
|
+
Is the same as
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
p do
|
90
|
+
w "Hi there!"
|
91
|
+
b
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
95
|
+
or
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
p do
|
99
|
+
write "Hi there!"
|
100
|
+
bold
|
101
|
+
end
|
102
|
+
```
|
103
|
+
|
104
|
+
Everything styling-related that is written either inside the block or in options hash will be applied to the whole parapraph.
|
105
|
+
|
106
|
+
You can mix and match different ways to define text & options.
|
107
|
+
|
108
|
+
```ruby
|
109
|
+
p "I'm a first string in this paragraph", :bold => true do
|
110
|
+
write "I'm a second one."
|
111
|
+
u
|
112
|
+
w "And we all will be bold and underlined in the same time!"
|
108
113
|
end
|
109
114
|
```
|
110
115
|
|
116
|
+
### Headings
|
117
|
+
|
118
|
+
**Currently not working as expected! Will be fixed soon!**
|
119
|
+
|
120
|
+
Generally the same as paragraphs, but have additional argument - the level of heading and styled by default.
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
h 1, "Chapter 1"
|
124
|
+
h 2, "Where our hero goes for an adventure"
|
125
|
+
```
|
126
|
+
|
127
|
+
### Table of Contents
|
128
|
+
|
129
|
+
**Currently not working as expected! Will be fixed soon!**
|
130
|
+
|
131
|
+
Inserts the ToC for a document with a caption.
|
132
|
+
|
133
|
+
```ruby
|
134
|
+
table_of_contents "Table of Contents"
|
135
|
+
```
|
136
|
+
|
137
|
+
### Footers & Headers
|
138
|
+
|
139
|
+
You can specify following properties for footers and headers:
|
140
|
+
|
141
|
+
- on which pages footer or header will appear (`:odd`, `:even` or only `:first`);
|
142
|
+
- alignment (`:center`, `:left`, `:right`)
|
143
|
+
- contents of a footer/header, including special keyword `:pagenum` which inserts page numbers
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
footer :pagenum, :align => :center
|
147
|
+
header "Proudly made by me", :pages => :odd
|
148
|
+
footer "2013", :pages => :first, :align => :right
|
149
|
+
```
|
150
|
+
|
151
|
+
### Breaks
|
152
|
+
|
153
|
+
You can insert `page_break` or newline inside a paragraph with `br`.
|
154
|
+
|
111
155
|
## Contributing
|
112
156
|
|
113
157
|
1. Fork it
|
data/lib/docxtor.rb
CHANGED
@@ -6,6 +6,9 @@ require "docxtor/version"
|
|
6
6
|
module Docxtor
|
7
7
|
autoload :Generator, 'docxtor/generator'
|
8
8
|
autoload :TemplateParser, 'docxtor/template_parser'
|
9
|
+
autoload :RunningElementsBuilder, 'docxtor/running_elements_builder'
|
10
|
+
autoload :RunningElement, 'docxtor/running_element'
|
11
|
+
autoload :ReferenceBuilder, 'docxtor/reference_builder'
|
9
12
|
|
10
13
|
module Document
|
11
14
|
autoload :Builder, 'docxtor/document/builder'
|
@@ -1,12 +1,17 @@
|
|
1
1
|
module Docxtor
|
2
2
|
module Document
|
3
3
|
class Builder
|
4
|
-
attr_accessor :content
|
4
|
+
attr_accessor :content, :running_elements
|
5
5
|
|
6
|
-
def initialize(&block)
|
6
|
+
def initialize(running_elements, &block)
|
7
|
+
@running_elements = running_elements
|
7
8
|
@content = render(&block)
|
8
9
|
end
|
9
10
|
|
11
|
+
def filename
|
12
|
+
"word/document.xml"
|
13
|
+
end
|
14
|
+
|
10
15
|
def render(&block)
|
11
16
|
xml = ::Builder::XmlMarkup.new
|
12
17
|
|
@@ -21,12 +26,22 @@ module Docxtor
|
|
21
26
|
"xmlns:w" => "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
22
27
|
"xmlns:wne" => "http://schemas.microsoft.com/office/word/2006/wordml" do
|
23
28
|
xml.w :body do
|
24
|
-
xml << Document::Root.new(&block).render(
|
29
|
+
xml << Document::Root.new(&block).render(::Builder::XmlMarkup.new)
|
30
|
+
|
31
|
+
render_running_elements xml
|
25
32
|
end
|
26
33
|
end
|
27
34
|
|
28
35
|
xml.target!
|
29
36
|
end
|
37
|
+
|
38
|
+
def render_running_elements xml
|
39
|
+
xml.w :sectPr do |xml|
|
40
|
+
running_elements.each do |re|
|
41
|
+
xml.w re.reference_name.to_sym, "r:id" => re.reference_id, "w:type" => "#{re.pages}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
30
45
|
end
|
31
46
|
end
|
32
47
|
end
|
@@ -11,6 +11,10 @@ module Docxtor
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
def method_missing name, *args
|
15
|
+
super unless [:header, :footer].include? name
|
16
|
+
end
|
17
|
+
|
14
18
|
def initialize(*args, &block)
|
15
19
|
@elements = []
|
16
20
|
|
@@ -82,8 +86,11 @@ module Docxtor
|
|
82
86
|
def get_properties_for(el)
|
83
87
|
props = properties[el]
|
84
88
|
if props
|
85
|
-
pairs = @params.
|
86
|
-
|
89
|
+
pairs = @params.map do |k, v|
|
90
|
+
unless props[k].nil?
|
91
|
+
props[k].is_a?(Hash) ? [props[k][:name], v] : [props[k], v]
|
92
|
+
end
|
93
|
+
end
|
87
94
|
Hash[pairs]
|
88
95
|
end
|
89
96
|
end
|
data/lib/docxtor/generator.rb
CHANGED
@@ -5,8 +5,13 @@ module Docxtor
|
|
5
5
|
template_parser = TemplateParser.new(template)
|
6
6
|
parts = template_parser.parts
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
running_elements = RunningElementsBuilder.new(&block).elements
|
9
|
+
parts += running_elements
|
10
|
+
|
11
|
+
parts << ReferenceBuilder.new(running_elements)
|
12
|
+
parts << Document::Builder.new(running_elements, &block)
|
13
|
+
|
14
|
+
Package::Builder.new(parts)
|
10
15
|
end
|
11
16
|
end
|
12
17
|
end
|
@@ -3,9 +3,8 @@ module Docxtor
|
|
3
3
|
class Builder
|
4
4
|
attr_reader :parts
|
5
5
|
|
6
|
-
def initialize(parts
|
6
|
+
def initialize(parts)
|
7
7
|
@parts = parts
|
8
|
-
@parts['document'] = Part.new("word/document.xml", document.content)
|
9
8
|
end
|
10
9
|
|
11
10
|
def save(filepath)
|
@@ -14,18 +13,10 @@ module Docxtor
|
|
14
13
|
end
|
15
14
|
end
|
16
15
|
|
17
|
-
def to_stream
|
18
|
-
ostream = Zip::ZipOutputStream.new("streamed", true)
|
19
|
-
write_parts(ostream)
|
20
|
-
string_io = ostream.close_buffer
|
21
|
-
string_io.rewind
|
22
|
-
string_io
|
23
|
-
end
|
24
|
-
|
25
16
|
private
|
26
17
|
|
27
18
|
def write_parts(ostream)
|
28
|
-
@parts.each do |
|
19
|
+
@parts.each do |part|
|
29
20
|
ostream.put_next_entry(part.filename)
|
30
21
|
ostream.puts part.content
|
31
22
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Docxtor
|
2
|
+
class ReferenceBuilder
|
3
|
+
attr_accessor :elements
|
4
|
+
|
5
|
+
def initialize elements
|
6
|
+
@elements = elements
|
7
|
+
@elements.each_with_index { |el, i| el.reference_id = "rId#{i+1}" }
|
8
|
+
end
|
9
|
+
|
10
|
+
def filename
|
11
|
+
"word/_rels/document.xml.rels"
|
12
|
+
end
|
13
|
+
|
14
|
+
def content
|
15
|
+
xml = ::Builder::XmlMarkup.new
|
16
|
+
|
17
|
+
xml.instruct! :xml, :version => "1.0", :encoding=>"UTF-8", :standalone => "yes"
|
18
|
+
xml.Relationships "xmlns" => "http://schemas.openxmlformats.org/package/2006/relationships" do |xml|
|
19
|
+
elements.each do |element|
|
20
|
+
xml.Relationship "Id" => element.reference_id,
|
21
|
+
"Target" => element.name,
|
22
|
+
"Type" => element.reference_type
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
xml.target!
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Docxtor
|
2
|
+
class RunningElement
|
3
|
+
attr_accessor :pages, :type, :reference_id
|
4
|
+
|
5
|
+
def initialize type, num, contents, options = {}
|
6
|
+
@type = type
|
7
|
+
@contents = contents
|
8
|
+
@align = options[:align]
|
9
|
+
@pages = options[:pages] || :default
|
10
|
+
@num = num
|
11
|
+
end
|
12
|
+
|
13
|
+
def reference_name
|
14
|
+
"#{type}Reference"
|
15
|
+
end
|
16
|
+
|
17
|
+
def name
|
18
|
+
"#{type}#{@num}.xml"
|
19
|
+
end
|
20
|
+
|
21
|
+
def filename
|
22
|
+
"word/#{name}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def reference_type
|
26
|
+
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/#{type}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def content
|
30
|
+
xml = ::Builder::XmlMarkup.new
|
31
|
+
|
32
|
+
xml.instruct! :xml, :version => "1.0", :encoding=>"UTF-8", :standalone => "yes"
|
33
|
+
xml.w :ftr, "xmlns:o" => "urn:schemas-microsoft-com:office:office",
|
34
|
+
"xmlns:r" => "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
|
35
|
+
"xmlns:v" => "urn:schemas-microsoft-com:vml",
|
36
|
+
"xmlns:w" => "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
|
37
|
+
"xmlns:w10" => "urn:schemas-microsoft-com:office:word",
|
38
|
+
"xmlns:wp" => "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" do |xml|
|
39
|
+
|
40
|
+
xml.w :p do |xml|
|
41
|
+
xml.w :pPr do |xml|
|
42
|
+
xml.w :jc, "w:val" => "#{@align}" if @align
|
43
|
+
end
|
44
|
+
if @contents == :pagenum
|
45
|
+
xml.w :r do |xml|
|
46
|
+
xml.w :fldChar, "w:fldCharType" => "begin"
|
47
|
+
end
|
48
|
+
xml.w :r do |xml|
|
49
|
+
xml.w :instrText, "PAGE"
|
50
|
+
end
|
51
|
+
xml.w :r do |xml|
|
52
|
+
xml.w :fldChar, "w:fldCharType" => "separate"
|
53
|
+
end
|
54
|
+
xml.w :r do |xml|
|
55
|
+
xml.w :t, "i"
|
56
|
+
end
|
57
|
+
xml.w :r do |xml|
|
58
|
+
xml.w :fldChar, "w:fldCharType" => "end"
|
59
|
+
end
|
60
|
+
else
|
61
|
+
xml.w :r do |xml|
|
62
|
+
xml.w :t, @contents
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Docxtor
|
2
|
+
class RunningElementsBuilder
|
3
|
+
attr_accessor :elements
|
4
|
+
|
5
|
+
def method_missing method_name, *args
|
6
|
+
num = 0
|
7
|
+
if [:header, :footer].include? method_name
|
8
|
+
num += 1
|
9
|
+
@elements << RunningElement.new(method_name, num, *args)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize &block
|
14
|
+
@elements = []
|
15
|
+
instance_eval &block
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -4,19 +4,13 @@ module Docxtor
|
|
4
4
|
|
5
5
|
FILES_PATTERN = File.join('**', '{*,.}{xml,rels}')
|
6
6
|
|
7
|
-
def initialize(template)
|
7
|
+
def initialize(template = nil)
|
8
8
|
@template = template || File.join(File.dirname(__FILE__), "..", "..", "templates", "default")
|
9
9
|
end
|
10
10
|
|
11
11
|
def parts
|
12
|
-
@parts ||= parse
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def parse
|
18
12
|
Dir.chdir(template) do
|
19
|
-
|
13
|
+
create_parts
|
20
14
|
end
|
21
15
|
end
|
22
16
|
|
@@ -29,9 +23,8 @@ module Docxtor
|
|
29
23
|
def create_part(file)
|
30
24
|
content = File.read(file)
|
31
25
|
part = Package::Part.new(file, content)
|
32
|
-
key = File.basename(file, '.xml')
|
33
26
|
|
34
|
-
|
27
|
+
part
|
35
28
|
end
|
36
29
|
|
37
30
|
end
|