docxify 0.0.2 → 0.0.5

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: 19220bad643ba9281144f2af8122d7c3300befdef7ed3dff796b81ccb493850c
4
+ data.tar.gz: fd960d429aedf127bfdca4eaf1d7a2aeda5a7c18577081a9f280169ccc74c23e
5
5
  SHA512:
6
- metadata.gz: d8ee36086086aef5941636ad168b0bc11e526d5e801fb482cdda6169b2065901069cdd9d6d68d05ab482bbc3c1541aad0258f051e673019590987b3991d36db1
7
- data.tar.gz: b34e167da1eb82d24cac8b15c54882a2b6f130dfc68281f024e02739ebd04880076847f9345f38ffc0dcaf7b36ffa3c194a521cc0c0b9d8b29e6a8098b065d52
6
+ metadata.gz: 7ef5802312027442107a8541ab7e34be20b8309403c12506b2d48ae77eaeaeb3c2a19877a20ac54dbcc88af3a92869dbc4e718a7647b1abecfce677a05ace286
7
+ data.tar.gz: b79ab3fc2a484c4882a0330c8bc25471ecb5304e8efa9260de945cdce57cd2ec2dae71133adaf7a10cf385f72d02c8f4f9255e0025ce47a442ce752f674939ec
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,25 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.0.5
4
+
5
+ Features:
6
+
7
+ - Paragraph font name, size, colour and yellow highlight done
8
+ - Document level default font name, size and colour done
9
+
10
+ ## 0.0.4
11
+
12
+ Features:
13
+
14
+ - Image insertion is working
15
+
16
+ ## 0.0.3
17
+
18
+ Features:
19
+
20
+ - Dividers and page breaks implemented
21
+ - Simple HTML parsing (for paragraphs) implemented
22
+
3
23
  ## 0.0.2
4
24
 
5
25
  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,17 +25,16 @@ 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
38
  @docx.add_page_break
40
39
  @docx.add_divider
41
40
 
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,12 @@ module DocXify
36
36
  zip.put_next_entry "word/document.xml"
37
37
  zip.write document.build_xml(self)
38
38
 
39
+ zip.put_next_entry "word/_rels/document.xml.rels"
40
+ zip.write document_xml_rels
41
+
39
42
  @document.images.each do |image|
40
43
  zip.put_next_entry "word/media/#{image.filename}"
41
- zip.write image.file_contents
44
+ zip.write image.data
42
45
  end
43
46
  end
44
47
 
@@ -12,7 +12,7 @@ module DocXify
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,35 @@ 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
+ @images << 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
94
  def add_table(headers, rows, options = {})
89
- add DocXify::Element::Table.new(self, headers, rows, options)
95
+ add DocXify::Element::Table.new(headers, rows, options)
90
96
  end
91
-
92
- # MARK: Private
93
-
94
- private
95
-
96
97
  end
97
98
  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.strip unless text.strip.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.strip
65
+ content = ""
66
+ else
67
+ content << char
68
+ end
69
+ end
70
+
71
+ last_char = char
72
+ end
73
+
74
+ result << text.strip unless text.strip.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,46 @@
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 contains_png_image?(data)
38
+ data[0, 8] == PNG_SIGNATURE
39
+ end
40
+
41
+ def contains_jpeg_image?(data)
42
+ data[0..1] == JPEG_START && data[-2..] == JPEG_END
43
+ end
44
+ end
45
+ end
46
+ 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
@@ -3,22 +3,49 @@ module DocXify
3
3
  class Paragraph < Base
4
4
  attr_accessor :text, :font, :size, :color, :background, :align, :inline_styling, :tab_stops_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
17
  @inline_styling = options[:inline_styling] || true
16
18
  @tab_stops_cm = options[:tab_stops_cm] || []
17
19
  end
18
20
 
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>"
21
+ def to_s(_container = nil)
22
+ nodes = if @inline_styling
23
+ parse_simple_html(@text)
24
+ else
25
+ [@text]
26
+ end
27
+
28
+ xml = "<w:p>"
29
+ xml << <<~XML
30
+ <w:pPr>
31
+ <w:jc w:val="#{@align}"/>
32
+ </w:pPr>
33
+ XML
34
+ xml << "<w:r>"
35
+ xml << <<~XML
36
+ <w:rPr>
37
+ <w:rFonts w:ascii="#{@font}" w:cs="#{@font}" w:hAnsi="#{@font}"/>
38
+ <w:color w:val="#{@color.gsub("#", "")}"/>
39
+ <w:sz w:val="#{DocXify.pt2halfpt(@size)}"/>
40
+ <w:szCs w:val="#{DocXify.pt2halfpt(@size)}"/>
41
+ #{"<w:highlight w:val=\"yellow\"/>" if @highlight}
42
+ </w:rPr>
43
+ XML
44
+
45
+ nodes.each do |node|
46
+ xml << "<w:t xml:space=\"preserve\">#{node}</w:t>"
47
+ end
48
+ xml << "</w:r></w:p>"
22
49
  end
23
50
  end
24
51
  end
@@ -0,0 +1,9 @@
1
+ module DocXify
2
+ module Element
3
+ class Table < Base
4
+ def to_s(_container = nil)
5
+ # TODO: Implement output
6
+ end
7
+ end
8
+ end
9
+ 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.5".freeze
3
3
  end
data/lib/docxify.rb CHANGED
@@ -2,10 +2,11 @@ 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"
@@ -22,24 +23,24 @@ module DocXify
22
23
  # Used for most sizes
23
24
  def self.cm2dxa(value)
24
25
  value = value.to_f
25
- raise ArgumentError, "Value must be greater than or equal to 0" if value < 0
26
+ raise ArgumentError.new("Value must be greater than or equal to 0") if value.negative?
26
27
 
27
- value * UNITS_PER_CM
28
+ (value * UNITS_PER_CM).to_i
28
29
  end
29
30
 
30
31
  # Used for font sizes
31
32
  def self.pt2halfpt(value)
32
33
  value = value.to_f
33
- raise ArgumentError, "Value must be greater than or equal to 0" if value < 0
34
+ raise ArgumentError.new("Value must be greater than or equal to 0") if value.negative?
34
35
 
35
- value * 2
36
+ (value * 2).to_i
36
37
  end
37
38
 
38
39
  # Used for image sizes
39
40
  def self.cm2emu(value)
40
41
  value = value.to_f
41
- raise ArgumentError, "Value must be greater than or equal to 0" if value < 0
42
+ raise ArgumentError.new("Value must be greater than or equal to 0") if value.negative?
42
43
 
43
- value * 360000
44
+ (value * 360_000).to_i
44
45
  end
45
46
  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.5
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-12 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,8 +43,8 @@ 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
@@ -55,6 +56,7 @@ metadata:
55
56
  homepage_uri: https://github.com/foundercatalyst/docxify
56
57
  source_code_uri: https://github.com/foundercatalyst/docxify
57
58
  changelog_uri: https://github.com/foundercatalyst/docxify/CHANGELOG.md
59
+ rubygems_mfa_required: 'true'
58
60
  post_install_message:
59
61
  rdoc_options: []
60
62
  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