docx_generator 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|