docx_generator 0.1.0 → 0.1.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.
- checksums.yaml +4 -4
- data/.gitignore +18 -18
- data/.rspec +1 -0
- data/Gemfile +6 -4
- data/Guardfile +11 -11
- data/LICENSE.txt +22 -22
- data/README.md +41 -41
- data/Rakefile +7 -7
- data/docx_generator.gemspec +36 -36
- data/examples/basic_document_with_blocks.rb +40 -36
- data/examples/basic_document_without_blocks.rb +9 -9
- data/generators.thor +10 -0
- data/generators/word_base.rb +106 -0
- data/lib/docx_generator.rb +9 -9
- data/lib/docx_generator/dsl.rb +9 -9
- data/lib/docx_generator/dsl/document.rb +84 -75
- data/lib/docx_generator/dsl/paragraph.rb +125 -72
- data/lib/docx_generator/dsl/text.rb +121 -71
- data/lib/docx_generator/element.rb +52 -52
- data/lib/docx_generator/version.rb +4 -4
- data/lib/docx_generator/word.rb +8 -8
- data/lib/docx_generator/word/base.rb +83 -82
- data/lib/docx_generator/word/extensions.rb +30 -18
- data/lib/docx_generator/word/formatting.rb +162 -58
- data/spec/docx_generator/dsl/document_spec.rb +89 -89
- data/spec/docx_generator/dsl/paragraph_spec.rb +107 -71
- data/spec/docx_generator/dsl/text_spec.rb +91 -65
- data/spec/docx_generator/element_spec.rb +44 -44
- data/spec/docx_generator/word/base_spec.rb +57 -57
- data/spec/docx_generator/word/extensions_spec.rb +15 -15
- data/spec/docx_generator/word/formatting_spec.rb +89 -41
- data/spec/spec_helper.rb +7 -7
- metadata +29 -55
- data/.rvmrc +0 -60
data/lib/docx_generator.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
require 'docx_generator/version'
|
2
|
-
require 'docx_generator/element'
|
3
|
-
require 'docx_generator/word'
|
4
|
-
require 'docx_generator/dsl'
|
5
|
-
require 'zip
|
6
|
-
|
7
|
-
# Main module of the library.
|
8
|
-
module DocxGenerator
|
9
|
-
end
|
1
|
+
require 'docx_generator/version'
|
2
|
+
require 'docx_generator/element'
|
3
|
+
require 'docx_generator/word'
|
4
|
+
require 'docx_generator/dsl'
|
5
|
+
require 'zip'
|
6
|
+
|
7
|
+
# Main module of the library.
|
8
|
+
module DocxGenerator
|
9
|
+
end
|
data/lib/docx_generator/dsl.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
require 'docx_generator/dsl/document'
|
2
|
-
require 'docx_generator/dsl/paragraph'
|
3
|
-
require 'docx_generator/dsl/text'
|
4
|
-
|
5
|
-
module DocxGenerator
|
6
|
-
# Namespace for the classes to be used directly by users.
|
7
|
-
module DSL
|
8
|
-
|
9
|
-
end
|
1
|
+
require 'docx_generator/dsl/document'
|
2
|
+
require 'docx_generator/dsl/paragraph'
|
3
|
+
require 'docx_generator/dsl/text'
|
4
|
+
|
5
|
+
module DocxGenerator
|
6
|
+
# Namespace for the classes to be used directly by users.
|
7
|
+
module DSL
|
8
|
+
|
9
|
+
end
|
10
10
|
end
|
@@ -1,75 +1,84 @@
|
|
1
|
-
module DocxGenerator
|
2
|
-
module DSL
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
<
|
47
|
-
<
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
1
|
+
module DocxGenerator
|
2
|
+
module DSL
|
3
|
+
# Represent the docx document.
|
4
|
+
class Document
|
5
|
+
# Filename of the document (without the docx extension).
|
6
|
+
attr_reader :filename
|
7
|
+
|
8
|
+
# Create a new docx document.
|
9
|
+
# @param filename [String] The filename of the docx file, without the docx extension.
|
10
|
+
def initialize(filename, &block)
|
11
|
+
@filename = filename + ".docx"
|
12
|
+
@objects = [] # It contains all the DSL elements
|
13
|
+
yield self if block
|
14
|
+
end
|
15
|
+
|
16
|
+
# Save the docx document to the target location.
|
17
|
+
def save
|
18
|
+
generate_archive(generate_content_types, generate_rels, generate_document)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Add a new paragraph to the document.
|
22
|
+
# @param options [Hash] Formatting options for the paragraph. See the full list in DocxGenerator::DSL::Paragraph.
|
23
|
+
def paragraph(options = {}, &block)
|
24
|
+
par = DocxGenerator::DSL::Paragraph.new(options)
|
25
|
+
yield par if block
|
26
|
+
@objects << par
|
27
|
+
end
|
28
|
+
|
29
|
+
# Add other objects to the document.
|
30
|
+
# @param objects [Object] Objects (like paragraphs).
|
31
|
+
# @return [DocxGenerator::DSL::Document] The document object.
|
32
|
+
def add(*objects)
|
33
|
+
objects.each do |object|
|
34
|
+
@objects << object
|
35
|
+
end
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def generate_content_types
|
42
|
+
<<EOF
|
43
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
44
|
+
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
45
|
+
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
|
46
|
+
<Default Extension="xml" ContentType="application/xml"/>
|
47
|
+
<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
|
48
|
+
</Types>
|
49
|
+
EOF
|
50
|
+
end
|
51
|
+
|
52
|
+
def generate_rels
|
53
|
+
<<EOF
|
54
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
55
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
56
|
+
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
|
57
|
+
</Relationships>
|
58
|
+
EOF
|
59
|
+
end
|
60
|
+
|
61
|
+
def generate_document
|
62
|
+
content = []
|
63
|
+
@objects.each do |object|
|
64
|
+
content << object.generate
|
65
|
+
end
|
66
|
+
|
67
|
+
'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' +
|
68
|
+
Word::Document.new({ "xmlns:w" => "http://schemas.openxmlformats.org/wordprocessingml/2006/main" },
|
69
|
+
[ Word::Body.new(content) ]).to_s
|
70
|
+
end
|
71
|
+
|
72
|
+
def generate_archive(content_types, rels, document)
|
73
|
+
File.delete(@filename) if File.exists?(@filename)
|
74
|
+
Zip::File.open(@filename, Zip::File::CREATE) do |docx|
|
75
|
+
docx.mkdir('_rels')
|
76
|
+
docx.mkdir('word')
|
77
|
+
docx.get_output_stream('[Content_Types].xml') { |f| f.puts content_types }
|
78
|
+
docx.get_output_stream('_rels/.rels') { |f| f.puts rels }
|
79
|
+
docx.get_output_stream('word/document.xml') { |f| f.puts document }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -1,72 +1,125 @@
|
|
1
|
-
module DocxGenerator
|
2
|
-
module DSL
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
@
|
22
|
-
end
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
1
|
+
module DocxGenerator
|
2
|
+
module DSL
|
3
|
+
# Represent a paragraph with formatting options
|
4
|
+
class Paragraph
|
5
|
+
# Create a new paragraph with the formatting options specified.
|
6
|
+
# The formatting properties can be passed with a Hash or they could be set by calling the methods on the object (either in the block or not).
|
7
|
+
# @param options [Hash] Formatting options.
|
8
|
+
# @option options [Boolean] alignment The alignment of the paragraph. See the specification for the complete list.
|
9
|
+
# @option options [Hash] spacing Various spacing options for the paragraph. See the specification for more details.
|
10
|
+
# @option options [Hash] indentation Various indentation properties for the paragraph. See the specification for more details.
|
11
|
+
# @option options [Array] tabs Custom tabulation stops. See the specification for more details.
|
12
|
+
def initialize(options = {}, &block)
|
13
|
+
@objects = []
|
14
|
+
@options = options
|
15
|
+
yield self if block
|
16
|
+
end
|
17
|
+
|
18
|
+
# Set the alignment of the paragraph. See the specification for more details.
|
19
|
+
# @param value [String] The alignment of the paragraph. See the specification for the complete list.
|
20
|
+
def alignment(value)
|
21
|
+
@options[:alignment] = value
|
22
|
+
end
|
23
|
+
|
24
|
+
# Set various spacing options for the paragraph. See the specification for more details.
|
25
|
+
# @param options [Hash] Various spacing options for the paragraph. See the specification for more details.
|
26
|
+
def spacing(options)
|
27
|
+
@options[:spacing] = options
|
28
|
+
end
|
29
|
+
|
30
|
+
# Set various indentation properties for the paragraph. See the specification for more details.
|
31
|
+
# @param properties [Hash] Various indentation properties for the paragraph. See the specification for more details.
|
32
|
+
def indentation(properties)
|
33
|
+
@options[:indentation] = properties
|
34
|
+
end
|
35
|
+
|
36
|
+
# Set custom tabulation stops. See the specification for more details.
|
37
|
+
# @param tab_stops [Array] Custom tabulation stops.
|
38
|
+
def tabs(tab_stops)
|
39
|
+
@options[:tabs] = tab_stops
|
40
|
+
end
|
41
|
+
|
42
|
+
# Prevent the addition of a space between two text fragments.
|
43
|
+
def no_space
|
44
|
+
@objects << DocxGenerator::Word::Extensions::NoSpace.new
|
45
|
+
end
|
46
|
+
|
47
|
+
# Add a newline
|
48
|
+
def newline
|
49
|
+
@objects << DocxGenerator::Word::Extensions::Newline.new
|
50
|
+
end
|
51
|
+
|
52
|
+
# Add a tabulation
|
53
|
+
def tab
|
54
|
+
@objects << DocxGenerator::Word::Tab.new
|
55
|
+
end
|
56
|
+
|
57
|
+
# Add a new text fragment to the paragraph.
|
58
|
+
# @param text_fragment [String] The text fragment.
|
59
|
+
# @param options [Hash] Formatting options for the text fragment. See the full list in DocxGenerator::DSL::Text.
|
60
|
+
def text(text_fragment, options = {}, &block)
|
61
|
+
text_object = DocxGenerator::DSL::Text.new(text_fragment, options)
|
62
|
+
yield text_object if block
|
63
|
+
@objects << text_object
|
64
|
+
end
|
65
|
+
|
66
|
+
# Generate the XML element objects.
|
67
|
+
# @return [DocxGenerator::Word::Paragraph] A Word::Paragraph object representing the paragraph.
|
68
|
+
def generate
|
69
|
+
text_fragments = generate_text_fragments
|
70
|
+
options = generate_paragraph_options
|
71
|
+
if options
|
72
|
+
Word::Paragraph.new({}, text_fragments.unshift(options))
|
73
|
+
else
|
74
|
+
Word::Paragraph.new({}, text_fragments)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Add other objects to the paragraph.
|
79
|
+
# @param objects [Object] Objects (like text fragments).
|
80
|
+
# @return [DocxGenerator::DSL::Paragraph] The paragraph object.
|
81
|
+
def add(*objects)
|
82
|
+
objects.each do |object|
|
83
|
+
@objects << object
|
84
|
+
end
|
85
|
+
self
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
def generate_text_fragments
|
90
|
+
text_fragments = []
|
91
|
+
@objects.each do |object|
|
92
|
+
if object.class == DocxGenerator::Word::Extensions::NoSpace
|
93
|
+
text_fragments.pop
|
94
|
+
elsif object.class == DocxGenerator::Word::Extensions::Newline
|
95
|
+
text_fragments.pop
|
96
|
+
text_fragments << object.generate
|
97
|
+
elsif object.respond_to?(:generate)
|
98
|
+
text_fragments << object.generate << Word::Extensions.space
|
99
|
+
end
|
100
|
+
end
|
101
|
+
text_fragments.pop if text_fragments.last.to_s == Word::Extensions.space.to_s # In order to remove the last space added
|
102
|
+
text_fragments
|
103
|
+
end
|
104
|
+
|
105
|
+
def generate_paragraph_options
|
106
|
+
unless @options.empty?
|
107
|
+
parsed_options = []
|
108
|
+
@options.each do |option, value|
|
109
|
+
parsed_options << parse_paragraph_option(option, value)
|
110
|
+
end
|
111
|
+
Word::ParagraphProperties.new(parsed_options)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def parse_paragraph_option(option, value)
|
116
|
+
case option
|
117
|
+
when :alignment then Word::Alignment.new(value)
|
118
|
+
when :spacing then Word::Spacing.new(value)
|
119
|
+
when :indentation then Word::Indentation.new(value)
|
120
|
+
when :tabs then Word::Tabs.new(value)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -1,71 +1,121 @@
|
|
1
|
-
module DocxGenerator
|
2
|
-
module DSL
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
def
|
19
|
-
@
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
def
|
27
|
-
@options[:
|
28
|
-
end
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
def
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
1
|
+
module DocxGenerator
|
2
|
+
module DSL
|
3
|
+
# Represent a text fragment with formatting options
|
4
|
+
class Text
|
5
|
+
# Create a new text fragment with the text specified.
|
6
|
+
# The formatting properties can be passed with a Hash or they could be set by calling the methods on the object (either in the block or not).
|
7
|
+
# @param text_fragment [String] The text fragment.
|
8
|
+
# @param options [Hash] Formatting options.
|
9
|
+
# @option options [Boolean] bold If the text should be in bold.
|
10
|
+
# @option options [Boolean] italics If the text should be in italics.
|
11
|
+
# @option options [Hash] underline The style of the underline and other options. See the specification for more details.
|
12
|
+
# @option options [Integer] size The size of the text (in points).
|
13
|
+
# @option options [Boolean] superscript If the text should be in superscript.
|
14
|
+
# @option options [Boolean] subscript If the text should be in subscript.
|
15
|
+
# @option options [Boolean] caps If the text should be displayed in capital letters.
|
16
|
+
# @option options [Boolean] small_caps If the text should be displayed in small capital letters.
|
17
|
+
# @option options [String] font The name of the font.
|
18
|
+
def initialize(text_fragment, options = {}, &block)
|
19
|
+
@text_fragment = text_fragment
|
20
|
+
@options = options
|
21
|
+
yield self if block
|
22
|
+
end
|
23
|
+
|
24
|
+
# Set whether the text should be in bold or not.
|
25
|
+
# @param value [Boolean] Whether the text should be in bold or not.
|
26
|
+
def bold(value)
|
27
|
+
@options[:bold] = value
|
28
|
+
end
|
29
|
+
|
30
|
+
# Set whether the text should be in italics or not.
|
31
|
+
# @param value [Boolean] Whether the text should be in italics or not.
|
32
|
+
def italics(value)
|
33
|
+
@options[:italics] = value
|
34
|
+
end
|
35
|
+
|
36
|
+
# Set the style of the underline and other options. See the specification for more details.
|
37
|
+
# @param value [Hash] The style of the underline and other options. See the specification for more details.
|
38
|
+
def underline(value)
|
39
|
+
@options[:underline] = value
|
40
|
+
end
|
41
|
+
|
42
|
+
# Set the size of the text (in points).
|
43
|
+
# @param value [Integer] The size of the text (in points).
|
44
|
+
def size(value)
|
45
|
+
@options[:size] = value
|
46
|
+
end
|
47
|
+
|
48
|
+
# Set whether the text should be in superscript.
|
49
|
+
# @param value [Boolean] Whether the text should be in superscript.
|
50
|
+
def superscript(value)
|
51
|
+
@options[:superscript] = value
|
52
|
+
end
|
53
|
+
|
54
|
+
# Set whether the text should be in subscript.
|
55
|
+
# @param value [Boolean] Whether the text should be in subscript.
|
56
|
+
def subscript(value)
|
57
|
+
@options[:subscript] = value
|
58
|
+
end
|
59
|
+
|
60
|
+
# Set whether the text should be displayed in capital letters.
|
61
|
+
# @param value [Boolean] Whether the text should be displayed in capital letters.
|
62
|
+
def caps(value)
|
63
|
+
@options[:caps] = value
|
64
|
+
end
|
65
|
+
|
66
|
+
# Set whether the text should be displayed in small capital letters.
|
67
|
+
# @param value [Boolean] Whether the text should be displayed in small capital letters.
|
68
|
+
def small_caps(value)
|
69
|
+
@options[:small_caps] = value
|
70
|
+
end
|
71
|
+
|
72
|
+
# Set the name of the font.
|
73
|
+
# @param value [String] The name of the font
|
74
|
+
def font(value)
|
75
|
+
@options[:font] = value
|
76
|
+
end
|
77
|
+
|
78
|
+
# Generate the XML element objects.
|
79
|
+
# @return [DocxGenerator::Word::Run] A Word::Run object representing the text fragment.
|
80
|
+
def generate
|
81
|
+
options = generate_text_options
|
82
|
+
text = Word::Text.new({}, [@text_fragment])
|
83
|
+
if options
|
84
|
+
Word::Run.new({}, [options, text])
|
85
|
+
else
|
86
|
+
Word::Run.new({}, [text])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Generate the XML representation of the text fragment
|
91
|
+
def to_s
|
92
|
+
generate.to_s
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
def generate_text_options
|
97
|
+
unless @options.empty?
|
98
|
+
parsed_options = []
|
99
|
+
@options.each do |option, value|
|
100
|
+
parsed_options << parse_text_option(option, value)
|
101
|
+
end
|
102
|
+
Word::RunProperties.new(parsed_options)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def parse_text_option(option, value)
|
107
|
+
case option
|
108
|
+
when :bold then Word::Bold.new(value)
|
109
|
+
when :italics then Word::Italics.new(value)
|
110
|
+
when :underline then Word::Underline.new(value)
|
111
|
+
when :size then Word::Size.new(value)
|
112
|
+
when :superscript then Word::VerticalAlign.new("superscript")
|
113
|
+
when :subscript then Word::VerticalAlign.new("subscript")
|
114
|
+
when :caps then Word::CapitalLetters.new(value)
|
115
|
+
when :small_caps then Word::SmallCapitalLetters.new(value)
|
116
|
+
when :font then Word::Font.new(value)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|