docxify 0.0.2 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6452a64308ce07a1158e0cb0af2aaeab67085f4e17726e4c098de78151ee1fc1
4
- data.tar.gz: 04a7c49e56af79e4ab67a3f66269dc1940856488257e73888cbdfea4a74b301b
3
+ metadata.gz: cb6c9076520d0776ed132e2abbc42166a6ff0106fce181d5d178ecf3abff1a96
4
+ data.tar.gz: 042d1e27e5572cd0b4868eb9af065d1b3831e25d80569eafd2086bda130ab7b1
5
5
  SHA512:
6
- metadata.gz: d8ee36086086aef5941636ad168b0bc11e526d5e801fb482cdda6169b2065901069cdd9d6d68d05ab482bbc3c1541aad0258f051e673019590987b3991d36db1
7
- data.tar.gz: b34e167da1eb82d24cac8b15c54882a2b6f130dfc68281f024e02739ebd04880076847f9345f38ffc0dcaf7b36ffa3c194a521cc0c0b9d8b29e6a8098b065d52
6
+ metadata.gz: 83ee99a55280b56efd7f571c00c8cb09eb026345b821173c389f40f3bffb907bc2f4b57ce08d6d587a0bc653cdbc4efc630a1400dd48e3dee78f005bf574469e
7
+ data.tar.gz: 62a9965149dde87c65db3877642fff5e6cf0cc8f02f373ab59422b78ca9a645522c2df45125268140f8b1e36b29a105b500ea06489f0fc5fee6056bff740bd6a
data/.rubocop.yml ADDED
@@ -0,0 +1,309 @@
1
+ AllCops:
2
+ SuggestExtensions: false
3
+ NewCops: enable
4
+ Exclude:
5
+ - 'Gemfile'
6
+ - 'Rakefile'
7
+ - 'spec/**/*.rb'
8
+ - 'vendor/**/*'
9
+ Style/FormatStringToken:
10
+ EnforcedStyle: unannotated
11
+ Style/FetchEnvVar:
12
+ Enabled: false
13
+ Style/StringChars:
14
+ Enabled: false
15
+ Naming/BlockForwarding:
16
+ EnforcedStyle: explicit
17
+ Metrics/ClassLength:
18
+ Enabled: false
19
+ Naming/MethodParameterName:
20
+ Enabled: false
21
+ Lint/SuppressedException:
22
+ Enabled: false
23
+ Metrics/ParameterLists:
24
+ Enabled: false
25
+ Metrics/BlockNesting:
26
+ Enabled: false
27
+ Metrics/BlockLength:
28
+ Enabled: false
29
+ Metrics/ModuleLength:
30
+ Enabled: false
31
+ Metrics/CyclomaticComplexity:
32
+ Enabled: false
33
+ Metrics/PerceivedComplexity:
34
+ Enabled: false
35
+ Metrics/MethodLength:
36
+ Enabled: false
37
+ Layout/HashAlignment:
38
+ Enabled: false
39
+ Layout/ArgumentAlignment:
40
+ Enabled: false
41
+ Layout/LineLength:
42
+ Enabled: false
43
+ Layout/SpaceAroundMethodCallOperator:
44
+ Enabled: true
45
+ Lint/RaiseException:
46
+ Enabled: true
47
+ Lint/StructNewOverride:
48
+ Enabled: true
49
+ Style/ExponentialNotation:
50
+ Enabled: true
51
+ Style/HashEachMethods:
52
+ Enabled: true
53
+ Style/Documentation:
54
+ Enabled: false
55
+ Bundler/OrderedGems:
56
+ Enabled: false
57
+ Style/FrozenStringLiteralComment:
58
+ Enabled: false
59
+ Style/TrailingCommaInHashLiteral:
60
+ Enabled: false
61
+ Layout/SpaceBeforeSemicolon:
62
+ Enabled: false
63
+ Style/ClassAndModuleChildren:
64
+ Enabled: false
65
+ Metrics/AbcSize:
66
+ Enabled: false
67
+ Lint/RescueException:
68
+ Enabled: false
69
+ Layout/MultilineMethodCallIndentation:
70
+ Enabled: false
71
+
72
+ # Prefer &&/|| over and/or.
73
+ Style/AndOr:
74
+ Enabled: true
75
+
76
+ Style/FormatString:
77
+ EnforcedStyle: percent
78
+
79
+ # Align `when` with `case`.
80
+ Layout/CaseIndentation:
81
+ Enabled: false
82
+
83
+ Layout/ClosingHeredocIndentation:
84
+ Enabled: true
85
+
86
+ # Align comments with method definitions.
87
+ Layout/CommentIndentation:
88
+ Enabled: true
89
+
90
+ Layout/ElseAlignment:
91
+ Enabled: true
92
+
93
+ Style/RedundantRegexpEscape:
94
+ Enabled: false
95
+
96
+ Style/RaiseArgs:
97
+ EnforcedStyle: compact
98
+
99
+ # Align `end` with the matching keyword or starting expression except for
100
+ # assignments, where it should be aligned with the LHS.
101
+ Layout/EndAlignment:
102
+ Enabled: true
103
+ EnforcedStyleAlignWith: variable
104
+ AutoCorrect: true
105
+
106
+ Layout/EmptyLineAfterMagicComment:
107
+ Enabled: true
108
+
109
+ Layout/EmptyLinesAroundAccessModifier:
110
+ Enabled: false
111
+
112
+ Layout/EmptyLinesAroundBlockBody:
113
+ Enabled: true
114
+
115
+ # In a regular class definition, no empty lines around the body.
116
+ Layout/EmptyLinesAroundClassBody:
117
+ Enabled: true
118
+
119
+ # In a regular method definition, no empty lines around the body.
120
+ Layout/EmptyLinesAroundMethodBody:
121
+ Enabled: true
122
+
123
+ # In a regular module definition, no empty lines around the body.
124
+ Layout/EmptyLinesAroundModuleBody:
125
+ Enabled: true
126
+
127
+ # Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
128
+ Style/HashSyntax:
129
+ Enabled: true
130
+ EnforcedShorthandSyntax: never
131
+
132
+ Layout/FirstArgumentIndentation:
133
+ Enabled: true
134
+
135
+ Style/RescueModifier:
136
+ Enabled: false
137
+
138
+ # Method definitions after `private` or `protected` isolated calls need one
139
+ # extra level of indentation.
140
+ Layout/IndentationConsistency:
141
+ Enabled: false
142
+
143
+ # Two spaces, no tabs (for indentation).
144
+ Layout/IndentationWidth:
145
+ Enabled: true
146
+
147
+ Layout/LeadingCommentSpace:
148
+ Enabled: true
149
+
150
+ Layout/SpaceAfterColon:
151
+ Enabled: true
152
+
153
+ Layout/SpaceAfterComma:
154
+ Enabled: true
155
+
156
+ Layout/SpaceAfterSemicolon:
157
+ Enabled: true
158
+
159
+ Layout/SpaceAroundEqualsInParameterDefault:
160
+ Enabled: true
161
+
162
+ Layout/SpaceAroundKeyword:
163
+ Enabled: true
164
+
165
+ Layout/SpaceBeforeComma:
166
+ Enabled: true
167
+
168
+ Layout/SpaceBeforeComment:
169
+ Enabled: true
170
+
171
+ Layout/SpaceBeforeFirstArg:
172
+ Enabled: true
173
+
174
+ Style/DefWithParentheses:
175
+ Enabled: true
176
+
177
+ Style/MethodDefParentheses:
178
+ Enabled: true
179
+
180
+ Style/RedundantFreeze:
181
+ Enabled: true
182
+
183
+ # Use `foo {}` not `foo{}`.
184
+ Layout/SpaceBeforeBlockBraces:
185
+ Enabled: true
186
+
187
+ # Use `foo { bar }` not `foo {bar}`.
188
+ Layout/SpaceInsideBlockBraces:
189
+ Enabled: true
190
+ EnforcedStyleForEmptyBraces: space
191
+
192
+ # Use `{ a: 1 }` not `{a:1}`.
193
+ Layout/SpaceInsideHashLiteralBraces:
194
+ Enabled: true
195
+
196
+ Layout/SpaceInsideParens:
197
+ Enabled: true
198
+
199
+ # Check quotes usage according to lint rule below.
200
+ Style/StringLiterals:
201
+ Enabled: true
202
+ EnforcedStyle: double_quotes
203
+ SupportedStyles:
204
+ - single_quotes
205
+ - double_quotes
206
+
207
+ Style/StringLiteralsInInterpolation:
208
+ Enabled: false
209
+
210
+ Style/HashLikeCase:
211
+ Enabled: false
212
+
213
+ Style/IfUnlessModifier:
214
+ Enabled: false
215
+
216
+ # Detect hard tabs, no hard tabs.
217
+ Layout/IndentationStyle:
218
+ Enabled: true
219
+
220
+ # Empty lines should not have any spaces.
221
+ Layout/TrailingEmptyLines:
222
+ Enabled: true
223
+
224
+ # No trailing whitespace.
225
+ Layout/TrailingWhitespace:
226
+ Enabled: true
227
+
228
+ # Use quotes for string literals when they are enough.
229
+ Style/RedundantPercentQ:
230
+ Enabled: true
231
+
232
+ Lint/AmbiguousOperator:
233
+ Enabled: true
234
+
235
+ Lint/AmbiguousRegexpLiteral:
236
+ Enabled: true
237
+
238
+ Lint/ErbNewArguments:
239
+ Enabled: true
240
+
241
+ Lint/ParenthesesAsGroupedExpression:
242
+ Enabled: false
243
+
244
+ # Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
245
+ Lint/RequireParentheses:
246
+ Enabled: true
247
+
248
+ Lint/ShadowingOuterLocalVariable:
249
+ Enabled: true
250
+
251
+ Lint/RedundantStringCoercion:
252
+ Enabled: true
253
+
254
+ Lint/UriEscapeUnescape:
255
+ Enabled: true
256
+
257
+ Lint/UselessAssignment:
258
+ Enabled: true
259
+
260
+ Lint/DeprecatedClassMethods:
261
+ Enabled: true
262
+
263
+ Style/GuardClause:
264
+ Enabled: false
265
+
266
+ Style/ParenthesesAroundCondition:
267
+ Enabled: true
268
+
269
+ Style/HashTransformKeys:
270
+ Enabled: true
271
+
272
+ Style/HashTransformValues:
273
+ Enabled: true
274
+
275
+ Style/RedundantBegin:
276
+ Enabled: true
277
+
278
+ Style/RedundantReturn:
279
+ Enabled: true
280
+ AllowMultipleReturnValues: true
281
+
282
+ Style/Semicolon:
283
+ Enabled: true
284
+ AllowAsExpressionSeparator: true
285
+
286
+ # Prefer Foo.method over Foo::method
287
+ Style/ColonMethodCall:
288
+ Enabled: true
289
+
290
+ Style/TrivialAccessors:
291
+ Enabled: true
292
+
293
+ Style/BarePercentLiterals:
294
+ Enabled: false
295
+
296
+ Style/IfInsideElse:
297
+ Enabled: false
298
+
299
+ Style/RegexpLiteral:
300
+ Enabled: false
301
+
302
+ Style/ParallelAssignment:
303
+ Enabled: false
304
+
305
+ Style/RedundantParentheses:
306
+ Enabled: false
307
+
308
+ Layout/FirstHashElementIndentation:
309
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.0.7
4
+
5
+ Features:
6
+
7
+ - Table support
8
+
9
+ ## 0.0.6
10
+
11
+ Features:
12
+
13
+ - Tab stops and hanging indents done
14
+ - Replacing of {CHECKBOX_EMPTY} and {CHECKBOX_CHECKED} with correct UTF-8 characters done
15
+
16
+ ## 0.0.5
17
+
18
+ Features:
19
+
20
+ - Paragraph font name, size, colour and yellow highlight done
21
+ - Document level default font name, size and colour done
22
+
23
+ ## 0.0.4
24
+
25
+ Features:
26
+
27
+ - Image insertion is working
28
+
29
+ ## 0.0.3
30
+
31
+ Features:
32
+
33
+ - Dividers and page breaks implemented
34
+ - Simple HTML parsing (for paragraphs) implemented
35
+
3
36
  ## 0.0.2
4
37
 
5
38
  Features:
data/LICENSE.md ADDED
@@ -0,0 +1,9 @@
1
+ # MIT License
2
+
3
+ Copyright ©️2024 FounderCatalyst IP Ltd
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -25,32 +25,42 @@ gem install docxify
25
25
 
26
26
  @docx.add_paragraph "Title", font: "Something", size: 18, color: "#00000"
27
27
  @docx.add_paragraph "Body copy"
28
- @docx.add_paragraph "This is <b>bold</b>, <i>Italic</i> and <u>Underlined</u>. It can also contain <a href='foo'>Links</a>."
28
+ @docx.add_paragraph "This is <b>bold</b>, <i>Italic</i> and <u>Underlined</u>."
29
+ @docx.add_paragraph "Text can also contain <a href='foo'>Links</a>."
29
30
  @docx.add_paragraph "Centred text", align: :center
30
31
  @docx.add_paragraph "Highlighted text", background: "#FFFF99"
31
- @docx.add_paragraph "This is <b>bold</b>, <i>Italic</i> and <u>Underlined</u>. It can also contain <a href='foo'>Links</a>.", inline_styling: false
32
+ @docx.add_paragraph "This won't show as <b>bold</b>", inline_styling: false
32
33
 
33
- @docx.add_paragraph "1.1.1\tBody copy", tab_stops_cm: [2]
34
+ @docx.add_paragraph "\t1.1.1\tBody copy", tab_stops_cm: [1, 2]
34
35
  @docx.add_paragraph "{CHECKBOX_EMPTY}\tEmpty checkbox", tab_stops_cm: [2]
35
36
  @docx.add_paragraph "{CHECKBOX_CHECKED}\tChecked checkbox", tab_stops_cm: [2]
36
37
 
37
- @docx.add_numbered_list_item "This is a list item", level: 0
38
-
39
- @docx.add_page_break
40
38
  @docx.add_divider
41
39
 
42
40
  @docx.add_image "file_path or data", align: :right, height_cm: 2, width_cm: 4
43
41
 
44
- headers = [
45
- DocXify::Element::TableCell.new("<b>Header 1</b>"),
46
- DocXify::Element::TableCell.new("<b>Header 2</b>")
47
- ]
48
- row = [
49
- DocXify::Element::TableCell.new("Content <b>here</b>", valign: :center, align: :left, nowrap: true, colspan: 3),
50
- DocXify::Element::TableCell.new("Content <b>here</b>")
51
- ]
52
- rows = [row]
53
- @docx.add_table headers, rows, expand: :full
42
+ @docx.add_page_break
43
+
44
+ @docx.container page_width: DocXify::A4_PORTRAIT_HEIGHT, page_height: DocXify::A4_PORTRAIT_WIDTH do |container|
45
+ rows = []
46
+ rows << [
47
+ DocXify::Element::TableCell.new("<b>Header 1</b>"),
48
+ DocXify::Element::TableCell.new("<b>Header 2</b>")
49
+ DocXify::Element::TableCell.new("<b>Header 3</b>")
50
+ DocXify::Element::TableCell.new("<b>Header 4</b>", width_cm: 10)
51
+ ]
52
+ rows << [
53
+ DocXify::Element::TableCell.new("Content 1", valign: :center, align: :left, nowrap: true, colspan: 3),
54
+ DocXify::Element::TableCell.new("Rowspan <b>here</b>", rowspan: true) # merges until a "nil" cell
55
+ ]
56
+ rows << [
57
+ DocXify::Element::TableCell.new("Secondary 1")
58
+ DocXify::Element::TableCell.new("Secondary 2")
59
+ DocXify::Element::TableCell.new("Secondary 3")
60
+ DocXify::Element::TableCell.new(nil) # Word requires that there's an empty cell merged with the previous rowspan
61
+ ]
62
+ container.add_table rows
63
+ end
54
64
 
55
65
  docx_binary_data = @docx.render
56
66
  # or
data/Rakefile CHANGED
@@ -1,8 +1,8 @@
1
1
  require "bundler/gem_tasks"
2
2
  require "rspec/core/rake_task"
3
+ require 'rubocop/rake_task'
3
4
 
4
5
  RSpec::Core::RakeTask.new(:spec)
6
+ RuboCop::RakeTask.new
5
7
 
6
- require "standard/rake"
7
-
8
- task default: %i[spec standard]
8
+ task default: %i[spec rubocop]
@@ -36,9 +36,14 @@ module DocXify
36
36
  zip.put_next_entry "word/document.xml"
37
37
  zip.write document.build_xml(self)
38
38
 
39
- @document.images.each do |image|
40
- zip.put_next_entry "word/media/#{image.filename}"
41
- zip.write image.file_contents
39
+ zip.put_next_entry "word/_rels/document.xml.rels"
40
+ zip.write document_xml_rels
41
+
42
+ @document.relationships.each do |relation|
43
+ if relation.is_a?(DocXify::Element::File)
44
+ zip.put_next_entry "word/media/#{relation.filename}"
45
+ zip.write relation.data
46
+ end
42
47
  end
43
48
  end
44
49
 
@@ -61,8 +66,8 @@ module DocXify
61
66
  <Relationship Id="rId4" Target="fontTable.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable"/>
62
67
  XML
63
68
 
64
- @document.images.each do |image|
65
- xml << "<Relationship Id=\"#{image.reference}\" Target=\"media/#{image.filename}\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\"/>"
69
+ @document.relationships.each do |relation|
70
+ xml << relation.to_s
66
71
  end
67
72
 
68
73
  xml << "</Relationships>"
@@ -1,18 +1,18 @@
1
1
  module DocXify
2
2
  class Document
3
3
  attr_accessor :font, :size, :color, :background
4
- attr_reader :content, :images
4
+ attr_reader :content, :relationships, :width
5
5
 
6
6
  def initialize(options = {})
7
7
  @content = []
8
- @images = []
8
+ @relationships = []
9
9
  @width = options[:width] || A4_PORTRAIT_WIDTH
10
10
  @height = options[:height] || A4_PORTRAIT_HEIGHT
11
11
  @font = options[:font] || "Times New Roman"
12
12
  @size = options[:size] || 12
13
13
  @color = options[:color] || 12
14
14
  @background = options[:background] if options[:background]
15
- @margins = {top: 2, bottom: 2, left: 2, right: 2}
15
+ @margins = { top: 2, bottom: 2, left: 2, right: 2 }
16
16
  end
17
17
 
18
18
  def default_styling(options = {})
@@ -37,7 +37,7 @@ module DocXify
37
37
  def build_xml(container)
38
38
  xml = <<~XML
39
39
  <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
40
- <w:document mc:Ignorable="w14 w15 w16se w16cid w16 w16cex w16sdtdh wp14" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:oel="http://schemas.microsoft.com/office/2019/extlst" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" xmlns:w16cex="http://schemas.microsoft.com/office/word/2018/wordml/cex" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16sdtdh="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape">
40
+ <w:document mc:Ignorable="w14 w15 w16se w16cid w16 w16cex w16sdtdh wp14" xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:oel="http://schemas.microsoft.com/office/2019/extlst" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" xmlns:w16cex="http://schemas.microsoft.com/office/word/2018/wordml/cex" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16sdtdh="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape">
41
41
  <w:body>
42
42
  XML
43
43
 
@@ -64,34 +64,36 @@ module DocXify
64
64
  end
65
65
 
66
66
  def add_image(file_path_or_data, options = {})
67
- file = DocXify::Element::File.new(self, file_path_or_data, options)
68
- @images << file
69
- add DocXify::Element::Image.new(self, file, options)
67
+ file = if file_path_or_data.is_a?(DocXify::Element::File)
68
+ file_path_or_data
69
+ else
70
+ add_file(file_path_or_data)
71
+ end
72
+ add DocXify::Element::Image.new(file, options)
70
73
  end
71
74
 
72
- def add_numbered_list_item(text, level: 0)
73
- add DocXify::Element::NumberedListItem.new(self, text, level: level)
75
+ def add_file(file_path_or_data)
76
+ file = DocXify::Element::File.new(file_path_or_data)
77
+ @relationships << file
78
+ file
74
79
  end
75
80
 
76
81
  def add_page_break
77
- add DocXify::Element::PageBreak.new(self)
82
+ add DocXify::Element::PageBreak.new
78
83
  end
79
84
 
80
85
  def add_divider
81
- add DocXify::Element::Divider.new(self)
86
+ add DocXify::Element::Divider.new
82
87
  end
83
88
 
84
89
  def add_paragraph(text, options = {})
85
- add DocXify::Element::Paragraph.new(self, text, options)
90
+ options[:document] = self
91
+ add DocXify::Element::Paragraph.new(text, options)
86
92
  end
87
93
 
88
- def add_table(headers, rows, options = {})
89
- add DocXify::Element::Table.new(self, headers, rows, options)
94
+ def add_table(rows, options = {})
95
+ options[:document] = self
96
+ add DocXify::Element::Table.new(rows, options)
90
97
  end
91
-
92
- # MARK: Private
93
-
94
- private
95
-
96
98
  end
97
99
  end
@@ -4,6 +4,76 @@ module DocXify
4
4
  def to_s(container = nil)
5
5
  raise NotImplementedError
6
6
  end
7
+
8
+ private
9
+
10
+ def parse_simple_html(html)
11
+ state = :text
12
+ tag = ""
13
+ content = ""
14
+ result = []
15
+ text = ""
16
+ last_char = ""
17
+
18
+ html.each_char do |char|
19
+ # puts "State: #{state}, Char: #{char}, Tag: #{tag}, Content: #{content}, Text: #{text}"
20
+ case state
21
+ when :text # This is a text node, not part of an HTML tag
22
+ if char == "<"
23
+ state = :tag
24
+ tag = ""
25
+ result << text unless text.empty?
26
+ text = ""
27
+ else
28
+ text << char
29
+ end
30
+ when :tag # Within an HTML tag itself
31
+ if char == ">"
32
+ state = :content
33
+ content = ""
34
+ tag_name, *attributes = tag.split
35
+ tag_name.gsub!(/\s*\//, "")
36
+ attributes.delete_if { |attr| attr == "/" }
37
+ if attributes.any?
38
+ attrs = {}
39
+ attributes.each do |attribute|
40
+ name, value = attribute.split("=")
41
+ value = value.to_s[1..-2] if value
42
+ attrs[name.to_sym] = value
43
+ end
44
+ result << { tag: tag_name, attributes: attrs, content: "" }
45
+ else
46
+ result << { tag: tag_name, content: "" }
47
+ end
48
+
49
+ if last_char == "/"
50
+ state = :text
51
+ end
52
+ elsif char == "/" && last_char == "<"
53
+ state = :closing_tag
54
+ else
55
+ tag << char
56
+ end
57
+ when :closing_tag
58
+ if char == ">"
59
+ state = :text
60
+ end
61
+ when :content # With the content of an HTML tag
62
+ if char == "<"
63
+ state = :tag
64
+ result.last[:content] = content
65
+ content = ""
66
+ else
67
+ content << char
68
+ end
69
+ end
70
+
71
+ last_char = char
72
+ end
73
+
74
+ result << text unless text.empty?
75
+ result
76
+ end
7
77
  end
8
78
  end
9
79
  end
@@ -0,0 +1,18 @@
1
+ module DocXify
2
+ module Element
3
+ class Divider < Base
4
+ def to_s(_container = nil)
5
+ <<~XML
6
+ <w:p>
7
+ <w:pPr>
8
+ <w:pBdr>
9
+ <w:bottom w:color="auto" w:space="1" w:sz="6" w:val="single"/>
10
+ </w:pBdr>
11
+ </w:pPr>
12
+ </w:p>
13
+ <w:p/>
14
+ XML
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,50 @@
1
+ require "digest/sha1"
2
+
3
+ module DocXify
4
+ module Element
5
+ class File < Base
6
+ PNG_SIGNATURE = "\x89PNG\r\n\u001A\n".b.freeze
7
+ JPEG_START = "\xFF\xD8".b.freeze
8
+ JPEG_END = "\xFF\xD9".b.freeze
9
+
10
+ attr_accessor :data, :filename
11
+
12
+ def initialize(file_path_or_data)
13
+ super()
14
+ load_file_data(file_path_or_data)
15
+ end
16
+
17
+ def load_file_data(file_path_or_data)
18
+ if contains_png_image?(file_path_or_data)
19
+ @data = file_path_or_data
20
+ @filename = "#{Digest::SHA1.hexdigest(@data)}.png"
21
+ elsif contains_jpeg_image?(file_path_or_data)
22
+ @data = file_path_or_data
23
+ @filename = "#{Digest::SHA1.hexdigest(@data)}.jpg"
24
+ elsif ::File.exist?(file_path_or_data)
25
+ @filename = ::File.basename(file_path_or_data)
26
+ @data = ::File.read(file_path_or_data, mode: "rb")
27
+ raise ArgumentError.new("Unsupported file type - images must be PNG or JPEG") unless contains_png_image?(@data) || contains_jpeg_image?(@data)
28
+ else
29
+ raise ArgumentError.new("Unsupported file type - images must be PNG or JPEG")
30
+ end
31
+ end
32
+
33
+ def reference
34
+ "image-#{Digest::SHA1.hexdigest(@data)[0, 8]}"
35
+ end
36
+
37
+ def to_s
38
+ "<Relationship Id=\"#{reference}\" Target=\"media/#{filename}\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\"/>"
39
+ end
40
+
41
+ def contains_png_image?(data)
42
+ data[0, 8] == PNG_SIGNATURE
43
+ end
44
+
45
+ def contains_jpeg_image?(data)
46
+ data[0..1] == JPEG_START && data[-2..] == JPEG_END
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,88 @@
1
+ module DocXify
2
+ module Element
3
+ class Image < Base
4
+ attr_accessor :file, :align, :height_cm, :width_cm
5
+
6
+ def initialize(file, options = {})
7
+ super()
8
+ @file = file
9
+
10
+ @align = options[:align] || :left
11
+ @height_cm = options[:height_cm] || 5
12
+ @width_cm = options[:width_cm] || 5
13
+ end
14
+
15
+ def id
16
+ rand(1_000_000_000)
17
+ end
18
+
19
+ def to_s(_container = nil)
20
+ xml = "<w:p>"
21
+
22
+ if @align == :right
23
+ xml << <<~XML
24
+ <w:pPr>
25
+ <w:jc w:val="right"/>
26
+ </w:pPr>
27
+ XML
28
+ elsif @align == :center
29
+ xml << <<~XML
30
+ <w:pPr>
31
+ <w:jc w:val="center"/>
32
+ </w:pPr>
33
+ XML
34
+ end
35
+
36
+ xml << <<~XML
37
+ <w:r>
38
+ <w:rPr>
39
+ <w:noProof/>
40
+ </w:rPr>
41
+ <w:drawing>
42
+ <wp:inline distB="0" distL="0" distR="0" distT="0">
43
+ <wp:extent cx="#{DocXify.cm2emu(@width_cm)}" cy="#{DocXify.cm2emu(@height_cm)}"/>
44
+ <wp:effectExtent b="0" l="0" r="0" t="0"/>
45
+ <wp:docPr id="#{id}" name="Picture 1"/>
46
+ <wp:cNvGraphicFramePr>
47
+ <a:graphicFrameLocks noChangeAspect="1" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"/>
48
+ </wp:cNvGraphicFramePr>
49
+ <a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
50
+ <a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
51
+ <pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
52
+ <pic:nvPicPr>
53
+ <pic:cNvPr id="#{id}" name="Picture #{id}"/>
54
+ <pic:cNvPicPr/>
55
+ </pic:nvPicPr>
56
+ <pic:blipFill>
57
+ <a:blip cstate="print" r:embed="#{@file.reference}">
58
+ <a:extLst>
59
+ <a:ext uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
60
+ <a14:useLocalDpi val="0" xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main"/>
61
+ </a:ext>
62
+ </a:extLst>
63
+ </a:blip>
64
+ <a:stretch>
65
+ <a:fillRect/>
66
+ </a:stretch>
67
+ </pic:blipFill>
68
+ <pic:spPr>
69
+ <a:xfrm>
70
+ <a:off x="0" y="0"/>
71
+ <a:ext cx="#{DocXify.cm2emu(@width_cm)}" cy="#{DocXify.cm2emu(@height_cm)}"/>
72
+ </a:xfrm>
73
+ <a:prstGeom prst="rect">
74
+ <a:avLst/>
75
+ </a:prstGeom>
76
+ </pic:spPr>
77
+ </pic:pic>
78
+ </a:graphicData>
79
+ </a:graphic>
80
+ </wp:inline>
81
+ </w:drawing>
82
+ </w:r>
83
+ </w:p>
84
+ XML
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,16 @@
1
+ module DocXify
2
+ module Element
3
+ class PageBreak < Base
4
+ def to_s(_container = nil)
5
+ <<~XML
6
+ <w:p>
7
+ <w:r>
8
+ <w:br w:type="page"/>
9
+ </w:r>
10
+ </w:p>
11
+ <w:p/>
12
+ XML
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,24 +1,99 @@
1
1
  module DocXify
2
2
  module Element
3
3
  class Paragraph < Base
4
- attr_accessor :text, :font, :size, :color, :background, :align, :inline_styling, :tab_stops_cm
4
+ attr_accessor :text, :font, :size, :color, :background, :align, :inline_styling, :tab_stops_cm, :hanging_cm
5
5
 
6
- def initialize(document, text, options = {})
7
- @document = document
6
+ def initialize(text, options = {})
7
+ super()
8
+ @document = options[:document]
8
9
  @text = text
9
- @font = options[:font] || document.font
10
- @size = options[:size] || document.size
11
- @color = options[:color] || document.color
10
+ @font = options[:font] || @document&.font || "Times New Roman"
11
+ @size = options[:size] || @document&.size || 14
12
+ @color = options[:color] || @document&.color || "#000000"
13
+ @highlight = options[:highlight] || false
12
14
  @background = options[:background] if options[:background]
13
- @background ||= document.background if document.background
15
+ @background ||= @document&.background if @document&.background
14
16
  @align = options[:align] || :left
15
- @inline_styling = options[:inline_styling] || true
17
+ @inline_styling = options.key?(:inline_styling) ? options[:inline_styling] : true
16
18
  @tab_stops_cm = options[:tab_stops_cm] || []
19
+ @hanging_cm = options[:hanging_cm] || 0
17
20
  end
18
21
 
19
- def to_s(container = nil)
20
- # TODO: Implement all optionality
21
- "<w:p><w:r><w:t xml:space=\"preserve\">#{@text}</w:t></w:r></w:p>"
22
+ def to_s(_container = nil)
23
+ nodes = if @inline_styling
24
+ parse_simple_html(@text)
25
+ else
26
+ [@text.gsub("<", "&lt;").gsub(">", "&gt;")]
27
+ end
28
+
29
+ xml = "<w:p>"
30
+
31
+ xml << "<w:pPr>"
32
+ xml << "<w:jc w:val=\"#{@align}\"/>" if @align != :left
33
+
34
+ if tab_stops_cm.any?
35
+ xml << "<w:tabs>"
36
+ tab_stops_cm.each do |stop|
37
+ xml << "<w:tab w:pos=\"#{DocXify.cm2dxa(stop)}\" w:val=\"left\"/>"
38
+ end
39
+ xml << "</w:tabs>"
40
+ end
41
+
42
+ if @hanging_cm&.positive?
43
+ xml << "<w:ind w:hanging=\"#{DocXify.cm2dxa(@hanging_cm)}\" w:left=\"#{DocXify.cm2dxa(@hanging_cm)}\"/>"
44
+ end
45
+
46
+ xml << "</w:pPr>"
47
+
48
+ nodes.each do |node|
49
+ if node.is_a?(Hash) && node[:tag] == "a"
50
+ xml << "<w:hyperlink r:id=\"#{ref_for_href(node[:attributes][:href])}\">"
51
+ end
52
+
53
+ xml << "<w:r>"
54
+ xml << <<~XML
55
+ <w:rPr>
56
+ <w:rFonts w:ascii="#{@font}" w:cs="#{@font}" w:hAnsi="#{@font}"/>
57
+ <w:color w:val="#{@color.gsub("#", "")}"/>
58
+ <w:sz w:val="#{DocXify.pt2halfpt(@size)}"/>
59
+ <w:szCs w:val="#{DocXify.pt2halfpt(@size)}"/>
60
+ #{"<w:highlight w:val=\"yellow\"/>" if @highlight}
61
+ #{"<w:b/><w:bCs/>" if node.is_a?(Hash) && node[:tag] == "b"}
62
+ #{"<w:i/><w:iCs/>" if node.is_a?(Hash) && node[:tag] == "i"}
63
+ #{"<w:u w:val=\"single\"/>" if node.is_a?(Hash) && (node[:tag] == "u" || node[:tag] == "a")}
64
+ #{"<w:rStyle w:val=\"Hyperlink\"/>" if node.is_a?(Hash) && node[:tag] == "a"}
65
+ </w:rPr>
66
+ XML
67
+
68
+ content = node.is_a?(Hash) ? node[:content] : node
69
+ content = content.gsub("{CHECKBOX_EMPTY}", "☐").gsub("{CHECKBOX_CHECKED}", "☒")
70
+ xml << "<w:t xml:space=\"preserve\">#{content}</w:t>"
71
+ xml << "</w:r>"
72
+
73
+ if node.is_a?(Hash) && node[:tag] == "a"
74
+ xml << "</w:hyperlink>"
75
+ end
76
+ end
77
+
78
+ xml << "</w:p>"
79
+ end
80
+
81
+ def ref_for_href(href)
82
+ relation = nil
83
+
84
+ @document.relationships.select { |r| r.is_a?(DocXify::Element::WebAddress) }.each do |r|
85
+ if r.target == href
86
+ relation = r
87
+ break
88
+ end
89
+ end
90
+
91
+ if relation.nil?
92
+ relation = DocXify::Element::WebAddress.new(href)
93
+ @document.relationships << relation
94
+ end
95
+
96
+ relation.reference
22
97
  end
23
98
  end
24
99
  end
@@ -0,0 +1,107 @@
1
+ # Structure of a table element looks something like this
2
+ # <w:tbl> - Table element
3
+ # <w:tblPr> - Table properties
4
+ # <w:tblGrid> - Table grid (column widths)
5
+ # <w:tr> - Table row
6
+ # <w:tc> - Table cell
7
+ # <w:tcPr> - Table cell properties
8
+ # <w:tcW w:type="dxa" w:w="1502"/> - Table cell width
9
+ # <w:vMerge w:val="restart"/> - Something about merging TODO - figure out
10
+ # <w:tcBorders> - Overriding table cell borders
11
+ # <w:top w:val="nil"/>
12
+ # <w:bottom w:color="auto" w:space="0" w:sz="4" w:val="single"/>
13
+ # <w:right w:val="nil"/>
14
+ # </w:tcBorders>
15
+ # <w:vAlign w:val="bottom"/>
16
+ # </w:tcPr>
17
+ # <w:p> - Paragraph element
18
+
19
+ module DocXify
20
+ module Element
21
+ class Table < Base
22
+ attr_accessor :rows, :column_widths
23
+
24
+ def initialize(rows, options = {})
25
+ super()
26
+ @document = options[:document]
27
+ @rows = rows
28
+ end
29
+
30
+ def to_s(_container = nil)
31
+ xml = ""
32
+ xml << table_element_start
33
+ xml << table_properties
34
+ xml << table_grid
35
+ @rows.each do |row|
36
+ xml << table_row(row)
37
+ end
38
+ xml << table_element_end
39
+ xml
40
+ end
41
+
42
+ def table_element_start
43
+ "<w:tbl>"
44
+ end
45
+
46
+ def table_properties
47
+ xml = ""
48
+ xml << "<w:tblPr>"
49
+ xml << '<w:tblStyle w:val="TableGrid"/>'
50
+ xml << '<w:tblW w:type="auto" w:w="0"/>'
51
+ xml << "<w:tblBorders>"
52
+ xml << '<w:top w:color="auto" w:space="0" w:sz="0" w:val="none"/>'
53
+ xml << '<w:left w:color="auto" w:space="0" w:sz="0" w:val="none"/>'
54
+ xml << '<w:bottom w:color="auto" w:space="0" w:sz="0" w:val="none"/>'
55
+ xml << '<w:right w:color="auto" w:space="0" w:sz="0" w:val="none"/>'
56
+ xml << "</w:tblBorders>"
57
+ xml << '<w:tblLook w:firstColumn="1" w:firstRow="1" w:lastColumn="0" w:lastRow="0" w:noHBand="0" w:noVBand="1" w:val="04A0"/>'
58
+ xml << "</w:tblPr>"
59
+ xml
60
+ end
61
+
62
+ def table_grid
63
+ default_equal_width = (@document.width / @rows.first.size).to_i
64
+
65
+ @column_widths = []
66
+ xml = "<w:tblGrid>"
67
+ @rows.first.each do |cell|
68
+ width = if cell.width_cm
69
+ DocXify.cm2dxa(cell.width_cm)
70
+ else
71
+ default_equal_width
72
+ end
73
+ xml << "<w:gridCol w:w=\"#{width}\"/>"
74
+ @column_widths << width
75
+ end
76
+
77
+ xml << "</w:tblGrid>"
78
+ xml
79
+ end
80
+
81
+ def table_row(row)
82
+ xml = "<w:tr>"
83
+ widths = @column_widths.dup
84
+ row.each do |cell|
85
+ if cell.nil?
86
+ cell = DocXify::Element::TableCell.new(nil)
87
+ end
88
+
89
+ if cell.width_cm.nil?
90
+ cell.width_cm = 0
91
+ (cell.colspan || 1).times do
92
+ cell.width_cm += DocXify.dxa2cm(widths.shift)
93
+ end
94
+ end
95
+
96
+ xml << cell.to_s
97
+ end
98
+ xml << "</w:tr>"
99
+ xml
100
+ end
101
+
102
+ def table_element_end
103
+ "</w:tbl>"
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,66 @@
1
+ module DocXify
2
+ module Element
3
+ class TableCell < Base
4
+ attr_accessor :content, :valign, :align, :nowrap, :colspan, :width_cm, :borders, :font, :size, :colour
5
+
6
+ def initialize(content, options = {})
7
+ super()
8
+ @content = content
9
+ @valign = options[:valign] || :top
10
+ @align = options[:align] || :left
11
+ @nowrap = options[:nowrap]
12
+ @colspan = options[:colspan]
13
+ @rowspan = options[:rowspan]
14
+ @width_cm = options[:width_cm]
15
+ @font = options[:font]
16
+ @size = options[:size]
17
+ @color = options[:color]
18
+ @borders = options[:borders]&.map(&:to_sym) || []
19
+ end
20
+
21
+ def to_s
22
+ xml = "<w:tc>"
23
+ xml << "<w:tcPr>"
24
+ xml << %Q(<w:tcW w:type="dxa" w:w="#{DocXify.cm2dxa(@width_cm)}"/>)
25
+ if !@colspan.nil? && @colspan.to_i > 1
26
+ xml << %Q(<w:gridSpan w:val="#{@colspan}"/>')
27
+ end
28
+
29
+ if borders.any?
30
+ xml << "<w:tcBorders>"
31
+ xml << (borders.include?(:top) ? '<w:top w:color="auto" w:space="0" w:sz="4" w:val="single"/>' : '<w:top w:val="nil"/>')
32
+ xml << (borders.include?(:bottom) ? '<w:bottom w:color="auto" w:space="0" w:sz="4" w:val="single"/>' : '<w:bottom w:val="nil"/>')
33
+ xml << (borders.include?(:left) ? '<w:left w:color="auto" w:space="0" w:sz="4" w:val="single"/>' : '<w:left w:val="nil"/>')
34
+ xml << (borders.include?(:right) ? '<w:right w:color="auto" w:space="0" w:sz="4" w:val="single"/>' : '<w:right w:val="nil"/>')
35
+ xml << "</w:tcBorders>"
36
+ end
37
+
38
+ if @valign != :top
39
+ xml << %Q(<w:vAlign w:val="#{@valign}"/>)
40
+ end
41
+
42
+ if @nowrap
43
+ xml << "<w:noWrap/>"
44
+ end
45
+
46
+ if @content.nil?
47
+ @content = "" # Nil is useful for rowspan, but we need to output something or Word breaks
48
+ end
49
+
50
+ if @rowspan
51
+ xml << '<w:vMerge w:val="restart"/>'
52
+ elsif @content == ""
53
+ xml << "<w:vMerge/>"
54
+ end
55
+
56
+ xml << "</w:tcPr>"
57
+
58
+ xml << DocXify::Element::Paragraph.new(@content, document: @document, font: @font, size: @size, color: @color, align: @align).to_s
59
+
60
+ xml << "</w:tc>"
61
+
62
+ xml
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,20 @@
1
+ module DocXify
2
+ module Element
3
+ class WebAddress < Base
4
+ attr_accessor :target
5
+
6
+ def initialize(target)
7
+ super()
8
+ @target = target
9
+ end
10
+
11
+ def reference
12
+ "url-#{Digest::SHA1.hexdigest(target)[0, 8]}"
13
+ end
14
+
15
+ def to_s
16
+ "<Relationship Id=\"#{reference}\" Target=\"#{target}/\" TargetMode=\"External\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink\"/>"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -15,6 +15,8 @@ module DocXify
15
15
  <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
16
16
  <Default ContentType="application/vnd.openxmlformats-package.relationships+xml" Extension="rels"/>
17
17
  <Default ContentType="application/xml" Extension="xml"/>
18
+ <Default ContentType="image/png" Extension="png"/>
19
+ <Default ContentType="image/jpeg" Extension="jpg"/>
18
20
  <Override ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" PartName="/word/document.xml"/>
19
21
  <Override ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml" PartName="/word/styles.xml"/>
20
22
  <Override ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml" PartName="/word/settings.xml"/>
@@ -1,3 +1,3 @@
1
1
  module DocXify
2
- VERSION = "0.0.2".freeze
2
+ VERSION = "0.0.7".freeze
3
3
  end
data/lib/docxify.rb CHANGED
@@ -2,13 +2,16 @@ require_relative "docxify/version"
2
2
  require_relative "docxify/document"
3
3
  require_relative "docxify/container"
4
4
  require_relative "docxify/template"
5
+
5
6
  require_relative "docxify/element/base"
6
7
  require_relative "docxify/element/divider"
8
+ require_relative "docxify/element/file"
7
9
  require_relative "docxify/element/image"
8
- require_relative "docxify/element/numbered_list_item"
9
10
  require_relative "docxify/element/page_break"
10
11
  require_relative "docxify/element/paragraph"
11
12
  require_relative "docxify/element/table"
13
+ require_relative "docxify/element/table_cell"
14
+ require_relative "docxify/element/web_address"
12
15
 
13
16
  module DocXify
14
17
  class Error < StandardError; end
@@ -22,24 +25,32 @@ module DocXify
22
25
  # Used for most sizes
23
26
  def self.cm2dxa(value)
24
27
  value = value.to_f
25
- raise ArgumentError, "Value must be greater than or equal to 0" if value < 0
28
+ raise ArgumentError.new("Value must be greater than or equal to 0") if value.negative?
29
+
30
+ (value * UNITS_PER_CM).to_i
31
+ end
32
+
33
+ # Inverse of cm2dxa
34
+ def self.dxa2cm(value)
35
+ value = value.to_f
36
+ raise ArgumentError.new("Value must be greater than or equal to 0") if value.negative?
26
37
 
27
- value * UNITS_PER_CM
38
+ (value / UNITS_PER_CM).to_i
28
39
  end
29
40
 
30
41
  # Used for font sizes
31
42
  def self.pt2halfpt(value)
32
43
  value = value.to_f
33
- raise ArgumentError, "Value must be greater than or equal to 0" if value < 0
44
+ raise ArgumentError.new("Value must be greater than or equal to 0") if value.negative?
34
45
 
35
- value * 2
46
+ (value * 2).to_i
36
47
  end
37
48
 
38
49
  # Used for image sizes
39
50
  def self.cm2emu(value)
40
51
  value = value.to_f
41
- raise ArgumentError, "Value must be greater than or equal to 0" if value < 0
52
+ raise ArgumentError.new("Value must be greater than or equal to 0") if value.negative?
42
53
 
43
- value * 360000
54
+ (value * 360_000).to_i
44
55
  end
45
56
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: docxify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Jeffries
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-04-11 00:00:00.000000000 Z
11
+ date: 2024-04-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubyzip
@@ -33,8 +33,9 @@ extensions: []
33
33
  extra_rdoc_files: []
34
34
  files:
35
35
  - ".rspec"
36
- - ".standard.yml"
36
+ - ".rubocop.yml"
37
37
  - CHANGELOG.md
38
+ - LICENSE.md
38
39
  - README.md
39
40
  - Rakefile
40
41
  - lib/docxify.rb
@@ -42,11 +43,13 @@ files:
42
43
  - lib/docxify/document.rb
43
44
  - lib/docxify/element/base.rb
44
45
  - lib/docxify/element/divider.rb
46
+ - lib/docxify/element/file.rb
45
47
  - lib/docxify/element/image.rb
46
- - lib/docxify/element/numbered_list_item.rb
47
48
  - lib/docxify/element/page_break.rb
48
49
  - lib/docxify/element/paragraph.rb
49
50
  - lib/docxify/element/table.rb
51
+ - lib/docxify/element/table_cell.rb
52
+ - lib/docxify/element/web_address.rb
50
53
  - lib/docxify/template.rb
51
54
  - lib/docxify/version.rb
52
55
  homepage: https://github.com/foundercatalyst/docxify
@@ -55,6 +58,7 @@ metadata:
55
58
  homepage_uri: https://github.com/foundercatalyst/docxify
56
59
  source_code_uri: https://github.com/foundercatalyst/docxify
57
60
  changelog_uri: https://github.com/foundercatalyst/docxify/CHANGELOG.md
61
+ rubygems_mfa_required: 'true'
58
62
  post_install_message:
59
63
  rdoc_options: []
60
64
  require_paths:
data/.standard.yml DELETED
@@ -1,3 +0,0 @@
1
- # For available configuration options, see:
2
- # https://github.com/standardrb/standard
3
- ruby_version: 3.0
File without changes