openxml-xlsx 0.1.2 → 0.2.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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +4 -4
  4. data/example +4 -3
  5. data/lib/openxml-xlsx.rb +1 -0
  6. data/lib/openxml/xlsx.rb +30 -0
  7. data/lib/{xlsx → openxml/xlsx}/elements.rb +4 -2
  8. data/lib/openxml/xlsx/elements/alignment.rb +22 -0
  9. data/lib/openxml/xlsx/elements/border.rb +28 -0
  10. data/lib/openxml/xlsx/elements/border_component.rb +21 -0
  11. data/lib/openxml/xlsx/elements/border_style.rb +22 -0
  12. data/lib/openxml/xlsx/elements/cell.rb +96 -0
  13. data/lib/openxml/xlsx/elements/defined_name.rb +13 -0
  14. data/lib/openxml/xlsx/elements/font.rb +22 -0
  15. data/lib/openxml/xlsx/elements/implied_number_format.rb +7 -0
  16. data/lib/openxml/xlsx/elements/indexed_color.rb +13 -0
  17. data/lib/openxml/xlsx/elements/number_format.rb +47 -0
  18. data/lib/openxml/xlsx/elements/pattern_fill.rb +20 -0
  19. data/lib/openxml/xlsx/elements/relationship.rb +20 -0
  20. data/lib/openxml/xlsx/elements/row.rb +37 -0
  21. data/lib/openxml/xlsx/elements/style.rb +29 -0
  22. data/lib/openxml/xlsx/elements/table_column.rb +8 -0
  23. data/lib/openxml/xlsx/elements/theme_color.rb +13 -0
  24. data/lib/openxml/xlsx/package.rb +52 -0
  25. data/lib/{xlsx → openxml/xlsx}/parts.rb +4 -2
  26. data/lib/openxml/xlsx/parts/shared_strings.rb +28 -0
  27. data/lib/openxml/xlsx/parts/stylesheet.rb +80 -0
  28. data/lib/openxml/xlsx/parts/table.rb +36 -0
  29. data/lib/openxml/xlsx/parts/workbook.rb +71 -0
  30. data/lib/openxml/xlsx/parts/worksheet.rb +90 -0
  31. data/lib/openxml/xlsx/version.rb +5 -0
  32. data/{xlsx.gemspec → openxml-xlsx.gemspec} +5 -5
  33. metadata +37 -36
  34. data/lib/xlsx.rb +0 -28
  35. data/lib/xlsx/elements/alignment.rb +0 -20
  36. data/lib/xlsx/elements/border.rb +0 -26
  37. data/lib/xlsx/elements/border_component.rb +0 -19
  38. data/lib/xlsx/elements/border_style.rb +0 -20
  39. data/lib/xlsx/elements/cell.rb +0 -94
  40. data/lib/xlsx/elements/defined_name.rb +0 -11
  41. data/lib/xlsx/elements/font.rb +0 -20
  42. data/lib/xlsx/elements/implied_number_format.rb +0 -5
  43. data/lib/xlsx/elements/indexed_color.rb +0 -11
  44. data/lib/xlsx/elements/number_format.rb +0 -45
  45. data/lib/xlsx/elements/pattern_fill.rb +0 -18
  46. data/lib/xlsx/elements/relationship.rb +0 -18
  47. data/lib/xlsx/elements/row.rb +0 -35
  48. data/lib/xlsx/elements/style.rb +0 -27
  49. data/lib/xlsx/elements/table_column.rb +0 -6
  50. data/lib/xlsx/elements/theme_color.rb +0 -11
  51. data/lib/xlsx/package.rb +0 -50
  52. data/lib/xlsx/parts/shared_strings.rb +0 -26
  53. data/lib/xlsx/parts/stylesheet.rb +0 -78
  54. data/lib/xlsx/parts/table.rb +0 -34
  55. data/lib/xlsx/parts/workbook.rb +0 -66
  56. data/lib/xlsx/parts/worksheet.rb +0 -88
  57. data/lib/xlsx/version.rb +0 -3
@@ -0,0 +1,37 @@
1
+ module OpenXml
2
+ module Xlsx
3
+ module Elements
4
+ class Row
5
+ attr_reader :worksheet, :number, :height, :hidden, :cells
6
+
7
+ def initialize(worksheet, options={})
8
+ @worksheet = worksheet
9
+ @number = options.fetch(:number)
10
+ @height = options[:height]
11
+ @hidden = options[:hidden]
12
+ @cells = []
13
+
14
+ Array(options[:cells]).each do |attributes|
15
+ add_cell attributes
16
+ end
17
+ end
18
+
19
+ def add_cell(attributes)
20
+ cells.push Xlsx::Elements::Cell.new(self, attributes)
21
+ end
22
+
23
+ def to_xml(xml)
24
+ attributes = {"r" => number}
25
+ attributes.merge!("ht" => height, "customHeight" => 1) if height
26
+ attributes.merge!("hidden" => 1) if hidden
27
+ xml.row(attributes) do
28
+ cells.each do |cell|
29
+ cell.to_xml(xml)
30
+ end
31
+ end
32
+ end
33
+
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,29 @@
1
+ module OpenXml
2
+ module Xlsx
3
+ module Elements
4
+ class Style < Struct.new(:format_id, :font_id, :fill_id, :border_id, :alignment)
5
+
6
+ def initialize(format_id=0, font_id=0, fill_id=0, border_id=0, alignment=nil)
7
+ super format_id || 0, font_id || 0, fill_id || 0, border_id || 0, alignment
8
+ end
9
+
10
+ def to_xml(xml)
11
+ attributes = {
12
+ numFmtId: format_id,
13
+ fontId: font_id,
14
+ fillId: fill_id,
15
+ borderId: border_id }
16
+ attributes.merge!(applyNumberFormat: 1) if format_id > 0
17
+ attributes.merge!(applyFont: 1) if font_id > 0
18
+ attributes.merge!(applyFill: 1) if fill_id > 0
19
+ attributes.merge!(applyBorder: 1) if border_id > 0
20
+ attributes.merge!(applyAlignment: 1) if alignment
21
+ xml.xf(attributes) do
22
+ alignment.to_xml(xml) if alignment
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,8 @@
1
+ module OpenXml
2
+ module Xlsx
3
+ module Elements
4
+ class TableColumn < Struct.new(:name)
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,13 @@
1
+ module OpenXml
2
+ module Xlsx
3
+ module Elements
4
+ class ThemeColor < Struct.new(:theme, :tint)
5
+
6
+ def to_xml(name, xml)
7
+ xml.public_send(name, theme: theme, tint: tint)
8
+ end
9
+
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,52 @@
1
+ require "openxml/package"
2
+
3
+ module OpenXml
4
+ module Xlsx
5
+ class Package < OpenXml::Package
6
+ attr_reader :xl_rels,
7
+ :shared_strings,
8
+ :stylesheet,
9
+ :workbook
10
+
11
+
12
+ content_types do
13
+ override "/xl/workbook.xml", TYPE_WORKBOOK
14
+ override "/xl/worksheets/sheet1.xml", TYPE_WORKSHEET
15
+ override "/xl/sharedStrings.xml", TYPE_SHARED_STRINGS
16
+ override "/xl/styles.xml", TYPE_STYLES
17
+ end
18
+
19
+
20
+ def initialize
21
+ super
22
+ rels.add_relationship REL_DOCUMENT, "xl/workbook.xml"
23
+
24
+ @xl_rels = OpenXml::Parts::Rels.new([
25
+ { "Type" => REL_SHARED_STRINGS, "Target" => "sharedStrings.xml" },
26
+ { "Type" => REL_STYLES, "Target" => "styles.xml" }
27
+ ])
28
+ @shared_strings = Xlsx::Parts::SharedStrings.new
29
+ @stylesheet = Xlsx::Parts::Stylesheet.new
30
+ @workbook = Xlsx::Parts::Workbook.new(self)
31
+
32
+ # docProps/app.xml
33
+ # docProps/core.xml
34
+ add_part "xl/_rels/workbook.xml.rels", xl_rels
35
+ # xl/calcChain.xml
36
+ add_part "xl/sharedStrings.xml", shared_strings
37
+ add_part "xl/styles.xml", stylesheet
38
+ # xl/theme/theme1.xml
39
+ add_part "xl/workbook.xml", workbook
40
+ end
41
+
42
+ def string_ref(string)
43
+ shared_strings.reference_of(string)
44
+ end
45
+
46
+ def style_ref(style)
47
+ stylesheet.reference_of(style)
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -1,5 +1,7 @@
1
- module Xlsx
2
- module Parts
1
+ module OpenXml
2
+ module Xlsx
3
+ module Parts
4
+ end
3
5
  end
4
6
  end
5
7
 
@@ -0,0 +1,28 @@
1
+ module OpenXml
2
+ module Xlsx
3
+ module Parts
4
+ class SharedStrings < OpenXml::Part
5
+ attr_reader :strings
6
+
7
+ def initialize
8
+ @strings = Hash.new { |hash, key| hash[key] = hash.length }
9
+ end
10
+
11
+ def reference_of(string)
12
+ strings[string]
13
+ end
14
+
15
+ def to_xml
16
+ build_standalone_xml do |xml|
17
+ xml.sst(xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main", uniqueCount: strings.length) do
18
+ strings.each do |string, i|
19
+ xml.si { xml.t(string) }
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,80 @@
1
+ module OpenXml
2
+ module Xlsx
3
+ module Parts
4
+ class Stylesheet < OpenXml::Part
5
+ include Xlsx::Elements
6
+
7
+ attr_reader :formats, :fonts, :fills, :borders, :styles
8
+
9
+ def initialize
10
+ @formats = []
11
+ @fonts = [Font.new("Calibri", 12)]
12
+ @fills = [PatternFill.new("none"), PatternFill.new("gray125")]
13
+ @borders = [Border.new]
14
+ @styles = [Style.new]
15
+ end
16
+
17
+ def reference_of(options={})
18
+ case format = options[:format]
19
+ when NumberFormat
20
+ options[:format_id] = Xlsx.index!(formats, format) + NUMBER_FORMAT_START_ID
21
+ when ImpliedNumberFormat
22
+ options[:format_id] = format.id
23
+ end
24
+ options[:font_id] = Xlsx.index!(fonts, options[:font]) if options.key? :font
25
+ options[:fill_id] = Xlsx.index!(fills, options[:fill]) if options.key? :fill
26
+ options[:border_id] = Xlsx.index!(borders, options[:border]) if options.key? :border
27
+
28
+ style = Style.new(
29
+ options.fetch(:format_id, 0),
30
+ options.fetch(:font_id, 0),
31
+ options.fetch(:fill_id, 0),
32
+ options.fetch(:border_id, 0),
33
+ options.fetch(:alignment, nil))
34
+
35
+ Xlsx.index!(styles, style)
36
+ end
37
+
38
+ def to_xml
39
+ build_standalone_xml do |xml|
40
+ xml.styleSheet(xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main", "xmlns:mc" => "http://schemas.openxmlformats.org/markup-compatibility/2006") do
41
+ xml.numFmts(count: formats.length) do
42
+ formats.each_with_index do |format, index|
43
+ format.to_xml(index + NUMBER_FORMAT_START_ID, xml)
44
+ end
45
+ end
46
+
47
+ xml.fonts(count: fonts.length) do
48
+ fonts.each do |font|
49
+ font.to_xml(xml)
50
+ end
51
+ end
52
+
53
+ xml.fills(count: fills.length) do
54
+ fills.each do |fill|
55
+ fill.to_xml(xml)
56
+ end
57
+ end
58
+
59
+ xml.borders(count: borders.length) do
60
+ borders.each do |border|
61
+ border.to_xml(xml)
62
+ end
63
+ end
64
+
65
+ xml.cellXfs(count: styles.length) do
66
+ styles.each do |style|
67
+ style.to_xml(xml)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ private
75
+ NUMBER_FORMAT_START_ID = 165.freeze
76
+
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,36 @@
1
+ module OpenXml
2
+ module Xlsx
3
+ module Parts
4
+ class Table < OpenXml::Part
5
+ attr_reader :id, :name, :ref, :columns
6
+
7
+ def initialize(id, name, ref, columns)
8
+ @id = id
9
+ @name = name
10
+ @ref = ref
11
+ @columns = columns
12
+ end
13
+
14
+ def filename
15
+ "table#{id}.xml"
16
+ end
17
+
18
+ def to_xml
19
+ build_standalone_xml do |xml|
20
+ xml.table(xmlns: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
21
+ id: id, name: name, displayName: name, ref: ref, totalsRowShown: 0) do
22
+ xml.autoFilter ref: ref
23
+ xml.tableColumns(count: columns.length) do
24
+ columns.each_with_index do |column, index|
25
+ xml.tableColumn(id: index + 1, name: column.name)
26
+ end
27
+ end
28
+ xml.tableStyleInfo(name: "TableStyleLight6", showFirstColumn: 0, showLastColumn: 0, showRowStripes: 1, showColumnStripes: 0)
29
+ end
30
+ end
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,71 @@
1
+ module OpenXml
2
+ module Xlsx
3
+ module Parts
4
+ class Workbook < OpenXml::Part
5
+ attr_reader :package, :worksheets, :tables, :defined_names
6
+
7
+ def initialize(package)
8
+ @package = package
9
+ @worksheets = []
10
+ @tables = []
11
+ @defined_names =[]
12
+ add_worksheet
13
+ end
14
+
15
+ def add_worksheet
16
+ worksheet = Worksheet.new(self, worksheets.length + 1)
17
+ package.xl_rels.add_relationship(
18
+ REL_WORKSHEET,
19
+ "worksheets/sheet#{worksheet.index}.xml",
20
+ "rId#{worksheet.index}")
21
+ package.add_part "xl/worksheets/_rels/sheet#{worksheet.index}.xml.rels", worksheet.rels
22
+ package.add_part "xl/worksheets/sheet#{worksheet.index}.xml", worksheet
23
+ worksheets.push worksheet
24
+ end
25
+
26
+ def add_table(table)
27
+ package.content_types.add_override "/xl/tables/#{table.filename}", TYPE_TABLE
28
+ package.add_part "xl/tables/#{table.filename}", table
29
+ tables.push table
30
+ end
31
+
32
+ def add_defined_names(*defined_names)
33
+ defined_names.flatten.each do |attributes|
34
+ add_defined_name attributes
35
+ end
36
+ end
37
+
38
+ def add_defined_name(attributes)
39
+ defined_names.push Xlsx::Elements::DefinedName.new(attributes[:name], attributes[:formula])
40
+ end
41
+
42
+ def to_xml
43
+ build_standalone_xml do |xml|
44
+ xml.workbook(root_namespaces) {
45
+ xml.bookViews {
46
+ xml.workbookView
47
+ }
48
+ xml.sheets { worksheets.each { |worksheet|
49
+ xml.sheet(
50
+ "name" => worksheet.name,
51
+ "sheetId" => worksheet.index,
52
+ "r:id" => "rId#{worksheet.index}")
53
+ } }
54
+ xml.definedNames do
55
+ defined_names.each { |defined_name| defined_name.to_xml(xml) }
56
+ end if defined_names.any?
57
+ }
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def root_namespaces
64
+ { "xmlns" => "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
65
+ "xmlns:r" => 'http://schemas.openxmlformats.org/officeDocument/2006/relationships' }
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,90 @@
1
+ module OpenXml
2
+ module Xlsx
3
+ module Parts
4
+ class Worksheet < OpenXml::Part
5
+ attr_reader :workbook, :index, :rows, :tables, :rels, :cell_ranges
6
+
7
+ def initialize(workbook, index)
8
+ @workbook = workbook
9
+ @index = index
10
+ @rows = []
11
+ @tables = []
12
+ @cell_ranges = []
13
+ @rels = OpenXml::Parts::Rels.new
14
+ @column_widths = {}
15
+ end
16
+
17
+ def column_widths(*args)
18
+ return @column_widths if args.none?
19
+ @column_widths = args.first
20
+ end
21
+
22
+ def add_rows(*rows)
23
+ rows.flatten.each do |attributes|
24
+ add_row attributes
25
+ end
26
+ end
27
+
28
+ def add_row(attributes)
29
+ rows.push Xlsx::Elements::Row.new(self, attributes)
30
+ end
31
+
32
+ def merge_cells(*ranges)
33
+ ranges.each { |range| cell_ranges.push range }
34
+ end
35
+
36
+ def add_table(id, name, ref, columns)
37
+ table = Xlsx::Parts::Table.new(id, name, ref, columns)
38
+ rels.add_relationship(REL_TABLE, "../tables/#{table.filename}")
39
+ workbook.add_table table
40
+ end
41
+
42
+ def to_xml
43
+ build_standalone_xml do |xml|
44
+ xml.worksheet(root_namespaces) do
45
+ xml.sheetViews do
46
+ xml.sheetView(showGridLines: 0, tabSelected: 1, workbookViewId: 0)
47
+ end
48
+ xml.sheetFormatPr(baseColWidth: 10, defaultColWidth: 13.33203125, defaultRowHeight: 20, customHeight: 1)
49
+ xml.cols do
50
+ column_widths.each do |column, width|
51
+ xml.col(min: column, max: column, width: width, customWidth: 1)
52
+ end
53
+ end if column_widths.any?
54
+ xml.sheetData do
55
+ rows.each { |row| row.to_xml(xml) }
56
+ end
57
+ xml.mergeCells(count: merge_cells.size) do
58
+ cell_ranges.each { |range| xml.mergeCell ref: range }
59
+ end if cell_ranges.any?
60
+ xml.pageMargins(left: 0.75, right: 0.75, top: 1, bottom: 1, header: 0.5, footer: 0.5)
61
+ xml.pageSetup(orientation: "portrait", horizontalDpi: 4294967292, verticalDpi: 4294967292)
62
+ xml.tableParts(count: tables.count) do
63
+ tables.each do |rel|
64
+ xml.tablePart("r:id" => rel.id)
65
+ end
66
+ end if tables.any?
67
+ end
68
+ end
69
+ end
70
+
71
+ def name
72
+ "Sheet#{index}"
73
+ end
74
+
75
+ private
76
+
77
+ def root_namespaces
78
+ { "xmlns" => "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
79
+ "xmlns:r" => "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
80
+ "xmlns:mc" => "http://schemas.openxmlformats.org/markup-compatibility/2006" }
81
+ end
82
+
83
+ def tables
84
+ rels.select { |rel| rel.type == REL_TABLE }
85
+ end
86
+
87
+ end
88
+ end
89
+ end
90
+ end