openxml-xlsx 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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