diff options
| author | ochko <[email protected]> | 2012-04-03 22:38:48 +0900 |
|---|---|---|
| committer | ochko <[email protected]> | 2012-04-03 22:38:48 +0900 |
| commit | 9950bced40b5b9593212a6b5e3718665c82a5898 (patch) | |
| tree | 33f5eabe6f1d04f874ff448a40f1e085a72a5ec4 | |
| parent | db2633cd108ee40e8fa740feae90a33a33087501 (diff) | |
| parent | e189f345fe3dd2710b2dbdd12e7f8969299949ab (diff) | |
| download | caxlsx-9950bced40b5b9593212a6b5e3718665c82a5898.tar.gz caxlsx-9950bced40b5b9593212a6b5e3718665c82a5898.zip | |
Merge branch 'master' of git://github.com/randym/axlsx
100 files changed, 1745 insertions, 1472 deletions
diff --git a/.travis.yml b/.travis.yml index b4a356ab..5fa532c1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,13 @@ rvm: - 1.9.2 - 1.9.3 - jruby-18mode + - rbx-18mode + - rbx-19mode + - jruby-19mode - ruby-head + - jruby-head matrix: allow_failures: - - rvm: jruby-18mode - - rvm: ruby-head
\ No newline at end of file + - rvm: ruby-head + - rvm: jruby-head + - rvm: jruby-19mode diff --git a/CHANGELOG.md b/CHANGELOG.md index 20b466ce..9962a604 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ CHANGELOG --------- +- ** February.2.12**: 1.0.16 release + https://github.com/randym/axlsx/compare/1.0.15...1.0.16 + - Bug fix for schema file locations when validating in rails + - Added hyperlink to images + - date1904 now automatically set in BSD and mac environments + - removed whitespace/indentation from xml outputs + - col_style now skips rows that do not contain cells at the column index + - **January.6.12**: 1.0.15 release https://github.com/randym/axlsx/compare/1.0.14...1.0.15 - Bug fix add_style specified number formats must be explicity applied for libraOffice @@ -15,7 +23,7 @@ CHANGELOG - Updated examples to output to a single workbook with multiple sheets - Added access to app and core package objects so you can set the creator and other properties of the package - The beginning of password protected xlsx files - roadmapped for January release. - + - **December.8.11**: 1.0.13 release - Fixing .gemspec errors that caused gem to miss the lib directory. Sorry about that. @@ -62,7 +70,7 @@ CHANGELOG ##October.22.11: 1.0.6 release - Bumping version to include docs. Bug in gemspec pointing to incorrect directory. -##October.22.11: 1.05 +##October.22.11: 1.05 - Added support for line charts - Updated examples and readme - Updated series title to be a real title ** NOTE ** If you are accessing titles directly you will need to update text assignation. @@ -70,7 +78,7 @@ CHANGELOG chart.series.first.title.text = 'Your Title' With this change you can assign a cell for the series title chart.series.title = sheet.rows.first.cells.first - If you are using the recommended + If you are using the recommended chart.add_series :data=>[], :labels=>[], :title You do not have to change anything. - BugFix: shape attribute for bar chart is now properly serialized @@ -2,23 +2,25 @@ Axlsx: Office Open XML Spreadsheet Generation ==================================== [](http://travis-ci.org/randym/axlsx/) -**IRC**: [irc.freenode.net / #axlsx](irc://irc.freenode.net/axlsx) +**IRC**:[irc.freenode.net / #axlsx](irc://irc.freenode.net/axlsx) -**Git**: [http://github.com/randym/axlsx](http://github.com/randym/axlsx) +**Git**:[http://github.com/randym/axlsx](http://github.com/randym/axlsx) -**Twitter**: [https://twitter.com/#!/morgan_randy](https://twitter.com/#!/morgan_randy) release announcements and news will be published here +**Twitter**: [https://twitter.com/#!/morgan_randy](https://twitter.com/#!/morgan_randy) release announcements and news will be published here -**Author**: Randy Morgan +**Author**: Randy Morgan -**Copyright**: 2011 +**Copyright**: 2011 - 2012 -**License**: MIT License +**License**: MIT License -**Latest Version**: 1.0.18 +**Latest Version**: 1.1.0 **Ruby Version**: 1.8.7, 1.9.2, 1.9.3 -**Release Date**: March 5th 2012 +**JRuby Version**: 1.6.7 + +**Release Date**: April 3st 2012 Synopsis -------- @@ -80,285 +82,396 @@ To install Axlsx, use the following command: #Usage ------ - require 'axlsx' +```ruby +require 'axlsx' + +p = Axlsx::Package.new +wb = p.workbook +``` + +#A Simple Workbook + +```ruby +wb.add_worksheet(:name => "Basic Worksheet") do |sheet| + sheet.add_row ["First Column", "Second", "Third"] + sheet.add_row [1, 2, 3] +end +``` - p = Axlsx::Package.new - wb = p.workbook +#Using Custom Styles -##A Simple Workbook +```ruby +wb.styles do |s| + black_cell = s.add_style :bg_color => "00", :fg_color => "FF", :sz => 14, :alignment => { :horizontal=> :center } + blue_cell = s.add_style :bg_color => "0000FF", :fg_color => "FF", :sz => 20, :alignment => { :horizontal=> :center } + wb.add_worksheet(:name => "Custom Styles") do |sheet| + sheet.add_row ["Text Autowidth", "Second", "Third"], :style => [black_cell, blue_cell, black_cell] + sheet.add_row [1, 2, 3], :style => Axlsx::STYLE_THIN_BORDER + end +end +``` - wb.add_worksheet(:name => "Basic Worksheet") do |sheet| - sheet.add_row ["First Column", "Second", "Third"] - sheet.add_row [1, 2, 3] - end +#Using Custom Border Styles -##Using Custom Styles and Row Heights +```ruby +wb.styles do |s| + red_border = s.add_style :border => {:style=>:thin, :color =>"FFFF0000"} + blue_border = s.add_style :border => {:style=>:thin, :color =>"FF0000FF"} + + wb.add_worksheet(:name => "Custom Borders") do |sheet| + sheet.add_row ["wrap", "me", "Up in Red"], :style => red_border + sheet.add_row [1, 2, 3], :style => blue_border + end +end +``` - wb.styles do |s| - black_cell = s.add_style :bg_color => "00", :fg_color => "FF", :sz => 14, :alignment => { :horizontal=> :center } - blue_cell = s.add_style :bg_color => "0000FF", :fg_color => "FF", :sz => 20, :alignment => { :horizontal=> :center } - wb.add_worksheet(:name => "Custom Styles") do |sheet| - sheet.add_row ["Text Autowidth", "Second", "Third"], :style => [black_cell, blue_cell, black_cell] - sheet.add_row [1, 2, 3], :style => Axlsx::STYLE_THIN_BORDER, :height => 20 - end - end ##Using Custom Formatting and date1904 - require 'date' - wb.styles do |s| - date = s.add_style(:format_code => "yyyy-mm-dd", :border => Axlsx::STYLE_THIN_BORDER) - padded = s.add_style(:format_code => "00#", :border => Axlsx::STYLE_THIN_BORDER) - percent = s.add_style(:format_code => "0000%", :border => Axlsx::STYLE_THIN_BORDER) - wb.date1904 = true # required for generation on mac - wb.add_worksheet(:name => "Formatting Data") do |sheet| - sheet.add_row ["Custom Formatted Date", "Percent Formatted Float", "Padded Numbers"], :style => Axlsx::STYLE_THIN_BORDER - sheet.add_row [Date::strptime('2012-01-19','%Y-%m-%d'), 0.2, 32], :style => [date, percent, padded] - end - end +```ruby +require 'date' +wb.styles do |s| + date = s.add_style(:format_code => "yyyy-mm-dd", :border => Axlsx::STYLE_THIN_BORDER) + padded = s.add_style(:format_code => "00#", :border => Axlsx::STYLE_THIN_BORDER) + percent = s.add_style(:format_code => "0000%", :border => Axlsx::STYLE_THIN_BORDER) + # wb.date1904 = true # Use the 1904 date system (Used by Excel for Mac < 2011) + wb.add_worksheet(:name => "Formatting Data") do |sheet| + sheet.add_row ["Custom Formatted Date", "Percent Formatted Float", "Padded Numbers"], :style => Axlsx::STYLE_THIN_BORDER + sheet.add_row [Date::strptime('2012-01-19','%Y-%m-%d'), 0.2, 32], :style => [date, percent, padded] + end +end +``` + ##Add an Image - wb.add_worksheet(:name => "Images") do |sheet| - img = File.expand_path('examples/image1.jpeg') - sheet.add_image(:image_src => img, :noSelect => true, :noMove => true) do |image| - image.width=720 - image.height=666 - image.start_at 2, 2 - end - end +```ruby +wb.add_worksheet(:name => "Images") do |sheet| + img = File.expand_path('../image1.jpeg', __FILE__) + sheet.add_image(:image_src => img, :noSelect => true, :noMove => true) do |image| + image.width=720 + image.height=666 + image.start_at 2, 2 + end +end +``` ##Add an Image with a hyperlink - wb.add_worksheet(:name => "Image with Hyperlink") do |sheet| - img = File.expand_path('examples/image1.jpeg') - sheet.add_image(:image_src => img, :noSelect => true, :noMove => true, :hyperlink=>"http://axlsx.blogspot.com") do |image| - image.width=720 - image.height=666 - image.hyperlink.tooltip = "Labeled Link" - image.start_at 2, 2 - end - end +```ruby +wb.add_worksheet(:name => "Image with Hyperlink") do |sheet| + img = File.expand_path('../image1.jpeg', __FILE__) + sheet.add_image(:image_src => img, :noSelect => true, :noMove => true, :hyperlink=>"http://axlsx.blogspot.com") do |image| + image.width=720 + image.height=666 + image.hyperlink.tooltip = "Labeled Link" + image.start_at 2, 2 + end +end +``` ##Asian Language Support - wb.add_worksheet(:name => "Unicode Support") do |sheet| - sheet.add_row ["日本語"] - sheet.add_row ["华语/華語"] - sheet.add_row ["한국어/조선말"] - end +```ruby +wb.add_worksheet(:name => "日本語でのシート名") do |sheet| + sheet.add_row ["日本語"] + sheet.add_row ["华语/華語"] + sheet.add_row ["한국어/조선말"] +end +``` ##Styling Columns - wb.styles do |s| - percent = s.add_style :num_fmt => 9 - wb.add_worksheet(:name => "Styling Columns") do |sheet| - sheet.add_row ['col 1', 'col 2', 'col 3', 'col 4'] - sheet.add_row [1, 2, 0.3, 4] - sheet.add_row [1, 2, 0.2, 4] - sheet.add_row [1, 2, 0.1, 4] - sheet.col_style 2, percent, :row_offset => 1 - end - end +```ruby +wb.styles do |s| + percent = s.add_style :num_fmt => 9 + wb.add_worksheet(:name => "Styling Columns") do |sheet| + sheet.add_row ['col 1', 'col 2', 'col 3', 'col 4'] + sheet.add_row [1, 2, 0.3, 4] + sheet.add_row [1, 2, 0.2, 4] + sheet.add_row [1, 2, 0.1, 4] + sheet.col_style 2, percent, :row_offset => 1 + end +end +``` + +##Hiding Columns + +```ruby +wb.styles do |s| + percent = s.add_style :num_fmt => 9 + wb.add_worksheet(:name => "Hidden Column") do |sheet| + sheet.add_row ['col 1', 'col 2', 'col 3', 'col 4'] + sheet.add_row [1, 2, 0.3, 4] + sheet.add_row [1, 2, 0.2, 4] + sheet.add_row [1, 2, 0.1, 4] + sheet.col_style 2, percent, :row_offset => 1 + sheet.column_info[1].hidden = true + end +end +``` ##Styling Rows - wb.styles do |s| - head = s.add_style :bg_color => "00", :fg_color => "FF" - percent = s.add_style :num_fmt => 9 - wb.add_worksheet(:name => "Styling Rows") do |sheet| - sheet.add_row ['col 1', 'col 2', 'col 3', 'col 4'] - sheet.add_row [1, 2, 0.3, 4] - sheet.add_row [1, 2, 0.2, 4] - sheet.add_row [1, 2, 0.1, 4] - sheet.col_style 2, percent, :row_offset => 1 - sheet.row_style 0, head - end - end +```ruby +wb.styles do |s| + head = s.add_style :bg_color => "00", :fg_color => "FF" + percent = s.add_style :num_fmt => 9 + wb.add_worksheet(:name => "Styling Rows") do |sheet| + sheet.add_row ['col 1', 'col 2', 'col 3', 'col 4'] + sheet.add_row [1, 2, 0.3, 4] + sheet.add_row [1, 2, 0.2, 4] + sheet.add_row [1, 2, 0.1, 4] + sheet.col_style 2, percent, :row_offset => 1 + sheet.row_style 0, head + end +end +``` ##Styling Cell Overrides - wb.add_worksheet(:name => "Cell Level Style Overrides") do |sheet| - # cell level style overides when adding cells - sheet.add_row ['col 1', 'col 2', 'col 3', 'col 4'], :sz => 16 - sheet.add_row [1, 2, 3, "=SUM(A2:C2)"] - # cell level style overrides via sheet range - sheet["A1:D1"].each { |c| c.color = "FF0000"} - sheet['A1:D2'].each { |c| c.style = Axlsx::STYLE_THIN_BORDER } - end +```ruby +wb.add_worksheet(:name => "Cell Level Style Overrides") do |sheet| + # cell level style overides when adding cells + sheet.add_row ['col 1', 'col 2', 'col 3', 'col 4'], :sz => 16 + sheet.add_row [1, 2, 3, "=SUM(A2:C2)"] + # cell level style overrides via sheet range + sheet["A1:D1"].each { |c| c.color = "FF0000"} + sheet['A1:D2'].each { |c| c.style = Axlsx::STYLE_THIN_BORDER } +end +``` ##Using formula - wb.add_worksheet(:name => "Using Formulas") do |sheet| - sheet.add_row ['col 1', 'col 2', 'col 3', 'col 4'] - sheet.add_row [1, 2, 3, "=SUM(A2:C2)"] - end +```ruby +wb.add_worksheet(:name => "Using Formulas") do |sheet| + sheet.add_row ['col 1', 'col 2', 'col 3', 'col 4'] + sheet.add_row [1, 2, 3, "=SUM(A2:C2)"] +end +``` ##Automatic cell types - wb.add_worksheet(:name => "Automatic cell types") do |sheet| - sheet.add_row ["Date", "Time", "String", "Boolean", "Float", "Integer"] - sheet.add_row [Date.today, Time.now, "value", true, 0.1, 1] - end +```ruby +wb.add_worksheet(:name => "Automatic cell types") do |sheet| + sheet.add_row ["Date", "Time", "String", "Boolean", "Float", "Integer"] + sheet.add_row [Date.today, Time.now, "value", true, 0.1, 1] +end +``` ##Merging Cells. - wb.add_worksheet(:name => 'Merging Cells') do |sheet| - # cell level style overides when adding cells - sheet.add_row ["col 1", "col 2", "col 3", "col 4"], :sz => 16 - sheet.add_row [1, 2, 3, "=SUM(A2:C2)"] - sheet.add_row [2, 3, 4, "=SUM(A3:C3)"] - sheet.add_row ["total", "", "", "=SUM(D2:D3)"] - sheet.merge_cells("A4:C4") - sheet["A1:D1"].each { |c| c.color = "FF0000"} - sheet["A1:D4"].each { |c| c.style = Axlsx::STYLE_THIN_BORDER } - end +```ruby +wb.add_worksheet(:name => 'Merging Cells') do |sheet| + # cell level style overides when adding cells + sheet.add_row ["col 1", "col 2", "col 3", "col 4"], :sz => 16 + sheet.add_row [1, 2, 3, "=SUM(A2:C2)"] + sheet.add_row [2, 3, 4, "=SUM(A3:C3)"] + sheet.add_row ["total", "", "", "=SUM(D2:D3)"] + sheet.merge_cells("A4:C4") + sheet["A1:D1"].each { |c| c.color = "FF0000"} + sheet["A1:D4"].each { |c| c.style = Axlsx::STYLE_THIN_BORDER } +end +``` ##Generating A Bar Chart - wb.add_worksheet(:name => "Bar Chart") do |sheet| - sheet.add_row ["A Simple Bar Chart"] - sheet.add_row ["First", "Second", "Third"] - sheet.add_row [1, 2, 3] - sheet.add_chart(Axlsx::Bar3DChart, :start_at => "A4", :end_at => "F17") do |chart| - chart.add_series :data => sheet["A3:C3"], :labels => sheet["A2:C2"], :title => sheet["A1"] - end - end +```ruby +wb.add_worksheet(:name => "Bar Chart") do |sheet| + sheet.add_row ["A Simple Bar Chart"] + sheet.add_row ["First", "Second", "Third"] + sheet.add_row [1, 2, 3] + sheet.add_chart(Axlsx::Bar3DChart, :start_at => "A4", :end_at => "F17") do |chart| + chart.add_series :data => sheet["A3:C3"], :labels => sheet["A2:C2"], :title => sheet["A1"] + end +end +``` + +##Hide Gridlines in chart + +```ruby +wb.add_worksheet(:name => "Chart With No Gridlines") do |sheet| + sheet.add_row ["A Simple Bar Chart"] + sheet.add_row ["First", "Second", "Third"] + sheet.add_row [1, 2, 3] + sheet.add_chart(Axlsx::Bar3DChart, :start_at => "A4", :end_at => "F17") do |chart| + chart.add_series :data => sheet["A3:C3"], :labels => sheet["A2:C2"], :title => sheet["A1"] + chart.valAxis.gridlines = false + chart.catAxis.gridlines = false + end +end +``` ##Generating A Pie Chart - wb.add_worksheet(:name => "Pie Chart") do |sheet| - sheet.add_row ["First", "Second", "Third", "Fourth"] - sheet.add_row [1, 2, 3, "=PRODUCT(A2:C2)"] - sheet.add_chart(Axlsx::Pie3DChart, :start_at => [0,2], :end_at => [5, 15], :title => "example 3: Pie Chart") do |chart| - chart.add_series :data => sheet["A2:D2"], :labels => sheet["A1:D1"] - end - end +```ruby +wb.add_worksheet(:name => "Pie Chart") do |sheet| + sheet.add_row ["First", "Second", "Third", "Fourth"] + sheet.add_row [1, 2, 3, "=PRODUCT(A2:C2)"] + sheet.add_chart(Axlsx::Pie3DChart, :start_at => [0,2], :end_at => [5, 15], :title => "example 3: Pie Chart") do |chart| + chart.add_series :data => sheet["A2:D2"], :labels => sheet["A1:D1"] + end +end +``` ##Data over time - wb.add_worksheet(:name=>'Charting Dates') do |sheet| - # cell level style overides when adding cells - sheet.add_row ['Date', 'Value'], :sz => 16 - sheet.add_row [Time.now - (7*60*60*24), 3] - sheet.add_row [Time.now - (6*60*60*24), 7] - sheet.add_row [Time.now - (5*60*60*24), 18] - sheet.add_row [Time.now - (4*60*60*24), 1] - sheet.add_chart(Axlsx::Bar3DChart) do |chart| - chart.start_at "B7" - chart.end_at "H27" - chart.add_series(:data => sheet["B2:B5"], :labels => sheet["A2:A5"], :title => sheet["B1"]) - end - end +```ruby +wb.add_worksheet(:name=>'Charting Dates') do |sheet| + # cell level style overides when adding cells + sheet.add_row ['Date', 'Value'], :sz => 16 + sheet.add_row [Time.now - (7*60*60*24), 3] + sheet.add_row [Time.now - (6*60*60*24), 7] + sheet.add_row [Time.now - (5*60*60*24), 18] + sheet.add_row [Time.now - (4*60*60*24), 1] + sheet.add_chart(Axlsx::Bar3DChart) do |chart| + chart.start_at "B7" + chart.end_at "H27" + chart.add_series(:data => sheet["B2:B5"], :labels => sheet["A2:A5"], :title => sheet["B1"]) + end +end +``` ##Generating A Line Chart - wb.add_worksheet(:name => "Line Chart") do |sheet| - sheet.add_row ["First", 1, 5, 7, 9] - sheet.add_row ["Second", 5, 2, 14, 9] - sheet.add_chart(Axlsx::Line3DChart, :title => "example 6: Line Chart", :rotX => 30, :rotY => 20) do |chart| - chart.start_at 0, 2 - chart.end_at 10, 15 - chart.add_series :data => sheet["B1:E1"], :title => sheet["A1"] - chart.add_series :data => sheet["B2:E2"], :title => sheet["A2"] - end - end +```ruby +wb.add_worksheet(:name => "Line Chart") do |sheet| + sheet.add_row ["First", 1, 5, 7, 9] + sheet.add_row ["Second", 5, 2, 14, 9] + sheet.add_chart(Axlsx::Line3DChart, :title => "example 6: Line Chart", :rotX => 30, :rotY => 20) do |chart| + chart.start_at 0, 2 + chart.end_at 10, 15 + chart.add_series :data => sheet["B1:E1"], :title => sheet["A1"] + chart.add_series :data => sheet["B2:E2"], :title => sheet["A2"] + end +end +``` ##Generating A Scatter Chart - wb.add_worksheet(:name => "Scatter Chart") do |sheet| - sheet.add_row ["First", 1, 5, 7, 9] - sheet.add_row ["", 1, 25, 49, 81] - sheet.add_row ["Second", 5, 2, 14, 9] - sheet.add_row ["", 5, 10, 15, 20] - sheet.add_chart(Axlsx::ScatterChart, :title => "example 7: Scatter Chart") do |chart| - chart.start_at 0, 4 - chart.end_at 10, 19 - chart.add_series :xData => sheet["B1:E1"], :yData => sheet["B2:E2"], :title => sheet["A1"] - chart.add_series :xData => sheet["B3:E3"], :yData => sheet["B4:E4"], :title => sheet["A3"] - end - end +```ruby +wb.add_worksheet(:name => "Scatter Chart") do |sheet| + sheet.add_row ["First", 1, 5, 7, 9] + sheet.add_row ["", 1, 25, 49, 81] + sheet.add_row ["Second", 5, 2, 14, 9] + sheet.add_row ["", 5, 10, 15, 20] + sheet.add_chart(Axlsx::ScatterChart, :title => "example 7: Scatter Chart") do |chart| + chart.start_at 0, 4 + chart.end_at 10, 19 + chart.add_series :xData => sheet["B1:E1"], :yData => sheet["B2:E2"], :title => sheet["A1"] + chart.add_series :xData => sheet["B3:E3"], :yData => sheet["B4:E4"], :title => sheet["A3"] + end +end +``` ##Auto Filter - wb.add_worksheet(:name => "Auto Filter") 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.auto_filter = "A2:D5" - end +```ruby +wb.add_worksheet(:name => "Auto Filter") 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.auto_filter = "A2:D5" +end +``` + +##Tables + +```ruby +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| - sheet.add_row ["I use auto_fit and am very wide", "I use a custom width and am narrow"] - sheet.column_widths nil, 3 - end - -##Specify Page Margins for printing - - margins = {:left => 3, :right => 3, :top => 1.2, :bottom => 1.2, :header => 0.7, :footer => 0.7} - wb.add_worksheet(:name => "print margins", :page_margins => margins) do |sheet| - sheet.add_row["this sheet uses customized page margins for printing"] - end +```ruby +wb.add_worksheet(:name => "custom column widths") do |sheet| + sheet.add_row ["I use autowidth and am very wide", "I use a custom width and am narrow"] + sheet.add_row ['abcdefg', 'This is a very long text and should flow into the right cell', nil, 'xxx' ] + sheet.column_widths nil, 3, 5, nil +end +``` ##Fit to page printing - wb.add_worksheet(:name => "fit to page") do |sheet| - sheet.add_row ['this all goes on one page'] - sheet.fit_to_page = true - end - +```ruby +wb.add_worksheet(:name => "fit to page") do |sheet| + sheet.add_row ['this all goes on one page'] + sheet.fit_to_page = true +end +``` ##Hide Gridlines in worksheet - wb.add_worksheet(:name => "No Gridlines") do |sheet| - sheet.add_row ["This", "Sheet", "Hides", "Gridlines"] - sheet.show_gridlines = false - end +```ruby +wb.add_worksheet(:name => "No Gridlines") do |sheet| + sheet.add_row ["This", "Sheet", "Hides", "Gridlines"] + sheet.show_gridlines = false +end +``` + +##Specify Page Margins for printing + +```ruby +margins = {:left => 3, :right => 3, :top => 1.2, :bottom => 1.2, :header => 0.7, :footer => 0.7} +wb.add_worksheet(:name => "print margins", :page_margins => margins) do |sheet| + sheet.add_row ["this sheet uses customized page margins for printing"] +end +``` ##Validate and Serialize - p.validate.each { |e| puts e.message } - p.serialize("example.xlsx") +```ruby +p.serialize("example.xlsx") - # alternatively, serialize to StringIO - s = p.to_stream() - File.open('example_streamed.xlsx', 'w') { |f| f.write(s.read) } +s = p.to_stream() +File.open('example_streamed.xlsx', 'w') { |f| f.write(s.read) } +``` ##Using Shared Strings - p.use_shared_strings = true - p.serialize("shared_strings_example.xlsx") +```ruby +p.use_shared_strings = true +p.serialize("shared_strings_example.xlsx") +``` -##Disabling Autowidth - p = Axlsx::Package.new - p.use_autowidth = false - wb = p.workbook - wb.add_worksheet(:name => "No Magick") do | sheet | - sheet.add_row ['oh look! no autowidth - and no magick loaded in your process'] - end - p.validate.each { |e| puts e.message } - p.serialize("no-use_autowidth.xlsx") +##Disabling Autowidth +```ruby +p = Axlsx::Package.new +p.use_autowidth = false +wb = p.workbook +wb.add_worksheet(:name => "No Magick") do | sheet | + sheet.add_row ['oh look! no autowidth - and no magick loaded in your process'] +end +p.validate.each { |e| puts e.message } +p.serialize("no-use_autowidth.xlsx") +``` #Documentation -------------- This gem is 100% documented with YARD, an exceptional documentation library. To see documentation for this, and all the gems installed on your system use: - gem install yard - yard server -g - +```bash +gem install yard +yard server -g +``` #Specs ------ This gem has 100% test coverage using test/unit. To execute tests for this gem, simply run rake in the gem directory. #Change log --------- -- ** March.??.12**: 1.0.19 release +- ** April.3.12**: 1.1.0 release - bugfix patch name_to_indecies to properly handle extended ranges. - bugfix properly serialize chart title. - lower rake minimum requirement for 1.8.7 apps that don't want to move on to 0.9 NOTE this will be reverted for 2.0.0 with workbook parsing! @@ -366,9 +479,12 @@ This gem has 100% test coverage using test/unit. To execute tests for this gem, - added support for turning off gridlines in charts. - added support for turning off gridlines in worksheet. - bugfix some apps like libraoffice require apply[x] attributes to be true. applyAlignment is now properly set. - - added option to *not* use RMagick - and default all assigned columns to the excel default of 8.43 - - added border style specification to styles#add_style - now you can pass in :border => {:style => :thin, :color =>"0000FF"} instead of creating a border object and border parts manually each time. - - Support for tables added in - Note: Pre 2011 versions of Mac office do not support this feature. + - added option use_autowidth. When this is false RMagick will not be loaded or used in the stack. However it is still a requirement in the gem. + - added border style specification to styles#add_style. See the example in the readme. + - Support for tables added in - Note: Pre 2011 versions of Mac office do not support this feature and will warn. + - Support for splatter charts added + - Major (like 7x faster!) performance updates. + - Gem now supports for JRuby 1.6.7, as well as expirimental support for Rubinius - ** March.5.12**: 1.0.18 release https://github.com/randym/axlsx/compare/1.0.17...1.0.18 @@ -387,13 +503,6 @@ This gem has 100% test coverage using test/unit. To execute tests for this gem, - Added in support for fixed column_widths - Removed unneeded dependencies on active-support and i18n -- ** February.2.12**: 1.0.16 release - https://github.com/randym/axlsx/compare/1.0.15...1.0.16 - - Bug fix for schema file locations when validating in rails - - Added hyperlink to images - - date1904 now automatically set in BSD and mac environments - - removed whitespace/indentation from xml outputs - - col_style now skips rows that do not contain cells at the column index Please see the {file:CHANGELOG.md} document for past release information. @@ -419,5 +528,5 @@ Please see the {file:CHANGELOG.md} document for past release information. #Copyright and License ---------- -Axlsx © 2011 by [Randy Morgan](mailto:[email protected]). Axlsx is +Axlsx © 2011-2012 by [Randy Morgan](mailto:[email protected]). Axlsx is licensed under the MIT license. Please see the {file:LICENSE} document for more information. diff --git a/axlsx.gemspec b/axlsx.gemspec index d67401d3..1dee3358 100644 --- a/axlsx.gemspec +++ b/axlsx.gemspec @@ -21,15 +21,12 @@ Gem::Specification.new do |s| s.add_runtime_dependency 'nokogiri', '>= 1.4.1' s.add_runtime_dependency 'rmagick', '>= 2.12.2' unless Object.const_defined? :JRUBY_VERSION s.add_runtime_dependency 'rmagick4j', '>= 0.3.7' if Object.const_defined? :JRUBY_VERSION - s.add_runtime_dependency 'rubyzip', '~> 0.9' s.add_runtime_dependency 'rake', '0.8.7' if RUBY_VERSION == "1.9.2" s.add_runtime_dependency 'rake', '>= 0.8.7' if ["1.9.3", "1.8.7"].include?(RUBY_VERSION) s.add_development_dependency 'yard' - s.add_development_dependency 'yard' - s.add_development_dependency 'rdiscount' - s.add_development_dependency 'perftools.rb' + # s.add_development_dependency 'rdiscount' s.required_ruby_version = '>= 1.8.7' s.require_path = 'lib' diff --git a/examples/example.rb b/examples/example.rb index 604ab597..d93f5dcc 100644 --- a/examples/example.rb +++ b/examples/example.rb @@ -95,6 +95,20 @@ wb.styles do |s| end end +##Hiding Columns + +wb.styles do |s| + percent = s.add_style :num_fmt => 9 + wb.add_worksheet(:name => "Hidden Column") do |sheet| + sheet.add_row ['col 1', 'col 2', 'col 3', 'col 4'] + sheet.add_row [1, 2, 0.3, 4] + sheet.add_row [1, 2, 0.2, 4] + sheet.add_row [1, 2, 0.1, 4] + sheet.col_style 2, percent, :row_offset => 1 + sheet.column_info[1].hidden = true + end +end + ##Styling Rows wb.styles do |s| @@ -252,7 +266,8 @@ end wb.add_worksheet(:name => "custom column widths") do |sheet| sheet.add_row ["I use autowidth and am very wide", "I use a custom width and am narrow"] - sheet.column_widths nil, 3 + sheet.add_row ['abcdefg', 'This is a very long text and should flow into the right cell', nil, 'xxx' ] + sheet.column_widths nil, 3, 5, nil end ##Fit to page printing diff --git a/lib/axlsx.rb b/lib/axlsx.rb index 09f351fc..46d1c9bf 100644 --- a/lib/axlsx.rb +++ b/lib/axlsx.rb @@ -57,7 +57,7 @@ module Axlsx def self.name_to_indices(name) raise ArgumentError, 'invalid cell name' unless name.size > 1 v = name[/[A-Z]+/].reverse.chars.reduce({:base=>1, :i=>0}) do |val, c| - val[:i] += ((c.bytes.first - 65) + val[:base]); val[:base] *= 26; val + val[:i] += ((c.bytes.first - 64) * val[:base]); val[:base] *= 26; val end [v[:i]-1, ((name[/[1-9][0-9]*/]).to_i)-1] @@ -71,9 +71,9 @@ module Axlsx chars = [] while index >= 26 do chars << ((index % 26) + 65).chr - index /= 26 + index = index / 26 - 1 end - chars << ((chars.empty? ? index : index-1) + 65).chr + chars << (index + 65).chr chars.reverse.join end @@ -81,7 +81,7 @@ module Axlsx # @example Relative Cell Reference # ws.rows.first.cells.first.r #=> "A1" def self.cell_r(c_index, r_index) - Axlsx::col_ref(c_index).to_s << (r_index+1).to_s - end + Axlsx::col_ref(c_index).to_s << (r_index+1).to_s + end end diff --git a/lib/axlsx/content_type/content_type.rb b/lib/axlsx/content_type/content_type.rb index 8b58bf04..003991c7 100644 --- a/lib/axlsx/content_type/content_type.rb +++ b/lib/axlsx/content_type/content_type.rb @@ -10,15 +10,15 @@ module Axlsx super [Override, Default] end - # Generates the xml document for [Content_Types].xml - # @return [String] The document as a string. - def to_xml() - builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml| - xml.Types(:xmlns => Axlsx::XML_NS_T) { - each { |type| type.to_xml(xml) } - } - end - builder.to_xml(:save_with => 0) + # Serializes the object + # @param [String] str + # @return [String] + def to_xml_string(str = '') + str << '<?xml version="1.0" encoding="UTF-8"?>' + str << '<Types xmlns="' << XML_NS_T << '">' + each { |type| type.to_xml_string(str) } + str << '</Types>' end + end end diff --git a/lib/axlsx/content_type/default.rb b/lib/axlsx/content_type/default.rb index bd572b14..c7cedd14 100644 --- a/lib/axlsx/content_type/default.rb +++ b/lib/axlsx/content_type/default.rb @@ -8,7 +8,7 @@ module Axlsx attr_reader :Extension # The type of content. - # @return [String] + # @return [String] attr_reader :ContentType #Creates a new Default object @@ -19,7 +19,7 @@ module Axlsx raise ArgumentError, "Extension and ContentType are required" unless options[:Extension] && options[:ContentType] options.each do |o| self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}=" - end + end end # Sets the file extension for this content type. def Extension=(v) Axlsx::validate_string v; @Extension = v end @@ -28,11 +28,14 @@ module Axlsx # @see Axlsx#validate_content_type def ContentType=(v) Axlsx::validate_content_type v; @ContentType = v end - # Serializes the object to xml - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.Default(self.instance_values) + def to_xml_string(str = '') + str << '<Default ' + str << instance_values.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ') + str << '/>' end + end end diff --git a/lib/axlsx/content_type/override.rb b/lib/axlsx/content_type/override.rb index 2513b8ff..eadf8e78 100644 --- a/lib/axlsx/content_type/override.rb +++ b/lib/axlsx/content_type/override.rb @@ -4,11 +4,11 @@ module Axlsx class Override # The type of content. - # @return [String] + # @return [String] attr_reader :ContentType # The name and location of the part. - # @return [String] + # @return [String] attr_reader :PartName #Creates a new Override object @@ -19,20 +19,24 @@ module Axlsx raise ArgumentError, "PartName and ContentType are required" unless options[:PartName] && options[:ContentType] options.each do |o| self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}=" - end + end end # The name and location of the part. def PartName=(v) Axlsx::validate_string v; @PartName = v end - # The content type. + # The content type. # @see Axlsx#validate_content_type def ContentType=(v) Axlsx::validate_content_type v; @ContentType = v end - # Serializes the Override object to xml - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. - def to_xml(xml) - xml.Override(self.instance_values) + # Serializes the object + # @param [String] str + # @return [String] + def to_xml_string(str = '') + str << '<Override ' + str << instance_values.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ') + str << '/>' end + end end diff --git a/lib/axlsx/doc_props/app.rb b/lib/axlsx/doc_props/app.rb index 16966da4..1b5fc2ad 100644 --- a/lib/axlsx/doc_props/app.rb +++ b/lib/axlsx/doc_props/app.rb @@ -17,7 +17,7 @@ module Axlsx attr_reader :Manager # @return [String] The name of the company generating the document. - attr_reader :Company + attr_reader :Company # @return [Integer] The number of pages in the document. attr_reader :Pages @@ -43,7 +43,7 @@ module Axlsx # @return [Integer] The number of slides that have notes. attr_reader :Notes - # @return [Integer] The total amount of time spent editing. + # @return [Integer] The total amount of time spent editing. attr_reader :TotalTime # @return [Integer] The number of hidden slides. @@ -60,11 +60,11 @@ module Axlsx # @return [Integer] The number of characters in the document including spaces. attr_reader :CharactersWithSpaces - + # @return [Boolean] Indicates if the document is shared. attr_reader :ShareDoc - # @return [String] The base for hyper links in the document. + # @return [String] The base for hyper links in the document. attr_reader :HyperLinkBase # @return [Boolean] Indicates that the hyper links in the document have been changed. @@ -96,7 +96,7 @@ module Axlsx # @option options [Boolean] ScaleCrop # @option options [Boolean] LinksUpToDate # @option options [Integer] CharactersWithSpaces - # @option options [Boolean] ShareDoc + # @option options [Boolean] ShareDoc # @option options [String] HyperLinkBase # @option options [String] HyperlinksChanged # @option options [String] Application @@ -109,70 +109,67 @@ module Axlsx end # Sets the Template property of your app.xml file - def Template=(v) Axlsx::validate_string v; @Template = v; end + def Template=(v) Axlsx::validate_string v; @Template = v; end # Sets the Manager property of your app.xml file - def Manager=(v) Axlsx::validate_string v; @Manager = v; end + def Manager=(v) Axlsx::validate_string v; @Manager = v; end # Sets the Company property of your app.xml file - def Company=(v) Axlsx::validate_string v; @Company = v; end + def Company=(v) Axlsx::validate_string v; @Company = v; end # Sets the Pages property of your app.xml file - def Pages=(v) Axlsx::validate_int v; @Pages = v; end + def Pages=(v) Axlsx::validate_int v; @Pages = v; end # Sets the Words property of your app.xml file - def Words=(v) Axlsx::validate_int v; @Words = v; end + def Words=(v) Axlsx::validate_int v; @Words = v; end # Sets the Characters property of your app.xml file - def Characters=(v) Axlsx::validate_int v; @Characters = v; end + def Characters=(v) Axlsx::validate_int v; @Characters = v; end # Sets the PresentationFormat property of your app.xml file - def PresentationFormat=(v) Axlsx::validate_string v; @PresentationFormat = v; end + def PresentationFormat=(v) Axlsx::validate_string v; @PresentationFormat = v; end # Sets the Lines property of your app.xml file - def Lines=(v) Axlsx::validate_int v; @Lines = v; end + def Lines=(v) Axlsx::validate_int v; @Lines = v; end # Sets the Paragraphs property of your app.xml file - def Paragraphs=(v) Axlsx::validate_int v; @Paragraphs = v; end + def Paragraphs=(v) Axlsx::validate_int v; @Paragraphs = v; end # Sets the Slides property of your app.xml file - def Slides=(v) Axlsx::validate_int v; @Slides = v; end + def Slides=(v) Axlsx::validate_int v; @Slides = v; end # Sets the Notes property of your app.xml file - def Notes=(v) Axlsx::validate_int v; @Notes = v; end + def Notes=(v) Axlsx::validate_int v; @Notes = v; end # Sets the TotalTime property of your app.xml file - def TotalTime=(v) Axlsx::validate_int v; @TotalTime = v; end + def TotalTime=(v) Axlsx::validate_int v; @TotalTime = v; end # Sets the HiddenSlides property of your app.xml file - def HiddenSlides=(v) Axlsx::validate_int v; @HiddenSlides = v; end + def HiddenSlides=(v) Axlsx::validate_int v; @HiddenSlides = v; end # Sets the MMClips property of your app.xml file - def MMClips=(v) Axlsx::validate_int v; @MMClips = v; end + def MMClips=(v) Axlsx::validate_int v; @MMClips = v; end # Sets the ScaleCrop property of your app.xml file - def ScaleCrop=(v) Axlsx::validate_boolean v; @ScaleCrop = v; end + def ScaleCrop=(v) Axlsx::validate_boolean v; @ScaleCrop = v; end # Sets the LinksUpToDate property of your app.xml file - def LinksUpToDate=(v) Axlsx::validate_boolean v; @LinksUpToDate = v; end + def LinksUpToDate=(v) Axlsx::validate_boolean v; @LinksUpToDate = v; end # Sets the CharactersWithSpaces property of your app.xml file - def CharactersWithSpaces=(v) Axlsx::validate_int v; @CharactersWithSpaces = v; end + def CharactersWithSpaces=(v) Axlsx::validate_int v; @CharactersWithSpaces = v; end # Sets the ShareDoc property of your app.xml file - def ShareDoc=(v) Axlsx::validate_boolean v; @ShareDoc = v; end + def ShareDoc=(v) Axlsx::validate_boolean v; @ShareDoc = v; end # Sets the HyperLinkBase property of your app.xml file - def HyperLinkBase=(v) Axlsx::validate_string v; @HyperLinkBase = v; end + def HyperLinkBase=(v) Axlsx::validate_string v; @HyperLinkBase = v; end # Sets the HyperLinksChanged property of your app.xml file - def HyperlinksChanged=(v) Axlsx::validate_boolean v; @HyperlinksChanged = v; end + def HyperlinksChanged=(v) Axlsx::validate_boolean v; @HyperlinksChanged = v; end # Sets the Application property of your app.xml file - def Application=(v) Axlsx::validate_string v; @Application = v; end + def Application=(v) Axlsx::validate_string v; @Application = v; end # Sets the AppVersion property of your app.xml file - def AppVersion=(v) Axlsx::validate_string v; @AppVersion = v; end + def AppVersion=(v) Axlsx::validate_string v; @AppVersion = v; end # Sets the DocSecurity property of your app.xml file - def DocSecurity=(v) Axlsx::validate_int v; @DocSecurity = v; end - - # Generate an app.xml document - # @return [String] The document as a string - def to_xml() - builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml| - xml.send(:Properties, :xmlns => APP_NS, :'xmlns:vt' => APP_NS_VT) { - self.instance_values.each do |name, value| - xml.send(name, value) - end - } - end - builder.to_xml(:save_with => 0) + def DocSecurity=(v) Axlsx::validate_int v; @DocSecurity = v; end + + # Serialize the app.xml document + # @return [String] + def to_xml_string(str = '') + str << '<?xml version="1.0" encoding="UTF-8"?>' + str << '<Properties xmlns="' << APP_NS << '" xmlns:vt="' << APP_NS_VT << '">' + str << instance_values.map { |key, value| '<' << key.to_s << '>' << value.to_s << '</' << key.to_s << '>' }.join + str << '</Properties>' end + end end diff --git a/lib/axlsx/doc_props/core.rb b/lib/axlsx/doc_props/core.rb index 96716a6b..b3c80991 100644 --- a/lib/axlsx/doc_props/core.rb +++ b/lib/axlsx/doc_props/core.rb @@ -7,29 +7,24 @@ module Axlsx # The author of the document. By default this is 'axlsx' # @return [String] attr_accessor :creator - + # Creates a new Core object. # @option options [String] creator def initialize(options={}) - @creator = options[:creator] || 'axlsx' + @creator = options[:creator] || 'axlsx' end - # Serializes the core object. The created dcterms item is set to the current time when this method is called. + # serializes the core.xml document # @return [String] - def to_xml() - builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml| - xml.send('cp:coreProperties', - :"xmlns:cp" => CORE_NS, - :'xmlns:dc' => CORE_NS_DC, - :'xmlns:dcmitype'=>CORE_NS_DCMIT, - :'xmlns:dcterms'=>CORE_NS_DCT, - :'xmlns:xsi'=>CORE_NS_XSI) { - xml['dc'].creator self.creator - xml['dcterms'].created Time.now.strftime('%Y-%m-%dT%H:%M:%S'), :'xsi:type'=>"dcterms:W3CDTF" - xml['cp'].revision 0 - } - end - builder.to_xml(:save_with => 0) + def to_xml_string(str = '') + str << '<?xml version="1.0" encoding="UTF-8"?>' + str << '<cp:coreProperties xmlns:cp="' << CORE_NS << '" xmlns:dc="' << CORE_NS_DC << '" ' + str << 'xmlns:dcmitype="' << CORE_NS_DCMIT << '" xmlns:dcterms="' << CORE_NS_DCT << '" ' + str << 'xmlns:xsi="' << CORE_NS_XSI << '">' + str << '<dc:creator>' << self.creator << '</dc:creator>' + str << '<dcterms:created xsi:type="dcterms:W3CDTF">' << Time.now.strftime('%Y-%m-%dT%H:%M:%S') << '</dcterms:created>' + str << '<cp:revision>0</cp:revision>' + str << '</cp:coreProperties>' end end end diff --git a/lib/axlsx/drawing/axis.rb b/lib/axlsx/drawing/axis.rb index 183cbcad..9206e848 100644 --- a/lib/axlsx/drawing/axis.rb +++ b/lib/axlsx/drawing/axis.rb @@ -83,29 +83,31 @@ module Axlsx # must be one of [:autoZero, :min, :max] def crosses=(v) RestrictionValidator.validate "#{self.class}.crosses", [:autoZero, :min, :max], v; @crosses = v; end - # Serializes the common axis - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.axId :val=>@axId - @scaling.to_xml(xml) - xml.delete :val=>0 - xml.axPos :val=>@axPos - xml.majorGridlines { - if self.gridlines == false - xml.spPr { - xml[:a].ln { - xml[:a].noFill - } - } - end - } - xml.numFmt :formatCode => @format_code, :sourceLinked=>"1" - xml.majorTickMark :val=>"none" - xml.minorTickMark :val=>"none" - xml.tickLblPos :val=>@tickLblPos - xml.crossAx :val=>@crossAx - xml.crosses :val=>@crosses + def to_xml_string(str = '') + str << '<c:axId val="' << @axId.to_s << '"/>' + @scaling.to_xml_string str + str << '<c:delete val="0"/>' + str << '<c:axPos val="' << @axPos.to_s << '"/>' + str << '<c:majorGridlines>' + if self.gridlines == false + str << '<c:spPr>' + str << '<a:ln>' + str << '<a:noFill/>' + str << '</a:ln>' + str << '</c:spPr>' + end + str << '</c:majorGridlines>' + str << '<c:numFmt formatCode="' << @format_code << '" sourceLinked="1"/>' + str << '<c:majorTickMark val="none"/>' + str << '<c:minorTickMark val="none"/>' + str << '<c:tickLblPos val="' << @tickLblPos.to_s << '"/>' + str << '<c:crossAx val="' << @crossAx.to_s << '"/>' + str << '<c:crosses val="' << @crosses.to_s << '"/>' end + end end diff --git a/lib/axlsx/drawing/bar_3D_chart.rb b/lib/axlsx/drawing/bar_3D_chart.rb index de179cb6..abed702b 100644 --- a/lib/axlsx/drawing/bar_3D_chart.rb +++ b/lib/axlsx/drawing/bar_3D_chart.rb @@ -41,7 +41,7 @@ module Axlsx # validation regex for gap amount percent GAP_AMOUNT_PERCENT = /0*(([0-9])|([1-9][0-9])|([1-4][0-9][0-9])|500)%/ - + # Creates a new bar chart object # @param [GraphicFrame] frame The workbook that owns this chart. # @option options [Cell, String] title @@ -67,14 +67,14 @@ module Axlsx @valAxId = rand(8 ** 8) @catAxis = CatAxis.new(@catAxId, @valAxId) @valAxis = ValAxis.new(@valAxId, @catAxId, :tickLblPos => :low) - super(frame, options) + super(frame, options) @series_type = BarSeries @view3D = View3D.new({:rAngAx=>1}.merge(options)) end # The direction of the bars in the chart # must be one of [:bar, :col] - def barDir=(v) + def barDir=(v) RestrictionValidator.validate "Bar3DChart.barDir", [:bar, :col], v @barDir = v end @@ -100,38 +100,39 @@ module Axlsx # The shabe of the bars or columns # must be one of [:cone, :coneToMax, :box, :cylinder, :pyramid, :pyramidToMax] - def shape=(v) + def shape=(v) RestrictionValidator.validate "Bar3DChart.shape", [:cone, :coneToMax, :box, :cylinder, :pyramid, :pyramidToMax], v @shape = v end - - # Serializes the bar chart + + # Serializes the object + # @param [String] str # @return [String] - def to_xml - super() do |xml| - xml.bar3DChart { - xml.barDir :val => barDir - xml.grouping :val=>grouping - xml.varyColors :val=>1 - @series.each { |ser| ser.to_xml(xml) } - xml.dLbls { - xml.showLegendKey :val=>0 - xml.showVal :val=>0 - xml.showCatName :val=>0 - xml.showSerName :val=>0 - xml.showPercent :val=>0 - xml.showBubbleSize :val=>0 - } - xml.gapWidth :val=>@gapWidth unless @gapWidth.nil? - xml.gapDepth :val=>@gapDepth unless @gapDepth.nil? - xml.shape :val=>@shape unless @shape.nil? - xml.axId :val=>@catAxId - xml.axId :val=>@valAxId - xml.axId :val=>0 - } - @catAxis.to_xml(xml) - @valAxis.to_xml(xml) + def to_xml_string(str = '') + super(str) do |str_inner| + str_inner << '<c:bar3DChart>' + str_inner << '<c:barDir val="' << barDir.to_s << '"/>' + str_inner << '<c:grouping val="' << grouping.to_s << '"/>' + str_inner << '<c:varyColors val="1"/>' + @series.each { |ser| ser.to_xml_string(str_inner) } + str_inner << '<c:dLbls>' + str_inner << '<c:showLegendKey val="0"/>' + str_inner << '<c:showVal val="0"/>' + str_inner << '<c:showCatName val="0"/>' + str_inner << '<c:showSerName val="0"/>' + str_inner << '<c:showPercent val="0"/>' + str_inner << '<c:showBubbleSize val="0"/>' + str_inner << '</c:dLbls>' + str_inner << '<c:gapWidth val="' << @gapWidth.to_s << '"/>' unless @gapWidth.nil? + str_inner << '<c:gapDepth val="' << @gapDepth.to_s << '"/>' unless @gapDepth.nil? + str_inner << '<c:shape val="' << @shape.to_s << '"/>' unless @shape.nil? + str_inner << '<c:axId val="' << @catAxId.to_s << '"/>' + str_inner << '<c:axId val="' << @valAxId.to_s << '"/>' + str_inner << '<c:axId val="0"/>' + str_inner << '</c:bar3DChart>' + @catAxis.to_xml_string str_inner + @valAxis.to_xml_string str_inner end - end - end + end + end end diff --git a/lib/axlsx/drawing/bar_series.rb b/lib/axlsx/drawing/bar_series.rb index 5be8fabc..86ae6367 100644 --- a/lib/axlsx/drawing/bar_series.rb +++ b/lib/axlsx/drawing/bar_series.rb @@ -6,8 +6,8 @@ module Axlsx # @see Chart#add_series class BarSeries < Series - - # The data for this series. + + # The data for this series. # @return [Array, SimpleTypedList] attr_reader :data @@ -31,28 +31,27 @@ module Axlsx super(chart, options) self.labels = CatAxisData.new(options[:labels]) unless options[:labels].nil? self.data = ValAxisData.new(options[:data]) unless options[:data].nil? - end + end # The shabe of the bars or columns # must be one of [:percentStacked, :clustered, :standard, :stacked] - def shape=(v) + def shape=(v) RestrictionValidator.validate "BarSeries.shape", [:cone, :coneToMax, :box, :cylinder, :pyramid, :pyramidToMax], v @shape = v end - # Serializes the series - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - super(xml) do |xml_inner| - @labels.to_xml(xml_inner) unless @labels.nil? - @data.to_xml(xml_inner) unless @data.nil? - xml_inner.shape :val=>@shape - end + def to_xml_string(str = '') + super(str) do |str_inner| + @labels.to_xml_string(str_inner) unless @labels.nil? + @data.to_xml_string(str_inner) unless @data.nil? + str_inner << '<shape val="' << @shape.to_s << '"/>' + end end - - private + private # assigns the data for this series def data=(v) DataTypeValidator.validate "Series.data", [SimpleTypedList], v; @data = v; end diff --git a/lib/axlsx/drawing/cat_axis.rb b/lib/axlsx/drawing/cat_axis.rb index ee408c56..a961d736 100644 --- a/lib/axlsx/drawing/cat_axis.rb +++ b/lib/axlsx/drawing/cat_axis.rb @@ -10,7 +10,7 @@ module Axlsx # specifies how the perpendicular axis is crossed # must be one of [:ctr, :l, :r] # @return [Symbol] - attr_reader :lblAlgn + attr_reader :lblAlgn # The offset of the labels # must be between a string between 0 and 1000 @@ -20,7 +20,7 @@ module Axlsx # regex for validating label offset LBL_OFFSET_REGEX = /0*(([0-9])|([1-9][0-9])|([1-9][0-9][0-9])|1000)%/ - # Creates a new CatAxis object + # Creates a new CatAxis object # @param [Integer] axId the id of this axis. Inherited # @param [Integer] crossAx the id of the perpendicular axis. Inherited # @option options [Symbol] axPos. Inherited @@ -28,13 +28,13 @@ module Axlsx # @option options [Symbol] crosses. Inherited # @option options [Boolean] auto # @option options [Symbol] lblAlgn - # @option options [Integer] lblOffset + # @option options [Integer] lblOffset def initialize(axId, crossAx, options={}) self.auto = 1 self.lblAlgn = :ctr self.lblOffset = "100%" super(axId, crossAx, options) - end + end # From the docs: This element specifies that this axis is a date or text axis based on the data that is used for the axis labels, not a specific choice. def auto=(v) Axlsx::validate_boolean(v); @auto = v; end @@ -47,18 +47,19 @@ module Axlsx # must be between a string between 0 and 1000 def lblOffset=(v) RegexValidator.validate "#{self.class}.lblOffset", LBL_OFFSET_REGEX, v; @lblOffset = v; end - # Serializes the category axis - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.catAx { - super(xml) - xml.auto :val=>@auto - xml.lblAlgn :val=>@lblAlgn - xml.lblOffset :val=>@lblOffset - } + def to_xml_string(str = '') + str << '<c:catAx>' + super(str) + str << '<c:auto val="' << @auto.to_s << '"/>' + str << '<c:lblAlgn val="' << @lblAlgn.to_s << '"/>' + str << '<c:lblOffset val="' << @lblOffset.to_s << '"/>' + str << '</c:catAx>' end + end - + end diff --git a/lib/axlsx/drawing/cat_axis_data.rb b/lib/axlsx/drawing/cat_axis_data.rb index b9b57d01..30df1132 100644 --- a/lib/axlsx/drawing/cat_axis_data.rb +++ b/lib/axlsx/drawing/cat_axis_data.rb @@ -11,26 +11,24 @@ module Axlsx data.each { |i| @list << i } if data.is_a?(SimpleTypedList) end - # Serializes the category axis data - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.cat { - xml.strRef { - xml.f Axlsx::cell_range(@list) - xml.strCache { - xml.ptCount :val=>size - each_with_index do |item, index| - v = item.is_a?(Cell) ? item.value : item - xml.pt(:idx=>index) { - xml.v v - } - end - } - } - } + def to_xml_string(str = '') + str << '<c:cat>' + str << '<c:strRef>' + str << '<c:f>' << Axlsx::cell_range(@list) << '</c:f>' + str << '<c:strCache>' + str << '<c:ptCount val="' << size.to_s << '"/>' + each_with_index do |item, index| + v = item.is_a?(Cell) ? item.value.to_s : item + str << '<c:pt idx="' << index.to_s << '"><c:v>' << v << '</c:v></c:pt>' + end + str << '</c:strCache>' + str << '</c:strRef>' + str << '</c:cat>' end end - + end diff --git a/lib/axlsx/drawing/chart.rb b/lib/axlsx/drawing/chart.rb index 0a8068df..62bff861 100644 --- a/lib/axlsx/drawing/chart.rb +++ b/lib/axlsx/drawing/chart.rb @@ -28,7 +28,7 @@ module Axlsx # @return [Title] attr_reader :title - # The style for the chart. + # The style for the chart. # see ECMA Part 1 §21.2.2.196 # @return [Integer] attr_reader :style @@ -36,13 +36,14 @@ module Axlsx # Show the legend in the chart # @return [Boolean] attr_reader :show_legend - + # Creates a new chart object # @param [GraphicalFrame] frame The frame that holds this chart. # @option options [Cell, String] title # @option options [Boolean] show_legend def initialize(frame, options={}) @style = 2 + @view3D = nil @graphic_frame=frame @graphic_frame.anchor.drawing.worksheet.workbook.charts << self @series = SimpleTypedList.new Series @@ -72,7 +73,7 @@ module Axlsx # The title object for the chart. # @param [String, Cell] v # @return [Title] - def title=(v) + def title=(v) DataTypeValidator.validate "#{self.class}.title", [String, Cell], v if v.is_a?(String) @title.text = v @@ -80,14 +81,14 @@ module Axlsx @title.cell = v end end - + # Show the legend in the chart # @param [Boolean] v # @return [Boolean] def show_legend=(v) Axlsx::validate_boolean(v); @show_legend = v; end - # The style for the chart. + # The style for the chart. # see ECMA Part 1 §21.2.2.196 # @param [Integer] v must be between 1 and 48 def style=(v) DataTypeValidator.validate "Chart.style", Integer, v, lambda { |arg| arg >= 1 && arg <= 48 }; @style = v; end @@ -112,40 +113,38 @@ module Axlsx @series.last end - # Chart Serialization - # serializes the chart - def to_xml - builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml| - xml.send('c:chartSpace', :'xmlns:c' => XML_NS_C, :'xmlns:a' => XML_NS_A) { - xml[:c].date1904 :val => Axlsx::Workbook.date1904 - xml[:c].style :val=>style - xml[:c].chart { - @title.to_xml(xml) - xml.autoTitleDeleted :val=>0 - @view3D.to_xml(xml) unless @view3D.nil? - - xml.floor { xml.thickness(:val=>0) } - xml.sideWall { xml.thickness(:val=>0) } - xml.backWall { xml.thickness(:val=>0) } - xml.plotArea { - xml.layout - yield xml if block_given? - } - if @show_legend - xml.legend { - xml.legendPos :val => "r" - xml.layout - xml.overlay :val => 0 - } - end - xml.plotVisOnly :val => 1 - xml.dispBlanksAs :val => :zero - xml.showDLblsOverMax :val => 1 - } - - } + # Serializes the object + # @param [String] str + # @return [String] + def to_xml_string(str = '') + str << '<?xml version="1.0" encoding="UTF-8"?>' + str << '<c:chartSpace xmlns:c="' << XML_NS_C << '" xmlns:a="' << XML_NS_A << '">' + str << '<c:date1904 val="' << Axlsx::Workbook.date1904.to_s << '"/>' + str << '<c:style val="' << style.to_s << '"/>' + str << '<c:chart>' + @title.to_xml_string str + # do these need the c: namespace as well??? + str << '<c:autoTitleDeleted val="0"/>' + @view3D.to_xml_string(str) if @view3D + str << '<c:floor><c:thickness val="0"/></c:floor>' + str << '<c:sideWall><c:thickness val="0"/></c:sideWall>' + str << '<c:backWall><c:thickness val="0"/></c:backWall>' + str << '<c:plotArea>' + str << '<c:layout/>' + yield str if block_given? + str << '</c:plotArea>' + if @show_legend + str << '<c:legend>' + str << '<c:legendPos val="r"/>' + str << '<c:layout/>' + str << '<c:overlay val="0"/>' + str << '</c:legend>' end - builder.to_xml(:save_with => 0) + str << '<c:plotVisOnly val="1"/>' + str << '<c:dispBlanksAs val="zero"/>' + str << '<c:showDLblsOverMax val="1"/>' + str << '</c:chart>' + str << '</c:chartSpace>' end # This is a short cut method to set the start anchor position diff --git a/lib/axlsx/drawing/drawing.rb b/lib/axlsx/drawing/drawing.rb index 93068a23..1267d22e 100644 --- a/lib/axlsx/drawing/drawing.rb +++ b/lib/axlsx/drawing/drawing.rb @@ -4,8 +4,8 @@ module Axlsx require 'axlsx/drawing/series_title.rb' require 'axlsx/drawing/series.rb' require 'axlsx/drawing/pie_series.rb' - require 'axlsx/drawing/bar_series.rb' - require 'axlsx/drawing/line_series.rb' + require 'axlsx/drawing/bar_series.rb' + require 'axlsx/drawing/line_series.rb' require 'axlsx/drawing/scatter_series.rb' require 'axlsx/drawing/scaling.rb' @@ -19,7 +19,7 @@ module Axlsx require 'axlsx/drawing/named_axis_data.rb' require 'axlsx/drawing/marker.rb' - + require 'axlsx/drawing/one_cell_anchor.rb' require 'axlsx/drawing/two_cell_anchor.rb' require 'axlsx/drawing/graphic_frame.rb' @@ -46,7 +46,7 @@ module Axlsx # The worksheet that owns the drawing # @return [Worksheet] attr_reader :worksheet - + # A collection of anchors for this drawing # only TwoCellAnchors are supported in this version # @return [SimpleTypedList] @@ -138,15 +138,15 @@ module Axlsx r end - # Serializes the drawing + # Serializes the object + # @param [String] str # @return [String] - def to_xml - builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml| - xml.send('xdr:wsDr', :'xmlns:xdr'=>XML_NS_XDR, :'xmlns:a'=>XML_NS_A, :'xmlns:c'=>XML_NS_C) { - anchors.each {|anchor| anchor.to_xml(xml) } - } - end - builder.to_xml(:save_with => 0) + def to_xml_string(str = '') + str << '<?xml version="1.0" encoding="UTF-8"?>' + str << '<xdr:wsDr xmlns:xdr="' << XML_NS_XDR << '" xmlns:a="' << XML_NS_A << '" xmlns:c="' << XML_NS_C << '">' + anchors.each { |anchor| anchor.to_xml_string(str) } + str << '</xdr:wsDr>' end + end end diff --git a/lib/axlsx/drawing/graphic_frame.rb b/lib/axlsx/drawing/graphic_frame.rb index 178e0ea8..6466a656 100644 --- a/lib/axlsx/drawing/graphic_frame.rb +++ b/lib/axlsx/drawing/graphic_frame.rb @@ -28,26 +28,26 @@ module Axlsx "rId#{@anchor.index+1}" end - # Serializes the graphic frame - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.graphicFrame { - xml.nvGraphicFramePr { - xml.cNvPr :id=>2, :name=>chart.title.text - xml.cNvGraphicFramePr - } - xml.xfrm { - xml[:a].off(:x=>0, :y=>0) - xml[:a].ext :cx=>0, :cy=>0 - } - xml[:a].graphic { - xml.graphicData(:uri=>XML_NS_C) { - xml[:c].chart :'xmlns:c'=>XML_NS_C, :'xmlns:r'=>XML_NS_R, :'r:id'=>rId - } - } - } - + def to_xml_string(str = '') + str << '<xdr:graphicFrame>' + str << '<xdr:nvGraphicFramePr>' + str << '<xdr:cNvPr id="2" name="' << chart.title.text << '"/>' + str << '<xdr:cNvGraphicFramePr/>' + str << '</xdr:nvGraphicFramePr>' + str << '<xdr:xfrm>' + str << '<a:off x="0" y="0"/>' + str << '<a:ext cx="0" cy="0"/>' + str << '</xdr:xfrm>' + str << '<a:graphic>' + str << '<a:graphicData uri="' << XML_NS_C << '">' + str << '<c:chart xmlns:c="' << XML_NS_C << '" xmlns:r="' << XML_NS_R << '" r:id="' << rId.to_s << '"/>' + str << '</a:graphicData>' + str << '</a:graphic>' + str << '</xdr:graphicFrame>' end + end end diff --git a/lib/axlsx/drawing/hyperlink.rb b/lib/axlsx/drawing/hyperlink.rb index 67b08f29..6caebb6e 100644 --- a/lib/axlsx/drawing/hyperlink.rb +++ b/lib/axlsx/drawing/hyperlink.rb @@ -31,12 +31,12 @@ module Axlsx # indicates that the link has already been clicked. # @return [Boolean] attr_reader :highlightClick - + # @see highlightClick # @param [Boolean] v The value to assign def highlightClick=(v) Axlsx::validate_boolean(v); @highlightClick = v end - # From the specs: Specifies whether to add this URI to the history when navigating to it. This allows for the viewing of this presentation without the storing of history information on the viewing machine. If this attribute is omitted, then a value of 1 or true is assumed. + # From the specs: Specifies whether to add this URI to the history when navigating to it. This allows for the viewing of this presentation without the storing of history information on the viewing machine. If this attribute is omitted, then a value of 1 or true is assumed. # @return [Boolean] attr_reader :history @@ -52,12 +52,12 @@ module Axlsx # @return [String] attr_accessor :tooltip - #Creates a hyperlink object + #Creates a hyperlink object # parent must be a Pic for now, although I expect that other object support this tag and its cNvPr parent # @param [Pic] parent # @option options [String] tooltip message shown when hyperlinked object is hovered over with mouse. # @option options [String] tgtFrame Target frame for opening hyperlink - # @option options [String] invalidUrl supposedly use to store the href when we know it is an invalid resource. + # @option options [String] invalidUrl supposedly use to store the href when we know it is an invalid resource. # @option options [String] href the target resource this hyperlink links to. # @option options [String] action A string that can be used to perform specific actions. For excel please see this reference: http://msdn.microsoft.com/en-us/library/ff532419%28v=office.12%29.aspx # @option options [Boolean] endSnd terminate any sound events when processing this link @@ -70,22 +70,23 @@ module Axlsx self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}=" end yield self if block_given? - - end + end - # Serializes the hyperlink - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) + def to_xml_string(str = '') h = self.instance_values.merge({:'r:id' => "rId#{id}", :'xmlns:r' => XML_NS_R }) h.delete('href') h.delete('parent') - xml[:a].hlinkClick h + str << '<a:hlinkClick ' + str << h.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ') + str << '/>' end private - # The relational ID for this hyperlink + # The relational ID for this hyperlink # @return [Integer] def id @parent.anchor.drawing.charts.size + @parent.anchor.drawing.images.size + @parent.anchor.drawing.hyperlinks.index(self) + 1 diff --git a/lib/axlsx/drawing/line_3D_chart.rb b/lib/axlsx/drawing/line_3D_chart.rb index 13e42dff..0f8a07f8 100644 --- a/lib/axlsx/drawing/line_3D_chart.rb +++ b/lib/axlsx/drawing/line_3D_chart.rb @@ -44,11 +44,11 @@ module Axlsx # validation regex for gap amount percent GAP_AMOUNT_PERCENT = /0*(([0-9])|([1-9][0-9])|([1-4][0-9][0-9])|500)%/ - + # Creates a new line chart object # @param [GraphicFrame] frame The workbook that owns this chart. # @option options [Cell, String] title - # @option options [Boolean] show_legend + # @option options [Boolean] show_legend # @option options [Symbol] grouping # @option options [String] gapDepth # @option options [Integer] rotX @@ -68,7 +68,7 @@ module Axlsx @catAxis = CatAxis.new(@catAxId, @valAxId) @valAxis = ValAxis.new(@valAxId, @catAxId) @serAxis = SerAxis.new(@serAxId, @valAxId) - super(frame, options) + super(frame, options) @series_type = LineSeries @view3D = View3D.new({:perspective=>30}.merge(options)) end @@ -85,31 +85,33 @@ module Axlsx @gapDepth=(v) end - # Serializes the bar chart + # Serializes the object + # @param [String] str # @return [String] - def to_xml - super() do |xml| - xml.line3DChart { - xml.grouping :val=>grouping - xml.varyColors :val=>1 - @series.each { |ser| ser.to_xml(xml) } - xml.dLbls { - xml.showLegendKey :val=>0 - xml.showVal :val=>0 - xml.showCatName :val=>0 - xml.showSerName :val=>0 - xml.showPercent :val=>0 - xml.showBubbleSize :val=>0 - } - xml.gapDepth :val=>@gapDepth unless @gapDepth.nil? - xml.axId :val=>@catAxId - xml.axId :val=>@valAxId - xml.axId :val=>@serAxId - } - @catAxis.to_xml(xml) - @valAxis.to_xml(xml) - @serAxis.to_xml(xml) + def to_xml_string(str = '') + super(str) do |str_inner| + str_inner << '<c:line3DChart>' + str_inner << '<c:grouping val="' << grouping.to_s << '"/>' + str_inner << '<c:varyColors val="1"/>' + @series.each { |ser| ser.to_xml_string(str_inner) } + str_inner << '<c:dLbls>' + str_inner << '<c:showLegendKey val="0"/>' + str_inner << '<c:showVal val="0"/>' + str_inner << '<c:showCatName val="0"/>' + str_inner << '<c:showSerName val="0"/>' + str_inner << '<c:showPercent val="0"/>' + str_inner << '<c:showBubbleSize val="0"/>' + str_inner << '</c:dLbls>' + str_inner << '<c:gapDepth val="' << @gapDepth.to_s << '"/>' unless @gapDepth.nil? + str_inner << '<c:axId val="' << @catAxId.to_s << '"/>' + str_inner << '<c:axId val="' << @valAxId.to_s << '"/>' + str_inner << '<c:axId val="' << @serAxId.to_s << '"/>' + str_inner << '</c:line3DChart>' + @catAxis.to_xml_string str_inner + @valAxis.to_xml_string str_inner + @serAxis.to_xml_string str_inner end - end - end + end + + end end diff --git a/lib/axlsx/drawing/line_series.rb b/lib/axlsx/drawing/line_series.rb index a7de888f..ac3840f1 100644 --- a/lib/axlsx/drawing/line_series.rb +++ b/lib/axlsx/drawing/line_series.rb @@ -5,8 +5,8 @@ module Axlsx # @see Worksheet#add_chart # @see Chart#add_series class LineSeries < Series - - # The data for this series. + + # The data for this series. # @return [ValAxisData] attr_reader :data @@ -23,19 +23,19 @@ module Axlsx super(chart, options) @labels = CatAxisData.new(options[:labels]) unless options[:labels].nil? @data = ValAxisData.new(options[:data]) unless options[:data].nil? - end + end - # Serializes the series - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - super(xml) do |xml_inner| - @labels.to_xml(xml_inner) unless @labels.nil? - @data.to_xml(xml_inner) unless @data.nil? - end + def to_xml_string(str = '') + super(str) do + @labels.to_xml_string(str) unless @labels.nil? + @data.to_xml_string(str) unless @data.nil? + end end - private + private # assigns the data for this series def data=(v) DataTypeValidator.validate "Series.data", [SimpleTypedList], v; @data = v; end diff --git a/lib/axlsx/drawing/marker.rb b/lib/axlsx/drawing/marker.rb index dac8604e..8da9477e 100644 --- a/lib/axlsx/drawing/marker.rb +++ b/lib/axlsx/drawing/marker.rb @@ -30,9 +30,9 @@ module Axlsx @col, @colOff, @row, @rowOff = 0, 0, 0, 0 options.each do |o| self.send("#{o[0]}=", o[1]) if self.respond_to? o[0] - end + end end - + # @see col def col=(v) Axlsx::validate_unsigned_int v; @col = v end # @see colOff @@ -41,7 +41,7 @@ module Axlsx def row=(v) Axlsx::validate_unsigned_int v; @row = v end # @see rowOff def rowOff=(v) Axlsx::validate_int v; @rowOff = v end - + # shortcut to set the column, row position for this marker # @param col the column for the marker # @param row the row of the marker @@ -49,14 +49,16 @@ module Axlsx self.col = col self.row = row end - # Serializes the marker - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) + def to_xml_string(str = '') [:col, :colOff, :row, :rowOff].each do |k| - xml.send(k.to_sym, self.send(k)) - end + str << '<xdr:' << k.to_s << '>' << self.send(k).to_s << '</xdr:' << k.to_s << '>' + end end + end end diff --git a/lib/axlsx/drawing/named_axis_data.rb b/lib/axlsx/drawing/named_axis_data.rb index b249196f..218057ed 100644 --- a/lib/axlsx/drawing/named_axis_data.rb +++ b/lib/axlsx/drawing/named_axis_data.rb @@ -1,31 +1,36 @@ # encoding: UTF-8 +# TODO: review cat, val and named access data to extend this and reduce replicated code. module Axlsx # The ValAxisData class manages the values for a chart value series. class NamedAxisData < CatAxisData + # creates a new NamedAxisData Object + # @param [String] name The serialized node name for the axis data object + # @param [Array] The data to associate with the axis data object def initialize(name, data=[]) super(data) @name = name end - # Serializes the value axis data - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.send(@name) { - xml.numRef { - xml.f Axlsx::cell_range(@list) - xml.numCache { - xml.formatCode 'General' - xml.ptCount :val=>size - each_with_index do |item, index| - v = item.is_a?(Cell) ? item.value : item - xml.pt(:idx=>index) { xml.v v } - end - } - } - } + def to_xml_string(str = '') + str << '<c:' << @name.to_s << '>' + str << '<c:numRef>' + str << '<c:f>' << Axlsx::cell_range(@list) << '</c:f>' + str << '<c:numCache>' + str << '<c:formatCode>General</c:formatCode>' + str << '<c:ptCount val="' << size.to_s << '"/>' + each_with_index do |item, index| + v = item.is_a?(Cell) ? item.value.to_s : item + str << '<c:pt idx="' << index.to_s << '"><c:v>' << v << '</c:v></c:pt>' + end + str << '</c:numCache>' + str << '</c:numRef>' + str << '</c:' << @name.to_s << '>' end + end end diff --git a/lib/axlsx/drawing/one_cell_anchor.rb b/lib/axlsx/drawing/one_cell_anchor.rb index 2cd43331..9a202cc1 100644 --- a/lib/axlsx/drawing/one_cell_anchor.rb +++ b/lib/axlsx/drawing/one_cell_anchor.rb @@ -33,15 +33,15 @@ module Axlsx # @param [Drawing] drawing # @option options [Array] start_at the col, row to start at # @option options [Integer] width - # @option options [Integer] height + # @option options [Integer] height # @option options [String] image_src the file location of the image you will render # @option options [String] name the name attribute for the rendered image - # @option options [String] descr the description of the image rendered + # @option options [String] descr the description of the image rendered def initialize(drawing, options={}) @drawing = drawing @width = 0 @height = 0 - drawing.anchors << self + drawing.anchors << self @from = Marker.new options.each do |o| self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}=" @@ -61,23 +61,24 @@ module Axlsx @drawing.anchors.index(self) end - # Serializes the anchor - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml[:xdr].oneCellAnchor { - xml.from { - from.to_xml(xml) - } - xml.ext ext - @object.to_xml(xml) - xml.clientData - } - end + def to_xml_string(str = '') + str << '<xdr:oneCellAnchor>' + str << '<xdr:from>' + from.to_xml_string(str) + str << '</xdr:from>' + str << '<xdr:ext cx="' << ext[:cx].to_s << '" cy="' << ext[:cy].to_s << '"/>' + @object.to_xml_string(str) + str << '<xdr:clientData/>' + str << '</xdr:oneCellAnchor>' + end private - # converts the pixel width and height to EMU units and returns a hash of + # converts the pixel width and height to EMU units and returns a hash of # !{:cx=>[Integer], :cy=>[Integer] # @return [Hash] def ext diff --git a/lib/axlsx/drawing/pic.rb b/lib/axlsx/drawing/pic.rb index 754a7e35..e5e005fa 100644 --- a/lib/axlsx/drawing/pic.rb +++ b/lib/axlsx/drawing/pic.rb @@ -28,7 +28,7 @@ module Axlsx # The picture locking attributes for this picture attr_reader :picture_locking - + # Creates a new Pic(ture) object # @param [Anchor] anchor the anchor that holds this image # @option options [String] name @@ -50,7 +50,7 @@ module Axlsx end attr_reader :hyperlink - + # sets or updates a hyperlink for this image. # @param [String] v The href value for the hyper link # @option options @see Hyperlink#initialize All options available to the Hyperlink class apply - however href will be overridden with the v parameter value. @@ -66,7 +66,7 @@ module Axlsx @hyperlink end - def image_src=(v) + def image_src=(v) Axlsx::validate_string(v) RestrictionValidator.validate 'Pic.image_src', ALLOWED_EXTENSIONS, File.extname(v).delete('.') raise ArgumentError, "File does not exist" unless File.exist?(v) @@ -84,8 +84,8 @@ module Axlsx # @return [String] def file_name File.basename(image_src) unless image_src.nil? - end - + end + # returns the extension of image_src without the preceeding '.' # @return [String] def extname @@ -93,7 +93,7 @@ module Axlsx end # The index of this image in the workbooks images collections - # @return [Index] + # @return [Index] def index @anchor.drawing.worksheet.workbook.images.index(self) end @@ -120,7 +120,7 @@ module Axlsx def width=(v) @anchor.width = v end - + # providing access to update the anchor's height attribute # @param [Integer] v # @see OneCellAnchor.width @@ -144,37 +144,24 @@ module Axlsx @anchor.from.row = y end - # Serializes the picture - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.pic { - xml.nvPicPr { - xml.cNvPr(:id=>"2", :name=>name, :descr=>descr) { - if @hyperlink.is_a?(Hyperlink) - @hyperlink.to_xml(xml) - end - } - xml.cNvPicPr { - picture_locking.to_xml(xml) - } - } - xml.blipFill { - xml[:a].blip :'xmlns:r' => XML_NS_R, :'r:embed'=>"rId#{id}" - xml[:a].stretch { - xml.fillRect - } - } - xml.spPr { - xml[:a].xfrm { - xml.off :x=>0, :y=>0 - xml.ext :cx=>2336800, :cy=>2161540 - } - xml[:a].prstGeom(:prst=>:rect) { - xml.avLst - } - } - } + def to_xml_string(str = '') + str << '<xdr:pic>' + str << '<xdr:nvPicPr>' + str << '<xdr:cNvPr id="2" name="' << name.to_s << '" descr="' << descr.to_s << '">' + @hyperlink.to_xml_string(str) if @hyperlink.is_a?(Hyperlink) + str << '</xdr:cNvPr><xdr:cNvPicPr>' + picture_locking.to_xml_string(str) + str << '</xdr:cNvPicPr></xdr:nvPicPr>' + str << '<xdr:blipFill>' + str << '<a:blip xmlns:r ="' << XML_NS_R << '" r:embed="rId' << id.to_s << '"/>' + str << '<a:stretch><a:fillRect/></a:stretch></xdr:blipFill><xdr:spPr>' + str << '<a:xfrm><a:off x="0" y="0"/><a:ext cx="2336800" cy="2161540"/></a:xfrm>' + str << '<a:prstGeom prst="rect"><a:avLst/></a:prstGeom></xdr:spPr></xdr:pic>' + end + end end diff --git a/lib/axlsx/drawing/picture_locking.rb b/lib/axlsx/drawing/picture_locking.rb index c05f1641..0d6f4e54 100644 --- a/lib/axlsx/drawing/picture_locking.rb +++ b/lib/axlsx/drawing/picture_locking.rb @@ -1,9 +1,9 @@ # encoding: UTF-8 module Axlsx - # The picture locking class defines the locking properties for pictures in your workbook. + # The picture locking class defines the locking properties for pictures in your workbook. class PictureLocking - - + + attr_reader :noGrp attr_reader :noSelect attr_reader :noRot @@ -31,43 +31,46 @@ module Axlsx options.each do |o| self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}=" end - end + end # @see noGrp - def noGrp=(v) Axlsx::validate_boolean v; @noGrp = v end + def noGrp=(v) Axlsx::validate_boolean v; @noGrp = v end # @see noSelect - def noSelect=(v) Axlsx::validate_boolean v; @noSelect = v end + def noSelect=(v) Axlsx::validate_boolean v; @noSelect = v end # @see noRot - def noRot=(v) Axlsx::validate_boolean v; @noRot = v end + def noRot=(v) Axlsx::validate_boolean v; @noRot = v end # @see noChangeAspect - def noChangeAspect=(v) Axlsx::validate_boolean v; @noChangeAspect = v end + def noChangeAspect=(v) Axlsx::validate_boolean v; @noChangeAspect = v end # @see noMove - def noMove=(v) Axlsx::validate_boolean v; @noMove = v end + def noMove=(v) Axlsx::validate_boolean v; @noMove = v end # @see noResize - def noResize=(v) Axlsx::validate_boolean v; @noResize = v end + def noResize=(v) Axlsx::validate_boolean v; @noResize = v end # @see noEditPoints - def noEditPoints=(v) Axlsx::validate_boolean v; @noEditPoints = v end + def noEditPoints=(v) Axlsx::validate_boolean v; @noEditPoints = v end # @see noAdjustHandles - def noAdjustHandles=(v) Axlsx::validate_boolean v; @noAdjustHandles = v end + def noAdjustHandles=(v) Axlsx::validate_boolean v; @noAdjustHandles = v end # @see noChangeArrowheads - def noChangeArrowheads=(v) Axlsx::validate_boolean v; @noChangeArrowheads = v end + def noChangeArrowheads=(v) Axlsx::validate_boolean v; @noChangeArrowheads = v end # @see noChangeShapeType - def noChangeShapeType=(v) Axlsx::validate_boolean v; @noChangeShapeType = v end + def noChangeShapeType=(v) Axlsx::validate_boolean v; @noChangeShapeType = v end - # Serializes the picture locking - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml[:a].picLocks(self.instance_values) + def to_xml_string(str = '') + str << '<a:picLocks ' + str << instance_values.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ') + str << '/>' end + end end diff --git a/lib/axlsx/drawing/pie_3D_chart.rb b/lib/axlsx/drawing/pie_3D_chart.rb index cb36e4f5..fea89d0e 100644 --- a/lib/axlsx/drawing/pie_3D_chart.rb +++ b/lib/axlsx/drawing/pie_3D_chart.rb @@ -11,7 +11,7 @@ module Axlsx # Creates a new pie chart object # @param [GraphicFrame] frame The workbook that owns this chart. # @option options [Cell, String] title - # @option options [Boolean] show_legend + # @option options [Boolean] show_legend # @option options [Symbol] grouping # @option options [String] gapDepth # @option options [Integer] rotX @@ -28,15 +28,17 @@ module Axlsx @view3D = View3D.new({:rotX=>30, :perspective=>30}.merge(options)) end - # Serializes the pie chart + # Serializes the object + # @param [String] str # @return [String] - def to_xml - super() do |xml| - xml[:c].pie3DChart { - xml[:c].varyColors :val=>1 - @series.each { |ser| ser.to_xml(xml) } - } + def to_xml_string(str = '') + super(str) do |str_inner| + str_inner << '<c:pie3DChart>' + str_inner << '<c:varyColors val="1"/>' + @series.each { |ser| ser.to_xml_string(str_inner) } + str_inner << '</c:pie3DChart>' end end + end end diff --git a/lib/axlsx/drawing/pie_series.rb b/lib/axlsx/drawing/pie_series.rb index 8e583806..0deac1be 100644 --- a/lib/axlsx/drawing/pie_series.rb +++ b/lib/axlsx/drawing/pie_series.rb @@ -1,12 +1,13 @@ # encoding: UTF-8 module Axlsx + # A PieSeries defines the data and labels and explosion for pie charts series. # @note The recommended way to manage series is to use Chart#add_series # @see Worksheet#add_chart # @see Chart#add_series class PieSeries < Series - # The data for this series. + # The data for this series. # @return [SimpleTypedList] attr_reader :data @@ -29,22 +30,24 @@ module Axlsx super(chart, options) self.labels = CatAxisData.new(options[:labels]) unless options[:labels].nil? self.data = ValAxisData.new(options[:data]) unless options[:data].nil? - end - + end + # @see explosion def explosion=(v) Axlsx::validate_unsigned_int(v); @explosion = v; end - # Serializes the series - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - super(xml) do |xml_inner| - xml_inner.explosion :val=>@explosion unless @explosion.nil? - @labels.to_xml(xml_inner) unless @labels.nil? - @data.to_xml(xml_inner) unless @data.nil? - end + def to_xml_string(str = '') + super(str) do |str_inner| + str_inner << '<c:explosion val="' << @explosion << '"/>' unless @explosion.nil? + @labels.to_xml_string str_inner unless @labels.nil? + @data.to_xml_string str_inner unless @data.nil? + end + str end - private + + private # assigns the data for this series def data=(v) DataTypeValidator.validate "Series.data", [SimpleTypedList], v; @data = v; end diff --git a/lib/axlsx/drawing/scaling.rb b/lib/axlsx/drawing/scaling.rb index 628aa016..29333bc7 100644 --- a/lib/axlsx/drawing/scaling.rb +++ b/lib/axlsx/drawing/scaling.rb @@ -33,7 +33,7 @@ module Axlsx self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}=" end end - + # @see logBase def logBase=(v) DataTypeValidator.validate "Scaling.logBase", [Integer, Fixnum], v, lambda { |arg| arg >= 2 && arg <= 1000}; @logBase = v; end # @see orientation @@ -44,16 +44,16 @@ module Axlsx # @see min def min=(v) DataTypeValidator.validate "Scaling.min", Float, v; @min = v; end - # Serializes the axId - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml[:c].scaling { - xml[:c].logBase :val=> @logBase unless @logBase.nil? - xml[:c].orientation :val=> @orientation unless @orientation.nil? - xml[:c].min :val => @min unless @min.nil? - xml[:c].max :val => @max unless @max.nil? - } + def to_xml_string(str = '') + str << '<c:scaling>' + str << '<c:logBase val="' << @logBase.to_s << '"/>' unless @logBase.nil? + str << '<c:orientation val="' << @orientation.to_s << '"/>' unless @orientation.nil? + str << '<c:min val="' << @min.to_s << '"/>' unless @min.nil? + str << '<c:max val="' << @max.to_s << '"/>' unless @max.nil? + str << '</c:scaling>' end end diff --git a/lib/axlsx/drawing/scatter_chart.rb b/lib/axlsx/drawing/scatter_chart.rb index f257303a..1495a907 100644 --- a/lib/axlsx/drawing/scatter_chart.rb +++ b/lib/axlsx/drawing/scatter_chart.rb @@ -1,6 +1,15 @@ # encoding: UTF-8 module Axlsx + + # The ScatterChart allows you to insert a scatter chart into your worksheet + # @see Worksheet#add_chart + # @see Chart#add_series + # @see README for an example class ScatterChart < Chart + + # The Style for the scatter chart + # must be one of :none | :line | :lineMarker | :marker | :smooth | :smoothMarker + # return [Symbol] attr_reader :scatterStyle # the x value axis @@ -11,6 +20,7 @@ module Axlsx # @return [ValAxis] attr_reader :yValAxis + # Creates a new scatter chart def initialize(frame, options={}) @scatterStyle = :lineMarker @xValAxId = rand(8 ** 8) @@ -19,32 +29,41 @@ module Axlsx @yValAxis = ValAxis.new(@yValAxId, @xValAxId) super(frame, options) @series_type = ScatterSeries + options.each do |o| + self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}=" + end end - # Serializes the bar chart - # @return [String] - def to_xml - super() do |xml| - xml.scatterChart { - xml.scatterStyle :val=>scatterStyle + # see #scatterStyle + def scatterStyle=(v) + Axlsx.validate_scatter_style(v) + @scatterStyle = v + end - # This is all repeated from line_3D_chart.rb! - xml.varyColors :val=>1 - @series.each { |ser| ser.to_xml(xml) } - xml.dLbls { - xml.showLegendKey :val=>0 - xml.showVal :val=>0 - xml.showCatName :val=>0 - xml.showSerName :val=>0 - xml.showPercent :val=>0 - xml.showBubbleSize :val=>0 - } - xml.axId :val=>@xValAxId - xml.axId :val=>@yValAxId - } - @xValAxis.to_xml(xml) - @yValAxis.to_xml(xml) + # Serializes the object + # @param [String] str + # @return [String] + def to_xml_string(str = '') + super do |str| + str << '<c:scatterChart>' + str << '<c:scatterStyle val="' << scatterStyle.to_s << '"/>' + str << '<c:varyColors val="1"/>' + @series.each { |ser| ser.to_xml_string(str) } + str << '<c:dLbls>' + str << '<c:showLegendKey val="0"/>' + str << '<c:showVal val="0"/>' + str << '<c:showCatName val="0"/>' + str << '<c:showSerName val="0"/>' + str << '<c:showPercent val="0"/>' + str << '<c:showBubbleSize val="0"/>' + str << '</c:dLbls>' + str << '<c:axId val="' << @xValAxId.to_s << '"/>' + str << '<c:axId val="' << @yValAxId.to_s << '"/>' + str << '</c:scatterChart>' + @xValAxis.to_xml_string str + @yValAxis.to_xml_string str end + str end end end diff --git a/lib/axlsx/drawing/scatter_series.rb b/lib/axlsx/drawing/scatter_series.rb index 52145cd1..2469e0bf 100644 --- a/lib/axlsx/drawing/scatter_series.rb +++ b/lib/axlsx/drawing/scatter_series.rb @@ -1,6 +1,13 @@ # encoding: UTF-8 module Axlsx + + # A ScatterSeries defines the x and y position of data in the chart + # @note The recommended way to manage series is to use Chart#add_series + # @see Worksheet#add_chart + # @see Chart#add_series + # @see examples/example.rb class ScatterSeries < Series + # The x data for this series. # @return [NamedAxisData] attr_reader :xData @@ -9,6 +16,7 @@ module Axlsx # @return [NamedAxisData] attr_reader :yData + # Creates a new ScatterSeries def initialize(chart, options={}) @xData, @yData = nil super(chart, options) @@ -17,15 +25,15 @@ module Axlsx @yData = NamedAxisData.new("yVal", options[:yData]) unless options[:yData].nil? end - # Serializes the series - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - super(xml) do |xml_inner| - @xData.to_xml(xml_inner) unless @xData.nil? - @yData.to_xml(xml_inner) unless @yData.nil? + def to_xml_string(str = '') + super(str) do |inner_str| + @xData.to_xml_string(inner_str) unless @xData.nil? + @yData.to_xml_string(inner_str) unless @yData.nil? end + str end - end end diff --git a/lib/axlsx/drawing/ser_axis.rb b/lib/axlsx/drawing/ser_axis.rb index 6fc5fec0..703786e5 100644 --- a/lib/axlsx/drawing/ser_axis.rb +++ b/lib/axlsx/drawing/ser_axis.rb @@ -22,7 +22,7 @@ module Axlsx def initialize(axId, crossAx, options={}) @tickLblSkip, @tickMarkSkip = nil, nil super(axId, crossAx, options) - end + end # @see tickLblSkip def tickLblSkip=(v) Axlsx::validate_unsigned_int(v); @tickLblSkip = v; end @@ -30,17 +30,17 @@ module Axlsx # @see tickMarkSkip def tickMarkSkip=(v) Axlsx::validate_unsigned_int(v); @tickMarkSkip = v; end - # Serializes the series axis - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml[:c].serAx { - super(xml) - xml[:c].tickLblSkip :val=>@tickLblSkip unless @tickLblSkip.nil? - xml[:c].tickMarkSkip :val=>@tickMarkSkip unless @tickMarkSkip.nil? - } + def to_xml_string(str = '') + str << '<c:serAx>' + super(str) + str << '<c:tickLblSkip val="' << @tickLblSkip.to_s << '"/>' unless @tickLblSkip.nil? + str << '<c:tickMarkSkip val="' << @tickMarkSkip.to_s << '"/>' unless @tickMarkSkip.nil? + str << '</c:serAx>' end end - + end diff --git a/lib/axlsx/drawing/series.rb b/lib/axlsx/drawing/series.rb index 1544bc48..798919b5 100644 --- a/lib/axlsx/drawing/series.rb +++ b/lib/axlsx/drawing/series.rb @@ -25,7 +25,7 @@ module Axlsx options.each do |o| self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}=" end - end + end # The index of this series in the chart's series. # @return [Integer] @@ -44,27 +44,27 @@ module Axlsx def order=(v) Axlsx::validate_unsigned_int(v); @order = v; end # @see title - def title=(v) + def title=(v) v = SeriesTitle.new(v) if v.is_a?(String) || v.is_a?(Cell) DataTypeValidator.validate "#{self.class}.title", SeriesTitle, v @title = v end - - private - + + private + # assigns the chart for this series - def chart=(v) DataTypeValidator.validate "Series.chart", Chart, v; @chart = v; end + def chart=(v) DataTypeValidator.validate "Series.chart", Chart, v; @chart = v; end - # Serializes the series - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.ser { - xml.idx :val=>index - xml.order :val=>order || index - title.to_xml(xml) unless title.nil? - yield xml if block_given? - } + def to_xml_string(str = '') + str << '<c:ser>' + str << '<c:idx val="' << index.to_s << '"/>' + str << '<c:order val="' << (order || index).to_s << '"/>' + title.to_xml_string(str) unless title.nil? + yield str if block_given? + str << '</c:ser>' end end diff --git a/lib/axlsx/drawing/series_title.rb b/lib/axlsx/drawing/series_title.rb index b13cec89..658be425 100644 --- a/lib/axlsx/drawing/series_title.rb +++ b/lib/axlsx/drawing/series_title.rb @@ -3,21 +3,21 @@ module Axlsx # A series title is a Title with a slightly different serialization than chart titles. class SeriesTitle < Title - # Serializes the series title - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml[:c].tx { - xml[:c].strRef { - xml[:c].f Axlsx::cell_range([@cell]) - xml[:c].strCache { - xml[:c].ptCount :val=>1 - xml[:c].pt(:idx=>0) { - xml[:c].v @text - } - } - } - } + def to_xml_string(str = '') + str << '<c:tx>' + str << '<c:strRef>' + str << '<c:f>' << Axlsx::cell_range([@cell]) << '</c:f>' + str << '<c:strCache>' + str << '<c:ptCount val="1"/>' + str << '<c:pt idx="0">' + str << '<c:v>' << @text << '</c:v>' + str << '</c:pt>' + str << '</c:strCache>' + str << '</c:strRef>' + str << '</c:tx>' end end end diff --git a/lib/axlsx/drawing/title.rb b/lib/axlsx/drawing/title.rb index cc382205..a85d8e11 100644 --- a/lib/axlsx/drawing/title.rb +++ b/lib/axlsx/drawing/title.rb @@ -2,7 +2,7 @@ module Axlsx # A Title stores information about the title of a chart class Title - + # The text to be shown. Setting this property directly with a string will remove the cell reference. # @return [String] attr_reader :text @@ -17,9 +17,9 @@ module Axlsx self.cell = title if title.is_a?(Cell) self.text = title.to_s unless title.is_a?(Cell) end - + # @see text - def text=(v) + def text=(v) DataTypeValidator.validate 'Title.text', String, v @text = v @cell = nil @@ -30,7 +30,7 @@ module Axlsx def cell=(v) DataTypeValidator.validate 'Title.text', Cell, v @cell = v - @text = v.value.to_s + @text = v.value.to_s v end @@ -38,29 +38,29 @@ module Axlsx #def layout=(v) DataTypeValidator.validate 'Title.layout', Layout, v; @layout = v; end #def overlay=(v) Axlsx::validate_boolean v; @overlay=v; end #def spPr=(v) DataTypeValidator.validate 'Title.spPr', SpPr, v; @spPr = v; end - - # Serializes the chart title - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml[:c].title { - unless @text.empty? - xml[:c].tx { - xml[:c].strRef { - xml[:c].f Axlsx::cell_range([@cell]) - xml[:c].strCache { - xml[:c].ptCount :val=>1 - xml[:c].pt(:idx=>0) { - xml[:c].v @text - } - } - } - } - end - xml[:c].layout - xml[:c].overlay :val=>0 - } + def to_xml_string(str = '') + str << '<c:title>' + unless @text.empty? + str << '<c:tx>' + str << '<c:strRef>' + str << '<c:f>' << Axlsx::cell_range([@cell]) << '</c:f>' + str << '<c:strCache>' + str << '<c:ptCount val="1"/>' + str << '<c:pt idx="0">' + str << '<c:v>' << @text << '</c:v>' + str << '</c:pt>' + str << '</c:strCache>' + str << '</c:strRef>' + str << '</c:tx>' + end + str << '<c:layout/>' + str << '<c:overlay val="0"/>' + str << '</c:title>' end - + end end diff --git a/lib/axlsx/drawing/two_cell_anchor.rb b/lib/axlsx/drawing/two_cell_anchor.rb index 436f2e7a..b496bd8a 100644 --- a/lib/axlsx/drawing/two_cell_anchor.rb +++ b/lib/axlsx/drawing/two_cell_anchor.rb @@ -26,7 +26,7 @@ module Axlsx attr_reader :drawing - # Creates a new TwoCellAnchor object and sets up a reference to the from and to markers in the + # Creates a new TwoCellAnchor object and sets up a reference to the from and to markers in the # graphic_frame's chart. That means that you can do stuff like # c = worksheet.add_chart Axlsx::Chart # c.start_at 5, 9 @@ -38,13 +38,13 @@ module Axlsx # @option options [Array] end_at the col, row to end at def initialize(drawing, options={}) @drawing = drawing - drawing.anchors << self + drawing.anchors << self @from, @to = Marker.new, Marker.new(:col => 5, :row=>10) end # Creates a graphic frame and chart object associated with this anchor # @return [Chart] - def add_chart(chart_type, options) + def add_chart(chart_type, options) @object = GraphicFrame.new(self, chart_type, options) @object.chart end @@ -54,24 +54,22 @@ module Axlsx def index @drawing.anchors.index(self) end - # Serializes the two cell anchor - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. - # @return [String] - def to_xml(xml) - #build it for now, break it down later! - xml[:xdr].twoCellAnchor { - xml.from { - from.to_xml(xml) - } - xml.to { - to.to_xml(xml) - } - @object.to_xml(xml) - xml.clientData - } - end - private + # Serializes the object + # @param [String] str + # @return [String] + def to_xml_string(str = '') + str << '<xdr:twoCellAnchor>' + str << '<xdr:from>' + from.to_xml_string str + str << '</xdr:from>' + str << '<xdr:to>' + to.to_xml_string str + str << '</xdr:to>' + object.to_xml_string(str) + str << '<xdr:clientData/>' + str << '</xdr:twoCellAnchor>' + end end end diff --git a/lib/axlsx/drawing/val_axis.rb b/lib/axlsx/drawing/val_axis.rb index c7091d49..6e55c8ea 100644 --- a/lib/axlsx/drawing/val_axis.rb +++ b/lib/axlsx/drawing/val_axis.rb @@ -22,14 +22,15 @@ module Axlsx # @see crossBetween def crossBetween=(v) RestrictionValidator.validate "ValAxis.crossBetween", [:between, :midCat], v; @crossBetween = v; end - # Serializes the value axis - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.valAx { - super(xml) - xml.crossBetween :val=>@crossBetween - } + def to_xml_string(str = '') + str << '<c:valAx>' + super(str) + str << '<c:crossBetween val="' << @crossBetween.to_s << '"/>' + str << '</c:valAx>' end + end end diff --git a/lib/axlsx/drawing/val_axis_data.rb b/lib/axlsx/drawing/val_axis_data.rb index 6b950443..61044cd6 100644 --- a/lib/axlsx/drawing/val_axis_data.rb +++ b/lib/axlsx/drawing/val_axis_data.rb @@ -3,25 +3,25 @@ module Axlsx # The ValAxisData class manages the values for a chart value series. class ValAxisData < CatAxisData - # Serializes the value axis data - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.val { - xml.numRef { - xml.f Axlsx::cell_range(@list) - xml.numCache { - xml.formatCode 'General' - xml.ptCount :val=>size - each_with_index do |item, index| - v = item.is_a?(Cell) ? item.value : item - xml.pt(:idx=>index) { xml.v v } - end - } - } - } + def to_xml_string(str = '') + str << '<c:val>' + str << '<c:numRef>' + str << '<c:f>' << Axlsx::cell_range(@list) << '</c:f>' + str << '<c:numCache>' + str << '<c:formatCode>General</c:formatCode>' + str << '<c:ptCount val="' << size.to_s << '"/>' + each_with_index do |item, index| + v = item.is_a?(Cell) ? item.value.to_s : item + str << '<c:pt idx="' << index.to_s << '"><c:v>' << v << '</c:v></c:pt>' + end + str << '</c:numCache>' + str << '</c:numRef>' + str << '</c:val>' end end - + end diff --git a/lib/axlsx/drawing/view_3D.rb b/lib/axlsx/drawing/view_3D.rb index d8a569b1..1090f4a7 100644 --- a/lib/axlsx/drawing/view_3D.rb +++ b/lib/axlsx/drawing/view_3D.rb @@ -5,34 +5,34 @@ module Axlsx # Validation for hPercent H_PERCENT_REGEX = /0*(([5-9])|([1-9][0-9])|([1-4][0-9][0-9])|500)%/ - + # validation for depthPercent DEPTH_PERCENT_REGEX = /0*(([2-9][0-9])|([1-9][0-9][0-9])|(1[0-9][0-9][0-9])|2000)%/ - # x rotation for the chart + # x rotation for the chart # must be between -90 and 90 # @return [Integer] attr_reader :rotX - + # height of chart as % of chart # must be between 5% and 500% # @return [String] attr_reader :hPercent - + # y rotation for the chart # must be between 0 and 360 # @return [Integer] attr_reader :rotY - + # depth or chart as % of chart width # must be between 20% and 2000% # @return [String] attr_reader :depthPercent - + # Chart axis are at right angles # @return [Boolean] attr_reader :rAngAx - + # field of view angle # @return [Integer] attr_reader :perspective @@ -45,10 +45,10 @@ module Axlsx # @option options [Boolean] rAngAx # @option options [Integer] perspective def initialize(options={}) - @rotX, @hPercent, @rotY, @depthPercent, @rAngAx, @perspective = nil, nil, nil, nil, nil, nil + @rotX, @hPercent, @rotY, @depthPercent, @rAngAx, @perspective = nil, nil, nil, nil, nil, nil options.each do |o| self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}=" - end + end end # @see rotX @@ -69,18 +69,20 @@ module Axlsx # @see perspective def perspective=(v) DataTypeValidator.validate "#{self.class}.perspective", [Integer, Fixnum], v, lambda {|arg| arg >= 0 && arg <= 240 }; @perspective = v; end - # Serializes the view3D properties - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml[:c].view3D { - xml[:c].rotX :val=>@rotX unless @rotX.nil? - xml[:c].hPercent :val=>@hPercent unless @hPercent.nil? - xml[:c].rotY :val=>@rotY unless @rotY.nil? - xml[:c].depthPercent :val=>@depthPercent unless @depthPercent.nil? - xml[:c].rAngAx :val=>@rAngAx unless @rAngAx.nil? - xml[:c].perspective :val=>@perspective unless @perspective.nil? - } + def to_xml_string(str = '') + str << '<c:view3D>' + str << '<c:rotX val="' << @rotX.to_s << '"/>' unless @rotX.nil? + str << '<c:hPercent val="' << @hPercent.to_s << '"/>' unless @hPercent.nil? + str << '<c:rotY val="' << @rotY.to_s << '"/>' unless @rotY.nil? + str << '<c:depthPercent val="' << @depthPercent.to_s << '"/>' unless @depthPercent.nil? + str << '<c:rAngAx val="' << @rAngAx.to_s << '"/>' unless @rAngAx.nil? + str << '<c:perspective val="' << @perspective.to_s << '"/>' unless @perspective.nil? + str << '</c:view3D>' end + end end diff --git a/lib/axlsx/package.rb b/lib/axlsx/package.rb index 35ab181a..3ab7b99a 100644 --- a/lib/axlsx/package.rb +++ b/lib/axlsx/package.rb @@ -139,7 +139,9 @@ module Axlsx # p.validate.each { |error| puts error.message } def validate errors = [] - parts.each { |part| errors.concat validate_single_doc(part[:schema], part[:doc]) unless part[:schema].nil? } + parts.each do |part| + errors.concat validate_single_doc(part[:schema], part[:doc]) unless part[:schema].nil? + end errors end @@ -170,25 +172,25 @@ module Axlsx # @private def parts @parts = [ - {:entry => RELS_PN, :doc => relationships.to_xml, :schema => RELS_XSD}, - {:entry => "xl/#{STYLES_PN}", :doc => workbook.styles.to_xml, :schema => SML_XSD}, - {:entry => CORE_PN, :doc => @core.to_xml, :schema => CORE_XSD}, - {:entry => APP_PN, :doc => @app.to_xml, :schema => APP_XSD}, - {:entry => WORKBOOK_RELS_PN, :doc => workbook.relationships.to_xml, :schema => RELS_XSD}, - {:entry => CONTENT_TYPES_PN, :doc => content_types.to_xml, :schema => CONTENT_TYPES_XSD}, - {:entry => WORKBOOK_PN, :doc => workbook.to_xml, :schema => SML_XSD} + {:entry => RELS_PN, :doc => relationships.to_xml_string, :schema => RELS_XSD}, + {:entry => "xl/#{STYLES_PN}", :doc => workbook.styles.to_xml_string, :schema => SML_XSD}, + {:entry => CORE_PN, :doc => @core.to_xml_string, :schema => CORE_XSD}, + {:entry => APP_PN, :doc => @app.to_xml_string, :schema => APP_XSD}, + {:entry => WORKBOOK_RELS_PN, :doc => workbook.relationships.to_xml_string, :schema => RELS_XSD}, + {:entry => CONTENT_TYPES_PN, :doc => content_types.to_xml_string, :schema => CONTENT_TYPES_XSD}, + {:entry => WORKBOOK_PN, :doc => workbook.to_xml_string, :schema => SML_XSD} ] workbook.drawings.each do |drawing| - @parts << {:entry => "xl/#{drawing.rels_pn}", :doc => drawing.relationships.to_xml, :schema => RELS_XSD} - @parts << {:entry => "xl/#{drawing.pn}", :doc => drawing.to_xml, :schema => DRAWING_XSD} + @parts << {:entry => "xl/#{drawing.rels_pn}", :doc => drawing.relationships.to_xml_string, :schema => RELS_XSD} + @parts << {:entry => "xl/#{drawing.pn}", :doc => drawing.to_xml_string, :schema => DRAWING_XSD} end workbook.tables.each do |table| - @parts << {:entry => "xl/#{table.pn}", :doc => table.to_xml, :schema => SML_XSD} + @parts << {:entry => "xl/#{table.pn}", :doc => table.to_xml_string, :schema => SML_XSD} end workbook.charts.each do |chart| - @parts << {:entry => "xl/#{chart.pn}", :doc => chart.to_xml, :schema => DRAWING_XSD} + @parts << {:entry => "xl/#{chart.pn}", :doc => chart.to_xml_string, :schema => DRAWING_XSD} end workbook.images.each do |image| @@ -200,7 +202,7 @@ module Axlsx end workbook.worksheets.each do |sheet| - @parts << {:entry => "xl/#{sheet.rels_pn}", :doc => sheet.relationships.to_xml, :schema => RELS_XSD} + @parts << {:entry => "xl/#{sheet.rels_pn}", :doc => sheet.relationships.to_xml_string, :schema => RELS_XSD} @parts << {:entry => "xl/#{sheet.pn}", :doc => sheet.to_xml_string, :schema => SML_XSD} end @parts @@ -215,7 +217,6 @@ module Axlsx def validate_single_doc(schema, doc) schema = Nokogiri::XML::Schema(File.open(schema)) doc = Nokogiri::XML(doc) - errors = [] schema.validate(doc).each do |error| errors << error diff --git a/lib/axlsx/rels/relationship.rb b/lib/axlsx/rels/relationship.rb index 3596d808..89a09ce1 100644 --- a/lib/axlsx/rels/relationship.rb +++ b/lib/axlsx/rels/relationship.rb @@ -47,14 +47,17 @@ module Axlsx # @see TargetMode def TargetMode=(v) RestrictionValidator.validate 'Relationship.TargetMode', [:External, :Internal], v; @TargetMode = v; end - # Serializes the relationship - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. - # @param [String] rId the reference id of the object. + # serialize relationship + # @param [String] str + # @param [Integer] rId the id for this relationship # @return [String] - def to_xml(xml, rId) + def to_xml_string(rId, str = '') h = self.instance_values - h[:Id] = rId - xml.Relationship(h) + h[:Id] = 'rId' << rId.to_s + str << '<Relationship ' + str << h.map { |key, value| '' << key.to_s << '="' << value.to_s << '"'}.join(' ') + str << '/>' end + end end diff --git a/lib/axlsx/rels/relationships.rb b/lib/axlsx/rels/relationships.rb index 8516bc69..e0d6ea13 100644 --- a/lib/axlsx/rels/relationships.rb +++ b/lib/axlsx/rels/relationships.rb @@ -11,6 +11,12 @@ require 'axlsx/rels/relationship.rb' super Relationship end + def to_xml_string(str = '') + str << '<?xml version="1.0" encoding="UTF-8"?>' + str << '<Relationships xmlns="' << RELS_R << '">' + each_with_index { |rel, index| rel.to_xml_string(index+1, str) } + str << '</Relationships>' + end # Serializes the relationships document. # @return [String] def to_xml() @@ -21,6 +27,6 @@ require 'axlsx/rels/relationship.rb' end builder.to_xml(:save_with => 0) end - + end end diff --git a/lib/axlsx/stylesheet/border.rb b/lib/axlsx/stylesheet/border.rb index f3d329fa..d23e5476 100644 --- a/lib/axlsx/stylesheet/border.rb +++ b/lib/axlsx/stylesheet/border.rb @@ -19,12 +19,12 @@ module Axlsx # @option options [Boolean] diagonalUp # @option options [Boolean] diagonalDown # @option options [Boolean] outline - # @example Making a border - # p = Axlsx::Package.new - # red_border = p.workbook.styles.add_style :border => {:style =>: thin, :color => "FFFF0000"} - # ws = p.workbook.add_worksheet - # ws.add_row [1,2,3], :style => red_border - # p.serialize('red_border.xlsx') + # @example - Making a border + # p = Axlsx::Package.new + # red_border = p.workbook.styles.add_style :border => { :style => :thin, :color => "FFFF0000" } + # ws = p.workbook.add_worksheet + # ws.add_row [1,2,3], :style => red_border + # p.serialize('red_border.xlsx') # # @note The recommended way to manage borders is with Style#add_style # @see Style#add_style @@ -42,16 +42,21 @@ module Axlsx # @see outline def outline=(v) Axlsx::validate_boolean v; @outline = v end - # Serializes the border element - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. - def to_xml(xml) - xml.border(self.instance_values.select{ |k,v| [:diagonalUp, :diagonalDown, :outline].include? k }) { - [:start, :end, :left, :right, :top, :bottom, :diagonal, :vertical, :horizontal].each do |k| - @prs.select { |pr| pr.name == k }.each do |part| - part.to_xml(xml) - end + # Serializes the object + # @param [String] str + # @return [String] + def to_xml_string(str = '') + str << '<border ' + h = self.instance_values.select{ |k,v| [:diagonalUp, :diagonalDown, :outline].include? k } + str << h.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ') + str << '>' + [:start, :end, :left, :right, :top, :bottom, :diagonal, :vertical, :horizontal].each do |k| + @prs.select { |pr| pr.name == k }.each do |part| + part.to_xml_string(str) end - } + end + str << '</border>' end + end end diff --git a/lib/axlsx/stylesheet/border_pr.rb b/lib/axlsx/stylesheet/border_pr.rb index 62fe3bab..eb1ecf4b 100644 --- a/lib/axlsx/stylesheet/border_pr.rb +++ b/lib/axlsx/stylesheet/border_pr.rb @@ -1,22 +1,22 @@ # encoding: UTF-8 module Axlsx - # A border part. + # A border part. class BorderPr - + # @return [Color] The color of this border part. attr_reader :color - # @return [Symbol] The syle of this border part. - # @note + # @return [Symbol] The syle of this border part. + # @note # The following are allowed - # :none + # :none # :thin # :medium # :dashed # :dotted # :thick # :double - # :hair + # :hair # :mediumDashed # :dashDot # :mediumDashDot @@ -26,7 +26,7 @@ module Axlsx attr_reader :style # @return [Symbol] The name of this border part - # @note + # @note # The following are allowed # :start # :end @@ -38,7 +38,7 @@ module Axlsx # :vertical # :horizontal attr_reader :name - + # Creates a new Border Part Object # @option options [Color] color # @option options [Symbol] name @@ -53,17 +53,18 @@ module Axlsx # @see name def name=(v) RestrictionValidator.validate "BorderPr.name", [:start, :end, :left, :right, :top, :bottom, :diagonal, :vertical, :horizontal], v; @name = v end # @see color - def color=(v) DataTypeValidator.validate(:color, Color, v); @color = v end + def color=(v) DataTypeValidator.validate(:color, Color, v); @color = v end # @see style def style=(v) RestrictionValidator.validate "BorderPr.style", [:none, :thin, :medium, :dashed, :dotted, :thick, :double, :hair, :mediumDashed, :dashDot, :mediumDashDot, :dashDotDot, :mediumDashDotDot, :slantDashDot], v; @style = v end - # Serializes the border part - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.send(@name, :style => @style) { - @color.to_xml(xml) if @color.is_a? Color - } + def to_xml_string(str = '') + str << '<' << @name.to_s << ' style="' << @style.to_s << '">' + @color.to_xml_string(str) if @color.is_a?(Color) + str << '</' << @name.to_s << '>' end + end end diff --git a/lib/axlsx/stylesheet/cell_alignment.rb b/lib/axlsx/stylesheet/cell_alignment.rb index 0a1ce60a..a38e3829 100644 --- a/lib/axlsx/stylesheet/cell_alignment.rb +++ b/lib/axlsx/stylesheet/cell_alignment.rb @@ -1,11 +1,11 @@ # encoding: UTF-8 module Axlsx # CellAlignment stores information about the cell alignment of a style Xf Object. - # @note Using Styles#add_style is the recommended way to manage cell alignment. + # @note Using Styles#add_style is the recommended way to manage cell alignment. # @see Styles#add_style class CellAlignment # The horizontal alignment of the cell. - # @note + # @note # The horizontal cell alignement style must be one of # :general # :left @@ -36,7 +36,7 @@ module Axlsx # Indicate if the text of the cell should wrap # @return [Boolean] attr_reader :wrapText - + # The amount of indent # @return [Integer] attr_reader :indent @@ -54,12 +54,12 @@ module Axlsx attr_reader :shrinkToFit # The reading order of the text - # 0 Context Dependent + # 0 Context Dependent # 1 Left-to-Right # 2 Right-to-Left # @return [Integer] attr_reader :readingOrder - + # Create a new cell_alignment object # @option options [Symbol] horizontal # @option options [Symbol] vertical @@ -74,33 +74,35 @@ module Axlsx options.each do |o| self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}=" end - end - + end + # @see horizontal - def horizontal=(v) Axlsx::validate_horizontal_alignment v; @horizontal = v end + def horizontal=(v) Axlsx::validate_horizontal_alignment v; @horizontal = v end # @see vertical - def vertical=(v) Axlsx::validate_vertical_alignment v; @vertical = v end + def vertical=(v) Axlsx::validate_vertical_alignment v; @vertical = v end # @see textRotation - def textRotation=(v) Axlsx::validate_unsigned_int v; @textRotation = v end + def textRotation=(v) Axlsx::validate_unsigned_int v; @textRotation = v end # @see wrapText - def wrapText=(v) Axlsx::validate_boolean v; @wrapText = v end + def wrapText=(v) Axlsx::validate_boolean v; @wrapText = v end # @see indent - def indent=(v) Axlsx::validate_unsigned_int v; @indent = v end + def indent=(v) Axlsx::validate_unsigned_int v; @indent = v end # @see relativeIndent - def relativeIndent=(v) Axlsx::validate_int v; @relativeIndent = v end + def relativeIndent=(v) Axlsx::validate_int v; @relativeIndent = v end # @see justifyLastLine - def justifyLastLine=(v) Axlsx::validate_boolean v; @justifyLastLine = v end + def justifyLastLine=(v) Axlsx::validate_boolean v; @justifyLastLine = v end # @see shrinkToFit - def shrinkToFit=(v) Axlsx::validate_boolean v; @shrinkToFit = v end + def shrinkToFit=(v) Axlsx::validate_boolean v; @shrinkToFit = v end # @see readingOrder - def readingOrder=(v) Axlsx::validate_unsigned_int v; @readingOrder = v end + def readingOrder=(v) Axlsx::validate_unsigned_int v; @readingOrder = v end - # Serializes the cell alignment - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.alignment(self.instance_values) + def to_xml_string(str = '') + str << '<alignment ' + str << instance_values.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ') + str << '/>' end - + end end diff --git a/lib/axlsx/stylesheet/cell_protection.rb b/lib/axlsx/stylesheet/cell_protection.rb index 89d85289..4309b0e8 100644 --- a/lib/axlsx/stylesheet/cell_protection.rb +++ b/lib/axlsx/stylesheet/cell_protection.rb @@ -4,7 +4,7 @@ module Axlsx # @note Using Styles#add_style is the recommended way to manage cell protection. # @see Styles#add_style class CellProtection - + # specifies locking for cells that have the style containing this protection # @return [Boolean] attr_reader :hidden @@ -23,15 +23,18 @@ module Axlsx end # @see hidden - def hidden=(v) Axlsx::validate_boolean v; @hidden = v end + def hidden=(v) Axlsx::validate_boolean v; @hidden = v end # @see locked - def locked=(v) Axlsx::validate_boolean v; @locked = v end + def locked=(v) Axlsx::validate_boolean v; @locked = v end - # Serializes the cell protection - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.protection(self.instance_values) + def to_xml_string(str = '') + str << '<protection ' + str << instance_values.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ') + str << '/>' end + end end diff --git a/lib/axlsx/stylesheet/cell_style.rb b/lib/axlsx/stylesheet/cell_style.rb index 0a40ab13..ed3aeda9 100644 --- a/lib/axlsx/stylesheet/cell_style.rb +++ b/lib/axlsx/stylesheet/cell_style.rb @@ -7,7 +7,7 @@ module Axlsx # The name of this cell style # @return [String] attr_reader :name - + # The formatting record id this named style utilizes # @return [Integer] # @see Axlsx::Xf @@ -55,12 +55,15 @@ module Axlsx # @see customBuiltin def customBuiltin=(v) Axlsx::validate_boolean v; @customBuiltin = v end - # Serializes the cell style - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.cellStyle(self.instance_values) + def to_xml_string(str = '') + str << '<cellStyle ' + str << instance_values.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ') + str << '/>' end + end end diff --git a/lib/axlsx/stylesheet/color.rb b/lib/axlsx/stylesheet/color.rb index 2a08fd3c..78171607 100644 --- a/lib/axlsx/stylesheet/color.rb +++ b/lib/axlsx/stylesheet/color.rb @@ -61,17 +61,16 @@ module Axlsx # Indexed colors are for backward compatability which I am choosing not to support # def indexed=(v) Axlsx::validate_unsigned_integer v; @indexed = v end - def to_xml_string - str = "<color " + # Serializes the object + # @param [String] str + # @return [String] + def to_xml_string(str = '') + str << "<color " self.instance_values.each do |key, value| - str << key << '="' << value.to_s << '" ' + str << key.to_s << '="' << value.to_s << '" ' end str << "/>" end - # Serializes the color - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. - # @return [String] - def to_xml(xml) xml.color(self.instance_values) end end end diff --git a/lib/axlsx/stylesheet/fill.rb b/lib/axlsx/stylesheet/fill.rb index 4dccaa8a..7bb5a437 100644 --- a/lib/axlsx/stylesheet/fill.rb +++ b/lib/axlsx/stylesheet/fill.rb @@ -12,17 +12,19 @@ module Axlsx attr_reader :fill_type # Creates a new Fill object - # @param [PatternFill, GradientFill] fill_type + # @param [PatternFill, GradientFill] fill_type # @raise [ArgumentError] if the fill_type parameter is not a PatternFill or a GradientFill instance def initialize(fill_type) self.fill_type = fill_type end - # Serializes the fill - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.fill { @fill_type.to_xml(xml) } + def to_xml_string(str = '') + str << '<fill>' + @fill_type.to_xml_string(str) + str << '</fill>' end # @see fill_type diff --git a/lib/axlsx/stylesheet/font.rb b/lib/axlsx/stylesheet/font.rb index 1d9bc5d4..657c4c30 100644 --- a/lib/axlsx/stylesheet/font.rb +++ b/lib/axlsx/stylesheet/font.rb @@ -7,7 +7,7 @@ module Axlsx # The name of the font # @return [String] attr_reader :name - + # The charset of the font # @return [Integer] # @note @@ -32,9 +32,9 @@ module Axlsx # 238 EASTEUROPE_CHARSET # 255 OEM_CHARSET attr_reader :charset - + # The font's family - # @note + # @note # The following are defined OOXML specification # 0 Not applicable. # 1 Roman @@ -107,13 +107,13 @@ module Axlsx end end # @see name - def name=(v) Axlsx::validate_string v; @name = v end + def name=(v) Axlsx::validate_string v; @name = v end # @see charset def charset=(v) Axlsx::validate_unsigned_int v; @charset = v end # @see family def family=(v) Axlsx::validate_unsigned_int v; @family = v end # @see b - def b=(v) Axlsx::validate_boolean v; @b = v end + def b=(v) Axlsx::validate_boolean v; @b = v end # @see i def i=(v) Axlsx::validate_boolean v; @i = v end # @see u @@ -123,7 +123,7 @@ module Axlsx # @see outline def outline=(v) Axlsx::validate_boolean v; @outline = v end # @see shadow - def shadow=(v) Axlsx::validate_boolean v; @shadow = v end + def shadow=(v) Axlsx::validate_boolean v; @shadow = v end # @see condense def condense=(v) Axlsx::validate_boolean v; @condense = v end # @see extend @@ -133,15 +133,15 @@ module Axlsx # @see sz def sz=(v) Axlsx::validate_unsigned_int v; @sz=v end - # Serializes the fill - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.font { - self.instance_values.each do |k, v| - v.is_a?(Color) ? v.to_xml(xml) : xml.send(k, {:val => v}) - end - } + def to_xml_string(str = '') + str << '<font>' + instance_values.each do |k, v| + v.is_a?(Color) ? v.to_xml_string(str) : (str << '<' << k.to_s << ' val="' << v.to_s << '"/>') + end + str << '</font>' end end end diff --git a/lib/axlsx/stylesheet/gradient_fill.rb b/lib/axlsx/stylesheet/gradient_fill.rb index 6090b570..514e0cfd 100644 --- a/lib/axlsx/stylesheet/gradient_fill.rb +++ b/lib/axlsx/stylesheet/gradient_fill.rb @@ -1,11 +1,11 @@ # encoding: UTF-8 module Axlsx # A GradientFill defines the color and positioning for gradiant cell fill. - # @see Open Office XML Part 1 §18.8.24 + # @see Open Office XML Part 1 §18.8.24 class GradientFill # The type of gradient. - # @note + # @note # valid options are # :linear # :path @@ -26,7 +26,7 @@ module Axlsx # Percentage format top # @return [Float] - attr_reader :top + attr_reader :top # Percentage format bottom # @return [Float] @@ -35,7 +35,7 @@ module Axlsx # Collection of stop objects # @return [SimpleTypedList] attr_reader :stop - + # Creates a new GradientFill object # @option options [Symbol] type # @option options [Float] degree @@ -52,25 +52,28 @@ module Axlsx end # @see type - def type=(v) Axlsx::validate_gradient_type v; @type = v end + def type=(v) Axlsx::validate_gradient_type v; @type = v end # @see degree - def degree=(v) Axlsx::validate_float v; @degree = v end + def degree=(v) Axlsx::validate_float v; @degree = v end # @see left - def left=(v) DataTypeValidator.validate "GradientFill.left", Float, v, lambda { |arg| arg >= 0.0 && arg <= 1.0}; @left = v end + def left=(v) DataTypeValidator.validate "GradientFill.left", Float, v, lambda { |arg| arg >= 0.0 && arg <= 1.0}; @left = v end # @see right - def right=(v) DataTypeValidator.validate "GradientFill.right", Float, v, lambda { |arg| arg >= 0.0 && arg <= 1.0}; @right = v end + def right=(v) DataTypeValidator.validate "GradientFill.right", Float, v, lambda { |arg| arg >= 0.0 && arg <= 1.0}; @right = v end # @see top - def top=(v) DataTypeValidator.validate "GradientFill.top", Float, v, lambda { |arg| arg >= 0.0 && arg <= 1.0}; @top = v end + def top=(v) DataTypeValidator.validate "GradientFill.top", Float, v, lambda { |arg| arg >= 0.0 && arg <= 1.0}; @top = v end # @see bottom - def bottom=(v) DataTypeValidator.validate "GradientFill.bottom", Float, v, lambda { |arg| arg >= 0.0 && arg <= 1.0}; @bottom= v end + def bottom=(v) DataTypeValidator.validate "GradientFill.bottom", Float, v, lambda { |arg| arg >= 0.0 && arg <= 1.0}; @bottom= v end - # Serializes the gradientFill - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.gradientFill(self.instance_values.reject { |k,v| k.to_sym == :stop }) { - @stop.each { |s| s.to_xml(xml) } - } + def to_xml_string(str = '') + str << '<gradientFill' + h = self.instance_values.reject { |k,v| k.to_sym == :stop } + str << h.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ') + str << '>' + @stop.each { |s| s.to_xml_string(str) } + str << '</gradientFill>' end end end diff --git a/lib/axlsx/stylesheet/gradient_stop.rb b/lib/axlsx/stylesheet/gradient_stop.rb index a05e6d33..94ca4795 100644 --- a/lib/axlsx/stylesheet/gradient_stop.rb +++ b/lib/axlsx/stylesheet/gradient_stop.rb @@ -1,7 +1,7 @@ # encoding: UTF-8 module Axlsx # The GradientStop object represents a color point in a gradient. - # @see Open Office XML Part 1 §18.8.24 + # @see Open Office XML Part 1 §18.8.24 class GradientStop # The color for this gradient stop # @return [Color] @@ -23,11 +23,15 @@ module Axlsx # @see color def color=(v) DataTypeValidator.validate "GradientStop.color", Color, v; @color=v end # @see position - def position=(v) DataTypeValidator.validate "GradientStop.position", Float, v, lambda { |arg| arg >= 0 && arg <= 1}; @position = v end + def position=(v) DataTypeValidator.validate "GradientStop.position", Float, v, lambda { |arg| arg >= 0 && arg <= 1}; @position = v end - # Serializes the gradientStop - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) xml.stop(:position => self.position) {self.color.to_xml(xml)} end + def to_xml_string(str = '') + str << '<stop position="' << position.to_s << '">' + self.color.to_xml_string(str) + str << '</stop>' + end end end diff --git a/lib/axlsx/stylesheet/num_fmt.rb b/lib/axlsx/stylesheet/num_fmt.rb index 261d5bb3..d5122f7e 100644 --- a/lib/axlsx/stylesheet/num_fmt.rb +++ b/lib/axlsx/stylesheet/num_fmt.rb @@ -1,11 +1,11 @@ # encoding: UTF-8 module Axlsx - # A NumFmt object defines an identifier and formatting code for data in cells. + # A NumFmt object defines an identifier and formatting code for data in cells. # @note The recommended way to manage styles is Styles#add_style class NumFmt # @return [Integer] An unsinged integer referencing a standard or custom number format. # @note - # These are the known formats I can dig up. The constant NUM_FMT_PERCENT is 9, and uses the default % formatting. Axlsx also defines a few formats for date and time that are commonly used in asia as NUM_FMT_YYYYMMDD and NUM_FRM_YYYYMMDDHHMMSS. + # These are the known formats I can dig up. The constant NUM_FMT_PERCENT is 9, and uses the default % formatting. Axlsx also defines a few formats for date and time that are commonly used in asia as NUM_FMT_YYYYMMDD and NUM_FRM_YYYYMMDDHHMMSS. # 1 0 # 2 0.00 # 3 #,##0 @@ -40,7 +40,7 @@ module Axlsx # @see Axlsx attr_reader :numFmtId - # @return [String] The formatting to use for this number format. + # @return [String] The formatting to use for this number format. # @see http://support.microsoft.com/kb/264372 attr_reader :formatCode def initialize(options={}) @@ -56,9 +56,15 @@ module Axlsx # @see formatCode def formatCode=(v) Axlsx::validate_string v; @formatCode = v end - # Creates a numFmt element applying the instance values of this object as attributes. - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. - def to_xml(xml) xml.numFmt(self.instance_values) end + + # Serializes the object + # @param [String] str + # @return [String] + def to_xml_string(str = '') + str << '<numFmt ' + str << instance_values.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ') + str << '/>' + end end end diff --git a/lib/axlsx/stylesheet/pattern_fill.rb b/lib/axlsx/stylesheet/pattern_fill.rb index 79910ede..0c0a51a6 100644 --- a/lib/axlsx/stylesheet/pattern_fill.rb +++ b/lib/axlsx/stylesheet/pattern_fill.rb @@ -7,15 +7,15 @@ module Axlsx # The color to use for the the background in solid fills. # @return [Color] - attr_reader :fgColor + attr_reader :fgColor # The color to use for the background of the fill when the type is not solid. # @return [Color] attr_reader :bgColor # The pattern type to use - # @note - # patternType must be one of + # @note + # patternType must be one of # :none # :solid # :mediumGray @@ -53,15 +53,30 @@ module Axlsx # @see bgColor def bgColor=(v) DataTypeValidator.validate "PatternFill.bgColor", Color, v; @bgColor=v end # @see patternType - def patternType=(v) Axlsx::validate_pattern_type v; @patternType = v end + def patternType=(v) Axlsx::validate_pattern_type v; @patternType = v end - # Serializes the pattern fill - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.patternFill(:patternType => self.patternType) { - self.instance_values.reject { |k,v| k.to_sym == :patternType }.each { |k,v| xml.send(k, v.instance_values) } - } + def to_xml_string(str = '') + str << '<patternFill patternType="' << patternType.to_s << '">' + if fgColor.is_a?(Color) + str << "<fgColor " + fgColor.instance_values.each do |key, value| + str << key.to_s << '="' << value.to_s << '" ' + end + str << "/>" + end + + if bgColor.is_a?(Color) + str << "<bgColor " + bgColor.instance_values.each do |key, value| + str << key.to_s << '="' << value.to_s << '" ' + end + str << "/>" + end + str << '</patternFill>' end + end end diff --git a/lib/axlsx/stylesheet/styles.rb b/lib/axlsx/stylesheet/styles.rb index a05067cd..1fb2e9b3 100644 --- a/lib/axlsx/stylesheet/styles.rb +++ b/lib/axlsx/stylesheet/styles.rb @@ -133,7 +133,7 @@ module Axlsx # @option options [String] font_name The name of the font to use # @option options [Integer] num_fmt The number format to apply # @option options [String] format_code The formatting to apply. If this is specified, num_fmt is ignored. - # @option options [Integer] border The border style to use. This can be the index of an existing border or a hash like {:style => :thin, :color => "FFFF0000"} to create a new border style + # @option options [Integer] border The border style to use. # @option options [String] bg_color The background color to apply to the cell # @option options [Boolean] hidden Indicates if the cell should be hidden # @option options [Boolean] locked Indicates if the cell should be locked @@ -148,7 +148,7 @@ module Axlsx # ws = p.workbook.add_worksheet # # # black text on a white background at 14pt with thin borders! - # title = ws.style.add_style(:bg_color => "FFFF0000", :fg_color=>"#FF000000", :sz=>14, :border=>Axlsx::STYLE_THIN_BORDER + # title = ws.style.add_style(:bg_color => "FFFF0000", :fg_color=>"#FF000000", :sz=>14, :border=> {:style => :thin, :color => "FFFF0000"} # # ws.add_row :values => ["Least Popular Pets"] # ws.add_row :values => ["", "Dry Skinned Reptiles", "Bald Cats", "Violent Parrots"], :style=>title @@ -250,17 +250,15 @@ module Axlsx cellXfs << xf end - # Serializes the styles document + # Serializes the object + # @param [String] str # @return [String] - def to_xml() - builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml| - xml.styleSheet(:xmlns => XML_NS) { - [:numFmts, :fonts, :fills, :borders, :cellStyleXfs, :cellXfs, :cellStyles, :dxfs, :tableStyles].each do |key| - self.instance_values[key.to_s].to_xml(xml) unless self.instance_values[key.to_s].nil? - end - } + def to_xml_string(str = '') + str << '<styleSheet xmlns="' << XML_NS << '">' + [:numFmts, :fonts, :fills, :borders, :cellStyleXfs, :cellXfs, :cellStyles, :dxfs, :tableStyles].each do |key| + self.instance_values[key.to_s].to_xml_string(str) unless self.instance_values[key.to_s].nil? end - builder.to_xml(:save_with => 0) + str << '</styleSheet>' end private diff --git a/lib/axlsx/stylesheet/table_style.rb b/lib/axlsx/stylesheet/table_style.rb index 4397cffb..324f33d6 100644 --- a/lib/axlsx/stylesheet/table_style.rb +++ b/lib/axlsx/stylesheet/table_style.rb @@ -36,13 +36,18 @@ module Axlsx # @see table def table=(v) Axlsx::validate_boolean v; @table=v end - # Serializes the table style - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) + def to_xml_string(str = '') attr = self.instance_values.select { |k, v| [:name, :pivot, :table].include? k } attr[:count] = self.size - xml.tableStyle(attr) { self.each { |table_style_el| table_style_el.to_xml(xml) } } + str << '<tableStyle ' + str << attr.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ') + str << '>' + each { |table_style_el| table_style_el.to_xml_string(str) } + str << '</tableStyle>' end + end end diff --git a/lib/axlsx/stylesheet/table_style_element.rb b/lib/axlsx/stylesheet/table_style_element.rb index a8901f0b..1a4c8803 100644 --- a/lib/axlsx/stylesheet/table_style_element.rb +++ b/lib/axlsx/stylesheet/table_style_element.rb @@ -1,7 +1,7 @@ # encoding: UTF-8 module Axlsx - # an element of style that belongs to a table style. - # @note tables and table styles are not supported in this version. This class exists in preparation for that support. + # an element of style that belongs to a table style. + # @note tables and table styles are not supported in this version. This class exists in preparation for that support. class TableStyleElement # The type of style element. The following type are allowed # :wholeTable @@ -39,7 +39,7 @@ module Axlsx # @return [Integer] attr_reader :size - # The dxfId this style element points to + # The dxfId this style element points to # @return [Integer] attr_reader :dxfId @@ -62,11 +62,14 @@ module Axlsx # @see dxfId def dxfId=(v) Axlsx::validate_unsigned_int v; @dxfId = v end - # Serializes the table style element - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.tableStyleElement self.instance_values + def to_xml_string(str = '') + str << '<tableStyleElement ' + str << instance_values.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ') + str << '/>' end + end end diff --git a/lib/axlsx/stylesheet/table_styles.rb b/lib/axlsx/stylesheet/table_styles.rb index f0e9c904..a43e7ce5 100644 --- a/lib/axlsx/stylesheet/table_styles.rb +++ b/lib/axlsx/stylesheet/table_styles.rb @@ -11,13 +11,13 @@ module Axlsx # The default pivot table style. The default value is 'PivotStyleLight6' # @return [String] attr_reader :defaultPivotStyle - + # Creates a new TableStyles object that is a container for TableStyle objects # @option options [String] defaultTableStyle # @option options [String] defaultPivotStyle def initialize(options={}) @defaultTableStyle = options[:defaultTableStyle] || "TableStyleMedium9" - @defaultPivotStyle = options[:defaultPivotStyle] || "PivotStyleLight16" + @defaultPivotStyle = options[:defaultPivotStyle] || "PivotStyleLight16" super TableStyle end # @see defaultTableStyle @@ -25,16 +25,19 @@ module Axlsx # @see defaultPivotStyle def defaultPivotStyle=(v) Axlsx::validate_string(v); @defaultPivotStyle = v; end - # Serializes the table styles element - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) + def to_xml_string(str = '') attr = self.instance_values.reject {|k, v| ![:defaultTableStyle, :defaultPivotStyle].include?(k.to_sym) } attr[:count] = self.size - xml.tableStyles(attr) { - self.each { |table_style| table_style.to_xml(xml) } - } + str << '<tableStyles ' + str << attr.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ') + str << '>' + each { |table_style| table_style.to_xml_string(str) } + str << '</tableStyles>' end + end end diff --git a/lib/axlsx/stylesheet/xf.rb b/lib/axlsx/stylesheet/xf.rb index 7b55336b..59329a63 100644 --- a/lib/axlsx/stylesheet/xf.rb +++ b/lib/axlsx/stylesheet/xf.rb @@ -22,7 +22,7 @@ module Axlsx # index (0 based) of the font to be used in this style # @return [Integer] attr_reader :fontId - + # index (0 based) of the fill to be used in this style # @return [Integer] attr_reader :fillId @@ -50,7 +50,7 @@ module Axlsx # indicates if the fontId should be applied # @return [Boolean] attr_reader :applyFont - + # indicates if the fillId should be applied # @return [Boolean] attr_reader :applyFill @@ -75,7 +75,7 @@ module Axlsx # @option options [Integer] xfId # @option options [Boolean] quotePrefix # @option options [Boolean] pivotButton - # @option options [Boolean] applyNumberFormat + # @option options [Boolean] applyNumberFormat # @option options [Boolean] applyFont # @option options [Boolean] applyFill # @option options [Boolean] applyBorder @@ -87,8 +87,8 @@ module Axlsx options.each do |o| self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}=" end - end - + end + # @see Xf#alignment def alignment=(v) DataTypeValidator.validate "Xf.alignment", CellAlignment, v; @alignment = v end @@ -96,44 +96,48 @@ module Axlsx def protection=(v) DataTypeValidator.validate "Xf.protection", CellProtection, v; @protection = v end # @see numFmtId - def numFmtId=(v) Axlsx::validate_unsigned_int v; @numFmtId = v end + def numFmtId=(v) Axlsx::validate_unsigned_int v; @numFmtId = v end # @see fontId - def fontId=(v) Axlsx::validate_unsigned_int v; @fontId = v end + def fontId=(v) Axlsx::validate_unsigned_int v; @fontId = v end # @see fillId - def fillId=(v) Axlsx::validate_unsigned_int v; @fillId = v end + def fillId=(v) Axlsx::validate_unsigned_int v; @fillId = v end # @see borderId - def borderId=(v) Axlsx::validate_unsigned_int v; @borderId = v end + def borderId=(v) Axlsx::validate_unsigned_int v; @borderId = v end # @see xfId - def xfId=(v) Axlsx::validate_unsigned_int v; @xfId = v end + def xfId=(v) Axlsx::validate_unsigned_int v; @xfId = v end # @see quotePrefix - def quotePrefix=(v) Axlsx::validate_boolean v; @quotePrefix = v end + def quotePrefix=(v) Axlsx::validate_boolean v; @quotePrefix = v end # @see pivotButton - def pivotButton=(v) Axlsx::validate_boolean v; @pivotButton = v end + def pivotButton=(v) Axlsx::validate_boolean v; @pivotButton = v end # @see applyNumberFormat - def applyNumberFormat=(v) Axlsx::validate_boolean v; @applyNumberFormat = v end + def applyNumberFormat=(v) Axlsx::validate_boolean v; @applyNumberFormat = v end # @see applyFont - def applyFont=(v) Axlsx::validate_boolean v; @applyFont = v end + def applyFont=(v) Axlsx::validate_boolean v; @applyFont = v end # @see applyFill - def applyFill=(v) Axlsx::validate_boolean v; @applyFill = v end + def applyFill=(v) Axlsx::validate_boolean v; @applyFill = v end # @see applyBorder - def applyBorder=(v) Axlsx::validate_boolean v; @applyBorder = v end + def applyBorder=(v) Axlsx::validate_boolean v; @applyBorder = v end # @see applyAlignment - def applyAlignment=(v) Axlsx::validate_boolean v; @applyAlignment = v end + def applyAlignment=(v) Axlsx::validate_boolean v; @applyAlignment = v end # @see applyProtection - def applyProtection=(v) Axlsx::validate_boolean v; @applyProtection = v end + def applyProtection=(v) Axlsx::validate_boolean v; @applyProtection = v end - # Serializes the xf elemen - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # Serializes the object + # @param [String] str # @return [String] - def to_xml(xml) - xml.xf(self.instance_values.reject { |k, v| [:alignment, :protection, :extList, :name].include? k.to_sym}) { - alignment.to_xml(xml) if self.alignment - protection.to_xml(xml) if self.protection - } + def to_xml_string(str = '') + str << '<xf ' + h = instance_values.reject { |k, v| [:alignment, :protection, :extList, :name].include? k.to_sym} + str << h.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ') + str << '>' + alignment.to_xml_string(str) if self.alignment + protection.to_xml_string(str) if self.protection + str << '</xf>' end + end end diff --git a/lib/axlsx/util/constants.rb b/lib/axlsx/util/constants.rb index 588dada5..c37b596a 100644 --- a/lib/axlsx/util/constants.rb +++ b/lib/axlsx/util/constants.rb @@ -171,7 +171,7 @@ module Axlsx # drawing rels part DRAWING_RELS_PN = "drawings/_rels/drawing%d.xml.rels" - + # drawing part TABLE_PN = "tables/table%d.xml" @@ -232,5 +232,4 @@ module Axlsx # error message for duplicate sheet names ERR_DUPLICATE_SHEET_NAME = "There is already a worksheet in this workbook named '%s'. Please use a unique name" - FIXED_COL_WIDTH = 8.43 end diff --git a/lib/axlsx/util/simple_typed_list.rb b/lib/axlsx/util/simple_typed_list.rb index ce34a9bb..8fc4795a 100644 --- a/lib/axlsx/util/simple_typed_list.rb +++ b/lib/axlsx/util/simple_typed_list.rb @@ -1,6 +1,6 @@ # encoding: UTF-8 module Axlsx - # A SimpleTypedList is a type restrictive collection that allows some of the methods from Array and supports basic xml serialization. + # A SimpleTypedList is a type restrictive collection that allows some of the methods from Array and supports basic xml serialization. # @private class SimpleTypedList # The class constants of allowed types @@ -12,14 +12,14 @@ module Axlsx attr_reader :locked_at # The tag name to use when serializing this object - # by default the parent node for all items in the list is the classname of the first allowed type with the first letter in lowercase. + # by default the parent node for all items in the list is the classname of the first allowed type with the first letter in lowercase. # @return [String] attr_reader :serialize_as # Creats a new typed list # @param [Array, Class] type An array of Class objects or a single Class object # @param [String] serialize The tag name to use in serialization - # @raise [ArgumentError] if all members of type are not Class objects + # @raise [ArgumentError] if all members of type are not Class objects def initialize type, serialize_as=nil if type.is_a? Array type.each { |item| raise ArgumentError, "All members of type must be Class objects" unless item.is_a? Class } @@ -39,7 +39,7 @@ module Axlsx @locked_at = @list.size self end - + def to_ary @list end @@ -58,7 +58,7 @@ module Axlsx def <<(v) DataTypeValidator.validate "SimpleTypedList.<<", @allowed_types, v @list << v - @list.size - 1 + @list.size - 1 end # alternate of << method @@ -104,14 +104,14 @@ module Axlsx return false unless @locked_at.is_a? Fixnum index < @locked_at end - + # override the equality method so that this object can be compared to a simple array. # if this object's list is equal to the specifiec array, we return true. def ==(v) v == @list end # method_mission override to pass allowed methods to the list. - # @note + # @note # the following methods are not allowed # :replace # :insert @@ -140,15 +140,23 @@ module Axlsx DELEGATES = Array.instance_methods - self.instance_methods - DESTRUCTIVE DELEGATES.each do |method| - class_eval %{ + class_eval %{ def #{method}(*args, &block) @list.send(:#{method}, *args, &block) end } end + def to_xml_string(str = '') + classname = @allowed_types[0].name.split('::').last + el_name = serialize_as || (classname[0,1].downcase + classname[1..-1]) + str << '<' << el_name << ' count="' << @list.size.to_s << '">' + @list.each { |item| item.to_xml_string(str) } + str << '</' << el_name << '>' + end + # Serializes the list - # If the serialize_as property is set, it is used as the parent node name. + # If the serialize_as property is set, it is used as the parent node name. # If the serialize_as property is nil, the first item in the list of allowed_types will be used, having the first letter of the class changed to lower case. # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. # @return [String] @@ -159,6 +167,7 @@ module Axlsx @list.each { |item| item.to_xml(xml) } } end + end diff --git a/lib/axlsx/util/validators.rb b/lib/axlsx/util/validators.rb index ce810e54..54a0aeb4 100644 --- a/lib/axlsx/util/validators.rb +++ b/lib/axlsx/util/validators.rb @@ -5,11 +5,11 @@ module Axlsx # Perform validation # @param [String] name The name of what is being validatied. This is included in the error message # @param [Array] choices The list of choices to validate against - # @param [Any] v The value to be validated + # @param [Any] v The value to be validated # @raise [ArgumentError] Raised if the value provided is not in the list of choices. # @return [Boolean] true if validation succeeds. def self.validate(name, choices, v) - raise ArgumentError, (ERR_RESTRICTION % [v.to_s, name, choices.inspect]) unless choices.include?(v) + raise ArgumentError, (ERR_RESTRICTION % [v.to_s, name, choices.inspect]) unless choices.include?(v) true end end @@ -55,7 +55,7 @@ module Axlsx # Requires that the value is a Fixnum Integer or Float and is greater or equal to 0 # @param [Any] v The value validated - # @raise [ArgumentError] raised if the value is not a Fixnum or Integer value greater or equal to 0 + # @raise [ArgumentError] raised if the value is not a Fixnun, Integer, Float value greater or equal to 0 # @return [Boolean] true if the data is valid def self.validate_unsigned_numeric(v) DataTypeValidator.validate("Invalid column width", [Fixnum, Integer, Float], v, lambda { |arg| arg.respond_to?(:>=) && arg >= 0 }) @@ -68,7 +68,7 @@ module Axlsx end # Requires that the value is a form that can be evaluated as a boolean in an xml document. - # The value must be an instance of Fixnum, String, Integer, Symbol, TrueClass or FalseClass and + # The value must be an instance of Fixnum, String, Integer, Symbol, TrueClass or FalseClass and # it must be one of 0, 1, "true", "false", :true, :false, true, false, "0", or "1" # @param [Any] v The value validated def self.validate_boolean(v) @@ -79,13 +79,13 @@ module Axlsx # @param [Any] v The value validated def self.validate_string(v) DataTypeValidator.validate :string, String, v - end + end # Requires that the value is a Float # @param [Any] v The value validated def self.validate_float(v) DataTypeValidator.validate :float, Float, v - end + end # Requires that the value is valid pattern type. # valid pattern types must be one of :none, :solid, :mediumGray, :darkGray, :lightGray, :darkHorizontal, :darkVertical, :darkDown, @@ -103,6 +103,13 @@ module Axlsx RestrictionValidator.validate :gradient_type, [:linear, :path], v end + # Requires that the value is a valid scatterStyle + # must be one of :none | :line | :lineMarker | :marker | :smooth | :smoothMarker + # must be one of "none" | "line" | "lineMarker" | "marker" | "smooth" | "smoothMarker" + # @param [Symbol|String] the value to validate + def self.validate_scatter_style(v) + Axlsx::RestrictionValidator.validate "ScatterChart.scatterStyle", [:none, :line, :lineMarker, :marker, :smooth, :smoothMarker], v.to_sym + end # Requires that the value is a valid horizontal_alignment # :general, :left, :center, :right, :fill, :justify, :centerContinuous, :distributed are allowed # @param [Any] v The value validated diff --git a/lib/axlsx/version.rb b/lib/axlsx/version.rb index fba7c709..4edbc831 100644 --- a/lib/axlsx/version.rb +++ b/lib/axlsx/version.rb @@ -5,6 +5,6 @@ module Axlsx # When using bunle exec rake and referencing the gem on github or locally # it will use the gemspec, which preloads this constant for the gem's version. # We check to make sure that it has not already been loaded - VERSION="1.0.18" unless Axlsx.const_defined? :VERSION + VERSION="1.1.0" unless defined? Axlsx::VERSION end diff --git a/lib/axlsx/workbook/shared_strings_table.rb b/lib/axlsx/workbook/shared_strings_table.rb index 0bdd7936..45402f5b 100644 --- a/lib/axlsx/workbook/shared_strings_table.rb +++ b/lib/axlsx/workbook/shared_strings_table.rb @@ -29,29 +29,18 @@ module Axlsx # Creates a new Shared Strings Table agains an array of cells # @param [Array] cells This is an array of all of the cells in the workbook def initialize(cells) - cells = cells.flatten.reject { |c| c.type != :string || c.value.start_with?('=') } + cells = cells.flatten.reject { |c| c.type != :string || c.value.nil? || c.value.start_with?('=') } @count = cells.size @unique_cells = [] @shared_xml_string = "" resolve(cells) end - def to_xml_string - '<sst xmlns="' << XML_NS << '" count="' << @count.to_s << '" uniqueCount="' << unique_count.to_s << '">' << @shared_xml_string << '</sst>' - end - - # Generate the xml document for the Shared Strings Table + # Serializes the object + # @param [String] str # @return [String] - def to_xml - - builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml| - xml.sst(:xmlns => Axlsx::XML_NS, :count => count, :uniqueCount => unique_count) { - @unique_cells.each do |cell| - xml.si { cell.run_xml(xml) } - end - } - end - builder.to_xml(:save_with => 0) + def to_xml_string + '<?xml version="1.0" encoding="UTF-8"?><sst xmlns="' << XML_NS << '" count="' << @count.to_s << '" uniqueCount="' << unique_count.to_s << '">' << @shared_xml_string << '</sst>' end private diff --git a/lib/axlsx/workbook/workbook.rb b/lib/axlsx/workbook/workbook.rb index a8e0a1af..ce4e161b 100644 --- a/lib/axlsx/workbook/workbook.rb +++ b/lib/axlsx/workbook/workbook.rb @@ -5,6 +5,7 @@ require 'axlsx/workbook/worksheet/date_time_converter.rb' require 'axlsx/workbook/worksheet/cell.rb' require 'axlsx/workbook/worksheet/page_margins.rb' require 'axlsx/workbook/worksheet/row.rb' +require 'axlsx/workbook/worksheet/col.rb' require 'axlsx/workbook/worksheet/worksheet.rb' require 'axlsx/workbook/shared_strings_table.rb' require 'axlsx/workbook/worksheet/table.rb' @@ -188,27 +189,29 @@ require 'axlsx/workbook/worksheet/table.rb' worksheet[cell_def.gsub(/.+!/,"")] end - # Serializes the workbook document + # Serialize the workbook + # @param [String] str # @return [String] - def to_xml() + def to_xml_string(str='') add_worksheet unless worksheets.size > 0 - builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml| - xml.workbook(:xmlns => XML_NS, :'xmlns:r' => XML_NS_R) { - xml.workbookPr(:date1904=>@@date1904) - #<x:workbookProtection workbookPassword="xsd:hexBinary data" lockStructure="1" lockWindows="1" /> - # Required to support rubyXL parsing as it requires sheetView, which requires this. - # and removed because it seems to cause some odd [Grouped] behaviour in excel. - # xml.bookViews { - # xml.workbookView :activeTab=>0 - # } - xml.sheets { - @worksheets.each_with_index do |sheet, index| - xml.sheet(:name=>sheet.name, :sheetId=>index+1, :"r:id"=>sheet.rId) - end - } - } + str << '<?xml version="1.0" encoding="UTF-8"?>' + str << '<workbook xmlns="' << XML_NS << '" xmlns:r="' << XML_NS_R << '">' + str << '<workbookPr date1904="' << @@date1904.to_s << '"/>' + str << '<sheets>' + @worksheets.each_with_index do |sheet, index| + str << '<sheet name="' << sheet.name << '" sheetId="' << (index+1).to_s << '" r:id="' << sheet.rId << '"/>' end - builder.to_xml(:save_with => 0) + str << '</sheets>' + str << '<definedNames>' + @worksheets.each_with_index do |sheet, index| + if sheet.auto_filter + str << '<definedName name="_xlnm._FilterDatabase" localSheetId="' << index.to_s << '" hidden="1">' + str << sheet.abs_auto_filter << '</definedName>' + end + end + str << '</definedNames>' + str << '</workbook>' end + end end diff --git a/lib/axlsx/workbook/worksheet/cell.rb b/lib/axlsx/workbook/worksheet/cell.rb index 24b380cb..f4c6ff09 100644 --- a/lib/axlsx/workbook/worksheet/cell.rb +++ b/lib/axlsx/workbook/worksheet/cell.rb @@ -1,4 +1,5 @@ # encoding: UTF-8 +require 'cgi' module Axlsx # A cell in a worksheet. # Cell stores inforamation requried to serialize a single worksheet cell to xml. You must provde the Row that the cell belongs to and the cells value. The data type will automatically be determed if you do not specify the :type option. The default style will be applied if you do not supply the :style option. Changing the cell's type will recast the value to the type specified. Altering the cell's value via the property accessor will also automatically cast the provided value to the cell's type. @@ -35,9 +36,6 @@ module Axlsx 'shadow', 'condense', 'extend', 'u', 'vertAlign', 'sz', 'color', 'scheme'] - INLINE_ATTR = [:font_name => { :validator=>:validate_string}] - - # The index of the cellXfs item to be applied to this cell. # @return [Integer] # @see Axlsx::Styles @@ -225,7 +223,8 @@ module Axlsx # equality comparison to test value, type and inline style attributes # this is how we work out if the cell needs to be added or already exists in the shared strings table def shareable_hash - self_hash = self.instance_values.reject { |key, val| !INLINE_STYLES.include?(key) } + self_hash = {} + INLINE_STYLES.each { |style| self_hash[style] = self.instance_variable_get("@" + style) } self_hash['color'] = self_hash['color'].instance_values if self_hash['color'] self_hash end @@ -276,9 +275,11 @@ module Axlsx self.row.worksheet.merge_cells "#{self.r}:#{range_end}" unless range_end.nil? end + # builds an xml text run based on this cells attributes. + # @param [String] str The string instance this run will be concated to. + # @return [String] def run_xml_string(str = '') if is_text_run? - puts 'text run' data = self.instance_values.reject{|key, value| value == nil } keys = data.keys & INLINE_STYLES keys.delete ['value', 'type'] @@ -299,52 +300,24 @@ module Axlsx end str end - # builds an xml text run based on this cells attributes. This is extracted from to_xml so that shared strings can use it. - # @param [Nokogiri::XML::Builder] xml The document builder instance this output will be added to. - # @return [String] the xml for this cell's text run - def run_xml(xml) - if (self.instance_values.keys & INLINE_STYLES).size > 0 - xml.r { - xml.rPr { - xml.rFont(:val=>@font_name) if @font_name - xml.charset(:val=>@charset) if @charset - xml.family(:val=>@family) if @family - xml.b(:val=>@b) if @b - xml.i(:val=>@i) if @i - xml.strike(:val=>@strike) if @strike - xml.outline(:val=>@outline) if @outline - xml.shadow(:val=>@shadow) if @shadow - xml.condense(:val=>@condense) if @condense - xml.extend(:val=>@extend) if @extend - @color.to_xml(xml) if @color - xml.sz(:val=>@sz) if @sz - xml.u(:val=>@u) if @u - # :baseline, :subscript, :superscript - xml.vertAlign(:val=>@vertAlign) if @vertAlign - # :none, major, :minor - xml.scheme(:val=>@scheme) if @scheme - } - xml.t @value.to_s - } - else - xml.t @value.to_s - end - end # Serializes the cell - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. + # @param [Integer] r_index The row index for the cell + # @param [Integer] c_index The cell index in the row. + # @param [String] str The string index the cell content will be appended to. Defaults to empty string. # @return [String] xml text for the cell def to_xml_string(r_index, c_index, str = '') + return str if @value.nil? str << '<c r="' << Axlsx::cell_r(c_index, r_index) << '" s="' << @style.to_s << '" ' case @type when :string #parse formula if @value.start_with?('=') - str << 't="str"><f>' << value.to_s.gsub('=', '') << '</f>' + str << 't="str"><f>' << @value.to_s.gsub('=', '') << '</f>' else #parse shared if @ssti - str << 't="s"><v>' << ssti << '</v>' + str << 't="s"><v>' << @ssti.to_s << '</v>' else str << 't="inlineStr"><is>' << run_xml_string << '</is>' end @@ -362,40 +335,6 @@ module Axlsx str << '</c>' end - def to_xml(xml) - if @type == :string - #parse formula - if @value.start_with?('=') - xml.c(:r => r, :s=>style, :t=>:str) { - xml.f @value.to_s.gsub('=', '') - } - else - #parse shared - if @ssti - xml.c(:r => r, :s=>style, :t => :s) { xml.v ssti } - else - #parse inline string - xml.c(:r => r, :s=>style, :t => :inlineStr) { - xml.is { - run_xml(xml) - } - } - end - end - elsif @type == :date - # TODO: See if this is subject to the same restriction as Time below - v = DateTimeConverter::date_to_serial @value - xml.c(:r => r, :s => style) { xml.v v } - elsif @type == :time - v = DateTimeConverter::time_to_serial @value - xml.c(:r => r, :s => style) { xml.v v } - elsif @type == :boolean - xml.c(:r => r, :s => style, :t => :b) { xml.v value } - else - xml.c(:r => r, :s => style) { xml.v value } - end - end - private # Utility method for setting inline style attributes @@ -444,6 +383,7 @@ module Axlsx # About Time - Time in OOXML is *different* from what you might expect. The history as to why is interesting, but you can safely assume that if you are generating docs on a mac, you will want to specify Workbook.1904 as true when using time typed values. # @see Axlsx#date1904 def cast_value(v) + return nil if v.nil? if @type == :date self.style = STYLE_DATE if self.style == 0 v @@ -458,7 +398,7 @@ module Axlsx v ? 1 : 0 else @type = :string - v.to_s + ::CGI.escapeHTML(v.to_s) end end end diff --git a/lib/axlsx/workbook/worksheet/col.rb b/lib/axlsx/workbook/worksheet/col.rb new file mode 100644 index 00000000..7a34ad40 --- /dev/null +++ b/lib/axlsx/workbook/worksheet/col.rb @@ -0,0 +1,114 @@ +# encoding: UTF-8 +module Axlsx + + # The Col class defines column attributes for columns in sheets. + class Col + + # First column affected by this 'column info' record. + # @return [Integer] + attr_reader :min + + # Last column affected by this 'column info' record. + # @return [Integer] + attr_reader :max + + # Flag indicating if the specified column(s) is set to 'best fit'. 'Best fit' is set to true under these conditions: + # The column width has never been manually set by the user, AND The column width is not the default width + # 'Best fit' means that when numbers are typed into a cell contained in a 'best fit' column, the column width should + # automatically resize to display the number. [Note: In best fit cases, column width must not be made smaller, only larger. end note] + # @return [Boolean] + attr_reader :bestFit + + # Flag indicating if the outlining of the affected column(s) is in the collapsed state. + # @return [Boolean] + attr_reader :collapsed + + # Flag indicating if the affected column(s) are hidden on this worksheet. + # @return [Boolean] + attr_reader :hidden + + # Outline level of affected column(s). Range is 0 to 7. + # @return [Integer] + attr_reader :outlineLevel + + # Flag indicating if the phonetic information should be displayed by default for the affected column(s) of the worksheet. + # @return [Boolean] + attr_reader :phonetic + + # Default style for the affected column(s). Affects cells not yet allocated in the column(s). In other words, this style applies to new columns. + # @return [Integer] + attr_reader :style + + # The width of the column + # @return [Numeric] + attr_reader :width + + # @return [Boolean] + attr_reader :customWidth + + # @see Col#collapsed + def collapsed=(v) + Axlsx.validate_boolean(v) + @collapsed = v + end + + # @see Col#hidden + def hidden=(v) + Axlsx.validate_boolean(v) + @hidden = v + end + + # @see Col#outline + def outlineLevel=(v) + Axlsx.validate_boolean(v) + @outlineLevel = v + end + + # @see Col#phonetic + def phonetic=(v) + Axlsx.validate_boolean(v) + @phonetic = v + end + + # @see Col#style + def style=(v) + Axlsx.validate_unsigned_int(v) + @style = v + end + + # @see Col#width + def width=(v) + Axlsx.validate_unsigned_numeric(v) unless v == nil + @customWidth = @bestFit = v != nil + @width = v + end + + # Create a new Col objects + # @param min First column affected by this 'column info' record. + # @param max Last column affected by this 'column info' record. + # @option options [Boolean] collapsed see Col#collapsed + # @option options [Boolean] hidden see Col#hidden + # @option options [Boolean] outlineLevel see Col#outlineLevel + # @option options [Boolean] phonetic see Col#phonetic + # @option options [Integer] style see Col#style + # @option options [Numeric] width see Col#width + def initialize(min, max, options={}) + Axlsx.validate_unsigned_int(max) + Axlsx.validate_unsigned_int(min) + @min = min + @max = max + options.each do |o| + self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}=" + end + end + + # Serialize this columns data to an xml string + # @param [String] str + # @return [String] + def to_xml_string(str = '') + attrs = self.instance_values.reject{ |key, value| value == nil } + str << '<col ' << attrs.map { |key, value| '' << key << '="' << value.to_s << '"' }.join(' ') << '/>' + end + + end +end diff --git a/lib/axlsx/workbook/worksheet/page_margins.rb b/lib/axlsx/workbook/worksheet/page_margins.rb index 1c456f2a..d2349f9e 100644 --- a/lib/axlsx/workbook/worksheet/page_margins.rb +++ b/lib/axlsx/workbook/worksheet/page_margins.rb @@ -83,15 +83,15 @@ module Axlsx # @see footer def footer=(v); Axlsx::validate_unsigned_numeric(v); @footer = v end - def to_xml_string - "<pageMargins left='%s' right='%s' top='%s' bottom='%s' header='%s' footer='%s'/>" % [left, right, top, bottom, header, footer] - end # Serializes the page margins element + # @param [String] str + # @return [String] # @note For compatibility, this is a noop unless custom margins have been specified. - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. # @see #custom_margins_specified? - def to_xml(xml) - xml.pageMargins :left => left, :right => right, :top => top, :bottom => bottom, :header => header, :footer => footer + def to_xml_string(str = '') + str << '<pageMargins ' + str << instance_values.map { |key, value| '' << key << '="' << value.to_s << '"' }.join(' ') + str << '/>' end end end diff --git a/lib/axlsx/workbook/worksheet/row.rb b/lib/axlsx/workbook/worksheet/row.rb index ac251ed8..4e5150da 100644 --- a/lib/axlsx/workbook/worksheet/row.rb +++ b/lib/axlsx/workbook/worksheet/row.rb @@ -59,6 +59,10 @@ module Axlsx worksheet.rows.index(self) end + # Serializes the row + # @param [Integer] r_index The row index, 0 based. + # @param [String] str The string this rows xml will be appended to. + # @return [String] def to_xml_string(r_index, str = '') str << '<row r="' << (r_index + 1 ).to_s << '" ' if custom_height? @@ -70,20 +74,12 @@ module Axlsx str << '</row>' str end - # Serializes the row - # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to. - # @return [String] - def to_xml(xml) - attrs = {:r => index+1} - attrs.merge!(:customHeight => 1, :ht => height) if custom_height? - xml.row(attrs) { |ixml| @cells.each { |cell| cell.to_xml(ixml) } } - end # Adds a singel sell to the row based on the data provided and updates the worksheet's autofit data. # @return [Cell] def add_cell(value="", options={}) c = Cell.new(self, value, options) - update_auto_fit_data + worksheet.send(:update_column_info, self.cells, self.cells.map(&:style)) c end @@ -117,13 +113,6 @@ module Axlsx # assigns the owning worksheet for this row def worksheet=(v) DataTypeValidator.validate "Row.worksheet", Worksheet, v; @worksheet=v; end - # Tell the worksheet to update autofit data for the columns based on this row's cells. - # @return [SimpleTypedList] - def update_auto_fit_data - worksheet.send(:update_auto_fit_data, self.cells) - end - - # Converts values, types, and style options into cells and associates them with this row. # A new cell is created for each item in the values array. # If value option is defined and is a symbol it is applied to all the cells created. diff --git a/lib/axlsx/workbook/worksheet/table.rb b/lib/axlsx/workbook/worksheet/table.rb index 831040f3..2fd15966 100644 --- a/lib/axlsx/workbook/worksheet/table.rb +++ b/lib/axlsx/workbook/worksheet/table.rb @@ -63,29 +63,28 @@ module Axlsx end end + # Serializes the object + # @param [String] str + # @return [String] + def to_xml_string(str = '') + str << '<?xml version="1.0" encoding="UTF-8"?>' + str << '<table xmlns="' << XML_NS << '" id="' << (index+1).to_s << '" name="' << @name << '" displayName="' << @name.gsub(/\s/,'_') << '" ' + str << 'ref="' << @ref << '" totalsRowShown="0">' + str << '<autoFilter ref="' << @ref << '"/>' + str << '<tableColumns count="' << header_cells.length.to_s << '">' + header_cells.each_with_index do |cell,index| + str << '<tableColumn id ="' << (index+1).to_s << '" name="' << cell.value << '"/>' + end + str << '</tableColumns>' + #TODO implement tableStyleInfo + str << '<tableStyleInfo showFirstColumn="0" showLastColumn="0" showRowStripes="1" showColumnStripes="0" name="TableStyleMedium9" />' + str << '</table>' + end # The style for the table. # TODO # def style=(v) DataTypeValidator.validate "Table.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) diff --git a/lib/axlsx/workbook/worksheet/worksheet.rb b/lib/axlsx/workbook/worksheet/worksheet.rb index 20c13d8b..4f26b568 100644 --- a/lib/axlsx/workbook/worksheet/worksheet.rb +++ b/lib/axlsx/workbook/worksheet/worksheet.rb @@ -53,6 +53,11 @@ module Axlsx # @return Boolean attr_reader :fit_to_page + + # Column info for the sheet + # @return [SimpleTypedList] + attr_reader :column_info + # Page margins for printing the worksheet. # @example # wb = Axlsx::Package.new.workbook @@ -96,7 +101,8 @@ module Axlsx @page_margins = PageMargins.new options[:page_margins] if options[:page_margins] @rows = SimpleTypedList.new Row - @cols = SimpleTypedList.new Cell + @column_info = SimpleTypedList.new Col + # @cols = SimpleTypedList.new Cell @tables = SimpleTypedList.new Table if self.workbook.use_autowidth @@ -160,7 +166,7 @@ module Axlsx end - # Indicates if gridlines should be shown in the sheet. + # Indicates if the worksheet should print in a single page. # This is true by default. # @return [Boolean] def fit_to_page=(v) @@ -189,6 +195,12 @@ module Axlsx @name=v end + # The absolute auto filter range + # @see auto_filter + def abs_auto_filter + Axlsx.cell_range(@auto_filter.split(':').collect { |name| name_to_cell(name)}) if @auto_filter + end + # The auto filter range for the worksheet # @param [String] v # @see auto_filter @@ -270,7 +282,8 @@ module Axlsx # @option options [Float] height the row's height (in points) def add_row(values=[], options={}) Row.new(self, values, options) - update_auto_fit_data @rows.last.cells, options.delete(:widths) || [] + update_column_info @rows.last.cells, options.delete(:widths) ||[], options.delete(:style) || [] + # update_auto_fit_data @rows.last.cells, options.delete(:widths) || [] yield @rows.last if block_given? @rows.last end @@ -329,9 +342,9 @@ module Axlsx # @param [Integer|Float|Fixnum|nil] values def column_widths(*args) args.each_with_index do |value, index| - raise ArgumentError, "Invalid column specification" unless index < @auto_fit_data.size + raise ArgumentError, "Invalid column specification" unless index < @column_info.size Axlsx::validate_unsigned_numeric(value) unless value == nil - @auto_fit_data[index][:fixed] = value + @column_info[index].width = value end end @@ -371,25 +384,25 @@ module Axlsx image end + # Serializes the object + # @param [String] str + # @return [String] def to_xml_string - str = "<worksheet xmlns=\"%s\" xmlns:r=\"%s\">" % [XML_NS, XML_NS_R] + str = '<?xml version="1.0" encoding="UTF-8"?>' + str.concat "<worksheet xmlns=\"%s\" xmlns:r=\"%s\">" % [XML_NS, XML_NS_R] str.concat "<sheetPr><pageSetUpPr fitToPage=\"%s\"></pageSetUpPr></sheetPr>" % fit_to_page if fit_to_page str.concat "<dimension ref=\"%s\"></dimension>" % dimension unless rows.size == 0 str.concat "<sheetViews><sheetView tabSelected='%s' workbookViewId='0' showGridLines='%s'><selection activeCell=\"A1\" sqref=\"A1\"/></sheetView></sheetViews>" % [@selected, show_gridlines] - if @auto_fit_data.size > 0 - str.concat "<cols>" - @auto_fit_data.each_with_index do |col, index| - min_max = index+1 - str.concat "<col min='%s' max='%s' width='%s' customWidth='1'></col>" % [min_max, min_max, auto_width(col)] - end + if @column_info.size > 0 + str << "<cols>" + @column_info.each { |col| col.to_xml_string(str) } str.concat '</cols>' end - str.concat '<sheetData>' @rows.each_with_index { |row, index| row.to_xml_string(index, str) } str.concat '</sheetData>' - str.concat page_margins.to_xml_string if @page_margins + page_margins.to_xml_string(str) if @page_margins str.concat "<autoFilter ref='%s'></autoFilter>" % @auto_filter if @auto_filter str.concat "<mergeCells count='%s'>%s</mergeCells>" % [@merged_cells.size, @merged_cells.reduce('') { |memo, obj| "<mergeCell ref='%s'></mergeCell>" % obj } ] unless @merged_cells.empty? str.concat "<drawing r:id='rId1'></drawing>" if @drawing @@ -399,54 +412,6 @@ module Axlsx str + '</worksheet>' end - # Serializes the worksheet document - # @return [String] - def to_xml - builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml| - xml.worksheet(:xmlns => XML_NS, - :'xmlns:r' => XML_NS_R) { - xml.sheetPr { - xml.pageSetUpPr :fitToPage => fit_to_page if fit_to_page - } - # another patch for the folks at rubyXL as thier parser depends on this optional element. - xml.dimension :ref=>dimension unless rows.size == 0 - # this is required by rubyXL, spec says who cares - but it seems they didnt notice - # grouping issue resolved by keeping tabSelected set to 0 - xml.sheetViews { - xml.sheetView(:tabSelected => @selected, :workbookViewId => 0, :showGridLines => show_gridlines) { - xml.selection :activeCell=>"A1", :sqref => "A1" - } - } - - if @auto_fit_data.size > 0 - xml.cols { - @auto_fit_data.each_with_index do |col, index| - min_max = index+1 - xml.col(:min=>min_max, :max=>min_max, :width => auto_width(col), :customWidth=>1) - end - } - end - xml.sheetData { - @rows.each do |row| - row.to_xml(xml) - end - } - xml.autoFilter :ref=>@auto_filter if @auto_filter - 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) - end - # The worksheet relationships. This is managed automatically by the worksheet # @return [Relationships] def relationships @@ -486,74 +451,34 @@ module Axlsx # assigns the owner workbook for this worksheet def workbook=(v) DataTypeValidator.validate "Worksheet.workbook", Workbook, v; @workbook = v; end - # Updates auto fit data. - # We store an auto_fit_data item for each column. when a row is added we multiple the font size by the length of the text to - # attempt to identify the longest cell in the column. This is not 100% accurate as it needs to take into account - # any formatting that will be applied to the data, as well as the actual rendering size when the length and size is equal - # for two cells. - - # @return [Array] of Cell objects - # @param [Array] cells an array of cells - # @param [Array] widths an array of cell widths @see Worksheet#add_row - def update_auto_fit_data(cells, widths=[]) - # TODO delay this until rendering. too much work when we dont know what they are going to do to the sheet. + + def update_column_info(cells, widths=[], style=[]) styles = self.workbook.styles cellXfs, fonts = styles.cellXfs, styles.fonts sz = 11 - cells.each_with_index do |item, index| - col = @auto_fit_data[index] ||= {:longest=>"", :sz=>sz, :fixed=>nil} + cells.each_with_index do |cell, index| + @column_info[index] ||= Col.new index+1, index+1 + col = @column_info[index] width = widths[index] - # set fixed width and skip if numeric width is given - col[:fixed] = width if [Integer, Float, Fixnum].include?(width.class) - # ignore default column widths and formula - next if width == :ignore || (item.value.is_a?(String) && item.value.start_with?('=')) - # make sure we can turn that fixed with off! - col[:fixed] = nil if width == :auto - next unless self.workbook.use_autowidth - - cell_xf = cellXfs[item.style] - font = fonts[cell_xf.fontId || 0] - sz = item.sz || font.sz || fonts[0].sz - if (col[:longest].scan(/./mu).size * col[:sz]) < (item.value.to_s.scan(/./mu).size * sz) - col[:sz] = sz - col[:longest] = item.value.to_s + col.width = width if [Integer, Float, Fixnum].include?(width.class) + c_style = style[index] if [Integer, Fixnum].include?(style[index].class) + next if width == :ignore || col.width || (cell.value.is_a?(String) && cell.value.start_with?('=')) + if self.workbook.use_autowidth + cell_xf = cellXfs[(c_style || 0)] + font = fonts[(cell_xf.fontId || 0)] + sz = cell.sz || font.sz || sz + col.width = [(col.width || 0), calculate_width(cell.value.to_s, sz)].max end end - cells end - # Determines the proper width for a column based on content. - # @note - # width = Truncate([!{Number of Characters} * !{Maximum Digit Width} + !{5 pixel padding}]/!{Maximum Digit Width}*256)/256 - # @return [Float] - # @param [Hash] A hash of auto_fit_data - def auto_width(col) - return col[:fixed] unless col[:fixed] == nil - return Axlsx::FIXED_COL_WIDTH unless self.workbook.use_autowidth - mdw_count, font_scale, mdw = 0, col[:sz]/11.0, 6.0 - mdw_count = col[:longest].scan(/./mu).reduce(0) do | count, char | + def calculate_width(text, sz) + mdw_count, font_scale, mdw = 0, sz/11.0, 6.0 + mdw_count = text.scan(/./mu).reduce(0) do | count, char | count +=1 if @magick_draw.get_type_metrics(char).max_advance >= mdw count end ((mdw_count * mdw + 5) / mdw * 256) / 256.0 * font_scale end - - # Something to look into: - # width calculation actually needs to be done agains the formatted value for items that apply a - # format - # def excel_format(cell) - # # The most common case. - # return time.value.to_s if cell.style == 0 - # - # # The second most common case - # num_fmt = workbook.styles.cellXfs[items.style].numFmtId - # return value.to_s if num_fmt == 0 - # - # format_code = workbook.styles.numFmts[num_fmt] - # # need to find some exceptionally fast way of parsing value according to - # # an excel format_code - # item.value.to_s - # end - end end diff --git a/lib/schema/dc.xsd b/lib/schema/dc.xsd index b8315e7e..fffd1522 100644 --- a/lib/schema/dc.xsd +++ b/lib/schema/dc.xsd @@ -12,7 +12,7 @@ Created 2003-04-02 - Created by + Created by Tim Cole ([email protected]) Tom Habing ([email protected]) @@ -23,14 +23,14 @@ This schema declares XML elements for the 15 DC elements from the http://purl.org/dc/elements/1.1/ namespace. - It defines a complexType SimpleLiteral which permits mixed content + It defines a complexType SimpleLiteral which permits mixed content and makes the xml:lang attribute available. It disallows child elements by use of minOcccurs/maxOccurs. However, this complexType does permit the derivation of other complexTypes which would permit child elements. - All elements are declared as substitutable for the abstract element any, + All elements are declared as substitutable for the abstract element any, which means that the default type for all elements is dc:SimpleLiteral. </xs:documentation> @@ -49,7 +49,7 @@ It permits text content only with optional xml:lang attribute. Text is allowed because mixed="true", but sub-elements - are disallowed because minOccurs="0" and maxOccurs="0" + are disallowed because minOccurs="0" and maxOccurs="0" are on the xs:any tag. This complexType allows for restriction or extension permitting @@ -89,7 +89,7 @@ <xs:annotation> <xs:documentation xml:lang="en"> This group is included as a convenience for schema authors - who need to refer to all the elements in the + who need to refer to all the elements in the http://purl.org/dc/elements/1.1/ namespace. </xs:documentation> </xs:annotation> diff --git a/lib/schema/dcmitype.xsd b/lib/schema/dcmitype.xsd index 54d9da00..69fcb5bd 100644 --- a/lib/schema/dcmitype.xsd +++ b/lib/schema/dcmitype.xsd @@ -5,6 +5,8 @@ elementFormDefault="qualified" attributeFormDefault="unqualified"> + <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="xml.xsd"/> + <xs:annotation> <xs:documentation xml:lang="en"> DCMI Type Vocabulary XML Schema @@ -12,7 +14,7 @@ Created 2003-04-02 - Created by + Created by Tim Cole ([email protected]) Tom Habing ([email protected]) @@ -24,7 +26,7 @@ the allowable values for the DCMI Type Vocabulary. </xs:documentation> - + </xs:annotation> @@ -43,7 +45,7 @@ <xs:enumeration value="Text"/> <xs:enumeration value="PhysicalObject"/> </xs:restriction> - </xs:simpleType> + </xs:simpleType> </xs:union> </xs:simpleType> diff --git a/lib/schema/dcterms.xsd b/lib/schema/dcterms.xsd index 055a6edf..da22580e 100644 --- a/lib/schema/dcterms.xsd +++ b/lib/schema/dcterms.xsd @@ -14,7 +14,7 @@ Created 2003-04-02 - Created by + Created by Tim Cole ([email protected]) Tom Habing ([email protected]) @@ -24,7 +24,7 @@ This schema declares XML elements for the DC elements and DC element refinements from the http://purl.org/dc/terms/ namespace. - + It reuses the complexType dc:SimpleLiteral, imported from the dc.xsd schema, which permits simple element content, and makes the xml:lang attribute available. @@ -32,22 +32,22 @@ This complexType permits the derivation of other complexTypes which would permit child elements. - DC elements are declared as substitutable for the abstract element dc:any, and - DC element refinements are defined as substitutable for the base elements + DC elements are declared as substitutable for the abstract element dc:any, and + DC element refinements are defined as substitutable for the base elements which they refine. - This means that the default type for all XML elements (i.e. all DC elements and + This means that the default type for all XML elements (i.e. all DC elements and element refinements) is dc:SimpleLiteral. Encoding schemes are defined as complexTypes which are restrictions - of the dc:SimpleLiteral complexType. These complexTypes restrict + of the dc:SimpleLiteral complexType. These complexTypes restrict values to an appropriates syntax or format using data typing, regular expressions, or enumerated lists. - - In order to specify one of these encodings an xsi:type attribute must + + In order to specify one of these encodings an xsi:type attribute must be used in the instance document. - Also, note that one shortcoming of this approach is that any type can be + Also, note that one shortcoming of this approach is that any type can be applied to any of the elements or refinements. There is no convenient way to restrict types to specific elements using this approach. @@ -184,7 +184,7 @@ <xs:attribute ref="xml:lang" use="prohibited"/> </xs:restriction> </xs:simpleContent> - </xs:complexType> + </xs:complexType> <xs:complexType name="DCMIType"> <xs:simpleContent> @@ -217,7 +217,7 @@ <xs:attribute ref="xml:lang" use="prohibited"/> </xs:restriction> </xs:simpleContent> - </xs:complexType> + </xs:complexType> <xs:complexType name="ISO639-2"> <xs:simpleContent> @@ -300,9 +300,9 @@ <xs:annotation> <xs:documentation xml:lang="en"> This group is included as a convenience for schema authors - who need to refer to all the DC elements and element refinements - in the http://purl.org/dc/elements/1.1/ and - http://purl.org/dc/terms namespaces. + who need to refer to all the DC elements and element refinements + in the http://purl.org/dc/elements/1.1/ and + http://purl.org/dc/terms namespaces. N.B. Refinements available via substitution groups. </xs:documentation> </xs:annotation> @@ -312,7 +312,7 @@ <xs:element ref="dc:any" /> </xs:choice> </xs:sequence> - </xs:group> + </xs:group> <xs:complexType name="elementOrRefinementContainer"> <xs:annotation> diff --git a/lib/schema/opc-coreProperties.xsd b/lib/schema/opc-coreProperties.xsd index a2d6cdac..2b7d5c1c 100644 --- a/lib/schema/opc-coreProperties.xsd +++ b/lib/schema/opc-coreProperties.xsd @@ -2,13 +2,17 @@ <xs:schema targetNamespace="http://schemas.openxmlformats.org/package/2006/metadata/core-properties"
xmlns="http://schemas.openxmlformats.org/package/2006/metadata/core-properties"
xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:dcterms="http://purl.org/dc/terms/" elementFormDefault="qualified" blockDefault="#all">
+ xmlns:dcterms="http://purl.org/dc/terms/"
+ elementFormDefault="qualified" blockDefault="#all">
<xs:import namespace="http://purl.org/dc/elements/1.1/"
schemaLocation="dc.xsd"/>
+
<xs:import namespace="http://purl.org/dc/terms/"
schemaLocation="dcterms.xsd"/>
- <xs:import id="xml" namespace="http://www.w3.org/XML/1998/namespace"/>
+
+ <xs:import namespace="http://www.w3.org/XML/1998/namespace"
+ schemaLocation="xml.xsd"/>
<xs:element name="coreProperties" type="CT_CoreProperties"/>
diff --git a/lib/schema/xml.xsd b/lib/schema/xml.xsd index d662b423..4f5ecc8b 100644 --- a/lib/schema/xml.xsd +++ b/lib/schema/xml.xsd @@ -1,6 +1,5 @@ <?xml version='1.0'?> -<!DOCTYPE xs:schema PUBLIC "-//W3C//DTD XMLSCHEMA 200102//EN" "XMLSchema.dtd" > -<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" xmlns:xs="http://www.w3.org/2001/XMLSchema" xml:lang="en"> +<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:annotation> <xs:documentation> @@ -8,7 +7,7 @@ http://www.w3.org/TR/REC-xml for information about this namespace. This schema document describes the XML namespace, in a form - suitable for import by other schema documents. + suitable for import by other schema documents. Note that local names in this namespace are intended to be defined only by the World Wide Web Consortium or its subgroups. The @@ -26,16 +25,16 @@ is a language code for the natural language of the content of any element; its value is inherited. This name is reserved by virtue of its definition in the XML specification. - + space (as an attribute name): denotes an attribute whose value is a keyword indicating what whitespace processing discipline is intended for the content of the element; its value is inherited. This name is reserved by virtue of its definition in the XML specification. - Father (in any context at all): denotes Jon Bosak, the chair of - the original XML Working Group. This name is reserved by - the following decision of the W3C XML Plenary and + Father (in any context at all): denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and XML Coordination groups: In appreciation for his vision, leadership and dedication @@ -64,7 +63,7 @@ <type . . .> . . . <attributeGroup ref="xml:specialAttrs"/> - + will define a type which will schema-validate an instance element with any of those attributes</xs:documentation> </xs:annotation> diff --git a/test/content_type/tc_content_type.rb b/test/content_type/tc_content_type.rb index 79141748..e353b1bb 100644 --- a/test/content_type/tc_content_type.rb +++ b/test/content_type/tc_content_type.rb @@ -4,7 +4,7 @@ require 'tc_helper.rb' class TestContentType < Test::Unit::TestCase def setup @package = Axlsx::Package.new - @doc = Nokogiri::XML(@package.send(:content_types).to_xml) + @doc = Nokogiri::XML(@package.send(:content_types).to_xml_string) end def test_valid_document @@ -51,12 +51,12 @@ class TestContentType < Test::Unit::TestCase o_path = "//xmlns:Override[@ContentType='%s']" ws = @package.workbook.add_worksheet - doc = Nokogiri::XML(@package.send(:content_types).to_xml) + doc = Nokogiri::XML(@package.send(:content_types).to_xml_string) assert_equal(doc.xpath("//xmlns:Override").size, 5, "adding a worksheet should add another type") assert_equal(doc.xpath(o_path % Axlsx::WORKSHEET_CT).last["PartName"], "/xl/#{ws.pn}", "Worksheet part invalid") ws = @package.workbook.add_worksheet - doc = Nokogiri::XML(@package.send(:content_types).to_xml) + doc = Nokogiri::XML(@package.send(:content_types).to_xml_string) assert_equal(doc.xpath("//xmlns:Override").size, 6, "adding workship should add another type") assert_equal(doc.xpath(o_path % Axlsx::WORKSHEET_CT).last["PartName"], "/xl/#{ws.pn}", "Worksheet part invalid") @@ -67,13 +67,13 @@ class TestContentType < Test::Unit::TestCase ws = @package.workbook.add_worksheet c = ws.add_chart Axlsx::Pie3DChart - doc = Nokogiri::XML(@package.send(:content_types).to_xml) + doc = Nokogiri::XML(@package.send(:content_types).to_xml_string) assert_equal(doc.xpath("//xmlns:Override").size, 7, "expected 7 types got #{doc.css("Types Override").size}") assert_equal(doc.xpath(o_path % Axlsx::DRAWING_CT).first["PartName"], "/xl/#{ws.drawing.pn}", "Drawing part name invlid") assert_equal(doc.xpath(o_path % Axlsx::CHART_CT).last["PartName"], "/xl/#{c.pn}", "Chart part name invlid") c = ws.add_chart Axlsx::Pie3DChart - doc = Nokogiri::XML(@package.send(:content_types).to_xml) + doc = Nokogiri::XML(@package.send(:content_types).to_xml_string) assert_equal(doc.xpath("//xmlns:Override").size, 8, "expected 7 types got #{doc.css("Types Override").size}") assert_equal(doc.xpath(o_path % Axlsx::CHART_CT).last["PartName"], "/xl/#{c.pn}", "Chart part name invlid") end diff --git a/test/content_type/tc_default.rb b/test/content_type/tc_default.rb index e5245b38..2fe0d965 100644 --- a/test/content_type/tc_default.rb +++ b/test/content_type/tc_default.rb @@ -2,10 +2,7 @@ require 'tc_helper.rb' class TestDefault < Test::Unit::TestCase - def setup - end - def teardown - end + def test_initialization_requires_Extension_and_ContentType assert_raise(ArgumentError, "raises argument error if Extension and/or ContentType are not specified") { Axlsx::Default.new } assert_raise(ArgumentError, "raises argument error if Extension and/or ContentType are not specified") { Axlsx::Default.new :Extension=>"xml" } @@ -18,21 +15,11 @@ class TestDefault < Test::Unit::TestCase assert_raise(ArgumentError, "raises argument error if invlalid ContentType is") { Axlsx::Default.new :ContentType=>"asdf" } end - def test_to_xml - schema = Nokogiri::XML::Schema(File.open(Axlsx::CONTENT_TYPES_XSD)) + def test_to_xml_string type = Axlsx::Default.new :Extension=>"xml", :ContentType=>Axlsx::XML_CT - builder = Nokogiri::XML::Builder.new(:encoding => Axlsx::ENCODING) do |xml| - xml.Types(:xmlns => Axlsx::XML_NS_T) { - type.to_xml(xml) - } - end - doc = Nokogiri::XML(builder.to_xml) - errors = [] - schema.validate(doc).each do |error| - puts error.message - errors << error - end - assert_equal(errors.size, 0, "[Content Types].xml Invalid" + errors.map{ |e| e.message }.to_s) + doc = Nokogiri::XML(type.to_xml_string) + assert_equal(doc.xpath("Default[@ContentType='#{Axlsx::XML_CT}']").size, 1) + assert_equal(doc.xpath("Default[@Extension='xml']").size, 1) end diff --git a/test/content_type/tc_override.rb b/test/content_type/tc_override.rb index 5005d12d..920f1667 100644 --- a/test/content_type/tc_override.rb +++ b/test/content_type/tc_override.rb @@ -2,10 +2,7 @@ require 'tc_helper.rb' class TestOverride < Test::Unit::TestCase - def setup - end - def teardown - end + def test_initialization_requires_Extension_and_ContentType err = "requires PartName and ContentType options" assert_raise(ArgumentError, err) { Axlsx::Override.new } @@ -19,20 +16,10 @@ class TestOverride < Test::Unit::TestCase end def test_to_xml - schema = Nokogiri::XML::Schema(File.open(Axlsx::CONTENT_TYPES_XSD)) type = Axlsx::Override.new :PartName=>"somechart.xml", :ContentType=>Axlsx::CHART_CT - builder = Nokogiri::XML::Builder.new(:encoding => Axlsx::ENCODING) do |xml| - xml.Types(:xmlns => Axlsx::XML_NS_T) { - type.to_xml(xml) - } - end - doc = Nokogiri::XML(builder.to_xml) - errors = [] - schema.validate(doc).each do |error| - puts error.message - errors << error - end - assert_equal(errors.size, 0, "Override content type caused invalid content_type doc" + errors.map{ |e| e.message }.to_s) + doc = Nokogiri::XML(type.to_xml_string) + assert_equal(doc.xpath("Override[@ContentType='#{Axlsx::CHART_CT}']").size, 1) + assert_equal(doc.xpath("Override[@PartName='somechart.xml']").size, 1) end diff --git a/test/doc_props/tc_app.rb b/test/doc_props/tc_app.rb index 31c87c41..bff2bb3d 100644 --- a/test/doc_props/tc_app.rb +++ b/test/doc_props/tc_app.rb @@ -1,14 +1,9 @@ require 'tc_helper.rb' class TestApp < Test::Unit::TestCase - def setup - end - def teardown - end - def test_valid_document schema = Nokogiri::XML::Schema(File.open(Axlsx::APP_XSD)) - doc = Nokogiri::XML(Axlsx::App.new.to_xml) + doc = Nokogiri::XML(Axlsx::App.new.to_xml_string) errors = [] schema.validate(doc).each do |error| errors << error diff --git a/test/doc_props/tc_core.rb b/test/doc_props/tc_core.rb index 5e75d812..e26d1236 100644 --- a/test/doc_props/tc_core.rb +++ b/test/doc_props/tc_core.rb @@ -4,7 +4,7 @@ class TestCore < Test::Unit::TestCase def setup @core = Axlsx::Core.new - @doc = Nokogiri::XML(@core.to_xml) + @doc = Nokogiri::XML(@core.to_xml_string) end def test_valid_document @@ -27,7 +27,7 @@ class TestCore < Test::Unit::TestCase def test_creator_as_option c = Axlsx::Core.new :creator => "some guy" - doc = Nokogiri::XML(c.to_xml) + doc = Nokogiri::XML(c.to_xml_string) assert(doc.xpath('//dc:creator').text == "some guy") end end diff --git a/test/drawing/tc_axis.rb b/test/drawing/tc_axis.rb index 234eba9c..c627b4d1 100644 --- a/test/drawing/tc_axis.rb +++ b/test/drawing/tc_axis.rb @@ -36,4 +36,9 @@ class TestAxis < Test::Unit::TestCase assert_nothing_raised("accepts valid crosses") { @axis.crosses = :min } end + def test_gridlines + assert_raise(ArgumentError, "requires valid gridlines") { @axis.gridlines = 'alice' } + assert_nothing_raised("accepts valid crosses") { @axis.gridlines = false } + end + end diff --git a/test/drawing/tc_bar_3D_chart.rb b/test/drawing/tc_bar_3D_chart.rb index 93997730..1f78fa0b 100644 --- a/test/drawing/tc_bar_3D_chart.rb +++ b/test/drawing/tc_bar_3D_chart.rb @@ -51,9 +51,9 @@ class TestBar3DChart < Test::Unit::TestCase assert(@chart.shape == :cone) end - def test_to_xml + def test_to_xml_string schema = Nokogiri::XML::Schema(File.open(Axlsx::DRAWING_XSD)) - doc = Nokogiri::XML(@chart.to_xml) + doc = Nokogiri::XML(@chart.to_xml_string) errors = [] schema.validate(doc).each do |error| errors.push error diff --git a/test/drawing/tc_chart.rb b/test/drawing/tc_chart.rb index c0e938cd..8047c018 100644 --- a/test/drawing/tc_chart.rb +++ b/test/drawing/tc_chart.rb @@ -58,9 +58,9 @@ class TestChart < Test::Unit::TestCase assert_equal(@chart.pn, "charts/chart1.xml") end - def test_to_xml + def test_to_xml_string schema = Nokogiri::XML::Schema(File.open(Axlsx::DRAWING_XSD)) - doc = Nokogiri::XML(@chart.to_xml) + doc = Nokogiri::XML(@chart.to_xml_string) errors = [] schema.validate(doc).each do |error| errors.push error diff --git a/test/drawing/tc_drawing.rb b/test/drawing/tc_drawing.rb index ac2dddbe..ce77ef9b 100644 --- a/test/drawing/tc_drawing.rb +++ b/test/drawing/tc_drawing.rb @@ -67,7 +67,7 @@ class TestDrawing < Test::Unit::TestCase def test_to_xml schema = Nokogiri::XML::Schema(File.open(Axlsx::DRAWING_XSD)) - doc = Nokogiri::XML(@ws.drawing.to_xml) + doc = Nokogiri::XML(@ws.drawing.to_xml_string) errors = [] schema.validate(doc).each do |error| errors.push error diff --git a/test/drawing/tc_line_3d_chart.rb b/test/drawing/tc_line_3d_chart.rb index 22dd6158..b419e00a 100644 --- a/test/drawing/tc_line_3d_chart.rb +++ b/test/drawing/tc_line_3d_chart.rb @@ -35,7 +35,7 @@ class TestLine3DChart < Test::Unit::TestCase def test_to_xml schema = Nokogiri::XML::Schema(File.open(Axlsx::DRAWING_XSD)) - doc = Nokogiri::XML(@chart.to_xml) + doc = Nokogiri::XML(@chart.to_xml_string) errors = [] schema.validate(doc).each do |error| errors.push error diff --git a/test/drawing/tc_pic.rb b/test/drawing/tc_pic.rb index 83ed4e1d..78750cbd 100644 --- a/test/drawing/tc_pic.rb +++ b/test/drawing/tc_pic.rb @@ -64,7 +64,7 @@ class TestPic < Test::Unit::TestCase def test_to_xml schema = Nokogiri::XML::Schema(File.open(Axlsx::DRAWING_XSD)) - doc = Nokogiri::XML(@image.anchor.drawing.to_xml) + doc = Nokogiri::XML(@image.anchor.drawing.to_xml_string) errors = [] schema.validate(doc).each do |error| errors.push error diff --git a/test/drawing/tc_pie_3D_chart.rb b/test/drawing/tc_pie_3D_chart.rb index 76bf49c5..5ac16e68 100644 --- a/test/drawing/tc_pie_3D_chart.rb +++ b/test/drawing/tc_pie_3D_chart.rb @@ -20,7 +20,7 @@ class TestPie3DChart < Test::Unit::TestCase def test_to_xml schema = Nokogiri::XML::Schema(File.open(Axlsx::DRAWING_XSD)) - doc = Nokogiri::XML(@chart.to_xml) + doc = Nokogiri::XML(@chart.to_xml_string) errors = [] schema.validate(doc).each do |error| errors.push error diff --git a/test/drawing/tc_scatter_chart.rb b/test/drawing/tc_scatter_chart.rb index 367cf56d..30178649 100644 --- a/test/drawing/tc_scatter_chart.rb +++ b/test/drawing/tc_scatter_chart.rb @@ -3,9 +3,20 @@ require 'tc_helper.rb' class TestScatterChart < Test::Unit::TestCase def setup @p = Axlsx::Package.new - ws = @p.workbook.add_worksheet - @row = ws.add_row ["one", 1, Time.now] - @chart = ws.add_chart Axlsx::ScatterChart, :title => "A Title" + @chart = nil + ws = @p.workbook.add_worksheet do |sheet| + sheet.add_row ["First", 1, 5, 7, 9] + sheet.add_row ["", 1, 25, 49, 81] + sheet.add_row ["Second", 5, 2, 14, 9] + sheet.add_row ["", 5, 10, 15, 20] + sheet.add_chart(Axlsx::ScatterChart, :title => "example 7: Scatter Chart") do |chart| + chart.start_at 0, 4 + chart.end_at 10, 19 + chart.add_series :xData => sheet["B1:E1"], :yData => sheet["B2:E2"], :title => sheet["A1"] + chart.add_series :xData => sheet["B3:E3"], :yData => sheet["B4:E4"], :title => sheet["A3"] + @chart = chart + end + end end def teardown @@ -18,9 +29,9 @@ class TestScatterChart < Test::Unit::TestCase assert(@chart.yValAxis.is_a?(Axlsx::ValAxis), "dependant value axis not created") end - def test_to_xml + def test_to_xml_string schema = Nokogiri::XML::Schema(File.open(Axlsx::DRAWING_XSD)) - doc = Nokogiri::XML(@chart.to_xml) + doc = Nokogiri::XML(@chart.to_xml_string) errors = [] schema.validate(doc).each do |error| errors.push error diff --git a/test/rels/tc_relationships.rb b/test/rels/tc_relationships.rb index 9a76d1e5..356e4691 100644 --- a/test/rels/tc_relationships.rb +++ b/test/rels/tc_relationships.rb @@ -5,7 +5,7 @@ class TestRelationships < Test::Unit::TestCase def test_valid_document @rels = Axlsx::Relationships.new schema = Nokogiri::XML::Schema(File.open(Axlsx::RELS_XSD)) - doc = Nokogiri::XML(@rels.to_xml) + doc = Nokogiri::XML(@rels.to_xml_string) errors = [] schema.validate(doc).each do |error| puts error.message @@ -13,7 +13,7 @@ class TestRelationships < Test::Unit::TestCase end @rels << Axlsx::Relationship.new(Axlsx::WORKSHEET_R, "bar") - doc = Nokogiri::XML(@rels.to_xml) + doc = Nokogiri::XML(@rels.to_xml_string) errors = [] schema.validate(doc).each do |error| puts error.message diff --git a/test/stylesheet/tc_styles.rb b/test/stylesheet/tc_styles.rb index 9db37157..ef14e151 100644 --- a/test/stylesheet/tc_styles.rb +++ b/test/stylesheet/tc_styles.rb @@ -9,7 +9,7 @@ class TestStyles < Test::Unit::TestCase def test_valid_document schema = Nokogiri::XML::Schema(File.open(Axlsx::SML_XSD)) - doc = Nokogiri::XML(@styles.to_xml) + doc = Nokogiri::XML(@styles.to_xml_string) errors = [] schema.validate(doc).each do |error| errors.push error diff --git a/test/tc_axlsx.rb b/test/tc_axlsx.rb new file mode 100644 index 00000000..fe3b7edd --- /dev/null +++ b/test/tc_axlsx.rb @@ -0,0 +1,39 @@ +require 'tc_helper.rb' + +class TestAxlsx < Test::Unit::TestCase + + def setup_wide + @wide_test_points = { "A3" => 0, + "Z3" => 25, + "B3" => 1, + "AA3" => 1 * 26 + 0, + "AAA3" => 1 * 26**2 + 1 * 26 + 0, + "AAZ3" => 1 * 26**2 + 1 * 26 + 25, + "ABA3" => 1 * 26**2 + 2 * 26 + 0, + "BZU3" => 2 * 26**2 + 26 * 26 + 20 + } + end + + def test_cell_range + #To do + end + + def test_name_to_indices + setup_wide + @wide_test_points.each do |key, value| + assert_equal(Axlsx.name_to_indices(key), [value,2]) + end + end + + def test_col_ref + setup_wide + @wide_test_points.each do |key, value| + assert_equal(Axlsx.col_ref(value), key.gsub(/\d+/, '')) + end + end + + def test_cell_r + # todo + end + +end diff --git a/test/workbook/tc_workbook.rb b/test/workbook/tc_workbook.rb index af2a7889..e6bb48a0 100644 --- a/test/workbook/tc_workbook.rb +++ b/test/workbook/tc_workbook.rb @@ -50,7 +50,7 @@ class TestWorkbook < Test::Unit::TestCase def test_to_xml schema = Nokogiri::XML::Schema(File.open(Axlsx::SML_XSD)) - doc = Nokogiri::XML(@wb.to_xml) + doc = Nokogiri::XML(@wb.to_xml_string) errors = [] schema.validate(doc).each do |error| errors.push error @@ -68,9 +68,19 @@ class TestWorkbook < Test::Unit::TestCase def test_to_xml_adds_worksheet_when_worksheets_is_empty assert(@wb.worksheets.empty?) - @wb.to_xml + @wb.to_xml_string assert(@wb.worksheets.size == 1) end + def test_to_xml_string_defined_names + @wb.add_worksheet do |sheet| + sheet.add_row [1, "two"] + sheet.auto_filter = "A1:B1" + end + doc = Nokogiri::XML(@wb.to_xml_string) + assert_equal(doc.xpath('//xmlns:workbook/xmlns:definedNames/xmlns:definedName').inner_text, @wb.worksheets[0].abs_auto_filter) + end + + end diff --git a/test/workbook/worksheet/table/tc_table.rb b/test/workbook/worksheet/table/tc_table.rb index fc29bf66..d4acf39a 100644 --- a/test/workbook/worksheet/table/tc_table.rb +++ b/test/workbook/worksheet/table/tc_table.rb @@ -56,10 +56,10 @@ class TestTable < Test::Unit::TestCase assert_equal(@ws.relationships.size, 2, "adding a table adds a relationship") end - def test_to_xml + def test_to_xml_string table = @ws.add_table("A1:D5") schema = Nokogiri::XML::Schema(File.open(Axlsx::SML_XSD)) - doc = Nokogiri::XML(table.to_xml) + doc = Nokogiri::XML(table.to_xml_string) errors = [] schema.validate(doc).each do |error| errors.push error diff --git a/test/workbook/worksheet/tc_cell.rb b/test/workbook/worksheet/tc_cell.rb index 499f9209..1cfd6169 100644 --- a/test/workbook/worksheet/tc_cell.rb +++ b/test/workbook/worksheet/tc_cell.rb @@ -41,6 +41,10 @@ class TestCell < Test::Unit::TestCase assert_equal(@c.r, "A1", "calculate cell reference") end + def test_wide_r + assert_equal(@cAA.r, "AA2", "calculate cell reference") + end + def test_r_abs assert_equal(@c.r_abs,"$A$1", "calculate absolute cell reference") assert_equal(@cAA.r_abs,"$AA$2", "needs to accept multi-digit columns") @@ -94,7 +98,9 @@ class TestCell < Test::Unit::TestCase @c.type = :float assert_equal(@c.send(:cast_value, "1.0"), 1.0) @c.type = :string - assert_equal(@c.send(:cast_value, nil), "") + assert_equal(@c.send(:cast_value, nil), nil) + @c.type = :float + assert_equal(@c.send(:cast_value, nil), nil) @c.type = :boolean assert_equal(@c.send(:cast_value, true), 1) assert_equal(@c.send(:cast_value, false), 0) @@ -225,17 +231,14 @@ class TestCell < Test::Unit::TestCase end def test_to_xml_string - builder = Nokogiri::XML::Builder.new(:encoding => Axlsx::ENCODING) do |xml| - @c.to_xml(xml) - end - c_xml = Nokogiri::XML(builder.to_xml(:save_with => 0)) + c_xml = Nokogiri::XML(@c.to_xml_string(1,1)) assert_equal(c_xml.xpath("/c[@s=1]").size, 1) end def test_to_xml # TODO This could use some much more stringent testing related to the xml content generated! row = @ws.add_row [Time.now, Date.today, true, 1, 1.0, "text", "=sum(A1:A2)"] schema = Nokogiri::XML::Schema(File.open(Axlsx::SML_XSD)) - doc = Nokogiri::XML(@ws.to_xml) + doc = Nokogiri::XML(@ws.to_xml_string) errors = [] schema.validate(doc).each do |error| errors.push error diff --git a/test/workbook/worksheet/tc_col.rb b/test/workbook/worksheet/tc_col.rb new file mode 100644 index 00000000..b28e26e9 --- /dev/null +++ b/test/workbook/worksheet/tc_col.rb @@ -0,0 +1,59 @@ +require 'tc_helper.rb' + +class TestCol < Test::Unit::TestCase + + def setup + @col = Axlsx::Col.new 1, 1 + end + + def test_min_max_required + assert_raise(ArgumentError, 'min and max must be specified when creating a new column') { Axlsx::Col.new } + assert_raise(ArgumentError, 'min and max must be specified when creating a new column') { Axlsx::Col.new nil, nil } + assert_nothing_raised { Axlsx::Col.new 1, 1 } + end + + def test_bestFit + assert_equal(@col.bestFit, nil) + assert_raise(NoMethodError, 'bestFit is read only') { @col.bestFit = 'bob' } + @col.width = 1.999 + assert_equal(@col.bestFit, true, 'bestFit should be true when width has been set') + end + + def test_collapsed + assert_equal(@col.collapsed, nil) + assert_raise(ArgumentError, 'collapsed must be boolean(ish)') { @col.collapsed = 'bob' } + assert_nothing_raised('collapsed must be boolean(ish)') { @col.collapsed = true } + end + + def test_customWidth + assert_equal(@col.customWidth, nil) + @col.width = 3 + assert_raise(NoMethodError, 'customWidth is read only') { @col.customWidth = 3 } + assert_equal(@col.customWidth, true, 'customWidth is true when width is set') + end + + def test_hidden + assert_equal(@col.hidden, nil) + assert_raise(ArgumentError, 'hidden must be boolean(ish)') { @col.hidden = 'bob' } + assert_nothing_raised(ArgumentError, 'hidden must be boolean(ish)') { @col.hidden = true } + end + + def test_outlineLevel + assert_equal(@col.outlineLevel, nil) + assert_raise(ArgumentError, 'outline level cannot be negative') { @col.outlineLevel = -1 } + assert_raise(ArgumentError, 'outline level cannot be greater than 7') { @col.outlineLevel = 8 } + assert_nothing_raised('can set outlineLevel') { @col.outlineLevel = 1 } + end + + def test_phonetic + assert_equal(@col.phonetic, nil) + assert_raise(ArgumentError, 'phonetic must be boolean(ish)') { @col.phonetic = 'bob' } + assert_nothing_raised(ArgumentError, 'phonetic must be boolean(ish)') { @col.phonetic = true } + end + + def test_style + assert_equal(@col.style, nil) + #TODO check that the style specified is actually in the styles xfs collection + end + +end diff --git a/test/workbook/worksheet/tc_page_margins.rb b/test/workbook/worksheet/tc_page_margins.rb index 4c5e43fa..386f47da 100644 --- a/test/workbook/worksheet/tc_page_margins.rb +++ b/test/workbook/worksheet/tc_page_margins.rb @@ -55,9 +55,7 @@ class TestPageMargins < Test::Unit::TestCase @pm.bottom = 1.4 @pm.header = 0.8 @pm.footer = 0.9 - xml = Nokogiri::XML::Builder.new - @pm.to_xml(xml) - doc = Nokogiri::XML.parse(xml.to_xml) + doc = Nokogiri::XML.parse(@pm.to_xml_string) assert_equal(1, doc.xpath(".//pageMargins[@left=1.1][@right=1.2][@top=1.3][@bottom=1.4][@header=0.8][@footer=0.9]").size) end diff --git a/test/workbook/worksheet/tc_row.rb b/test/workbook/worksheet/tc_row.rb index 47b0f054..a953566e 100644 --- a/test/workbook/worksheet/tc_row.rb +++ b/test/workbook/worksheet/tc_row.rb @@ -27,6 +27,19 @@ class TestRow < Test::Unit::TestCase r.cells.each { |c| assert_equal(c.style,1) } end + def test_nil_cells + row = @ws.add_row([nil,1,2,nil,4,5,nil]) + r_s_xml = Nokogiri::XML(row.to_xml_string(0, '')) + assert_equal(r_s_xml.xpath(".//row/c").size, 4) + end + + def test_nil_cell_r + row = @ws.add_row([nil,1,2,nil,4,5,nil]) + r_s_xml = Nokogiri::XML(row.to_xml_string(0, '')) + assert_equal(r_s_xml.xpath(".//row/c").first['r'], 'B1') + assert_equal(r_s_xml.xpath(".//row/c").last['r'], 'F1') + end + def test_index assert_equal(@row.index, @row.worksheet.rows.index(@row)) end @@ -53,9 +66,7 @@ class TestRow < Test::Unit::TestCase end def test_to_xml_without_custom_height - xml = Nokogiri::XML::Builder.new - @row.to_xml(xml) - doc = Nokogiri::XML.parse(xml.to_xml) + doc = Nokogiri::XML.parse(@row.to_xml_string(0)) assert_equal(0, doc.xpath(".//row[@ht]").size) assert_equal(0, doc.xpath(".//row[@customHeight]").size) end @@ -72,12 +83,4 @@ class TestRow < Test::Unit::TestCase assert_equal(r_s_xml.xpath(".//row[@r=1][@ht=20][@customHeight=1]").size, 1) end - def test_to_xml_with_custom_height - @row.height = 20 - xml = Nokogiri::XML::Builder.new - @row.to_xml(xml) - doc = Nokogiri::XML.parse(xml.to_xml) - assert_equal(1, doc.xpath(".//row[@ht=20][@customHeight=1]").size) - end - end diff --git a/test/workbook/worksheet/tc_worksheet.rb b/test/workbook/worksheet/tc_worksheet.rb index d9a89a69..499df864 100644 --- a/test/workbook/worksheet/tc_worksheet.rb +++ b/test/workbook/worksheet/tc_worksheet.rb @@ -2,8 +2,9 @@ require 'tc_helper.rb' class TestWorksheet < Test::Unit::TestCase def setup - p = Axlsx::Package.new - @ws = p.workbook.add_worksheet + @p = Axlsx::Package.new + @wb = @p.workbook + @ws = @wb.add_worksheet end @@ -27,7 +28,7 @@ class TestWorksheet < Test::Unit::TestCase def test_no_autowidth @ws.workbook.use_autowidth = false @ws.add_row [1,2,3,4] - assert_equal(@ws.send(:auto_width, @ws.auto_fit_data[0]), Axlsx::FIXED_COL_WIDTH) + assert_equal(@ws.column_info[0].width, nil) end def test_initialization_options @@ -234,9 +235,15 @@ class TestWorksheet < Test::Unit::TestCase assert_equal(doc.xpath('//xmlns:worksheet/xmlns:tableParts/xmlns:tablePart[@r:id="rId1"]').size, 1) end - def test_to_xml + def test_abs_auto_filter + @ws.add_row [1, "two", 3] + @ws.auto_filter = "A1:C1" + assert_equal(@ws.abs_auto_filter, "'Sheet1'!$A$1:$C$1") + end + + def test_to_xml_string schema = Nokogiri::XML::Schema(File.open(Axlsx::SML_XSD)) - doc = Nokogiri::XML(@ws.to_xml) + doc = Nokogiri::XML(@ws.to_xml_string) errors = [] schema.validate(doc).each do |error| errors.push error @@ -248,7 +255,7 @@ class TestWorksheet < Test::Unit::TestCase def test_valid_with_page_margins @ws.page_margins.set :left => 9 schema = Nokogiri::XML::Schema(File.open(Axlsx::SML_XSD)) - doc = Nokogiri::XML(@ws.to_xml) + doc = Nokogiri::XML(@ws.to_xml_string) errors = [] schema.validate(doc).each do |error| errors.push error @@ -276,52 +283,11 @@ class TestWorksheet < Test::Unit::TestCase assert_nothing_raised { @ws.name = Array.new(31, "A").join('') } end - def test_update_auto_with_data - small = @ws.workbook.styles.add_style(:sz=>2) - big = @ws.workbook.styles.add_style(:sz=>10) - - @ws.add_row ["chasing windmills", "penut"], :style=>small - assert(@ws.auto_fit_data.size == 2, "a data item for each column") - - assert_equal(@ws.auto_fit_data[0], {:sz => 2, :longest => "chasing windmills", :fixed=>nil}, "adding a row updates auto_fit_data if the product of the string length and font is greater for the column") - - - @ws.add_row ["mule"], :style=>big - assert_equal(@ws.auto_fit_data[0], {:sz=>10,:longest=>"mule", :fixed=>nil}, "adding a row updates auto_fit_data if the product of the string length and font is greater for the column") - end - def test_set_fixed_width_column @ws.add_row ["mule", "donkey", "horse"], :widths => [20, :ignore, nil] - assert(@ws.auto_fit_data.size == 3, "a data item for each column") - assert_equal({:sz=>11, :longest=>"mule", :fixed=>20 }, @ws.auto_fit_data[0], "adding a row with fixed width updates :fixed attribute") - assert_equal({:sz=>11, :longest=>"", :fixed=>nil}, @ws.auto_fit_data[1], ":ignore does not set any data") - assert_equal({:sz=>11, :longest=>"horse", :fixed=>nil}, @ws.auto_fit_data[2], "nil, well really anything else just works as normal") - @ws.add_row ["mule", "donkey", "horse"] - assert_equal({:sz=>11, :longest=>"donkey", :fixed=>nil}, @ws.auto_fit_data[1]) - - end - - def test_fixed_widths_with_merged_cells - @ws.add_row ["hey, I'm like really long and stuff so I think you will merge me."] - @ws.merge_cells "A1:C1" - @ws.add_row ["but Im Short!"], :widths=> [14.8] - assert_equal(@ws.send(:auto_width, @ws.auto_fit_data[0]), 14.8) - end - - def test_fixed_width_to_auto - @ws.add_row ["hey, I'm like really long and stuff so I think you will merge me."] - @ws.merge_cells "A1:C1" - @ws.add_row ["but Im Short!"], :widths=> [14.8] - assert_equal(@ws.send(:auto_width, @ws.auto_fit_data[0]), 14.8) - @ws.add_row ["no, I like auto!"], :widths=>[:auto] - assert_equal(@ws.auto_fit_data[0][:fixed], nil) - end - - def test_auto_width - assert(@ws.send(:auto_width, {:sz=>11, :longest=>"fisheries"}) > @ws.send(:auto_width, {:sz=>11, :longest=>"fish"}), "longer strings get a longer auto_width at the same font size") - - assert(@ws.send(:auto_width, {:sz=>11, :longest=>"fish"}) < @ws.send(:auto_width, {:sz=>12, :longest=>"fish"}), "larger fonts produce longer with with same string") - assert_equal(@ws.send(:auto_width, {:sz=>11, :longest => "This is a really long string", :fixed=>0.2}), 0.2, "fixed rules!") + assert(@ws.column_info.size == 3, "a data item for each column") + assert_equal(@ws.column_info[0].width, 20, "adding a row with fixed width updates :fixed attribute") + assert_equal(@ws.column_info[1].width, nil, ":ignore does not set any data") end def test_fixed_height @@ -329,12 +295,10 @@ class TestWorksheet < Test::Unit::TestCase assert_equal(40, @ws.rows[-1].height) end - def test_set_column_width @ws.add_row ["chasing windmills", "penut"] - assert_equal(@ws.auto_fit_data[0][:fixed], nil, 'no fixed by default') @ws.column_widths nil, 0.5 - assert_equal(@ws.auto_fit_data[1][:fixed], 0.5, 'eat my width') + assert_equal(@ws.column_info[1].width, 0.5, 'eat my width') assert_raise(ArgumentError, 'reject invalid columns') { @ws.column_widths 2, 7, nil } assert_raise(ArgumentError, 'only accept unsigned ints') { @ws.column_widths 2, 7, -1 } assert_raise(ArgumentError, 'only accept Integer, Float or Fixnum') { @ws.column_widths 2, 7, "-1" } |
