workbook 0.4.9 → 0.4.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,8 +5,9 @@ module Workbook
5
5
  module RawObjectsStorage
6
6
 
7
7
  # A raw is a 'raw' object, representing a workbook, or cell, or whatever... in a particular format (defined by its class)
8
- def add_raw raw_object
9
- raws[raw_object.class]=raw_object
8
+ def add_raw raw_object, options={}
9
+ class_of_obj = options[:raw_object_class] ? options[:raw_object_class] : raw_object.class
10
+ raws[class_of_obj]=raw_object
10
11
  end
11
12
 
12
13
  # Returns true if there is a template for a certain class, otherwise false
@@ -1,5 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
- require 'rubyXL'
2
+ require 'roo'
3
3
  require 'workbook/readers/xls_shared'
4
4
 
5
5
 
@@ -16,55 +16,22 @@ module Workbook
16
16
  end
17
17
  def load_xlsx file_obj
18
18
  file_obj = file_obj.path if file_obj.is_a? File
19
- sp = RubyXL::Parser.parse(file_obj)
20
- template.add_raw sp
19
+ # file_obj = file_obj.match(/^\/(.*)/) ? file_obj : "./#{file_obj}"
20
+ # p "opening #{file_obj}"
21
+ sp = Roo::Excelx.new(file_obj)
22
+ template.add_raw sp, raw_object_class: Roo::Spreadsheet
21
23
  parse_xlsx sp
22
24
  end
23
25
 
24
- def parse_xlsx xlsx_spreadsheet=template.raws[RubyXL::Workbook], options={}
26
+ def parse_xlsx xlsx_spreadsheet=template.raws[Roo::Spreadsheet], options={}
25
27
  options = {:additional_type_parsing=>false}.merge options
26
- #number_of_worksheets = xlsx_spreadsheet.worksheets.count
27
- xlsx_spreadsheet.worksheets.each_with_index do |worksheet, si|
28
- s = create_or_open_sheet_at(si)
29
- col_widths = []
30
- begin
31
- col_widths = xlsx_spreadsheet.worksheets.first.cols.collect{|a| a[:attributes][:width].to_f if a[:attributes]}
32
- rescue
33
- # Column widths couldn't be read, no big deal...
34
- end
35
-
36
- worksheet.each_with_index do |row, ri|
37
- if row
38
- r = s.table.create_or_open_row_at(ri)
39
- row.cells.each_with_index do |cell,ci|
40
- if cell.nil?
41
- r[ci] = Workbook::Cell.new nil
42
- else
43
- r[ci] = Workbook::Cell.new cell.value
44
- r[ci].parse!
45
- xls_format = cell.style_index
46
- col_width = nil
47
-
48
- if ri == 0
49
- col_width = col_widths[ci]
50
- end
51
- f = template.create_or_find_format_by "style_index_#{cell.style_index}", col_width
52
- f[:width]= col_width
53
- background_color = cell.fill_color
54
- background_color = (background_color.length == 8) ? background_color[2..8] : background_color #ignoring alpha for now.
55
- f[:background_color] = "##{background_color}"
56
-
57
- f[:number_format] = ms_formatting_to_strftime(cell.number_format)
58
- # f[:font_family] = cell.font_name
59
- # f[:color] = "##{cell.font_color}"
60
-
61
- f.add_raw xls_format
62
-
63
- r[ci].format = f
64
- end
65
- end
66
- end
28
+ sheet_index = 0
29
+ xlsx_spreadsheet.each_with_pagename do |sheet_name, sheet|
30
+ s = create_or_open_sheet_at(sheet_index)
31
+ sheet.each_with_index do |row, rowi|
32
+ s.table << row
67
33
  end
34
+ sheet_index += 1
68
35
  end
69
36
  end
70
37
  end
data/lib/workbook/row.rb CHANGED
@@ -20,7 +20,7 @@ module Workbook
20
20
  cells.each do |c|
21
21
  c = c.clone if options[:clone_cells]
22
22
  unless c.is_a? Workbook::Cell
23
- c = Workbook::Cell.new(c)
23
+ c = Workbook::Cell.new(c, {row:self})
24
24
  c.parse!(options[:cell_parse_options]) if options[:parse_cells_on_batch_creation]
25
25
  end
26
26
  push c
@@ -62,14 +62,14 @@ module Workbook
62
62
  # Add cell
63
63
  # @param [Workbook::Cell, Numeric,String,Time,Date,TrueClass,FalseClass,NilClass] cell or value to add
64
64
  def push(cell)
65
- cell = Workbook::Cell.new(cell) unless cell.class == Workbook::Cell
65
+ cell = Workbook::Cell.new(cell, {row:self}) unless cell.class == Workbook::Cell
66
66
  super(cell)
67
67
  end
68
68
 
69
69
  # Add cell
70
70
  # @param [Workbook::Cell, Numeric,String,Time,Date,TrueClass,FalseClass,NilClass] cell or value to add
71
71
  def <<(cell)
72
- cell = Workbook::Cell.new(cell) unless cell.class == Workbook::Cell
72
+ cell = Workbook::Cell.new(cell, {row:self}) unless cell.class == Workbook::Cell
73
73
  super(cell)
74
74
  end
75
75
 
@@ -108,7 +108,7 @@ module Workbook
108
108
  end
109
109
  return rv
110
110
  elsif index_or_hash.is_a? String
111
- symbolized = Workbook::Cell.new(index_or_hash).to_sym
111
+ symbolized = Workbook::Cell.new(index_or_hash, {row:self}).to_sym
112
112
  self[symbolized]
113
113
  else
114
114
  if index_or_hash
@@ -131,7 +131,7 @@ module Workbook
131
131
  if index_or_hash.is_a? Symbol
132
132
  index = table_header_keys.index(index_or_hash)
133
133
  elsif index_or_hash.is_a? String
134
- symbolized = Workbook::Cell.new(index_or_hash).to_sym
134
+ symbolized = Workbook::Cell.new(index_or_hash, {row:self}).to_sym
135
135
  index = table_header_keys.index(symbolized)
136
136
  end
137
137
 
@@ -145,6 +145,7 @@ module Workbook
145
145
  end
146
146
  value_celled.value=(value)
147
147
  end
148
+ value_celled.row = self
148
149
  super(index,value_celled)
149
150
  end
150
151
 
@@ -214,6 +215,13 @@ module Workbook
214
215
  return hash
215
216
  end
216
217
 
218
+ # Quick assessor to the book's template, if it exists
219
+ #
220
+ # @return [Workbook::Template]
221
+ def template
222
+ table.template if table
223
+ end
224
+
217
225
  # Returns a hash representation of this row
218
226
  #
219
227
  # it differs from #to_hash as it doesn't contain the Workbook's Workbook::Cell-objects,
@@ -34,6 +34,9 @@ module Workbook
34
34
  first
35
35
  end
36
36
 
37
+ # Returns the name of this sheet
38
+ #
39
+ # @return [String] the name, defaulting to "Sheet {index}" when none is set
37
40
  def name
38
41
  @name ||= "Sheet #{book.index(self)+1}"
39
42
  end
@@ -231,5 +231,19 @@ module Workbook
231
231
  self
232
232
  end
233
233
 
234
+ # Returns The dimensions of this sheet based on longest row
235
+ # @return [Array] x-width, y-height
236
+ def dimensions
237
+ height = self.count
238
+ width = self.collect{|a| a.length}.max
239
+ [width,height]
240
+ end
241
+
242
+ def columns
243
+ @columns ||= header.collect do |header_cell|
244
+ Column.new(self)
245
+ end
246
+ end
247
+
234
248
  end
235
249
  end
@@ -50,5 +50,10 @@ module Workbook
50
50
  end
51
51
  return @formats[name][variant]
52
52
  end
53
+
54
+ def set_default_formats!
55
+ header_fmt = create_or_find_format_by :header
56
+ header_fmt[:font_weight] = 'bold'
57
+ end
53
58
  end
54
59
  end
@@ -1,9 +1,21 @@
1
- require 'workbook/cell'
1
+ # require 'workbook/modules/cell'
2
2
 
3
3
  module Workbook
4
4
  module Types
5
5
  class Date < Date
6
- include Workbook::Cell
6
+ include Workbook::Modules::Cell
7
+
8
+ def initialize(*args)
9
+ super(*args)
10
+ end
11
+
12
+ def value
13
+ self
14
+ end
15
+
16
+ def value= a
17
+ throw "#value= is no longer available"
18
+ end
7
19
  end
8
20
  end
9
21
  end
@@ -1,9 +1,7 @@
1
- require 'workbook/cell'
2
-
3
1
  module Workbook
4
2
  module Types
5
3
  class FalseClass < FalseClass
6
- include Workbook::Cell
4
+ include Workbook::Modules::Cell
7
5
  end
8
6
  end
9
7
  end
@@ -1,4 +1,4 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  module Workbook
3
- VERSION = '0.4.9'
3
+ VERSION = '0.4.10'
4
4
  end
@@ -1,82 +1,112 @@
1
1
  # -*- encoding : utf-8 -*-
2
- require 'rubyXL'
2
+ require 'axlsx'
3
3
  require 'workbook/readers/xls_shared'
4
4
 
5
5
  module Workbook
6
6
  module Writers
7
7
  module XlsxWriter
8
8
 
9
- # Generates an RubyXL doc, ready for export to XLSX
9
+ # Generates an axlsx doc, ready for export to XLSX
10
10
  #
11
11
  # @param [Hash] options A hash with options (unused so far)
12
- # @return [Spreadsheet] A Spreadsheet object, ready for writing or more lower level operations
12
+ # @return [Axlsx::Package] An object, ready for writing or more lower level operations
13
13
  def to_xlsx options={}
14
- book = init_xlsx_spreadsheet_template
15
- book.theme = RubyXL::Theme.new unless book.theme #workaround bug in rubyxl
14
+ formats_to_xlsx_format
15
+ book = init_xlsx_spreadsheet_template.workbook
16
16
  book.worksheets.pop(book.worksheets.count - self.count) if book.worksheets and book.worksheets.count > self.count
17
17
  self.each_with_index do |s,si|
18
- xls_sheet = xlsx_sheet(si)
19
- xls_sheet.sheet_name = s.name
20
-
18
+ xlsx_sheet = xlsx_sheet(si)
19
+ xlsx_sheet.name = s.name
21
20
  s.table.each_with_index do |r, ri|
21
+ xlsx_row = xlsx_sheet[ri] ? xlsx_sheet[ri] : xlsx_sheet.add_row
22
+ xlsx_row.height = 16
23
+ xlsx_row_a = xlsx_row.to_ary
22
24
  r.each_with_index do |c, ci|
23
- xls_sheet.add_cell(ri, ci, c.value)
24
-
25
+ xlsx_row.add_cell(c.value) unless xlsx_row_a[ci]
26
+ xlsx_cell = xlsx_row_a[ci]
27
+ xlsx_cell.value = c.value
28
+ xlsx_cell.style = c.format.raws[Fixnum] if c.format.raws[Fixnum]
25
29
  end
30
+ xlsx_sheet.send(:update_column_info, xlsx_row.cells, [])
26
31
  end
27
- (xls_sheet.count + 1 - s.table.count).times do |time|
28
- row_to_remove = s.table.count+time
29
-
30
- xls_sheet.delete_row(row_to_remove)
31
- # xls_sheet.row_updated(row_to_remove, xls_sheet.row(row_to_remove))
32
+ (xlsx_sheet.rows.count - s.table.count).times do |time|
33
+ xlsx_sheet.rows.pop
32
34
  end
33
- # xls_sheet.updated_from(s.table.count)
34
- # xls_sheet.dimensions
35
-
36
35
  end
37
- book
36
+ init_xlsx_spreadsheet_template
38
37
  end
39
38
 
40
- # Generates an RubyXL doc, ready for export to XLSX
39
+ # Generates an string ready to be streamed as XLSX
41
40
  #
42
41
  # @param [Hash] options A hash with options (unused so far)
43
42
  # @return [String] A string, ready for streaming, e.g. `send_data workbook.stream_xlsx`
44
43
  def stream_xlsx options = {}
45
- to_xlsx(options).stream.string
44
+ to_xlsx(options).to_stream.string
46
45
  end
47
46
 
48
- # Write the current workbook to Microsoft Excel's new format (using the RubyXL gem)
47
+ # Write the current workbook to Microsoft Excel's XML format (using the Axlsx gem)
49
48
  #
50
49
  # @param [String] filename
51
50
  # @param [Hash] options see #to_xlsx
52
51
  def write_to_xlsx filename="#{title}.xlsx", options={}
53
- if to_xlsx(options).write(filename)
52
+ if to_xlsx(options).serialize(filename)
54
53
  return filename
55
54
  end
56
55
  end
57
56
 
58
57
  def xlsx_sheet a
59
- if xlsx_template.worksheets[a]
60
- return xlsx_template.worksheets[a]
58
+ if xlsx_template.workbook.worksheets[a]
59
+ return xlsx_template.workbook.worksheets[a]
61
60
  else
62
- xlsx_template.create_worksheet
63
- self.xls_sheet a
61
+ xlsx_template.workbook.add_worksheet
62
+ self.xlsx_sheet a
64
63
  end
65
64
  end
66
65
 
67
66
  def xlsx_template
68
- return template.raws[RubyXL::Workbook]
67
+ return template.raws[Axlsx::Package]
69
68
  end
70
69
 
71
70
  def init_xlsx_spreadsheet_template
72
- if self.xlsx_template.is_a? RubyXL::Workbook
71
+ if self.xlsx_template.is_a? Axlsx::Package
73
72
  return self.xlsx_template
74
73
  else
75
- t = RubyXL::Workbook.new
74
+ t = Axlsx::Package.new
76
75
  template.add_raw t
76
+ template.set_default_formats!
77
77
  return t
78
78
  end
79
79
  end
80
+
81
+ def formats_to_xlsx_format
82
+ template.formats.each do |n,v|
83
+ v.each do | t,s |
84
+ format_to_xlsx_format(s)
85
+ end
86
+ end
87
+ end
88
+
89
+ def format_to_xlsx_format f
90
+ xlsfmt = nil
91
+ unless f.is_a? Workbook::Format
92
+ f = Workbook::Format.new f
93
+ end
94
+
95
+ xlsfmt={}
96
+ xlsfmt[:fg_color] = "#{f[:color]}00" if f[:color]
97
+ xlsfmt[:b] = true if f[:font_weight] == "bold" or f[:font_weight].to_i >= 600 or f[:"font_style"].to_s.match "oblique"
98
+ xlsfmt[:i] = true if f[:font_style] == "italic"
99
+ xlsfmt[:u] = true if f[:text_decoration].to_s.match("underline")
100
+ xlsfmt[:bg_color] = f[:background_color] if f[:background_color]
101
+ xlsfmt[:format_code] = strftime_to_ms_format(f[:number_format]) if f[:number_format]
102
+ xlsfmt[:font_name] = f[:font_family].split.first if f[:font_family]
103
+ xlsfmt[:family] = parse_font_family(f) if f[:font_family]
104
+ f.add_raw init_xlsx_spreadsheet_template.workbook.styles.add_style(xlsfmt)
105
+ # wb.styles{|a| p a.add_style({}).class }
106
+
107
+ f.add_raw xlsfmt
108
+ return xlsfmt
109
+ end
80
110
  end
81
111
  end
82
112
  end
data/test/test_column.rb CHANGED
@@ -3,6 +3,16 @@ require File.join(File.dirname(__FILE__), 'helper')
3
3
 
4
4
  class TestColumn < Minitest::Test
5
5
 
6
+ def new_table
7
+ Workbook::Table.new([
8
+ ["a","b","c","d"],
9
+ [true,3.2,"asdf",1],
10
+ [true,3.2,"asdf",1],
11
+ [false,3.2,"asdf",1],
12
+ [true,3.2,"asdf",1]
13
+ ])
14
+ end
15
+
6
16
  def test_init
7
17
  c = Workbook::Column.new
8
18
  assert_equal(Workbook::Column, c.class)
@@ -21,4 +31,24 @@ class TestColumn < Minitest::Test
21
31
  assert_equal(Workbook::Table.new, c.table)
22
32
  assert_raises(ArgumentError) { c.table = false }
23
33
  end
34
+
35
+ def test_index
36
+ t = new_table
37
+ assert_equal(t.columns.first.index, 0)
38
+ assert_equal(t.columns.last.index, 3)
39
+ end
40
+
41
+ def test_column_type
42
+ t = new_table
43
+ assert_equal([:boolean, :float, :string, :integer], t.columns.collect{|a| a.column_type})
44
+ t = new_table
45
+ t.last.last.value = 1.1
46
+ assert_equal([:boolean, :float, :string, :string], t.columns.collect{|a| a.column_type})
47
+ t = new_table
48
+ t[2][3] = nil
49
+ assert_equal([:boolean, :float, :string, :integer], t.columns.collect{|a| a.column_type})
50
+ t = new_table
51
+ t[2].delete_at(3)
52
+ assert_equal([:boolean, :float, :string, :integer], t.columns.collect{|a| a.column_type})
53
+ end
24
54
  end
@@ -1,7 +1,7 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  require File.join(File.dirname(__FILE__), 'helper')
3
3
 
4
- class TestCell < Minitest::Test
4
+ class TestModulesCell < Minitest::Test
5
5
 
6
6
 
7
7
  def test_init
@@ -115,4 +115,11 @@ class TestCell < Minitest::Test
115
115
  assert_equal(3,c.rowspan)
116
116
  assert_equal(nil,c.colspan)
117
117
  end
118
+
119
+ def cell_type
120
+ {1 => :integer, 3.2 => :float, true => :boolean, "asdf" => :string}.each do |k,v|
121
+ c = Workbook::Cel.new(k)
122
+ assert_equal(v,c.cell_type)
123
+ end
124
+ end
118
125
  end
@@ -9,7 +9,7 @@ module Readers
9
9
  assert_equal(90588,w.sheet.table[2][:b].value)
10
10
  assert_equal(DateTime.new(2011,11,15),w.sheet.table[3][:d].value)
11
11
  # assert_equal("#CCFFCC",w.sheet.table[3][:c].format[:background_color]) #colour compatibility turned off for now...
12
- # assert_equal(8,w.sheet.table.first[:b].format[:width].round)
12
+ #assert_equal(8,w.sheet.table.first[:b].format[:width].round)
13
13
  # assert_equal(4,w.sheet.table.first[:a].format[:width].round)
14
14
  # assert_equal(25,w.sheet.table.first[:c].format[:width].round)
15
15
  end
@@ -29,11 +29,5 @@ module Readers
29
29
  assert_equal(nil,w.ms_formatting_to_strftime(nil));
30
30
  assert_equal(nil,w.ms_formatting_to_strftime(""));
31
31
  end
32
- # def test_monkey_patched_ruby_xl_is_date_format?
33
- # w = RubyXL::Workbook.new
34
- # assert_equal(false, w.is_date_format?(nil))
35
- # assert_equal(false, w.is_date_format?(""))
36
- # assert_equal(true, w.is_date_format?("D-M-YYY"))
37
- # end
38
32
  end
39
33
  end