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.
@@ -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/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
@@ -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
- class Document
4
- attr_reader :filename
5
-
6
- def initialize(filename, &block)
7
- @filename = filename + ".docx"
8
- @objects = [] # It contains all the DSL elements
9
- yield self if block
10
- end
11
-
12
- # Could be better
13
- def save
14
- content_types = generate_content_types
15
- rels = generate_rels
16
- document = generate_document
17
-
18
- File.delete(@filename) if File.exists?(@filename)
19
- Zip::ZipFile.open(@filename, Zip::ZipFile::CREATE) do |docx|
20
- docx.mkdir('_rels')
21
- docx.mkdir('word')
22
- docx.get_output_stream('[Content_Types].xml') { |f| f.puts content_types }
23
- docx.get_output_stream('_rels/.rels') { |f| f.puts rels }
24
- docx.get_output_stream('word/document.xml') { |f| f.puts document }
25
- end
26
- end
27
-
28
- def paragraph(options = {}, &block)
29
- par = DocxGenerator::DSL::Paragraph.new(options)
30
- yield par if block
31
- @objects << par
32
- end
33
-
34
- def add(*objects)
35
- objects.each do |object|
36
- @objects << object
37
- end
38
- self
39
- end
40
-
41
- private
42
-
43
- def generate_content_types
44
- <<EOF
45
- <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
46
- <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
47
- <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
48
- <Default Extension="xml" ContentType="application/xml"/>
49
- <Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
50
- </Types>
51
- EOF
52
- end
53
-
54
- def generate_rels
55
- <<EOF
56
- <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
57
- <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
58
- <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
59
- </Relationships>
60
- EOF
61
- end
62
-
63
- def generate_document
64
- content = []
65
- @objects.each do |object|
66
- content << object.generate
67
- end
68
-
69
- '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>' +
70
- Word::Document.new({ "xmlns:w" => "http://schemas.openxmlformats.org/wordprocessingml/2006/main" },
71
- [ Word::Body.new(content) ]).to_s
72
- end
73
- end
74
- end
75
- end
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
- class Paragraph
4
- def initialize(options = {}, &block)
5
- @objects = []
6
- @options = options
7
- yield self if block
8
- end
9
-
10
- def alignment(value)
11
- @options[:alignment] = value
12
- end
13
-
14
- def no_space
15
- @objects << DocxGenerator::Word::Extensions::NoSpace.new
16
- end
17
-
18
- def text(text_fragment, options = {}, &block)
19
- text_object = DocxGenerator::DSL::Text.new(text_fragment, options)
20
- yield text_object if block
21
- @objects << text_object
22
- end
23
-
24
- def generate
25
- text_fragments = generate_text_fragments
26
- options = generate_paragraph_options
27
- if options
28
- Word::Paragraph.new({}, text_fragments.unshift(options))
29
- else
30
- Word::Paragraph.new({}, text_fragments)
31
- end
32
- end
33
-
34
- def add(*objects)
35
- objects.each do |object|
36
- @objects << object
37
- end
38
- self
39
- end
40
-
41
- private
42
- def generate_text_fragments
43
- text_fragments = []
44
- @objects.each do |object|
45
- if object.respond_to?(:generate)
46
- text_fragments << object.generate << Word::Extensions.space
47
- elsif object.class == DocxGenerator::Word::Extensions::NoSpace
48
- text_fragments.pop
49
- end
50
- end
51
- text_fragments.pop # In order to remove the last space added
52
- text_fragments
53
- end
54
-
55
- def generate_paragraph_options
56
- unless @options.empty?
57
- parsed_options = []
58
- @options.each do |option, value|
59
- parsed_options << parse_paragraph_option(option, value)
60
- end
61
- Word::ParagraphProperties.new(parsed_options)
62
- end
63
- end
64
-
65
- def parse_paragraph_option(option, value)
66
- case option
67
- when :alignment then Word::Alignment.new(value)
68
- end
69
- end
70
- end
71
- end
72
- end
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
- class Text
4
- def initialize(text_fragment, options = {}, &block)
5
- @text_fragment = text_fragment
6
- @options = options
7
- yield self if block
8
- end
9
-
10
- def bold(value)
11
- @options[:bold] = value
12
- end
13
-
14
- def italics(value)
15
- @options[:italics] = value
16
- end
17
-
18
- def underline(value)
19
- @options[:underline] = value
20
- end
21
-
22
- def size(value)
23
- @options[:size] = value
24
- end
25
-
26
- def superscript(value)
27
- @options[:superscript] = value
28
- end
29
-
30
- def subscript(value)
31
- @options[:subscript] = value
32
- end
33
-
34
- def generate
35
- options = generate_text_options
36
- text = Word::Text.new({}, [@text_fragment])
37
- if options
38
- Word::Run.new({}, [options, text])
39
- else
40
- Word::Run.new({}, [text])
41
- end
42
- end
43
-
44
- def to_s
45
- generate.to_s
46
- end
47
-
48
- private
49
- def generate_text_options
50
- unless @options.empty?
51
- parsed_options = []
52
- @options.each do |option, value|
53
- parsed_options << parse_text_option(option, value)
54
- end
55
- Word::RunProperties.new(parsed_options)
56
- end
57
- end
58
-
59
- def parse_text_option(option, value)
60
- case option
61
- when :bold then Word::Bold.new(value)
62
- when :italics then Word::Italics.new(value)
63
- when :underline then Word::Underline.new(value)
64
- when :size then Word::Size.new(value)
65
- when :superscript then Word::VerticalAlign.new("superscript")
66
- when :subscript then Word::VerticalAlign.new("subscript")
67
- end
68
- end
69
- end
70
- end
71
- end
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