workbook 0.4.7 → 0.4.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/workbook/book.rb +15 -1
- data/lib/workbook/column.rb +8 -2
- data/lib/workbook/readers/xls_shared.rb +5 -0
- data/lib/workbook/row.rb +4 -5
- data/lib/workbook/sheet.rb +0 -1
- data/lib/workbook/table.rb +12 -4
- data/lib/workbook/version.rb +1 -1
- data/lib/workbook/writers/html_writer.rb +12 -12
- data/lib/workbook/writers/xls_writer.rb +27 -30
- data/test/artifacts/heavy.xlsx +0 -0
- data/test/test_column.rb +11 -2
- data/test/test_readers_xlsx_reader.rb +0 -1
- data/test/test_table.rb +2 -0
- data/workbook.gemspec +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d9cf45e1ff6addbcf502334bf786df43a7c7714a
|
4
|
+
data.tar.gz: 6f219b42f0c6b17f8ed9ac32c57b3032efe74f12
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8ca18e838d71e6bee71a343728f9d0e7cd5843511e7e2e13c9d5a6432e2ecad2d78dc37913d87b4744f86f4ab46e386449fbf2f9488a143329514704c1221726
|
7
|
+
data.tar.gz: db7378ab0541f0f6ecdc0fa66f707f5c58e908da0086d57eac010d8b4057534ac4cb7c3d809520a6702ada150a3f88c141913b4e5bbdf9096d7e3d21db733faa
|
data/README.md
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Workbook
|
2
|
-
[](https://codeclimate.com/github/murb/workbook) [](https://codeclimate.com/github/murb/workbook) [](https://travis-ci.org/murb/workbook) [](http://badge.fury.io/rb/workbook)
|
3
3
|
|
4
4
|
Goal of this gem is to make working with workbooks (spreadsheets) as programmer friendly as possible. Not reinventing a totally new DSL or all kinds of new methodnames, but just borrowing from known concepts such as hashes and arrays (much like (Faster)CSV does)). Workbook is a gem that mimicks a typical spreadsheet, a bundle of sheets, bundled in a *workbook*. A sheet may contain one or more tables (which might the multi table sheets of Apple Numbers or Excel ranges). Basically:
|
5
5
|
|
@@ -130,7 +130,7 @@ In case you want to display a formatted table in HTML, some conversion is offere
|
|
130
130
|
## Compatibility
|
131
131
|
|
132
132
|
Workbook is automatically tested for ruby 1.9, 2.0 and 2.1. Most of it works with 1.8.7 and jruby but not all tests give equal results.
|
133
|
-
Check [Travis for Workbook's current build status](https://travis-ci.org/murb/workbook) [ [](https://travis-ci.org/murb/workbook).
|
134
134
|
|
135
135
|
## Future
|
136
136
|
|
data/lib/workbook/book.rb
CHANGED
@@ -15,7 +15,21 @@ module Workbook
|
|
15
15
|
# The Book class is the container of sheets. It can be inialized by either the standard initalizer or the open method. The
|
16
16
|
# Book class can also keep a reference to a template class, storing shared formatting options.
|
17
17
|
#
|
18
|
-
SUPPORTED_MIME_TYPES =
|
18
|
+
SUPPORTED_MIME_TYPES = [
|
19
|
+
"application/zip",
|
20
|
+
"text/plain",
|
21
|
+
"application/x-ariadne-download",
|
22
|
+
"application/vnd.ms-excel",
|
23
|
+
"application/excel",
|
24
|
+
"application/vnd.ms-office",
|
25
|
+
"text/csv",
|
26
|
+
"text/tab-separated-values",
|
27
|
+
"application/x-ms-excel",
|
28
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
29
|
+
"application/vnd.oasis.opendocument.spreadsheet",
|
30
|
+
"application/x-vnd.oasis.opendocument.spreadsheet",
|
31
|
+
"CDF V2 Document, No summary info"
|
32
|
+
]
|
19
33
|
|
20
34
|
class Book < Array
|
21
35
|
|
data/lib/workbook/column.rb
CHANGED
@@ -3,9 +3,10 @@ module Workbook
|
|
3
3
|
|
4
4
|
# Column helps us to store general properties of a column, and lets us easily perform operations on values within a column
|
5
5
|
class Column
|
6
|
-
attr_accessor :limit #character limit
|
6
|
+
attr_accessor :limit, :table #character limit
|
7
7
|
|
8
|
-
def initialize(options={})
|
8
|
+
def initialize(table=nil, options={})
|
9
|
+
self.table = table
|
9
10
|
options.each{ |k,v| self.public_send("#{k}=",v) }
|
10
11
|
end
|
11
12
|
|
@@ -14,6 +15,11 @@ module Workbook
|
|
14
15
|
@column_type
|
15
16
|
end
|
16
17
|
|
18
|
+
def table= t
|
19
|
+
raise(ArgumentError, "value should be nil or Workbook::Table") unless [NilClass,Workbook::Table].include? t.class
|
20
|
+
@table = t
|
21
|
+
end
|
22
|
+
|
17
23
|
def column_type= column_type
|
18
24
|
if [:primary_key, :string, :text, :integer, :float, :decimal, :datetime, :date, :binary, :boolean].include? column_type
|
19
25
|
@column_type = column_type
|
@@ -2,6 +2,11 @@
|
|
2
2
|
module Workbook
|
3
3
|
module Readers
|
4
4
|
module XlsShared
|
5
|
+
|
6
|
+
# Converts standard (ruby/C++/unix/...) strftime formatting to MS's formatting
|
7
|
+
#
|
8
|
+
# @param [String, nil] numberformat (nil returns nil)
|
9
|
+
# @return [String, nil]
|
5
10
|
def ms_formatting_to_strftime ms_nr_format
|
6
11
|
if ms_nr_format
|
7
12
|
ms_nr_format = ms_nr_format.to_s.downcase
|
data/lib/workbook/row.rb
CHANGED
@@ -14,13 +14,12 @@ module Workbook
|
|
14
14
|
# @param [Workbook::Table] table a row normally belongs to a table, reference it here
|
15
15
|
# @param [Hash] options Supprted options: parse_cells_on_batch_creation (parse cell values during row-initalization, default: false), cell_parse_options (default {}, see Workbook::Modules::TypeParser)
|
16
16
|
def initialize cells=[], table=nil, options={}
|
17
|
-
options=options ? {:parse_cells_on_batch_creation=>false,:cell_parse_options=>{}}.merge(options) : {}
|
17
|
+
options=options ? {:parse_cells_on_batch_creation=>false,:cell_parse_options=>{},:clone_cells=>false}.merge(options) : {}
|
18
18
|
cells = [] if cells==nil
|
19
19
|
self.table= table
|
20
20
|
cells.each do |c|
|
21
|
-
|
22
|
-
|
23
|
-
else
|
21
|
+
c = c.clone if options[:clone_cells]
|
22
|
+
unless c.is_a? Workbook::Cell
|
24
23
|
c = Workbook::Cell.new(c)
|
25
24
|
c.parse!(options[:cell_parse_options]) if options[:parse_cells_on_batch_creation]
|
26
25
|
end
|
@@ -258,7 +257,7 @@ module Workbook
|
|
258
257
|
#
|
259
258
|
# @return [Workbook::Row] a cloned copy of self with cells
|
260
259
|
def clone
|
261
|
-
Workbook::Row.new(
|
260
|
+
Workbook::Row.new(self, nil, {:clone_cells=>true})
|
262
261
|
end
|
263
262
|
|
264
263
|
# remove all the trailing nil-cells (returning a trimmed clone)
|
data/lib/workbook/sheet.rb
CHANGED
@@ -41,7 +41,6 @@ module Workbook
|
|
41
41
|
# Set the first table of this sheet with a table or array of cells/values
|
42
42
|
# @param [Workbook::Table, Array<Array>] table The new first table of this sheet
|
43
43
|
# @param [Hash] options are forwarded to Workbook::Table.new
|
44
|
-
|
45
44
|
# @return [Workbook::Table] the first table of this sheet
|
46
45
|
def table= table, options={}
|
47
46
|
if table.is_a? Workbook::Table
|
data/lib/workbook/table.rb
CHANGED
@@ -15,15 +15,17 @@ module Workbook
|
|
15
15
|
|
16
16
|
attr_accessor :sheet
|
17
17
|
attr_accessor :name
|
18
|
+
attr_accessor :columns
|
18
19
|
|
19
20
|
def initialize row_cel_values=[], sheet=nil, options={}
|
20
21
|
row_cel_values = [] if row_cel_values == nil
|
21
|
-
row_cel_values.
|
22
|
+
row_cel_values.each_with_index do |r,ri|
|
22
23
|
if r.is_a? Workbook::Row
|
23
24
|
r.table = self
|
24
25
|
else
|
25
26
|
r = Workbook::Row.new(r,self, options)
|
26
27
|
end
|
28
|
+
define_columns_with_row(r) if ri == 0
|
27
29
|
end
|
28
30
|
self.sheet = sheet
|
29
31
|
# Column data is considered as a 'row' with 'cells' that contain 'formatting'
|
@@ -54,6 +56,12 @@ module Workbook
|
|
54
56
|
@header = h
|
55
57
|
end
|
56
58
|
|
59
|
+
def define_columns_with_row(r)
|
60
|
+
self.columns = r.collect do |column|
|
61
|
+
Workbook::Column.new self, {}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
57
65
|
# Generates a new row, with optionally predefined cell-values, that is already connected to this table.
|
58
66
|
def new_row cell_values=[]
|
59
67
|
r = Workbook::Row.new(cell_values,self)
|
@@ -148,10 +156,10 @@ module Workbook
|
|
148
156
|
# @return [Workbook::Row, Workbook::Cell, nil]
|
149
157
|
def [](index_or_string)
|
150
158
|
if index_or_string.is_a? String
|
151
|
-
match = index_or_string.
|
152
|
-
|
159
|
+
match = index_or_string.match(/([A-Z]+)([0-9]*)/i)
|
160
|
+
col_index = alpha_index_to_number_index(match[1])
|
153
161
|
row_index = match[2].to_i - 1
|
154
|
-
return self[row_index][
|
162
|
+
return self[row_index][col_index]
|
155
163
|
elsif index_or_string.is_a? Range
|
156
164
|
collection = to_a[index_or_string].collect{|a| a.clone}
|
157
165
|
return Workbook::Table.new collection
|
data/lib/workbook/version.rb
CHANGED
@@ -10,7 +10,6 @@ module Workbook
|
|
10
10
|
# @param [Hash] options A hash with options
|
11
11
|
# @return [String] A String containing the HTML code
|
12
12
|
def to_html options={}
|
13
|
-
options = {:style_with_inline_css=>false}.merge(options)
|
14
13
|
builder = Nokogiri::XML::Builder.new do |doc|
|
15
14
|
doc.html {
|
16
15
|
doc.body {
|
@@ -56,13 +55,9 @@ module Workbook
|
|
56
55
|
if header
|
57
56
|
doc.tr do
|
58
57
|
header.each do |cell|
|
59
|
-
|
60
|
-
td_options = classnames != "" ? {:class=>classnames} : {}
|
61
|
-
td_options = td_options.merge({:style=>cell.format.to_css}) if options[:style_with_inline_css] and cell.format.to_css != ""
|
62
|
-
td_options = td_options.merge({:colspan=>cell.colspan}) if cell.colspan
|
63
|
-
td_options = td_options.merge({:rowspan=>cell.rowspan}) if cell.rowspan
|
58
|
+
th_options = build_cell_options cell, options
|
64
59
|
unless cell.value.class == Workbook::NilValue
|
65
|
-
doc.th(
|
60
|
+
doc.th(th_options) do
|
66
61
|
doc.text cell.value
|
67
62
|
end
|
68
63
|
end
|
@@ -75,11 +70,7 @@ module Workbook
|
|
75
70
|
unless row.header?
|
76
71
|
doc.tr do
|
77
72
|
row.each do |cell|
|
78
|
-
|
79
|
-
td_options = classnames != "" ? {:class=>classnames} : {}
|
80
|
-
td_options = td_options.merge({:style=>cell.format.to_css}) if options[:style_with_inline_css] and cell.format.to_css != ""
|
81
|
-
td_options = td_options.merge({:colspan=>cell.colspan}) if cell.colspan
|
82
|
-
td_options = td_options.merge({:rowspan=>cell.rowspan}) if cell.rowspan
|
73
|
+
td_options = build_cell_options cell, options
|
83
74
|
unless cell.value.class == Workbook::NilValue
|
84
75
|
doc.td(td_options) do
|
85
76
|
doc.text cell.value
|
@@ -94,6 +85,15 @@ module Workbook
|
|
94
85
|
end
|
95
86
|
return builder.doc.to_xhtml
|
96
87
|
end
|
88
|
+
private
|
89
|
+
def build_cell_options cell, options={}
|
90
|
+
classnames = cell.format.all_names.join(" ").strip
|
91
|
+
td_options = classnames != "" ? {:class=>classnames} : {}
|
92
|
+
td_options = td_options.merge({:style=>cell.format.to_css}) if options[:style_with_inline_css] and cell.format.to_css != ""
|
93
|
+
td_options = td_options.merge({:colspan=>cell.colspan}) if cell.colspan
|
94
|
+
td_options = td_options.merge({:rowspan=>cell.rowspan}) if cell.rowspan
|
95
|
+
return td_options
|
96
|
+
end
|
97
97
|
end
|
98
98
|
end
|
99
99
|
end
|
@@ -30,25 +30,33 @@ module Workbook
|
|
30
30
|
end
|
31
31
|
(xls_sheet.last_row_index + 1 - s.table.count).times do |time|
|
32
32
|
row_to_remove = s.table.count+time
|
33
|
-
xls_sheet
|
34
|
-
xls_sheet.row(row_to_remove)[ci]=nil
|
35
|
-
end
|
36
|
-
|
37
|
-
xls_sheet.delete_row(row_to_remove)
|
38
|
-
xls_sheet.row_updated(row_to_remove, xls_sheet.row(row_to_remove))
|
33
|
+
remove_row(xls_sheet,row_to_remove)
|
39
34
|
end
|
40
35
|
xls_sheet.updated_from(s.table.count)
|
41
36
|
xls_sheet.dimensions
|
42
37
|
|
43
38
|
end
|
44
|
-
# kind of a hack,
|
39
|
+
# kind of a hack, deleting by popping from xls worksheet results in errors in MS Excel (not LibreOffice)
|
45
40
|
# book.worksheets.pop(book.worksheets.count - self.count) if book.worksheets and book.worksheets.count > self.count
|
46
|
-
book.worksheets.each_with_index do |
|
47
|
-
|
41
|
+
book.worksheets.each_with_index do |xls_sheet, si|
|
42
|
+
if self[si]
|
43
|
+
xls_sheet.visibility = :visible
|
44
|
+
else
|
45
|
+
xls_sheet.visibility = :strong_hidden
|
46
|
+
#also make sure all data is removed, in case someone finds out about this 'trick'
|
47
|
+
xls_sheet.name = "RemovedSheet#{si}"
|
48
|
+
(xls_sheet.last_row_index + 1).times do |row_index|
|
49
|
+
remove_row(xls_sheet,row_index)
|
50
|
+
end
|
51
|
+
end
|
48
52
|
end
|
53
|
+
# even after removing the worksheet's content... which solved some incompatibilities, but not for popping worksheets
|
54
|
+
# book.worksheets.pop(book.worksheets.count - self.count) if book.worksheets and book.worksheets.count > self.count
|
49
55
|
book
|
50
56
|
end
|
51
57
|
|
58
|
+
|
59
|
+
|
52
60
|
# Generates an Spreadsheet (from the spreadsheet gem) in order to build an XlS
|
53
61
|
#
|
54
62
|
# @param [Workbook::Format, Hash] f A Workbook::Format or hash with format-options (:font_weight, :rotation, :background_color, :number_format, :text_direction, :color, :font_family)
|
@@ -97,27 +105,6 @@ module Workbook
|
|
97
105
|
end
|
98
106
|
end
|
99
107
|
|
100
|
-
|
101
|
-
# Attempt to convert html-hex color value to xls color number
|
102
|
-
#
|
103
|
-
# @param [String] hex color
|
104
|
-
# @return [String] xls color
|
105
|
-
def html_color_to_xls_color hex
|
106
|
-
Workbook::Readers::XlsShared::XLS_COLORS.each do |k,v|
|
107
|
-
return k if (v == hex or (hex and hex != "" and k == hex.to_sym))
|
108
|
-
end
|
109
|
-
return nil
|
110
|
-
end
|
111
|
-
|
112
|
-
# Converts standard (ruby/C++/unix/...) strftime formatting to MS's formatting
|
113
|
-
#
|
114
|
-
# @param [String, nil] numberformat (nil returns nil)
|
115
|
-
# @return [String, nil]
|
116
|
-
def strftime_to_ms_format numberformat
|
117
|
-
return nil if numberformat.nil?
|
118
|
-
return numberformat.gsub('%Y','yyyy').gsub('%A','dddd').gsub('%B','mmmm').gsub('%a','ddd').gsub('%b','mmm').gsub('%y','yy').gsub('%d','dd').gsub('%m','mm').gsub('%y','y').gsub('%y','%%y').gsub('%e','d')
|
119
|
-
end
|
120
|
-
|
121
108
|
# Write the current workbook to Microsoft Excel format (using the spreadsheet gem)
|
122
109
|
#
|
123
110
|
# @param [String] filename
|
@@ -150,6 +137,16 @@ module Workbook
|
|
150
137
|
return t
|
151
138
|
end
|
152
139
|
end
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
def remove_row(xls_sheet,row_index)
|
144
|
+
xls_sheet.row(row_index).each_with_index do |c, ci|
|
145
|
+
xls_sheet.row(row_index)[ci]=nil
|
146
|
+
end
|
147
|
+
xls_sheet.delete_row(row_index)
|
148
|
+
xls_sheet.row_updated(row_index, xls_sheet.row(row_index))
|
149
|
+
end
|
153
150
|
end
|
154
151
|
end
|
155
152
|
end
|
Binary file
|
data/test/test_column.rb
CHANGED
@@ -6,10 +6,19 @@ class TestColumn < Test::Unit::TestCase
|
|
6
6
|
def test_init
|
7
7
|
c = Workbook::Column.new
|
8
8
|
assert_equal(Workbook::Column, c.class)
|
9
|
-
c = Workbook::Column.new({:limit=>20,:default=>"asdf", :column_type=>:boolean})
|
9
|
+
c = Workbook::Column.new(nil, {:limit=>20,:default=>"asdf", :column_type=>:boolean})
|
10
|
+
c = Workbook::Column.new(Workbook::Table.new, {:limit=>20,:default=>"asdf", :column_type=>:boolean})
|
10
11
|
assert_equal(20, c.limit)
|
11
12
|
assert_equal(Workbook::Cell.new("asdf"), c.default)
|
12
13
|
assert_equal(:boolean, c.column_type)
|
13
|
-
assert_raise(ArgumentError) { Workbook::Column.new(
|
14
|
+
assert_raise(ArgumentError) { Workbook::Column.new(true) }
|
15
|
+
assert_raise(ArgumentError) { Workbook::Column.new(nil, {:limit=>20,:default=>"asdf", :column_type=>:bodfolean}) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_table
|
19
|
+
c = Workbook::Column.new
|
20
|
+
c.table = Workbook::Table.new
|
21
|
+
assert_equal(Workbook::Table.new, c.table)
|
22
|
+
assert_raise(ArgumentError) { c.table = false }
|
14
23
|
end
|
15
24
|
end
|
@@ -29,7 +29,6 @@ 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
|
-
|
33
32
|
# def test_monkey_patched_ruby_xl_is_date_format?
|
34
33
|
# w = RubyXL::Workbook.new
|
35
34
|
# assert_equal(false, w.is_date_format?(nil))
|
data/test/test_table.rb
CHANGED
data/workbook.gemspec
CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
|
|
15
15
|
s.authors = ["Maarten Brouwers"]
|
16
16
|
s.add_development_dependency 'ruby-prof', '~> 0.14'
|
17
17
|
s.add_dependency('rubyzip', '~>1')
|
18
|
-
s.add_dependency('spreadsheet', '~> 0
|
18
|
+
s.add_dependency('spreadsheet', '~> 1.0')
|
19
19
|
s.add_dependency('fastercsv') if RUBY_VERSION < "1.9"
|
20
20
|
s.add_dependency("rchardet", "~> 1.3")
|
21
21
|
s.add_dependency("rake", '~> 10.0')
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: workbook
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Maarten Brouwers
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0
|
47
|
+
version: '1.0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0
|
54
|
+
version: '1.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rchardet
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -250,6 +250,7 @@ files:
|
|
250
250
|
- test/artifacts/excel_different_types.xls
|
251
251
|
- test/artifacts/excel_different_types.xlsx
|
252
252
|
- test/artifacts/failing_import1.xls
|
253
|
+
- test/artifacts/heavy.xlsx
|
253
254
|
- test/artifacts/native_xlsx.xlsx
|
254
255
|
- test/artifacts/sheet_with_combined_cells.ods
|
255
256
|
- test/artifacts/sheetduplication.xls
|
@@ -305,7 +306,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
305
306
|
version: '0'
|
306
307
|
requirements: []
|
307
308
|
rubyforge_project: workbook
|
308
|
-
rubygems_version: 2.2.
|
309
|
+
rubygems_version: 2.2.2
|
309
310
|
signing_key:
|
310
311
|
specification_version: 4
|
311
312
|
summary: Workbook is a datastructure to contain books of tables (an anlogy used in
|
@@ -325,6 +326,7 @@ test_files:
|
|
325
326
|
- test/artifacts/excel_different_types.xls
|
326
327
|
- test/artifacts/excel_different_types.xlsx
|
327
328
|
- test/artifacts/failing_import1.xls
|
329
|
+
- test/artifacts/heavy.xlsx
|
328
330
|
- test/artifacts/native_xlsx.xlsx
|
329
331
|
- test/artifacts/sheet_with_combined_cells.ods
|
330
332
|
- test/artifacts/sheetduplication.xls
|
@@ -359,4 +361,3 @@ test_files:
|
|
359
361
|
- test/test_writers_json_writer.rb
|
360
362
|
- test/test_writers_xls_writer.rb
|
361
363
|
- test/test_writers_xlsx_writer.rb
|
362
|
-
has_rdoc:
|