caracal 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +23 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +941 -0
  6. data/Rakefile +2 -0
  7. data/caracal.gemspec +27 -0
  8. data/lib/caracal.rb +31 -0
  9. data/lib/caracal/core/file_name.rb +39 -0
  10. data/lib/caracal/core/fonts.rb +75 -0
  11. data/lib/caracal/core/images.rb +37 -0
  12. data/lib/caracal/core/line_breaks.rb +29 -0
  13. data/lib/caracal/core/list_styles.rb +92 -0
  14. data/lib/caracal/core/lists.rb +57 -0
  15. data/lib/caracal/core/models/base_model.rb +51 -0
  16. data/lib/caracal/core/models/border_model.rb +120 -0
  17. data/lib/caracal/core/models/font_model.rb +64 -0
  18. data/lib/caracal/core/models/image_model.rb +118 -0
  19. data/lib/caracal/core/models/line_break_model.rb +15 -0
  20. data/lib/caracal/core/models/link_model.rb +65 -0
  21. data/lib/caracal/core/models/list_item_model.rb +105 -0
  22. data/lib/caracal/core/models/list_model.rb +130 -0
  23. data/lib/caracal/core/models/list_style_model.rb +129 -0
  24. data/lib/caracal/core/models/margin_model.rb +76 -0
  25. data/lib/caracal/core/models/page_break_model.rb +15 -0
  26. data/lib/caracal/core/models/page_number_model.rb +69 -0
  27. data/lib/caracal/core/models/page_size_model.rb +70 -0
  28. data/lib/caracal/core/models/paragraph_model.rb +141 -0
  29. data/lib/caracal/core/models/relationship_model.rb +108 -0
  30. data/lib/caracal/core/models/rule_model.rb +27 -0
  31. data/lib/caracal/core/models/style_model.rb +134 -0
  32. data/lib/caracal/core/models/table_cell_model.rb +155 -0
  33. data/lib/caracal/core/models/table_model.rb +206 -0
  34. data/lib/caracal/core/models/text_model.rb +92 -0
  35. data/lib/caracal/core/page_breaks.rb +29 -0
  36. data/lib/caracal/core/page_numbers.rb +51 -0
  37. data/lib/caracal/core/page_settings.rb +72 -0
  38. data/lib/caracal/core/relationships.rb +90 -0
  39. data/lib/caracal/core/rules.rb +35 -0
  40. data/lib/caracal/core/styles.rb +86 -0
  41. data/lib/caracal/core/tables.rb +41 -0
  42. data/lib/caracal/core/text.rb +73 -0
  43. data/lib/caracal/document.rb +242 -0
  44. data/lib/caracal/errors.rb +23 -0
  45. data/lib/caracal/renderers/app_renderer.rb +41 -0
  46. data/lib/caracal/renderers/content_types_renderer.rb +53 -0
  47. data/lib/caracal/renderers/core_renderer.rb +44 -0
  48. data/lib/caracal/renderers/document_renderer.rb +349 -0
  49. data/lib/caracal/renderers/fonts_renderer.rb +56 -0
  50. data/lib/caracal/renderers/footer_renderer.rb +69 -0
  51. data/lib/caracal/renderers/numbering_renderer.rb +87 -0
  52. data/lib/caracal/renderers/package_relationships_renderer.rb +50 -0
  53. data/lib/caracal/renderers/relationships_renderer.rb +48 -0
  54. data/lib/caracal/renderers/settings_renderer.rb +58 -0
  55. data/lib/caracal/renderers/styles_renderer.rb +163 -0
  56. data/lib/caracal/renderers/xml_renderer.rb +83 -0
  57. data/lib/caracal/version.rb +3 -0
  58. data/lib/tilt/caracal.rb +21 -0
  59. data/spec/lib/caracal/core/file_name_spec.rb +54 -0
  60. data/spec/lib/caracal/core/fonts_spec.rb +119 -0
  61. data/spec/lib/caracal/core/images_spec.rb +25 -0
  62. data/spec/lib/caracal/core/line_breaks_spec.rb +25 -0
  63. data/spec/lib/caracal/core/list_styles_spec.rb +121 -0
  64. data/spec/lib/caracal/core/lists_spec.rb +43 -0
  65. data/spec/lib/caracal/core/models/base_model_spec.rb +38 -0
  66. data/spec/lib/caracal/core/models/border_model_spec.rb +159 -0
  67. data/spec/lib/caracal/core/models/font_model_spec.rb +92 -0
  68. data/spec/lib/caracal/core/models/image_model_spec.rb +192 -0
  69. data/spec/lib/caracal/core/models/line_break_model_spec.rb +21 -0
  70. data/spec/lib/caracal/core/models/link_model_spec.rb +139 -0
  71. data/spec/lib/caracal/core/models/list_item_model_spec.rb +190 -0
  72. data/spec/lib/caracal/core/models/list_model_spec.rb +178 -0
  73. data/spec/lib/caracal/core/models/list_style_model_spec.rb +212 -0
  74. data/spec/lib/caracal/core/models/margin_model_spec.rb +111 -0
  75. data/spec/lib/caracal/core/models/page_break_model_spec.rb +21 -0
  76. data/spec/lib/caracal/core/models/page_number_model_spec.rb +101 -0
  77. data/spec/lib/caracal/core/models/page_size_model_spec.rb +91 -0
  78. data/spec/lib/caracal/core/models/paragraph_model_spec.rb +162 -0
  79. data/spec/lib/caracal/core/models/relationship_model_spec.rb +183 -0
  80. data/spec/lib/caracal/core/models/rule_model_spec.rb +108 -0
  81. data/spec/lib/caracal/core/models/style_model_spec.rb +187 -0
  82. data/spec/lib/caracal/core/models/table_cell_model_spec.rb +221 -0
  83. data/spec/lib/caracal/core/models/table_model_spec.rb +222 -0
  84. data/spec/lib/caracal/core/models/text_model_spec.rb +132 -0
  85. data/spec/lib/caracal/core/page_breaks_spec.rb +25 -0
  86. data/spec/lib/caracal/core/page_numbers_spec.rb +80 -0
  87. data/spec/lib/caracal/core/page_settings_spec.rb +143 -0
  88. data/spec/lib/caracal/core/relationships_spec.rb +119 -0
  89. data/spec/lib/caracal/core/rules_spec.rb +25 -0
  90. data/spec/lib/caracal/core/styles_spec.rb +129 -0
  91. data/spec/lib/caracal/core/tables_spec.rb +25 -0
  92. data/spec/lib/caracal/core/text_spec.rb +52 -0
  93. data/spec/lib/caracal/errors_spec.rb +10 -0
  94. data/spec/spec_helper.rb +8 -0
  95. metadata +245 -0
@@ -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
@@ -0,0 +1,41 @@
1
+ require 'nokogiri'
2
+
3
+ require 'caracal/renderers/xml_renderer'
4
+
5
+
6
+ module Caracal
7
+ module Renderers
8
+ class AppRenderer < XmlRenderer
9
+
10
+ #-------------------------------------------------------------
11
+ # Public Methods
12
+ #-------------------------------------------------------------
13
+
14
+ # This method produces the xml required for the `docProps/app.xml`
15
+ # sub-document.
16
+ #
17
+ def to_xml
18
+ builder = ::Nokogiri::XML::Builder.with(declaration_xml) do |xml|
19
+ xml.send 'Properties', root_options do
20
+ xml.send 'Application', 'Caracal'
21
+ end
22
+ end
23
+ builder.to_xml(save_options)
24
+ end
25
+
26
+
27
+ #-------------------------------------------------------------
28
+ # Private Methods
29
+ #-------------------------------------------------------------
30
+ private
31
+
32
+ def root_options
33
+ {
34
+ 'xmlns' => 'http://schemas.openxmlformats.org/officeDocument/2006/extended-properties',
35
+ 'xmlns:vt' => 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes'
36
+ }
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,53 @@
1
+ require 'nokogiri'
2
+
3
+ require 'caracal/renderers/xml_renderer'
4
+
5
+
6
+ module Caracal
7
+ module Renderers
8
+ class ContentTypesRenderer < XmlRenderer
9
+
10
+ #-------------------------------------------------------------
11
+ # Public Methods
12
+ #-------------------------------------------------------------
13
+
14
+ # This method produces the xml required for the `_[ContentTypes].xml`
15
+ # sub-document.
16
+ #
17
+ def to_xml
18
+ builder = ::Nokogiri::XML::Builder.with(declaration_xml) do |xml|
19
+ xml.send 'Types', root_options do
20
+ xml.send 'Default', { 'Extension' => 'gif', 'ContentType' => 'image/gif' }
21
+ xml.send 'Default', { 'Extension' => 'jpeg', 'ContentType' => 'image/jpeg' }
22
+ xml.send 'Default', { 'Extension' => 'jpg', 'ContentType' => 'image/jpeg' }
23
+ xml.send 'Default', { 'Extension' => 'png', 'ContentType' => 'image/png' }
24
+ xml.send 'Default', { 'Extension' => 'rels', 'ContentType' => 'application/vnd.openxmlformats-package.relationships+xml' }
25
+ xml.send 'Default', { 'Extension' => 'xml', 'ContentType' => 'application/xml' }
26
+ xml.send 'Override', { 'PartName' => '/docProps/app.xml', 'ContentType' => 'application/vnd.openxmlformats-officedocument.extended-properties+xml' }
27
+ xml.send 'Override', { 'PartName' => '/docProps/core.xml', 'ContentType' => 'application/vnd.openxmlformats-package.core-properties+xml' }
28
+ xml.send 'Override', { 'PartName' => '/word/document.xml', 'ContentType' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml' }
29
+ xml.send 'Override', { 'PartName' => '/word/footer1.xml', 'ContentType' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml' }
30
+ xml.send 'Override', { 'PartName' => '/word/fontTable.xml', 'ContentType' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml' }
31
+ xml.send 'Override', { 'PartName' => '/word/numbering.xml', 'ContentType' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml' }
32
+ xml.send 'Override', { 'PartName' => '/word/settings.xml', 'ContentType' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml' }
33
+ xml.send 'Override', { 'PartName' => '/word/styles.xml', 'ContentType' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml' }
34
+ end
35
+ end
36
+ builder.to_xml(save_options)
37
+ end
38
+
39
+
40
+ #-------------------------------------------------------------
41
+ # Private Methods
42
+ #-------------------------------------------------------------
43
+ private
44
+
45
+ def root_options
46
+ {
47
+ 'xmlns' => 'http://schemas.openxmlformats.org/package/2006/content-types'
48
+ }
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,44 @@
1
+ require 'nokogiri'
2
+
3
+ require 'caracal/renderers/xml_renderer'
4
+
5
+
6
+ module Caracal
7
+ module Renderers
8
+ class CoreRenderer < XmlRenderer
9
+
10
+ #-------------------------------------------------------------
11
+ # Public Methods
12
+ #-------------------------------------------------------------
13
+
14
+ # This method produces the xml required for the `docProps/core.xml`
15
+ # sub-document.
16
+ #
17
+ def to_xml
18
+ builder = ::Nokogiri::XML::Builder.with(declaration_xml) do |xml|
19
+ xml.send 'cp:coreProperties', root_options do
20
+ xml['dc'].title document.name
21
+ end
22
+ end
23
+ builder.to_xml(save_options)
24
+ end
25
+
26
+
27
+ #-------------------------------------------------------------
28
+ # Private Methods
29
+ #-------------------------------------------------------------
30
+ private
31
+
32
+ def root_options
33
+ {
34
+ 'xmlns:cp' => 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties',
35
+ 'xmlns:dc' => 'http://purl.org/dc/elements/1.1/',
36
+ 'xmlns:dcterms' => 'http://purl.org/dc/terms/',
37
+ 'xmlns:dcmitype' => 'http://purl.org/dc/dcmitype/',
38
+ 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance'
39
+ }
40
+ end
41
+
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,349 @@
1
+ require 'nokogiri'
2
+
3
+ require 'caracal/renderers/xml_renderer'
4
+ require 'caracal/errors'
5
+
6
+
7
+ module Caracal
8
+ module Renderers
9
+ class DocumentRenderer < XmlRenderer
10
+
11
+ #-------------------------------------------------------------
12
+ # Public Methods
13
+ #-------------------------------------------------------------
14
+
15
+ # This method produces the xml required for the `word/document.xml`
16
+ # sub-document.
17
+ #
18
+ def to_xml
19
+ builder = ::Nokogiri::XML::Builder.with(declaration_xml) do |xml|
20
+ xml.send 'w:document', root_options do
21
+ xml.send 'w:background', { 'w:color' => 'FFFFFF' }
22
+ xml.send 'w:body' do
23
+
24
+ #============= CONTENTS ===================================
25
+
26
+ document.contents.each do |model|
27
+ method = render_method_for_model(model)
28
+ send(method, xml, model)
29
+ end
30
+
31
+ #============= PAGE SETTINGS ==============================
32
+
33
+ xml.send 'w:sectPr' do
34
+ if document.page_number_show
35
+ if rel = document.find_relationship('footer1.xml')
36
+ xml.send 'w:footerReference', { 'r:id' => rel.formatted_id, 'w:type' => 'default' }
37
+ end
38
+ end
39
+ xml.send 'w:pgSz', page_size_options
40
+ xml.send 'w:pgMar', page_margin_options
41
+ end
42
+
43
+ end
44
+ end
45
+ end
46
+ builder.to_xml(save_options)
47
+ end
48
+
49
+
50
+ #-------------------------------------------------------------
51
+ # Private Methods
52
+ #-------------------------------------------------------------
53
+ private
54
+
55
+ #============= COMMON RENDERERS ==========================
56
+
57
+ # This method converts a model class name to a rendering
58
+ # function on this class (e.g., Caracal::Core::Models::ParagraphModel
59
+ # translates to `render_paragraph`).
60
+ #
61
+ def render_method_for_model(model)
62
+ type = model.class.name.split('::').last.downcase.gsub('model', '')
63
+ "render_#{ type }"
64
+ end
65
+
66
+ # This method renders a standard node of run properties based on the
67
+ # model's attributes.
68
+ #
69
+ def render_run_attributes(xml, model)
70
+ if model.respond_to? :run_attributes
71
+ attrs = model.run_attributes.delete_if { |k, v| v.nil? }
72
+
73
+ xml.send 'w:rPr' do
74
+ unless attrs.empty?
75
+ xml.send 'w:rStyle', { 'w:val' => attrs[:style] } unless attrs[:style].nil?
76
+ xml.send 'w:color', { 'w:val' => attrs[:color] } unless attrs[:color].nil?
77
+ xml.send 'w:sz', { 'w:val' => attrs[:size] } unless attrs[:size].nil?
78
+ xml.send 'w:b', { 'w:val' => (attrs[:bold] ? '1' : '0') } unless attrs[:bold].nil?
79
+ xml.send 'w:i', { 'w:val' => (attrs[:italic] ? '1' : '0') } unless attrs[:italic].nil?
80
+ xml.send 'w:u', { 'w:val' => (attrs[:underline] ? 'single' : 'none') } unless attrs[:underline].nil?
81
+ end
82
+ xml.send 'w:rtl', { 'w:val' => '0' }
83
+ end
84
+ end
85
+ end
86
+
87
+
88
+ #============= MODEL RENDERERS ===========================
89
+
90
+ def render_image(xml, model)
91
+ unless ds = document.default_style
92
+ raise Caracal::Errors::NoDefaultStyleError 'Document must declare a default paragraph style.'
93
+ end
94
+
95
+ rel = document.relationship({ target: model.image_url, type: :image })
96
+ rel_id = rel.relationship_id
97
+ rel_name = rel.formatted_target
98
+
99
+ xml.send 'w:p', paragraph_options do
100
+ xml.send 'w:pPr' do
101
+ xml.send 'w:spacing', { 'w:lineRule' => 'auto', 'w:line' => ds.style_line }
102
+ xml.send 'w:contextualSpacing', { 'w:val' => '0' }
103
+ xml.send 'w:jc', { 'w:val' => model.image_align.to_s }
104
+ xml.send 'w:rPr'
105
+ end
106
+ xml.send 'w:r', run_options do
107
+ xml.send 'w:drawing' do
108
+ xml.send 'wp:inline', { distR: model.formatted_right, distT: model.formatted_top, distB: model.formatted_bottom, distL: model.formatted_left } do
109
+ xml.send 'wp:extent', { cx: model.formatted_width, cy: model.formatted_height }
110
+ xml.send 'wp:effectExtent', { t: 0, b: 0, r: 0, l: 0 }
111
+ xml.send 'wp:docPr', { id: rel_id, name: rel_name }
112
+ xml.send 'a:graphic' do
113
+ xml.send 'a:graphicData', { uri: 'http://schemas.openxmlformats.org/drawingml/2006/picture' } do
114
+ xml.send 'pic:pic' do
115
+ xml.send 'pic:nvPicPr' do
116
+ xml.send 'pic:cNvPr', { id: rel_id, name: rel_name }
117
+ xml.send 'pic:cNvPicPr', { preferRelativeSize: 0 }
118
+ end
119
+ xml.send 'pic:blipFill' do
120
+ xml.send 'a:blip', { 'r:embed' => rel.formatted_id }
121
+ xml.send 'a:srcRect', { t: 0, b: 0, r: 0, l: 0 }
122
+ xml.send 'a:stretch' do
123
+ xml.send 'a:fillRect'
124
+ end
125
+ end
126
+ xml.send 'pic:spPr' do
127
+ xml.send 'a:xfrm' do
128
+ xml.send 'a:ext', { cx: model.formatted_width, cy: model.formatted_height }
129
+ end
130
+ xml.send 'a:prstGeom', { prst: 'rect' }
131
+ xml.send 'a:ln'
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+ xml.send 'w:r', run_options do
140
+ xml.send 'w:rPr' do
141
+ xml.send 'w:rtl', { 'w:val' => '0' }
142
+ end
143
+ end
144
+ end
145
+ end
146
+
147
+ def render_linebreak(xml, model)
148
+ xml.send 'w:p', paragraph_options do
149
+ xml.send 'w:pPr' do
150
+ xml.send 'w:contextualSpacing', { 'w:val' => '0' }
151
+ end
152
+ xml.send 'w:r', run_options do
153
+ xml.send 'w:rtl', { 'w:val' => '0' }
154
+ end
155
+ end
156
+ end
157
+
158
+ def render_link(xml, model)
159
+ rel = document.relationship({ target: model.link_href, type: :link })
160
+
161
+ xml.send 'w:hyperlink', { 'r:id' => rel.formatted_id } do
162
+ xml.send 'w:r', run_options do
163
+ render_run_attributes(xml, model)
164
+ xml.send 'w:t', { 'xml:space' => 'preserve' }, model.link_content
165
+ end
166
+ end
167
+ end
168
+
169
+ def render_list(xml, model)
170
+ if model.list_level == 0
171
+ document.toplevel_lists << model
172
+ list_num = document.toplevel_lists.length # numbering uses 1-based index
173
+ end
174
+
175
+ model.recursive_items.each do |item|
176
+ render_listitem(xml, item, list_num)
177
+ end
178
+ end
179
+
180
+ def render_listitem(xml, model, list_num)
181
+ ls = document.find_list_style(model.list_item_type, model.list_item_level)
182
+ hanging = ls.style_left.to_i - ls.style_line.to_i - 1
183
+
184
+ xml.send 'w:p', paragraph_options do
185
+ xml.send 'w:pPr' do
186
+ xml.send 'w:numPr' do
187
+ xml.send 'w:ilvl', { 'w:val' => model.list_item_level }
188
+ xml.send 'w:numId', { 'w:val' => list_num }
189
+ end
190
+ xml.send 'w:ind', { 'w:left' => ls.style_left, 'w:hanging' => hanging }
191
+ xml.send 'w:contextualSpacing', { 'w:val' => '1' }
192
+ xml.send 'w:rPr' do
193
+ xml.send 'w:u', { 'w:val' => 'none' }
194
+ end
195
+ end
196
+ model.runs.each do |run|
197
+ method = render_method_for_model(run)
198
+ send(method, xml, run)
199
+ end
200
+ end
201
+ end
202
+
203
+ def render_pagebreak(xml, model)
204
+ xml.send 'w:p', paragraph_options do
205
+ xml.send 'w:r', run_options do
206
+ xml.send 'w:br', { 'w:type' => 'page' }
207
+ end
208
+ end
209
+ end
210
+
211
+ def render_paragraph(xml, model)
212
+ run_props = [:color, :size, :bold, :italic, :underline].map { |m| model.send("paragraph_#{ m }") }.compact
213
+
214
+ xml.send 'w:p', paragraph_options do
215
+ xml.send 'w:pPr' do
216
+ xml.send 'w:pStyle', { 'w:val' => model.paragraph_style } unless model.paragraph_style.nil?
217
+ xml.send 'w:contextualSpacing', { 'w:val' => '0' }
218
+ xml.send 'w:jc', { 'w:val' => model.paragraph_align } unless model.paragraph_align.nil?
219
+ render_run_attributes(xml, model)
220
+ end
221
+ model.runs.each do |run|
222
+ method = render_method_for_model(run)
223
+ send(method, xml, run)
224
+ end
225
+ end
226
+ end
227
+
228
+ def render_rule(xml, model)
229
+ options = { 'w:color' => model.rule_color, 'w:sz' => model.rule_size, 'w:val' => model.rule_line, 'w:space' => model.rule_spacing }
230
+
231
+ xml.send 'w:p', paragraph_options do
232
+ xml.send 'w:pPr' do
233
+ xml.send 'w:pBdr' do
234
+ xml.send 'w:top', options
235
+ end
236
+ end
237
+ end
238
+ end
239
+
240
+ def render_text(xml, model)
241
+ xml.send 'w:r', run_options do
242
+ render_run_attributes(xml, model)
243
+ xml.send 'w:t', { 'xml:space' => 'preserve' }, model.text_content
244
+ end
245
+ end
246
+
247
+ def render_table(xml, model)
248
+ xml.send 'w:tbl' do
249
+ xml.send 'w:tblPr' do
250
+ xml.send 'w:tblStyle', { 'w:val' => 'DefaultTable' }
251
+ xml.send 'w:bidiVisual', { 'w:val' => '0' }
252
+ xml.send 'w:tblW', { 'w:w' => model.table_width.to_f, 'w:type' => 'dxa' }
253
+ xml.send 'w:tblInd', { 'w:w' => '0.0', 'w:type' => 'dxa' }
254
+ xml.send 'w:jc', { 'w:val' => model.table_align }
255
+ xml.send 'w:tblBorders' do
256
+ %w(top left bottom right horizontal vertical).each do |m|
257
+ size = model.send("table_border_#{ m }_size")
258
+ if size > 0
259
+ options = {
260
+ 'w:color' => model.send("table_border_#{ m }_color"),
261
+ 'w:val' => model.send("table_border_#{ m }_line"),
262
+ 'w:sz' => size,
263
+ 'w:space' => model.send("table_border_#{ m }_spacing")
264
+ }
265
+ xml.send "w:#{ Caracal::Core::Models::BorderModel.formatted_type(m) }", options
266
+ end
267
+ end
268
+ end
269
+ xml.send 'w:tblLayout', { 'w:type' => 'fixed' }
270
+ xml.send 'w:tblLook', { 'w:val' => '0600' }
271
+ end
272
+ xml.send 'w:tblGrid' do
273
+ model.rows.first.each do |tc|
274
+ xml.send 'w:gridCol', { 'w:w' => tc.cell_width }
275
+ end
276
+ xml.send 'w:tblGridChange', { 'w:id' => '0' } do
277
+ xml.send 'w:tblGrid' do
278
+ model.rows.first.each do |tc|
279
+ xml.send 'w:gridCol', { 'w:w' => tc.cell_width }
280
+ end
281
+ end
282
+ end
283
+ end
284
+ model.rows.each do |row|
285
+ xml.send 'w:tr' do
286
+ row.each do |tc|
287
+ xml.send 'w:tc' do
288
+ xml.send 'tcPr' do
289
+ xml.send 'w:shd', { 'w:fill' => tc.cell_background }
290
+ xml.send 'w:tcMar' do
291
+ %w(top left bottom right).each do |d|
292
+ xml.send "w:#{ d }", { 'w:w' => tc.send("cell_margin_#{ d }").to_f, 'w:type' => 'dxa' }
293
+ end
294
+ end
295
+ end
296
+ tc.contents.each do |m|
297
+ method = render_method_for_model(m)
298
+ send(method, xml, m)
299
+ end
300
+ end
301
+ end
302
+ end
303
+ end
304
+ end
305
+ end
306
+
307
+
308
+
309
+ #============= OPTIONS ===================================
310
+
311
+ def root_options
312
+ {
313
+ 'xmlns:mc' => 'http://schemas.openxmlformats.org/markup-compatibility/2006',
314
+ 'xmlns:o' => 'urn:schemas-microsoft-com:office:office',
315
+ 'xmlns:r' => 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
316
+ 'xmlns:m' => 'http://schemas.openxmlformats.org/officeDocument/2006/math',
317
+ 'xmlns:v' => 'urn:schemas-microsoft-com:vml',
318
+ 'xmlns:wp' => 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing',
319
+ 'xmlns:w10' => 'urn:schemas-microsoft-com:office:word',
320
+ 'xmlns:w' => 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',
321
+ 'xmlns:wne' => 'http://schemas.microsoft.com/office/word/2006/wordml',
322
+ 'xmlns:sl' => 'http://schemas.openxmlformats.org/schemaLibrary/2006/main',
323
+ 'xmlns:a' => 'http://schemas.openxmlformats.org/drawingml/2006/main',
324
+ 'xmlns:pic' => 'http://schemas.openxmlformats.org/drawingml/2006/picture',
325
+ 'xmlns:c' => 'http://schemas.openxmlformats.org/drawingml/2006/chart',
326
+ 'xmlns:lc' => 'http://schemas.openxmlformats.org/drawingml/2006/lockedCanvas',
327
+ 'xmlns:dgm' => 'http://schemas.openxmlformats.org/drawingml/2006/diagram'
328
+ }
329
+ end
330
+
331
+ def page_margin_options
332
+ {
333
+ 'w:top' => document.page_margin_top,
334
+ 'w:bottom' => document.page_margin_bottom,
335
+ 'w:left' => document.page_margin_left,
336
+ 'w:right' => document.page_margin_right
337
+ }
338
+ end
339
+
340
+ def page_size_options
341
+ {
342
+ 'w:w' => document.page_width,
343
+ 'w:h' => document.page_height
344
+ }
345
+ end
346
+
347
+ end
348
+ end
349
+ end