docxify 0.0.5 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19220bad643ba9281144f2af8122d7c3300befdef7ed3dff796b81ccb493850c
4
- data.tar.gz: fd960d429aedf127bfdca4eaf1d7a2aeda5a7c18577081a9f280169ccc74c23e
3
+ metadata.gz: 9ce756578c53df736bb1a6641722c8915ccc6bfdf24ce19c21e4bd64624f8405
4
+ data.tar.gz: 62039225ee265819d72a6cd6ef64a6cd7150b89d99f93fc1a0dfcf7994cafa4c
5
5
  SHA512:
6
- metadata.gz: 7ef5802312027442107a8541ab7e34be20b8309403c12506b2d48ae77eaeaeb3c2a19877a20ac54dbcc88af3a92869dbc4e718a7647b1abecfce677a05ace286
7
- data.tar.gz: b79ab3fc2a484c4882a0330c8bc25471ecb5304e8efa9260de945cdce57cd2ec2dae71133adaf7a10cf385f72d02c8f4f9255e0025ce47a442ce752f674939ec
6
+ metadata.gz: 514adbdd7c383dc3a373f460b9c548b532e3885b16d75030e5a12e070a13d41e3addab9cbed4cd89794e2bb057e67599e44d1399981d5a6e94c9fb1c5747dc6c
7
+ data.tar.gz: d3d04f7f8ad20fcdc4478cfe07247f4dc1d687423d4df46336ffd742cbbf941846e8831b8344279db182c324e3eac515856937152162be89f84590c095d80f14
data/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 0.0.8
4
+
5
+ Features:
6
+
7
+ - Allow changing of following section's page layotu
8
+
9
+ ## 0.0.7
10
+
11
+ Features:
12
+
13
+ - Table support
14
+
15
+ ## 0.0.6
16
+
17
+ Features:
18
+
19
+ - Tab stops and hanging indents done
20
+ - Replacing of {CHECKBOX_EMPTY} and {CHECKBOX_CHECKED} with correct UTF-8 characters done
21
+
3
22
  ## 0.0.5
4
23
 
5
24
  Features:
data/README.md CHANGED
@@ -35,21 +35,32 @@ gem install docxify
35
35
  @docx.add_paragraph "{CHECKBOX_EMPTY}\tEmpty checkbox", tab_stops_cm: [2]
36
36
  @docx.add_paragraph "{CHECKBOX_CHECKED}\tChecked checkbox", tab_stops_cm: [2]
37
37
 
38
- @docx.add_page_break
39
38
  @docx.add_divider
40
39
 
41
40
  @docx.add_image "file_path or data", align: :right, height_cm: 2, width_cm: 4
42
41
 
43
- headers = [
42
+ @docx.add_page_break
43
+
44
+ @docx.page_layout width: DocXify::A4_PORTRAIT_HEIGHT, height: DocXify::A4_PORTRAIT_WIDTH, orientation: :landscape
45
+
46
+ rows = []
47
+ rows << [
44
48
  DocXify::Element::TableCell.new("<b>Header 1</b>"),
45
49
  DocXify::Element::TableCell.new("<b>Header 2</b>")
50
+ DocXify::Element::TableCell.new("<b>Header 3</b>")
51
+ DocXify::Element::TableCell.new("<b>Header 4</b>", width_cm: 10)
52
+ ]
53
+ rows << [
54
+ DocXify::Element::TableCell.new("Content 1", valign: :center, align: :left, nowrap: true, colspan: 3),
55
+ DocXify::Element::TableCell.new("Rowspan <b>here</b>", rowspan: true) # merges until a "nil" cell
46
56
  ]
47
- row = [
48
- DocXify::Element::TableCell.new("Content <b>here</b>", valign: :center, align: :left, nowrap: true, colspan: 3),
49
- DocXify::Element::TableCell.new("Content <b>here</b>")
57
+ rows << [
58
+ DocXify::Element::TableCell.new("Secondary 1")
59
+ DocXify::Element::TableCell.new("Secondary 2")
60
+ DocXify::Element::TableCell.new("Secondary 3")
61
+ DocXify::Element::TableCell.new(nil) # Word requires that there's an empty cell merged with the previous rowspan
50
62
  ]
51
- rows = [row]
52
- @docx.add_table headers, rows, expand: :full
63
+ container.add_table rows
53
64
 
54
65
  docx_binary_data = @docx.render
55
66
  # or
@@ -39,9 +39,11 @@ module DocXify
39
39
  zip.put_next_entry "word/_rels/document.xml.rels"
40
40
  zip.write document_xml_rels
41
41
 
42
- @document.images.each do |image|
43
- zip.put_next_entry "word/media/#{image.filename}"
44
- zip.write image.data
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
45
47
  end
46
48
  end
47
49
 
@@ -64,8 +66,8 @@ module DocXify
64
66
  <Relationship Id="rId4" Target="fontTable.xml" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable"/>
65
67
  XML
66
68
 
67
- @document.images.each do |image|
68
- 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
69
71
  end
70
72
 
71
73
  xml << "</Relationships>"
@@ -1,18 +1,19 @@
1
1
  module DocXify
2
2
  class Document
3
- attr_accessor :font, :size, :color, :background
4
- attr_reader :content, :images
3
+ attr_accessor :font, :size, :color, :background, :margins, :page_layout
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
+ @orientation = options[:orientation] || :portrait
11
12
  @font = options[:font] || "Times New Roman"
12
13
  @size = options[:size] || 12
13
14
  @color = options[:color] || 12
14
15
  @background = options[:background] if options[:background]
15
- @margins = { top: 2, bottom: 2, left: 2, right: 2 }
16
+ @margins = { top: 2, bottom: 2, left: 2, right: 2 }.merge(options[:margins] || {})
16
17
  end
17
18
 
18
19
  def default_styling(options = {})
@@ -41,17 +42,21 @@ module DocXify
41
42
  <w:body>
42
43
  XML
43
44
 
45
+ # See the note in DocXify::Element::PageLayout for why it's not just handled the same as any other element
46
+ @page_layout = DocXify::Element::PageLayout.new(width: @width, height: @height, orientation: @orientatation, document: self)
47
+
44
48
  @content.each do |element|
45
- xml << element.to_s(container)
49
+ if element.is_a?(DocXify::Element::PageLayout)
50
+ xml << @page_layout.to_s
51
+ @page_layout = element
52
+ else
53
+ xml << element.to_s(container)
54
+ end
46
55
  end
47
56
 
57
+ xml << @page_layout.to_s
58
+
48
59
  xml << <<~XML
49
- <w:sectPr >
50
- <w:pgSz w:h="#{@height}" w:w="#{@width}"/>
51
- <w:pgMar w:bottom="#{DocXify.cm2dxa @margins[:bottom]}" w:footer="708" w:gutter="0" w:header="708" w:left="#{DocXify.cm2dxa @margins[:left]}" w:right="#{DocXify.cm2dxa @margins[:right]}" w:top="#{DocXify.cm2dxa @margins[:top]}"/>
52
- <w:cols w:space="708"/>
53
- <w:docGrid w:linePitch="360"/>
54
- </w:sectPr>
55
60
  </w:body>
56
61
  </w:document>
57
62
  XML
@@ -74,7 +79,7 @@ module DocXify
74
79
 
75
80
  def add_file(file_path_or_data)
76
81
  file = DocXify::Element::File.new(file_path_or_data)
77
- @images << file
82
+ @relationships << file
78
83
  file
79
84
  end
80
85
 
@@ -82,6 +87,11 @@ module DocXify
82
87
  add DocXify::Element::PageBreak.new
83
88
  end
84
89
 
90
+ def add_page_layout(options = {})
91
+ options[:document] = self
92
+ add DocXify::Element::PageLayout.new(options)
93
+ end
94
+
85
95
  def add_divider
86
96
  add DocXify::Element::Divider.new
87
97
  end
@@ -91,8 +101,9 @@ module DocXify
91
101
  add DocXify::Element::Paragraph.new(text, options)
92
102
  end
93
103
 
94
- def add_table(headers, rows, options = {})
95
- add DocXify::Element::Table.new(headers, rows, options)
104
+ def add_table(rows, options = {})
105
+ options[:document] = self
106
+ add DocXify::Element::Table.new(rows, options)
96
107
  end
97
108
  end
98
109
  end
@@ -22,7 +22,7 @@ module DocXify
22
22
  if char == "<"
23
23
  state = :tag
24
24
  tag = ""
25
- result << text.strip unless text.strip.empty?
25
+ result << text unless text.empty?
26
26
  text = ""
27
27
  else
28
28
  text << char
@@ -61,7 +61,7 @@ module DocXify
61
61
  when :content # With the content of an HTML tag
62
62
  if char == "<"
63
63
  state = :tag
64
- result.last[:content] = content.strip
64
+ result.last[:content] = content
65
65
  content = ""
66
66
  else
67
67
  content << char
@@ -71,7 +71,7 @@ module DocXify
71
71
  last_char = char
72
72
  end
73
73
 
74
- result << text.strip unless text.strip.empty?
74
+ result << text unless text.empty?
75
75
  result
76
76
  end
77
77
  end
@@ -34,6 +34,10 @@ module DocXify
34
34
  "image-#{Digest::SHA1.hexdigest(@data)[0, 8]}"
35
35
  end
36
36
 
37
+ def to_s
38
+ "<Relationship Id=\"#{reference}\" Target=\"media/#{filename}\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\"/>"
39
+ end
40
+
37
41
  def contains_png_image?(data)
38
42
  data[0, 8] == PNG_SIGNATURE
39
43
  end
@@ -8,7 +8,6 @@ module DocXify
8
8
  <w:br w:type="page"/>
9
9
  </w:r>
10
10
  </w:p>
11
- <w:p/>
12
11
  XML
13
12
  end
14
13
  end
@@ -1,7 +1,7 @@
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
6
  def initialize(text, options = {})
7
7
  super()
@@ -14,38 +14,86 @@ module DocXify
14
14
  @background = options[:background] if options[:background]
15
15
  @background ||= @document&.background if @document&.background
16
16
  @align = options[:align] || :left
17
- @inline_styling = options[:inline_styling] || true
17
+ @inline_styling = options.key?(:inline_styling) ? options[:inline_styling] : true
18
18
  @tab_stops_cm = options[:tab_stops_cm] || []
19
+ @hanging_cm = options[:hanging_cm] || 0
19
20
  end
20
21
 
21
22
  def to_s(_container = nil)
22
23
  nodes = if @inline_styling
23
24
  parse_simple_html(@text)
24
25
  else
25
- [@text]
26
+ [@text.gsub("<", "&lt;").gsub(">", "&gt;")]
26
27
  end
27
28
 
28
29
  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
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>"
44
47
 
45
48
  nodes.each do |node|
46
- xml << "<w:t xml:space=\"preserve\">#{node}</w:t>"
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
47
76
  end
48
- xml << "</w:r></w:p>"
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
49
97
  end
50
98
  end
51
99
  end
@@ -1,8 +1,106 @@
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
+
1
19
  module DocXify
2
20
  module Element
3
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
+
4
30
  def to_s(_container = nil)
5
- # TODO: Implement output
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>"
6
104
  end
7
105
  end
8
106
  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
@@ -1,3 +1,3 @@
1
1
  module DocXify
2
- VERSION = "0.0.5".freeze
2
+ VERSION = "0.0.8".freeze
3
3
  end
data/lib/docxify.rb CHANGED
@@ -8,8 +8,11 @@ require_relative "docxify/element/divider"
8
8
  require_relative "docxify/element/file"
9
9
  require_relative "docxify/element/image"
10
10
  require_relative "docxify/element/page_break"
11
+ require_relative "docxify/element/page_layout"
11
12
  require_relative "docxify/element/paragraph"
12
13
  require_relative "docxify/element/table"
14
+ require_relative "docxify/element/table_cell"
15
+ require_relative "docxify/element/web_address"
13
16
 
14
17
  module DocXify
15
18
  class Error < StandardError; end
@@ -28,6 +31,14 @@ module DocXify
28
31
  (value * UNITS_PER_CM).to_i
29
32
  end
30
33
 
34
+ # Inverse of cm2dxa
35
+ def self.dxa2cm(value)
36
+ value = value.to_f
37
+ raise ArgumentError.new("Value must be greater than or equal to 0") if value.negative?
38
+
39
+ (value / UNITS_PER_CM).to_i
40
+ end
41
+
31
42
  # Used for font sizes
32
43
  def self.pt2halfpt(value)
33
44
  value = value.to_f
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.5
4
+ version: 0.0.8
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-12 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
@@ -48,6 +48,8 @@ files:
48
48
  - lib/docxify/element/page_break.rb
49
49
  - lib/docxify/element/paragraph.rb
50
50
  - lib/docxify/element/table.rb
51
+ - lib/docxify/element/table_cell.rb
52
+ - lib/docxify/element/web_address.rb
51
53
  - lib/docxify/template.rb
52
54
  - lib/docxify/version.rb
53
55
  homepage: https://github.com/foundercatalyst/docxify