caracal 0.1.0

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.
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,206 @@
1
+ require 'caracal/core/models/base_model'
2
+ require 'caracal/core/models/border_model'
3
+ require 'caracal/core/models/table_cell_model'
4
+
5
+
6
+ module Caracal
7
+ module Core
8
+ module Models
9
+
10
+ # This class handles block options passed to the table
11
+ # method.
12
+ #
13
+ class TableModel < BaseModel
14
+
15
+ #-------------------------------------------------------------
16
+ # Configuration
17
+ #-------------------------------------------------------------
18
+
19
+ # constants
20
+ const_set(:DEFAULT_TABLE_ALIGN, :center) # weirdly, works better w/ full width
21
+ const_set(:DEFAULT_TABLE_BORDER_COLOR, 'auto')
22
+ const_set(:DEFAULT_TABLE_BORDER_LINE, :single)
23
+ const_set(:DEFAULT_TABLE_BORDER_SIZE, 0) # units in 1/8 points
24
+ const_set(:DEFAULT_TABLE_BORDER_SPACING, 0)
25
+
26
+ # accessors
27
+ attr_reader :table_align
28
+ attr_reader :table_width
29
+ attr_reader :table_border_color
30
+ attr_reader :table_border_line
31
+ attr_reader :table_border_size
32
+ attr_reader :table_border_spacing
33
+ attr_reader :table_border_top # returns border model
34
+ attr_reader :table_border_bottom # returns border model
35
+ attr_reader :table_border_left # returns border model
36
+ attr_reader :table_border_right # returns border model
37
+ attr_reader :table_border_horizontal # returns border model
38
+ attr_reader :table_border_vertical # returns border model
39
+
40
+ # initialization
41
+ def initialize(**options, &block)
42
+ @table_align = DEFAULT_TABLE_ALIGN
43
+ @table_border_color = DEFAULT_TABLE_BORDER_COLOR
44
+ @table_border_line = DEFAULT_TABLE_BORDER_LINE
45
+ @table_border_size = DEFAULT_TABLE_BORDER_SIZE
46
+ @table_border_spacing = DEFAULT_TABLE_BORDER_SPACING
47
+
48
+ super options, &block
49
+ end
50
+
51
+
52
+ #-------------------------------------------------------------
53
+ # Public Methods
54
+ #-------------------------------------------------------------
55
+
56
+ #=============== DATA ACCESSORS =======================
57
+
58
+ def cells
59
+ rows.flatten
60
+ end
61
+
62
+ def cols
63
+ rows.reduce([]) do |array, row|
64
+ row.each_with_index do |cell, index|
65
+ array[index] = [] if array[index].nil?
66
+ array[index] << cell
67
+ end
68
+ array
69
+ end
70
+ end
71
+
72
+ def rows
73
+ @table_data || [[]]
74
+ end
75
+
76
+
77
+ #=============== STYLES ===============================
78
+
79
+ # This method sets explicit widths on all wrapped cells
80
+ # that do not already have widths asided.
81
+ #
82
+ def calculate_width(container_width)
83
+ width(container_width) unless table_width.to_i > 0
84
+
85
+ cells.each { |c| c.calculate_width(default_cell_width) }
86
+ end
87
+
88
+ # This method allows tables to be styled several cells
89
+ # at a time.
90
+ #
91
+ # For example, this would style a header row.
92
+ #
93
+ # docx.table data do |t|
94
+ # t.cell_style t.rows[0], background: '3366cc', color: 'ffffff', bold: true
95
+ # end
96
+ #
97
+ def cell_style(models, **options)
98
+ [models].flatten.each do |m|
99
+ m.apply_styles(options)
100
+ end
101
+ end
102
+
103
+
104
+ #=============== GETTERS ==============================
105
+
106
+ # border attrs
107
+ [:top, :bottom, :left, :right, :horizontal, :vertical].each do |m|
108
+ [:color, :line, :size, :spacing].each do |attr|
109
+ define_method "table_border_#{ m }_#{ attr }" do
110
+ model = send("table_border_#{ m }")
111
+ value = (model) ? model.send("border_#{ attr }") : send("table_border_#{ attr }")
112
+ end
113
+ end
114
+ define_method "table_border_#{ m }_total_size" do
115
+ model = send("table_border_#{ m }")
116
+ value = (model) ? model.total_size : table_border_size + (2 * table_border_spacing)
117
+ end
118
+ end
119
+
120
+
121
+ #=============== SETTERS ==============================
122
+
123
+ # integers
124
+ [:border_size, :border_spacing, :width].each do |m|
125
+ define_method "#{ m }" do |value|
126
+ instance_variable_set("@table_#{ m }", value.to_i)
127
+ end
128
+ end
129
+
130
+ # models
131
+ [:top, :bottom, :left, :right, :horizontal, :vertical].each do |m|
132
+ define_method "border_#{ m }" do |**options, &block|
133
+ options.merge!({ type: m })
134
+ instance_variable_set("@table_border_#{ m }", Caracal::Core::Models::BorderModel.new(options, &block))
135
+ end
136
+ end
137
+
138
+ # strings
139
+ [:border_color].each do |m|
140
+ define_method "#{ m }" do |value|
141
+ instance_variable_set("@table_#{ m }", value.to_s)
142
+ end
143
+ end
144
+
145
+ # symbols
146
+ [:border_line, :align].each do |m|
147
+ define_method "#{ m }" do |value|
148
+ instance_variable_set("@table_#{ m }", value.to_s.to_sym)
149
+ end
150
+ end
151
+
152
+ # .data
153
+ def data(value)
154
+ begin
155
+ @table_data = value.map do |data_row|
156
+ data_row.map do |data_cell|
157
+ case data_cell.class.name
158
+ when 'Caracal::Core::Models::TableCellModel'
159
+ data_cell
160
+ when 'Hash'
161
+ Caracal::Core::Models::TableCellModel.new(data_cell)
162
+ when 'Proc'
163
+ Caracal::Core::Models::TableCellModel.new(&data_cell)
164
+ when 'String'
165
+ Caracal::Core::Models::TableCellModel.new({ content: data_cell.to_s })
166
+ end
167
+ end
168
+ end
169
+ rescue
170
+ raise Caracal::Errors::InvalidTableDataError, 'Table data must be a two-dimensional array.'
171
+ end
172
+ end
173
+
174
+
175
+ #=============== VALIDATION ==============================
176
+
177
+ def valid?
178
+ cells.first.is_a?(Caracal::Core::Models::TableCellModel)
179
+ end
180
+
181
+
182
+ #-------------------------------------------------------------
183
+ # Private Instance Methods
184
+ #-------------------------------------------------------------
185
+ private
186
+
187
+ def default_cell_width
188
+ cell_widths = rows.first.map { |c| c.cell_width.to_i }
189
+ remaining_width = table_width - cell_widths.reduce(&:+).to_i
190
+ remaining_cols = cols.size - cell_widths.reject { |w| w == 0 }.size
191
+ default_width = (remaining_cols == 0) ? 0 : (remaining_width / remaining_cols)
192
+ end
193
+
194
+ def option_keys
195
+ k = []
196
+ k << [:data, :align, :width]
197
+ k << [:border_color, :border_line, :border_size, :border_spacing]
198
+ k << [:border_bottom, :border_left, :border_right, :border_top, :border_horizontal, :border_vertical]
199
+ k.flatten
200
+ end
201
+
202
+ end
203
+
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,92 @@
1
+ require 'caracal/core/models/base_model'
2
+
3
+
4
+ module Caracal
5
+ module Core
6
+ module Models
7
+
8
+ # This class encapsulates the logic needed to store and manipulate
9
+ # text data.
10
+ #
11
+ class TextModel < BaseModel
12
+
13
+ #-------------------------------------------------------------
14
+ # Configuration
15
+ #-------------------------------------------------------------
16
+
17
+ # accessors
18
+ attr_reader :text_content
19
+ attr_reader :text_style
20
+ attr_reader :text_color
21
+ attr_reader :text_size
22
+ attr_reader :text_bold
23
+ attr_reader :text_italic
24
+ attr_reader :text_underline
25
+
26
+
27
+
28
+ #-------------------------------------------------------------
29
+ # Public Instance Methods
30
+ #-------------------------------------------------------------
31
+
32
+ #=============== GETTERS ==============================
33
+
34
+ # .run_attributes
35
+ def run_attributes
36
+ {
37
+ style: text_style,
38
+ color: text_color,
39
+ size: text_size,
40
+ bold: text_bold,
41
+ italic: text_italic,
42
+ underline: text_underline,
43
+ }
44
+ end
45
+
46
+
47
+ #=============== SETTERS ==============================
48
+
49
+ # booleans
50
+ [:bold, :italic, :underline].each do |m|
51
+ define_method "#{ m }" do |value|
52
+ instance_variable_set("@text_#{ m }", !!value)
53
+ end
54
+ end
55
+
56
+ # integers
57
+ [:size].each do |m|
58
+ define_method "#{ m }" do |value|
59
+ instance_variable_set("@text_#{ m }", value.to_i)
60
+ end
61
+ end
62
+
63
+ # strings
64
+ [:color, :content, :style].each do |m|
65
+ define_method "#{ m }" do |value|
66
+ instance_variable_set("@text_#{ m }", value.to_s)
67
+ end
68
+ end
69
+
70
+
71
+ #=============== VALIDATION ===========================
72
+
73
+ def valid?
74
+ a = [:content]
75
+ a.map { |m| send("text_#{ m }") }.compact.size == a.size
76
+ end
77
+
78
+
79
+ #-------------------------------------------------------------
80
+ # Private Instance Methods
81
+ #-------------------------------------------------------------
82
+ private
83
+
84
+ def option_keys
85
+ [:content, :style, :color, :size, :bold, :italic, :underline]
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,29 @@
1
+ require 'caracal/core/models/page_break_model'
2
+
3
+
4
+ module Caracal
5
+ module Core
6
+
7
+ # This module encapsulates all the functionality related to adding page
8
+ # breaks to the document.
9
+ #
10
+ module PageBreaks
11
+ def self.included(base)
12
+ base.class_eval do
13
+
14
+ #-------------------------------------------------------------
15
+ # Public Methods
16
+ #-------------------------------------------------------------
17
+
18
+ def page
19
+ model = Caracal::Core::Models::PageBreakModel.new()
20
+ contents << model
21
+ model
22
+ end
23
+
24
+ end
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,51 @@
1
+ require 'caracal/core/models/page_number_model'
2
+ require 'caracal/errors'
3
+
4
+
5
+ module Caracal
6
+ module Core
7
+
8
+ # This module encapsulates all the functionality related to setting the
9
+ # document's page number behavior.
10
+ #
11
+ module PageNumbers
12
+ def self.included(base)
13
+ base.class_eval do
14
+
15
+ #-------------------------------------------------------------
16
+ # Configuration
17
+ #-------------------------------------------------------------
18
+
19
+ # constants
20
+ const_set(:DEFAULT_PAGE_NUMBER_ALIGN, :center)
21
+
22
+ # accessors
23
+ attr_reader :page_number_show
24
+ attr_reader :page_number_align
25
+
26
+
27
+ #-------------------------------------------------------------
28
+ # Public Methods
29
+ #-------------------------------------------------------------
30
+
31
+ # This method controls whether and how page numbers are displayed
32
+ # on the document.
33
+ #
34
+ def page_numbers(show = nil, **options, &block)
35
+ options.merge!({ show: !!show })
36
+ model = Caracal::Core::Models::PageNumberModel.new(options, &block)
37
+
38
+ if model.valid?
39
+ @page_number_show = model.page_number_show
40
+ @page_number_align = model.page_number_align
41
+ else
42
+ raise Caracal::Errors::InvalidModelError, 'page_numbers :align parameter must be :left, :center, or :right'
43
+ end
44
+ end
45
+
46
+ end
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,72 @@
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_height
23
+ attr_reader :page_margin_top
24
+ attr_reader :page_margin_bottom
25
+ attr_reader :page_margin_left
26
+ attr_reader :page_margin_right
27
+
28
+
29
+ #-------------------------------------------------------------
30
+ # Public Methods
31
+ #-------------------------------------------------------------
32
+
33
+ # This method controls the physical margins of the printed page. Defaults
34
+ # to 1in on each side.
35
+ #
36
+ def page_margins(**options, &block)
37
+ model = Caracal::Core::Models::MarginModel.new(options, &block)
38
+
39
+ if model.valid?
40
+ if (model.margin_top + model.margin_bottom < page_height) && (model.margin_left + model.margin_right < page_width)
41
+ @page_margin_top = model.margin_top
42
+ @page_margin_bottom = model.margin_bottom
43
+ @page_margin_left = model.margin_left
44
+ @page_margin_right = model.margin_right
45
+ else
46
+ raise Caracal::Errors::InvalidModelError, 'page_margins method requires margins to be smaller than the page size.'
47
+ end
48
+ else
49
+ raise Caracal::Errors::InvalidModelError, 'page_margins method requires non-zero :top, :bottom, :left, and :right options.'
50
+ end
51
+ end
52
+
53
+ # This method controls the physical width and height of the printed page. Defaults
54
+ # to US standard A4 portrait size.
55
+ #
56
+ def page_size(**options, &block)
57
+ model = Caracal::Core::Models::PageSizeModel.new(options, &block)
58
+
59
+ if model.valid?
60
+ @page_width = model.page_width
61
+ @page_height = model.page_height
62
+ else
63
+ raise Caracal::Errors::InvalidModelError, 'page_size method requires non-zero :width and :height options.'
64
+ end
65
+ end
66
+
67
+ end
68
+ end
69
+ end
70
+
71
+ end
72
+ end