summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--examples/example.rb14
-rw-r--r--lib/axlsx.rb2
-rw-r--r--lib/axlsx/package.rb8
-rw-r--r--lib/axlsx/table/table.rb97
-rw-r--r--lib/axlsx/util/constants.rb3
-rw-r--r--lib/axlsx/workbook/workbook.rb10
-rw-r--r--lib/axlsx/workbook/worksheet/worksheet.rb20
-rw-r--r--test/table/tc_table.rb72
8 files changed, 224 insertions, 2 deletions
diff --git a/examples/example.rb b/examples/example.rb
index d834a51c..2191f6a6 100644
--- a/examples/example.rb
+++ b/examples/example.rb
@@ -206,6 +206,18 @@ wb.add_worksheet(:name => "Auto Filter") do |sheet|
sheet.auto_filter = "A2:D5"
end
+##Tables
+
+wb.add_worksheet(:name => "Table") do |sheet|
+ sheet.add_row ["Build Matrix"]
+ sheet.add_row ["Build", "Duration", "Finished", "Rvm"]
+ sheet.add_row ["19.1", "1 min 32 sec", "about 10 hours ago", "1.8.7"]
+ sheet.add_row ["19.2", "1 min 28 sec", "about 10 hours ago", "1.9.2"]
+ sheet.add_row ["19.3", "1 min 35 sec", "about 10 hours ago", "1.9.3"]
+ sheet.add_table "A2:D5", :name => 'Build Matrix'
+end
+
+
##Specifying Column Widths
wb.add_worksheet(:name => "custom column widths") do |sheet|
@@ -235,7 +247,7 @@ end
##Validate and Serialize
-p.validate.each { |e| puts e.message }
+#p.validate.each { |e| puts e.message }
p.serialize("example.xlsx")
s = p.to_stream()
diff --git a/lib/axlsx.rb b/lib/axlsx.rb
index 3c6361e0..399e740e 100644
--- a/lib/axlsx.rb
+++ b/lib/axlsx.rb
@@ -22,7 +22,7 @@ require 'axlsx/rels/relationships.rb'
require 'axlsx/drawing/drawing.rb'
require 'axlsx/workbook/workbook.rb'
require 'axlsx/package.rb'
-
+require 'axlsx/table/table.rb'
#required gems
require 'nokogiri'
require 'zip/zip'
diff --git a/lib/axlsx/package.rb b/lib/axlsx/package.rb
index 164b342b..73e72493 100644
--- a/lib/axlsx/package.rb
+++ b/lib/axlsx/package.rb
@@ -183,6 +183,10 @@ module Axlsx
@parts << {:entry => "xl/#{drawing.pn}", :doc => drawing.to_xml, :schema => DRAWING_XSD}
end
+ workbook.tables.each do |table|
+ @parts << {:entry => "xl/#{table.pn}", :doc => table.to_xml, :schema => SML_XSD}
+ end
+
workbook.charts.each do |chart|
@parts << {:entry => "xl/#{chart.pn}", :doc => chart.to_xml, :schema => DRAWING_XSD}
end
@@ -232,6 +236,10 @@ module Axlsx
c_types << Axlsx::Override.new(:PartName => "/xl/#{chart.pn}",
:ContentType => CHART_CT)
end
+ workbook.tables.each do |table|
+ c_types << Axlsx::Override.new(:PartName => "/xl/#{table.pn}",
+ :ContentType => TABLE_CT)
+ end
workbook.worksheets.each do |sheet|
c_types << Axlsx::Override.new(:PartName => "/xl/#{sheet.pn}",
:ContentType => WORKSHEET_CT)
diff --git a/lib/axlsx/table/table.rb b/lib/axlsx/table/table.rb
new file mode 100644
index 00000000..be78d4a0
--- /dev/null
+++ b/lib/axlsx/table/table.rb
@@ -0,0 +1,97 @@
+# encoding: UTF-8
+module Axlsx
+ # Table
+ # @note Worksheet#add_table is the recommended way to create charts for your worksheets.
+ # @see README for examples
+ class Table
+
+
+ # The reference to the table data
+ # @return [String]
+ attr_reader :ref
+
+ # The name of the table.
+ # @return [String]
+ attr_reader :name
+
+ # The style for the table.
+ # @return [TableStyle]
+ attr_reader :style
+
+ # Creates a new Table object
+ # @param [String] ref The reference to the table data.
+ # @param [Sheet] ref The sheet containing the table data.
+ # @option options [Cell, String] name
+ # @option options [TableStyle] style
+ def initialize(ref, sheet, options={})
+ @ref = ref
+ @sheet = sheet
+ @style = nil
+ @sheet.workbook.tables << self
+ @name = "Table#{index+1}"
+ options.each do |o|
+ self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
+ end
+ yield self if block_given?
+ end
+
+ # The index of this chart in the workbooks charts collection
+ # @return [Integer]
+ def index
+ @sheet.workbook.tables.index(self)
+ end
+
+ # The part name for this table
+ # @return [String]
+ def pn
+ "#{TABLE_PN % (index+1)}"
+ end
+
+ # The relation reference id for this table
+ # @return [String]
+ def rId
+ "rId#{index+1}"
+ end
+
+ # The name of the Table.
+ # @param [String, Cell] v
+ # @return [Title]
+ def name=(v)
+ DataTypeValidator.validate "#{self.class}.name", [String], v
+ if v.is_a?(String)
+ @name = v
+ end
+ end
+
+
+ # The style for the table.
+ # TODO
+ # def style=(v) DataTypeValidator.validate "Chart.style", Integer, v, lambda { |arg| arg >= 1 && arg <= 48 }; @style = v; end
+
+ # Table Serialization
+ # serializes the table
+ def to_xml
+ builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml|
+ xml.table(:xmlns => XML_NS, :id => index+1, :name => @name, :displayName => @name.gsub(/\s/,'_'), :ref => @ref, :totalsRowShown => 0) {
+ xml.autoFilter :ref=>@ref
+ xml.tableColumns(:count => header_cells.length) {
+ header_cells.each_with_index do |cell,index|
+ xml.tableColumn :id => index+1, :name => cell.value
+ end
+ }
+ xml.tableStyleInfo :showFirstColumn=>"0", :showLastColumn=>"0", :showRowStripes=>"1", :showColumnStripes=>"0", :name=>"TableStyleMedium9"
+ #TODO implement tableStyleInfo
+ }
+ end
+ builder.to_xml(:save_with => 0)
+ end
+
+ private
+
+ # get the header cells (hackish)
+ def header_cells
+ header = @ref.gsub(/^(\w+)(\d+)\:(\w+)\d+$/, '\1\2:\3\2')
+ @sheet[header]
+ end
+ end
+end
diff --git a/lib/axlsx/util/constants.rb b/lib/axlsx/util/constants.rb
index bfc67918..588dada5 100644
--- a/lib/axlsx/util/constants.rb
+++ b/lib/axlsx/util/constants.rb
@@ -171,6 +171,9 @@ module Axlsx
# drawing rels part
DRAWING_RELS_PN = "drawings/_rels/drawing%d.xml.rels"
+
+ # drawing part
+ TABLE_PN = "tables/table%d.xml"
# chart part
CHART_PN = "charts/chart%d.xml"
diff --git a/lib/axlsx/workbook/workbook.rb b/lib/axlsx/workbook/workbook.rb
index cd37a00e..b6e0a9db 100644
--- a/lib/axlsx/workbook/workbook.rb
+++ b/lib/axlsx/workbook/workbook.rb
@@ -74,6 +74,14 @@ require 'axlsx/workbook/shared_strings_table.rb'
# @return [SimpleTypedList]
attr_reader :drawings
+ # A colllection of tables associated with this workbook
+ # @note The recommended way to manage drawings is Worksheet#add_table
+ # @see Worksheet#add_table
+ # @see Table
+ # @return [SimpleTypedList]
+ attr_reader :tables
+
+
# The styles associated with this workbook
# @note The recommended way to manage styles is Styles#add_style
# @see Style#add_style
@@ -107,7 +115,9 @@ require 'axlsx/workbook/shared_strings_table.rb'
@drawings = SimpleTypedList.new Drawing
@charts = SimpleTypedList.new Chart
@images = SimpleTypedList.new Pic
+ @tables = SimpleTypedList.new Table
@use_autowidth = true
+
self.date1904= !options[:date1904].nil? && options[:date1904]
yield self if block_given?
end
diff --git a/lib/axlsx/workbook/worksheet/worksheet.rb b/lib/axlsx/workbook/worksheet/worksheet.rb
index 49d3739d..ad4e7dbb 100644
--- a/lib/axlsx/workbook/worksheet/worksheet.rb
+++ b/lib/axlsx/workbook/worksheet/worksheet.rb
@@ -12,6 +12,9 @@ module Axlsx
# @return [Workbook]
attr_reader :workbook
+ # The tables in this worksheet
+ # @return [Array] of Table
+ attr_reader :tables
# The rows in this worksheet
# @note The recommended way to manage rows is Worksheet#add_row
@@ -371,6 +374,13 @@ module Axlsx
chart
end
+ def add_table(ref, options={})
+ table = Table.new(ref, self, options)
+ @tables << table
+ yield table if block_given?
+ table
+ end
+
# Adds a media item to the worksheets drawing
# @param [Class] media_type
# @option options [] unknown
@@ -416,6 +426,13 @@ module Axlsx
xml.mergeCells(:count=>@merged_cells.size) { @merged_cells.each { | mc | xml.mergeCell(:ref=>mc) } } unless @merged_cells.empty?
page_margins.to_xml(xml) if @page_margins
xml.drawing :"r:id"=>"rId1" if @drawing
+ unless @tables.empty?
+ xml.tableParts(:count => @tables.length) {
+ @tables.each do |table|
+ xml.tablePart :'r:id' => table.rId
+ end
+ }
+ end
}
end
builder.to_xml(:save_with => 0)
@@ -425,6 +442,9 @@ module Axlsx
# @return [Relationships]
def relationships
r = Relationships.new
+ @tables.each do |table|
+ r << Relationship.new(TABLE_R, "../#{table.pn}")
+ end
r << Relationship.new(DRAWING_R, "../#{@drawing.pn}") if @drawing
r
end
diff --git a/test/table/tc_table.rb b/test/table/tc_table.rb
new file mode 100644
index 00000000..d6bc95d0
--- /dev/null
+++ b/test/table/tc_table.rb
@@ -0,0 +1,72 @@
+require 'test/unit'
+require 'axlsx.rb'
+
+class TestTable < Test::Unit::TestCase
+ def setup
+ p = Axlsx::Package.new
+ @ws = p.workbook.add_worksheet
+ 40.times do
+ @ws << ["aa","aa","aa","aa","aa","aa"]
+ end
+ end
+
+ def test_initialization
+ assert(@ws.workbook.tables.empty?)
+ assert(@ws.tables.empty?)
+
+ end
+
+ def test_add_table
+ name = "test"
+ table = @ws.add_table("A1:D5", :name => name)
+ assert(table.is_a?(Axlsx::Table), "must create a table")
+ assert_equal(@ws.workbook.tables.last, table, "must be added to workbook table collection")
+ assert_equal(@ws.tables.last, table, "must be added to worksheet table collection")
+ assert_equal(table.name, name, "options for name are applied")
+
+ end
+
+ def test_charts
+ assert(@ws.drawing.charts.empty?)
+ chart = @ws.add_chart(Axlsx::Pie3DChart, :title=>"bob", :start_at=>[0,0], :end_at=>[1,1])
+ assert_equal(@ws.drawing.charts.last, chart, "add chart is returned")
+ chart = @ws.add_chart(Axlsx::Pie3DChart, :title=>"nancy", :start_at=>[1,5], :end_at=>[5,10])
+ assert_equal(@ws.drawing.charts.last, chart, "add chart is returned")
+ end
+
+ def test_pn
+ table = @ws.add_table("A1:D5")
+ assert_equal(@ws.tables.first.pn, "tables/table1.xml")
+ end
+
+ def test_rId
+ table = @ws.add_table("A1:D5")
+ assert_equal(@ws.tables.first.rId, "rId1")
+ end
+
+ def test_index
+ table = @ws.add_table("A1:D5")
+ assert_equal(@ws.tables.first.index, @ws.workbook.tables.index(@ws.tables.first))
+ end
+
+ def test_relationships
+ assert(@ws.relationships.empty?)
+ table = @ws.add_table("A1:D5")
+ assert_equal(@ws.relationships.size, 1, "adding a table adds a relationship")
+ table = @ws.add_table("F1:J5")
+ assert_equal(@ws.relationships.size, 2, "adding a table adds a relationship")
+ end
+
+ def test_to_xml
+ table = @ws.add_table("A1:D5")
+ schema = Nokogiri::XML::Schema(File.open(Axlsx::SML_XSD))
+ doc = Nokogiri::XML(table.to_xml)
+ errors = []
+ schema.validate(doc).each do |error|
+ errors.push error
+ puts error.message
+ end
+ assert(errors.empty?, "error free validation")
+ end
+
+end