caracal_the_curve 1.4.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 +7 -0
- data/.github/workflows/main.yml +22 -0
- data/.github/workflows/publish_gem.yml +40 -0
- data/.gitignore +25 -0
- data/.travis.yml +20 -0
- data/CHANGELOG.md +141 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +842 -0
- data/Rakefile +7 -0
- data/caracal.gemspec +28 -0
- data/lib/caracal/core/bookmarks.rb +52 -0
- data/lib/caracal/core/custom_properties.rb +49 -0
- data/lib/caracal/core/file_name.rb +43 -0
- data/lib/caracal/core/fonts.rb +75 -0
- data/lib/caracal/core/iframes.rb +42 -0
- data/lib/caracal/core/ignorables.rb +47 -0
- data/lib/caracal/core/images.rb +37 -0
- data/lib/caracal/core/list_styles.rb +93 -0
- data/lib/caracal/core/lists.rb +57 -0
- data/lib/caracal/core/models/base_model.rb +51 -0
- data/lib/caracal/core/models/bookmark_model.rb +86 -0
- data/lib/caracal/core/models/border_model.rb +120 -0
- data/lib/caracal/core/models/custom_property_model.rb +60 -0
- data/lib/caracal/core/models/font_model.rb +64 -0
- data/lib/caracal/core/models/iframe_model.rb +148 -0
- data/lib/caracal/core/models/image_model.rb +133 -0
- data/lib/caracal/core/models/line_break_model.rb +15 -0
- data/lib/caracal/core/models/link_model.rb +94 -0
- data/lib/caracal/core/models/list_item_model.rb +108 -0
- data/lib/caracal/core/models/list_model.rb +132 -0
- data/lib/caracal/core/models/list_style_model.rb +118 -0
- data/lib/caracal/core/models/margin_model.rb +76 -0
- data/lib/caracal/core/models/namespace_model.rb +65 -0
- data/lib/caracal/core/models/page_break_model.rb +61 -0
- data/lib/caracal/core/models/page_number_model.rb +95 -0
- data/lib/caracal/core/models/page_size_model.rb +79 -0
- data/lib/caracal/core/models/paragraph_model.rb +186 -0
- data/lib/caracal/core/models/relationship_model.rb +114 -0
- data/lib/caracal/core/models/rule_model.rb +27 -0
- data/lib/caracal/core/models/style_model.rb +165 -0
- data/lib/caracal/core/models/table_cell_model.rb +176 -0
- data/lib/caracal/core/models/table_model.rb +206 -0
- data/lib/caracal/core/models/text_model.rb +118 -0
- data/lib/caracal/core/namespaces.rb +89 -0
- data/lib/caracal/core/page_breaks.rb +29 -0
- data/lib/caracal/core/page_numbers.rb +58 -0
- data/lib/caracal/core/page_settings.rb +74 -0
- data/lib/caracal/core/relationships.rb +90 -0
- data/lib/caracal/core/rules.rb +35 -0
- data/lib/caracal/core/styles.rb +86 -0
- data/lib/caracal/core/tables.rb +42 -0
- data/lib/caracal/core/text.rb +75 -0
- data/lib/caracal/document.rb +272 -0
- data/lib/caracal/errors.rb +23 -0
- data/lib/caracal/renderers/app_renderer.rb +41 -0
- data/lib/caracal/renderers/content_types_renderer.rb +54 -0
- data/lib/caracal/renderers/core_renderer.rb +44 -0
- data/lib/caracal/renderers/custom_renderer.rb +64 -0
- data/lib/caracal/renderers/document_renderer.rb +427 -0
- data/lib/caracal/renderers/fonts_renderer.rb +56 -0
- data/lib/caracal/renderers/footer_renderer.rb +90 -0
- data/lib/caracal/renderers/numbering_renderer.rb +88 -0
- data/lib/caracal/renderers/package_relationships_renderer.rb +51 -0
- data/lib/caracal/renderers/relationships_renderer.rb +48 -0
- data/lib/caracal/renderers/settings_renderer.rb +58 -0
- data/lib/caracal/renderers/styles_renderer.rb +181 -0
- data/lib/caracal/renderers/xml_renderer.rb +83 -0
- data/lib/caracal/utilities.rb +23 -0
- data/lib/caracal/version.rb +3 -0
- data/lib/caracal.rb +40 -0
- data/lib/tilt/caracal.rb +21 -0
- data/spec/lib/caracal/core/bookmarks_spec.rb +35 -0
- data/spec/lib/caracal/core/file_name_spec.rb +54 -0
- data/spec/lib/caracal/core/fonts_spec.rb +119 -0
- data/spec/lib/caracal/core/iframes_spec.rb +29 -0
- data/spec/lib/caracal/core/ignorables_spec.rb +79 -0
- data/spec/lib/caracal/core/images_spec.rb +25 -0
- data/spec/lib/caracal/core/list_styles_spec.rb +121 -0
- data/spec/lib/caracal/core/lists_spec.rb +43 -0
- data/spec/lib/caracal/core/models/base_model_spec.rb +38 -0
- data/spec/lib/caracal/core/models/bookmark_model_spec.rb +135 -0
- data/spec/lib/caracal/core/models/border_model_spec.rb +159 -0
- data/spec/lib/caracal/core/models/font_model_spec.rb +92 -0
- data/spec/lib/caracal/core/models/iframe_model_spec.rb +83 -0
- data/spec/lib/caracal/core/models/image_model_spec.rb +225 -0
- data/spec/lib/caracal/core/models/line_break_model_spec.rb +21 -0
- data/spec/lib/caracal/core/models/link_model_spec.rb +179 -0
- data/spec/lib/caracal/core/models/list_item_model_spec.rb +197 -0
- data/spec/lib/caracal/core/models/list_model_spec.rb +178 -0
- data/spec/lib/caracal/core/models/list_style_model_spec.rb +198 -0
- data/spec/lib/caracal/core/models/margin_model_spec.rb +111 -0
- data/spec/lib/caracal/core/models/namespace_model_spec.rb +107 -0
- data/spec/lib/caracal/core/models/page_break_model_spec.rb +21 -0
- data/spec/lib/caracal/core/models/page_number_model_spec.rb +136 -0
- data/spec/lib/caracal/core/models/page_size_model_spec.rb +101 -0
- data/spec/lib/caracal/core/models/paragraph_model_spec.rb +196 -0
- data/spec/lib/caracal/core/models/relationship_model_spec.rb +193 -0
- data/spec/lib/caracal/core/models/rule_model_spec.rb +108 -0
- data/spec/lib/caracal/core/models/style_model_spec.rb +225 -0
- data/spec/lib/caracal/core/models/table_cell_model_spec.rb +230 -0
- data/spec/lib/caracal/core/models/table_model_spec.rb +222 -0
- data/spec/lib/caracal/core/models/text_model_spec.rb +154 -0
- data/spec/lib/caracal/core/namespaces_spec.rb +116 -0
- data/spec/lib/caracal/core/page_breaks_spec.rb +25 -0
- data/spec/lib/caracal/core/page_numbers_spec.rb +89 -0
- data/spec/lib/caracal/core/page_settings_spec.rb +151 -0
- data/spec/lib/caracal/core/relationships_spec.rb +119 -0
- data/spec/lib/caracal/core/rules_spec.rb +25 -0
- data/spec/lib/caracal/core/styles_spec.rb +129 -0
- data/spec/lib/caracal/core/tables_spec.rb +25 -0
- data/spec/lib/caracal/core/text_spec.rb +52 -0
- data/spec/lib/caracal/errors_spec.rb +10 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/support/_fixtures/snippet.docx +0 -0
- metadata +292 -0
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'caracal/core/models/margin_model'
|
2
|
+
require 'caracal/core/models/page_size_model'
|
3
|
+
require 'caracal/errors'
|
4
|
+
|
5
|
+
|
6
|
+
module Caracal
|
7
|
+
module Core
|
8
|
+
|
9
|
+
# This module encapsulates all the functionality related to setting the
|
10
|
+
# document's size and margins.
|
11
|
+
#
|
12
|
+
module PageSettings
|
13
|
+
def self.included(base)
|
14
|
+
base.class_eval do
|
15
|
+
|
16
|
+
#-------------------------------------------------------------
|
17
|
+
# Configuration
|
18
|
+
#-------------------------------------------------------------
|
19
|
+
|
20
|
+
# accessors
|
21
|
+
attr_reader :page_width
|
22
|
+
attr_reader :page_orientation
|
23
|
+
attr_reader :page_height
|
24
|
+
attr_reader :page_margin_top
|
25
|
+
attr_reader :page_margin_bottom
|
26
|
+
attr_reader :page_margin_left
|
27
|
+
attr_reader :page_margin_right
|
28
|
+
|
29
|
+
|
30
|
+
#-------------------------------------------------------------
|
31
|
+
# Public Methods
|
32
|
+
#-------------------------------------------------------------
|
33
|
+
|
34
|
+
# This method controls the physical margins of the printed page. Defaults
|
35
|
+
# to 1in on each side.
|
36
|
+
#
|
37
|
+
def page_margins(options={}, &block)
|
38
|
+
model = Caracal::Core::Models::MarginModel.new(options, &block)
|
39
|
+
|
40
|
+
if model.valid?
|
41
|
+
if (model.margin_top + model.margin_bottom < page_height) && (model.margin_left + model.margin_right < page_width)
|
42
|
+
@page_margin_top = model.margin_top
|
43
|
+
@page_margin_bottom = model.margin_bottom
|
44
|
+
@page_margin_left = model.margin_left
|
45
|
+
@page_margin_right = model.margin_right
|
46
|
+
else
|
47
|
+
raise Caracal::Errors::InvalidModelError, 'page_margins method requires margins to be smaller than the page size.'
|
48
|
+
end
|
49
|
+
else
|
50
|
+
raise Caracal::Errors::InvalidModelError, 'page_margins method requires non-zero :top, :bottom, :left, and :right options.'
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# This method controls the physical width and height of the printed page. Defaults
|
55
|
+
# to US standard A4 portrait size.
|
56
|
+
#
|
57
|
+
def page_size(options={}, &block)
|
58
|
+
model = Caracal::Core::Models::PageSizeModel.new(options, &block)
|
59
|
+
|
60
|
+
if model.valid?
|
61
|
+
@page_width = model.page_width
|
62
|
+
@page_height = model.page_height
|
63
|
+
@page_orientation = model.page_orientation
|
64
|
+
else
|
65
|
+
raise Caracal::Errors::InvalidModelError, 'page_size method requires non-zero :width and :height options.'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'caracal/core/models/relationship_model'
|
2
|
+
require 'caracal/errors'
|
3
|
+
|
4
|
+
|
5
|
+
module Caracal
|
6
|
+
module Core
|
7
|
+
|
8
|
+
# This module encapsulates all the functionality related to registering and
|
9
|
+
# retrieving relationships.
|
10
|
+
#
|
11
|
+
module Relationships
|
12
|
+
def self.included(base)
|
13
|
+
base.class_eval do
|
14
|
+
|
15
|
+
#-------------------------------------------------------------
|
16
|
+
# Configuration
|
17
|
+
#-------------------------------------------------------------
|
18
|
+
|
19
|
+
attr_reader :relationship_counter
|
20
|
+
|
21
|
+
|
22
|
+
#-------------------------------------------------------------
|
23
|
+
# Class Methods
|
24
|
+
#-------------------------------------------------------------
|
25
|
+
|
26
|
+
def self.default_relationships
|
27
|
+
[
|
28
|
+
{ target: 'fontTable.xml', type: :font },
|
29
|
+
{ target: 'footer1.xml', type: :footer },
|
30
|
+
{ target: 'numbering.xml', type: :numbering },
|
31
|
+
{ target: 'settings.xml', type: :setting },
|
32
|
+
{ target: 'styles.xml', type: :style }
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
#-------------------------------------------------------------
|
38
|
+
# Public Methods
|
39
|
+
#-------------------------------------------------------------
|
40
|
+
|
41
|
+
#============== ATTRIBUTES ==========================
|
42
|
+
|
43
|
+
def relationship(options={}, &block)
|
44
|
+
id = relationship_counter.to_i + 1
|
45
|
+
options.merge!({ id: id })
|
46
|
+
|
47
|
+
model = Caracal::Core::Models::RelationshipModel.new(options, &block)
|
48
|
+
if model.valid?
|
49
|
+
@relationship_counter = id
|
50
|
+
rel = register_relationship(model)
|
51
|
+
else
|
52
|
+
raise Caracal::Errors::InvalidModelError, 'relationship must specify the :id, :target, and :type attributes.'
|
53
|
+
end
|
54
|
+
rel
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
#============== GETTERS =============================
|
59
|
+
|
60
|
+
def relationships
|
61
|
+
@relationships ||= []
|
62
|
+
end
|
63
|
+
|
64
|
+
def find_relationship(target)
|
65
|
+
relationships.find { |r| r.matches?(target) }
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
#============== REGISTRATION ========================
|
70
|
+
|
71
|
+
def register_relationship(model)
|
72
|
+
unless r = find_relationship(model.relationship_target)
|
73
|
+
relationships << model
|
74
|
+
r = model
|
75
|
+
end
|
76
|
+
r
|
77
|
+
end
|
78
|
+
|
79
|
+
def unregister_relationship(target)
|
80
|
+
if r = find_relationship(target)
|
81
|
+
relationships.delete(r)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'caracal/core/models/rule_model'
|
2
|
+
require 'caracal/errors'
|
3
|
+
|
4
|
+
|
5
|
+
module Caracal
|
6
|
+
module Core
|
7
|
+
|
8
|
+
# This module encapsulates all the functionality related to adding
|
9
|
+
# horizontal rules to the document.
|
10
|
+
#
|
11
|
+
module Rules
|
12
|
+
def self.included(base)
|
13
|
+
base.class_eval do
|
14
|
+
|
15
|
+
#-------------------------------------------------------------
|
16
|
+
# Public Methods
|
17
|
+
#-------------------------------------------------------------
|
18
|
+
|
19
|
+
def hr(options={}, &block)
|
20
|
+
model = Caracal::Core::Models::RuleModel.new(options, &block)
|
21
|
+
|
22
|
+
if model.valid?
|
23
|
+
contents << model
|
24
|
+
else
|
25
|
+
raise Caracal::Errors::InvalidModelError, 'Horizontal rules require non-zero :size and :spacing values.'
|
26
|
+
end
|
27
|
+
model
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'caracal/core/models/style_model'
|
2
|
+
require 'caracal/errors'
|
3
|
+
|
4
|
+
|
5
|
+
module Caracal
|
6
|
+
module Core
|
7
|
+
|
8
|
+
# This module encapsulates all the functionality related to defining
|
9
|
+
# paragraph styles.
|
10
|
+
#
|
11
|
+
module Styles
|
12
|
+
def self.included(base)
|
13
|
+
base.class_eval do
|
14
|
+
|
15
|
+
#-------------------------------------------------------------
|
16
|
+
# Class Methods
|
17
|
+
#-------------------------------------------------------------
|
18
|
+
|
19
|
+
def self.default_styles
|
20
|
+
[
|
21
|
+
{ id: 'Normal', name: 'normal', font: 'Arial', size: 20, line: 320, color: '333333' },
|
22
|
+
{ id: 'Heading1', name: 'heading 1', font: 'Palatino', size: 36, bottom: 120 },
|
23
|
+
{ id: 'Heading2', name: 'heading 2', font: 'Arial', size: 26, top: 120, bottom: 160, bold: true },
|
24
|
+
{ id: 'Heading3', name: 'heading 3', font: 'Arial', size: 24, top: 120, bottom: 160, bold: true, italic: true, color: '666666' },
|
25
|
+
{ id: 'Heading4', name: 'heading 4', font: 'Palatino', size: 24, top: 120, bottom: 120, bold: true },
|
26
|
+
{ id: 'Heading5', name: 'heading 5', font: 'Arial', size: 22, top: 120, bottom: 120, bold: true },
|
27
|
+
{ id: 'Heading6', name: 'heading 6', font: 'Arial', size: 22, top: 120, bottom: 120, underline: true, italic: true, color: '666666' },
|
28
|
+
{ id: 'Title', name: 'title', font: 'Palatino', size: 60 },
|
29
|
+
{ id: 'Subtitle', name: 'subtitle', font: 'Arial', size: 28, top: 60 }
|
30
|
+
]
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
#-------------------------------------------------------------
|
35
|
+
# Public Methods
|
36
|
+
#-------------------------------------------------------------
|
37
|
+
|
38
|
+
#============== ATTRIBUTES ==========================
|
39
|
+
|
40
|
+
def style(options={}, &block)
|
41
|
+
model = Caracal::Core::Models::StyleModel.new(options, &block)
|
42
|
+
|
43
|
+
if model.valid?
|
44
|
+
register_style(model)
|
45
|
+
else
|
46
|
+
raise Caracal::Errors::InvalidModelError, 'style must define an :id and :name.'
|
47
|
+
end
|
48
|
+
model
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
#============== GETTERS =============================
|
53
|
+
|
54
|
+
def styles
|
55
|
+
@styles ||= []
|
56
|
+
end
|
57
|
+
|
58
|
+
def default_style
|
59
|
+
styles.find { |s| s.style_default }
|
60
|
+
end
|
61
|
+
|
62
|
+
def find_style(id)
|
63
|
+
styles.find { |s| s.matches?(id) }
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
#============== REGISTRATION ========================
|
68
|
+
|
69
|
+
def register_style(model)
|
70
|
+
unregister_style(model.style_id)
|
71
|
+
styles << model
|
72
|
+
model
|
73
|
+
end
|
74
|
+
|
75
|
+
def unregister_style(id)
|
76
|
+
if s = find_style(id)
|
77
|
+
styles.delete(s)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'caracal/core/models/table_model'
|
2
|
+
require 'caracal/errors'
|
3
|
+
|
4
|
+
|
5
|
+
module Caracal
|
6
|
+
module Core
|
7
|
+
|
8
|
+
# This module encapsulates all the functionality related to adding tables
|
9
|
+
# to the document.
|
10
|
+
#
|
11
|
+
module Tables
|
12
|
+
def self.included(base)
|
13
|
+
base.class_eval do
|
14
|
+
|
15
|
+
#-------------------------------------------------------------
|
16
|
+
# Public Methods
|
17
|
+
#-------------------------------------------------------------
|
18
|
+
|
19
|
+
def table(*args, &block)
|
20
|
+
options = Caracal::Utilities.extract_options!(args)
|
21
|
+
options.merge!({ data: args.first }) if args.first
|
22
|
+
|
23
|
+
model = Caracal::Core::Models::TableModel.new(options, &block)
|
24
|
+
if respond_to?(:page_width)
|
25
|
+
container_width = page_width - page_margin_left - page_margin_right
|
26
|
+
model.calculate_width(container_width)
|
27
|
+
end
|
28
|
+
|
29
|
+
if model.valid?
|
30
|
+
contents << model
|
31
|
+
else
|
32
|
+
raise Caracal::Errors::InvalidModelError, 'Table must be provided data for at least one cell.'
|
33
|
+
end
|
34
|
+
model
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'caracal/core/models/paragraph_model'
|
2
|
+
require 'caracal/core/models/line_break_model'
|
3
|
+
require 'caracal/errors'
|
4
|
+
|
5
|
+
|
6
|
+
module Caracal
|
7
|
+
module Core
|
8
|
+
|
9
|
+
# This module encapsulates all the functionality related to adding text
|
10
|
+
# to the document.
|
11
|
+
#
|
12
|
+
module Text
|
13
|
+
def self.included(base)
|
14
|
+
base.class_eval do
|
15
|
+
|
16
|
+
#-------------------------------------------------------------
|
17
|
+
# Public Methods
|
18
|
+
#-------------------------------------------------------------
|
19
|
+
|
20
|
+
#============== PARAGRAPHS ==========================
|
21
|
+
|
22
|
+
def p(*args, &block)
|
23
|
+
options = Caracal::Utilities.extract_options!(args)
|
24
|
+
options.merge!({ content: args.first }) if args.first
|
25
|
+
|
26
|
+
model = Caracal::Core::Models::ParagraphModel.new(options, &block)
|
27
|
+
if model.valid?
|
28
|
+
contents << model
|
29
|
+
else
|
30
|
+
raise Caracal::Errors::InvalidModelError, 'Paragraphs and headings, which delegate to the :p command, require at least one text string.'
|
31
|
+
end
|
32
|
+
model
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
#============== HEADINGS ============================
|
37
|
+
|
38
|
+
# All heading methods simply delegate to the paragraph
|
39
|
+
# model with an explicitly set style class.
|
40
|
+
#
|
41
|
+
[:h1, :h2, :h3, :h4, :h5, :h6].each do |cmd|
|
42
|
+
define_method "#{ cmd }" do |*args, &block|
|
43
|
+
options = Caracal::Utilities.extract_options!(args)
|
44
|
+
options.merge!({ style: style_id_for_header(cmd) })
|
45
|
+
p(args.first, options, &block)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
#-------------------------------------------------------------
|
51
|
+
# Private Methods
|
52
|
+
#-------------------------------------------------------------
|
53
|
+
private
|
54
|
+
|
55
|
+
# This method translates the html-like command to the
|
56
|
+
# corresponding style id.
|
57
|
+
#
|
58
|
+
def style_id_for_header(command)
|
59
|
+
case command.to_s
|
60
|
+
when 'h1' then 'Heading1'
|
61
|
+
when 'h2' then 'Heading2'
|
62
|
+
when 'h3' then 'Heading3'
|
63
|
+
when 'h4' then 'Heading4'
|
64
|
+
when 'h5' then 'Heading5'
|
65
|
+
when 'h6' then 'Heading6'
|
66
|
+
else 'Normal'
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,272 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'zip'
|
3
|
+
|
4
|
+
require 'caracal/core/bookmarks'
|
5
|
+
require 'caracal/core/custom_properties'
|
6
|
+
require 'caracal/core/file_name'
|
7
|
+
require 'caracal/core/fonts'
|
8
|
+
require 'caracal/core/iframes'
|
9
|
+
require 'caracal/core/ignorables'
|
10
|
+
require 'caracal/core/images'
|
11
|
+
require 'caracal/core/list_styles'
|
12
|
+
require 'caracal/core/lists'
|
13
|
+
require 'caracal/core/namespaces'
|
14
|
+
require 'caracal/core/page_breaks'
|
15
|
+
require 'caracal/core/page_numbers'
|
16
|
+
require 'caracal/core/page_settings'
|
17
|
+
require 'caracal/core/relationships'
|
18
|
+
require 'caracal/core/rules'
|
19
|
+
require 'caracal/core/styles'
|
20
|
+
require 'caracal/core/tables'
|
21
|
+
require 'caracal/core/text'
|
22
|
+
|
23
|
+
require 'caracal/renderers/app_renderer'
|
24
|
+
require 'caracal/renderers/content_types_renderer'
|
25
|
+
require 'caracal/renderers/core_renderer'
|
26
|
+
require 'caracal/renderers/custom_renderer'
|
27
|
+
require 'caracal/renderers/document_renderer'
|
28
|
+
require 'caracal/renderers/fonts_renderer'
|
29
|
+
require 'caracal/renderers/footer_renderer'
|
30
|
+
require 'caracal/renderers/numbering_renderer'
|
31
|
+
require 'caracal/renderers/package_relationships_renderer'
|
32
|
+
require 'caracal/renderers/relationships_renderer'
|
33
|
+
require 'caracal/renderers/settings_renderer'
|
34
|
+
require 'caracal/renderers/styles_renderer'
|
35
|
+
|
36
|
+
|
37
|
+
module Caracal
|
38
|
+
class Document
|
39
|
+
|
40
|
+
#------------------------------------------------------
|
41
|
+
# Configuration
|
42
|
+
#------------------------------------------------------
|
43
|
+
|
44
|
+
# mixins (order is important)
|
45
|
+
include Caracal::Core::CustomProperties
|
46
|
+
include Caracal::Core::FileName
|
47
|
+
include Caracal::Core::Ignorables
|
48
|
+
include Caracal::Core::Namespaces
|
49
|
+
include Caracal::Core::Relationships
|
50
|
+
|
51
|
+
include Caracal::Core::Fonts
|
52
|
+
include Caracal::Core::PageSettings
|
53
|
+
include Caracal::Core::PageNumbers
|
54
|
+
include Caracal::Core::Styles
|
55
|
+
include Caracal::Core::ListStyles
|
56
|
+
|
57
|
+
include Caracal::Core::Bookmarks
|
58
|
+
include Caracal::Core::IFrames
|
59
|
+
include Caracal::Core::Images
|
60
|
+
include Caracal::Core::Lists
|
61
|
+
include Caracal::Core::PageBreaks
|
62
|
+
include Caracal::Core::Rules
|
63
|
+
include Caracal::Core::Tables
|
64
|
+
include Caracal::Core::Text
|
65
|
+
|
66
|
+
|
67
|
+
#------------------------------------------------------
|
68
|
+
# Public Class Methods
|
69
|
+
#------------------------------------------------------
|
70
|
+
|
71
|
+
#============ OUTPUT ==================================
|
72
|
+
|
73
|
+
# This method renders a new Word document and returns it as a
|
74
|
+
# a string.
|
75
|
+
#
|
76
|
+
def self.render(f_name = nil, &block)
|
77
|
+
docx = new(f_name, &block)
|
78
|
+
buffer = docx.render
|
79
|
+
|
80
|
+
buffer.rewind
|
81
|
+
buffer.sysread
|
82
|
+
end
|
83
|
+
|
84
|
+
# This method renders a new Word document and saves it to the
|
85
|
+
# file system.
|
86
|
+
#
|
87
|
+
def self.save(f_name = nil, &block)
|
88
|
+
docx = new(f_name, &block)
|
89
|
+
docx.save
|
90
|
+
# buffer = docx.render
|
91
|
+
#
|
92
|
+
# File.open(docx.path, 'wb') { |f| f.write(buffer.string) }
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
|
97
|
+
#------------------------------------------------------
|
98
|
+
# Public Instance Methods
|
99
|
+
#------------------------------------------------------
|
100
|
+
|
101
|
+
# This method instantiates a new word document.
|
102
|
+
#
|
103
|
+
def initialize(name = nil, &block)
|
104
|
+
file_name(name)
|
105
|
+
|
106
|
+
page_size
|
107
|
+
page_margins top: 1440, bottom: 1440, left: 1440, right: 1440
|
108
|
+
page_numbers
|
109
|
+
|
110
|
+
[:font, :list_style, :namespace, :relationship, :style].each do |method|
|
111
|
+
collection = self.class.send("default_#{ method }s")
|
112
|
+
collection.each do |item|
|
113
|
+
send(method, item)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
if block_given?
|
118
|
+
(block.arity < 1) ? instance_eval(&block) : block[self]
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
|
123
|
+
#============ GETTERS =================================
|
124
|
+
|
125
|
+
# This method returns an array of models which constitute the
|
126
|
+
# set of instructions for producing the document content.
|
127
|
+
#
|
128
|
+
def contents
|
129
|
+
@contents ||= []
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
#============ RENDERING ===============================
|
134
|
+
|
135
|
+
# This method renders the word document instance into
|
136
|
+
# a string buffer. Order is important!
|
137
|
+
#
|
138
|
+
def render
|
139
|
+
buffer = ::Zip::OutputStream.write_buffer do |zip|
|
140
|
+
render_package_relationships(zip)
|
141
|
+
render_content_types(zip)
|
142
|
+
render_app(zip)
|
143
|
+
render_core(zip)
|
144
|
+
render_custom(zip)
|
145
|
+
render_fonts(zip)
|
146
|
+
render_footer(zip)
|
147
|
+
render_settings(zip)
|
148
|
+
render_styles(zip)
|
149
|
+
render_document(zip)
|
150
|
+
render_relationships(zip) # Must go here: Depends on document renderer
|
151
|
+
render_media(zip) # Must go here: Depends on document renderer
|
152
|
+
render_numbering(zip) # Must go here: Depends on document renderer
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
#============ SAVING ==================================
|
158
|
+
|
159
|
+
def save
|
160
|
+
buffer = render
|
161
|
+
|
162
|
+
File.open(path, 'wb') { |f| f.write(buffer.string) }
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
#------------------------------------------------------
|
167
|
+
# Private Instance Methods
|
168
|
+
#------------------------------------------------------
|
169
|
+
private
|
170
|
+
|
171
|
+
#============ RENDERERS ===============================
|
172
|
+
|
173
|
+
def render_app(zip)
|
174
|
+
content = ::Caracal::Renderers::AppRenderer.render(self)
|
175
|
+
|
176
|
+
zip.put_next_entry('docProps/app.xml')
|
177
|
+
zip.write(content)
|
178
|
+
end
|
179
|
+
|
180
|
+
def render_content_types(zip)
|
181
|
+
content = ::Caracal::Renderers::ContentTypesRenderer.render(self)
|
182
|
+
|
183
|
+
zip.put_next_entry('[Content_Types].xml')
|
184
|
+
zip.write(content)
|
185
|
+
end
|
186
|
+
|
187
|
+
def render_core(zip)
|
188
|
+
content = ::Caracal::Renderers::CoreRenderer.render(self)
|
189
|
+
|
190
|
+
zip.put_next_entry('docProps/core.xml')
|
191
|
+
zip.write(content)
|
192
|
+
end
|
193
|
+
|
194
|
+
def render_custom(zip)
|
195
|
+
content = ::Caracal::Renderers::CustomRenderer.render(self)
|
196
|
+
|
197
|
+
zip.put_next_entry('docProps/custom.xml')
|
198
|
+
zip.write(content)
|
199
|
+
end
|
200
|
+
|
201
|
+
def render_document(zip)
|
202
|
+
content = ::Caracal::Renderers::DocumentRenderer.render(self)
|
203
|
+
|
204
|
+
zip.put_next_entry('word/document.xml')
|
205
|
+
zip.write(content)
|
206
|
+
end
|
207
|
+
|
208
|
+
def render_fonts(zip)
|
209
|
+
content = ::Caracal::Renderers::FontsRenderer.render(self)
|
210
|
+
|
211
|
+
zip.put_next_entry('word/fontTable.xml')
|
212
|
+
zip.write(content)
|
213
|
+
end
|
214
|
+
|
215
|
+
def render_footer(zip)
|
216
|
+
content = ::Caracal::Renderers::FooterRenderer.render(self)
|
217
|
+
|
218
|
+
zip.put_next_entry('word/footer1.xml')
|
219
|
+
zip.write(content)
|
220
|
+
end
|
221
|
+
|
222
|
+
def render_media(zip)
|
223
|
+
images = relationships.select { |r| r.relationship_type == :image }
|
224
|
+
images.each do |rel|
|
225
|
+
if rel.relationship_data.to_s.size > 0
|
226
|
+
content = rel.relationship_data
|
227
|
+
else
|
228
|
+
content = open(rel.relationship_target).read
|
229
|
+
end
|
230
|
+
|
231
|
+
zip.put_next_entry("word/#{ rel.formatted_target }")
|
232
|
+
zip.write(content)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
def render_numbering(zip)
|
237
|
+
content = ::Caracal::Renderers::NumberingRenderer.render(self)
|
238
|
+
|
239
|
+
zip.put_next_entry('word/numbering.xml')
|
240
|
+
zip.write(content)
|
241
|
+
end
|
242
|
+
|
243
|
+
def render_package_relationships(zip)
|
244
|
+
content = ::Caracal::Renderers::PackageRelationshipsRenderer.render(self)
|
245
|
+
|
246
|
+
zip.put_next_entry('_rels/.rels')
|
247
|
+
zip.write(content)
|
248
|
+
end
|
249
|
+
|
250
|
+
def render_relationships(zip)
|
251
|
+
content = ::Caracal::Renderers::RelationshipsRenderer.render(self)
|
252
|
+
|
253
|
+
zip.put_next_entry('word/_rels/document.xml.rels')
|
254
|
+
zip.write(content)
|
255
|
+
end
|
256
|
+
|
257
|
+
def render_settings(zip)
|
258
|
+
content = ::Caracal::Renderers::SettingsRenderer.render(self)
|
259
|
+
|
260
|
+
zip.put_next_entry('word/settings.xml')
|
261
|
+
zip.write(content)
|
262
|
+
end
|
263
|
+
|
264
|
+
def render_styles(zip)
|
265
|
+
content = ::Caracal::Renderers::StylesRenderer.render(self)
|
266
|
+
|
267
|
+
zip.put_next_entry('word/styles.xml')
|
268
|
+
zip.write(content)
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
272
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Caracal
|
2
|
+
module Errors
|
3
|
+
# This error is raised whenever a model is created with
|
4
|
+
# invalid options.
|
5
|
+
#
|
6
|
+
InvalidModelError = Class.new(StandardError)
|
7
|
+
|
8
|
+
# This error is raised whenever a table model is passed an
|
9
|
+
# invalid data structure.
|
10
|
+
#
|
11
|
+
InvalidTableDataError = Class.new(StandardError)
|
12
|
+
|
13
|
+
# This error is raised if the document does not have a default
|
14
|
+
# style declared.
|
15
|
+
#
|
16
|
+
NoDefaultStyleError = Class.new(StandardError)
|
17
|
+
|
18
|
+
# This error is raised when a class lacks a valid reference to a
|
19
|
+
# Caracal document object.
|
20
|
+
#
|
21
|
+
NoDocumentError = Class.new(StandardError)
|
22
|
+
end
|
23
|
+
end
|