roo 1.13.2 → 2.0.1
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/.gitignore +7 -0
- data/.simplecov +4 -0
- data/.travis.yml +13 -0
- data/CHANGELOG.md +515 -0
- data/Gemfile +16 -10
- data/Guardfile +24 -0
- data/LICENSE +3 -1
- data/README.md +254 -0
- data/Rakefile +23 -23
- data/examples/roo_soap_client.rb +28 -31
- data/examples/roo_soap_server.rb +4 -6
- data/examples/write_me.rb +9 -10
- data/lib/roo/base.rb +334 -395
- data/lib/roo/csv.rb +120 -113
- data/lib/roo/excelx/cell.rb +77 -0
- data/lib/roo/excelx/comments.rb +22 -0
- data/lib/roo/excelx/extractor.rb +22 -0
- data/lib/roo/excelx/relationships.rb +25 -0
- data/lib/roo/excelx/shared_strings.rb +37 -0
- data/lib/roo/excelx/sheet.rb +107 -0
- data/lib/roo/excelx/sheet_doc.rb +200 -0
- data/lib/roo/excelx/styles.rb +64 -0
- data/lib/roo/excelx/workbook.rb +59 -0
- data/lib/roo/excelx.rb +413 -597
- data/lib/roo/font.rb +17 -0
- data/lib/roo/libre_office.rb +5 -0
- data/lib/roo/link.rb +15 -0
- data/lib/roo/{openoffice.rb → open_office.rb} +681 -496
- data/lib/roo/spreadsheet.rb +20 -23
- data/lib/roo/utils.rb +78 -0
- data/lib/roo/version.rb +3 -0
- data/lib/roo.rb +18 -24
- data/roo.gemspec +20 -204
- data/spec/lib/roo/base_spec.rb +1 -4
- data/spec/lib/roo/csv_spec.rb +21 -13
- data/spec/lib/roo/excelx/format_spec.rb +7 -6
- data/spec/lib/roo/excelx_spec.rb +424 -11
- data/spec/lib/roo/libreoffice_spec.rb +16 -6
- data/spec/lib/roo/openoffice_spec.rb +13 -8
- data/spec/lib/roo/spreadsheet_spec.rb +40 -12
- data/spec/lib/roo/utils_spec.rb +106 -0
- data/spec/spec_helper.rb +2 -1
- data/test/test_generic_spreadsheet.rb +117 -139
- data/test/test_helper.rb +9 -56
- data/test/test_roo.rb +274 -478
- metadata +65 -303
- data/CHANGELOG +0 -417
- data/Gemfile.lock +0 -78
- data/README.markdown +0 -126
- data/VERSION +0 -1
- data/lib/roo/excel.rb +0 -355
- data/lib/roo/excel2003xml.rb +0 -300
- data/lib/roo/google.rb +0 -292
- data/lib/roo/roo_rails_helper.rb +0 -83
- data/lib/roo/worksheet.rb +0 -18
- data/scripts/txt2html +0 -67
- data/spec/lib/roo/excel2003xml_spec.rb +0 -15
- data/spec/lib/roo/excel_spec.rb +0 -17
- data/spec/lib/roo/google_spec.rb +0 -64
- data/test/files/1900_base.xls +0 -0
- data/test/files/1900_base.xlsx +0 -0
- data/test/files/1904_base.xls +0 -0
- data/test/files/1904_base.xlsx +0 -0
- data/test/files/Bibelbund.csv +0 -3741
- data/test/files/Bibelbund.ods +0 -0
- data/test/files/Bibelbund.xls +0 -0
- data/test/files/Bibelbund.xlsx +0 -0
- data/test/files/Bibelbund.xml +0 -62518
- data/test/files/Bibelbund1.ods +0 -0
- data/test/files/Pfand_from_windows_phone.xlsx +0 -0
- data/test/files/bad_excel_date.xls +0 -0
- data/test/files/bbu.ods +0 -0
- data/test/files/bbu.xls +0 -0
- data/test/files/bbu.xlsx +0 -0
- data/test/files/bbu.xml +0 -152
- data/test/files/bode-v1.ods.zip +0 -0
- data/test/files/bode-v1.xls.zip +0 -0
- data/test/files/boolean.csv +0 -2
- data/test/files/boolean.ods +0 -0
- data/test/files/boolean.xls +0 -0
- data/test/files/boolean.xlsx +0 -0
- data/test/files/boolean.xml +0 -112
- data/test/files/borders.ods +0 -0
- data/test/files/borders.xls +0 -0
- data/test/files/borders.xlsx +0 -0
- data/test/files/borders.xml +0 -144
- data/test/files/bug-numbered-sheet-names.xlsx +0 -0
- data/test/files/bug-row-column-fixnum-float.xls +0 -0
- data/test/files/bug-row-column-fixnum-float.xml +0 -127
- data/test/files/comments.ods +0 -0
- data/test/files/comments.xls +0 -0
- data/test/files/comments.xlsx +0 -0
- data/test/files/csvtypes.csv +0 -1
- data/test/files/datetime.ods +0 -0
- data/test/files/datetime.xls +0 -0
- data/test/files/datetime.xlsx +0 -0
- data/test/files/datetime.xml +0 -142
- data/test/files/datetime_floatconv.xls +0 -0
- data/test/files/datetime_floatconv.xml +0 -148
- data/test/files/dreimalvier.ods +0 -0
- data/test/files/emptysheets.ods +0 -0
- data/test/files/emptysheets.xls +0 -0
- data/test/files/emptysheets.xlsx +0 -0
- data/test/files/emptysheets.xml +0 -105
- data/test/files/excel2003.xml +0 -21140
- data/test/files/false_encoding.xls +0 -0
- data/test/files/false_encoding.xml +0 -132
- data/test/files/file_item_error.xlsx +0 -0
- data/test/files/formula.ods +0 -0
- data/test/files/formula.xls +0 -0
- data/test/files/formula.xlsx +0 -0
- data/test/files/formula.xml +0 -134
- data/test/files/formula_parse_error.xls +0 -0
- data/test/files/formula_parse_error.xml +0 -1833
- data/test/files/formula_string_error.xlsx +0 -0
- data/test/files/html-escape.ods +0 -0
- data/test/files/link.xls +0 -0
- data/test/files/link.xlsx +0 -0
- data/test/files/matrix.ods +0 -0
- data/test/files/matrix.xls +0 -0
- data/test/files/named_cells.ods +0 -0
- data/test/files/named_cells.xls +0 -0
- data/test/files/named_cells.xlsx +0 -0
- data/test/files/no_spreadsheet_file.txt +0 -1
- data/test/files/numbers1.csv +0 -18
- data/test/files/numbers1.ods +0 -0
- data/test/files/numbers1.xls +0 -0
- data/test/files/numbers1.xlsx +0 -0
- data/test/files/numbers1.xml +0 -312
- data/test/files/numeric-link.xlsx +0 -0
- data/test/files/only_one_sheet.ods +0 -0
- data/test/files/only_one_sheet.xls +0 -0
- data/test/files/only_one_sheet.xlsx +0 -0
- data/test/files/only_one_sheet.xml +0 -67
- data/test/files/paragraph.ods +0 -0
- data/test/files/paragraph.xls +0 -0
- data/test/files/paragraph.xlsx +0 -0
- data/test/files/paragraph.xml +0 -127
- data/test/files/prova.xls +0 -0
- data/test/files/ric.ods +0 -0
- data/test/files/simple_spreadsheet.ods +0 -0
- data/test/files/simple_spreadsheet.xls +0 -0
- data/test/files/simple_spreadsheet.xlsx +0 -0
- data/test/files/simple_spreadsheet.xml +0 -225
- data/test/files/simple_spreadsheet_from_italo.ods +0 -0
- data/test/files/simple_spreadsheet_from_italo.xls +0 -0
- data/test/files/simple_spreadsheet_from_italo.xml +0 -242
- data/test/files/so_datetime.csv +0 -7
- data/test/files/style.ods +0 -0
- data/test/files/style.xls +0 -0
- data/test/files/style.xlsx +0 -0
- data/test/files/style.xml +0 -154
- data/test/files/time-test.csv +0 -2
- data/test/files/time-test.ods +0 -0
- data/test/files/time-test.xls +0 -0
- data/test/files/time-test.xlsx +0 -0
- data/test/files/time-test.xml +0 -131
- data/test/files/type_excel.ods +0 -0
- data/test/files/type_excel.xlsx +0 -0
- data/test/files/type_excelx.ods +0 -0
- data/test/files/type_excelx.xls +0 -0
- data/test/files/type_openoffice.xls +0 -0
- data/test/files/type_openoffice.xlsx +0 -0
- data/test/files/whitespace.ods +0 -0
- data/test/files/whitespace.xls +0 -0
- data/test/files/whitespace.xlsx +0 -0
- data/test/files/whitespace.xml +0 -184
- data/test/rm_sub_test.rb +0 -12
- data/test/rm_test.rb +0 -7
- data/website/index.html +0 -385
- data/website/index.txt +0 -423
- data/website/javascripts/rounded_corners_lite.inc.js +0 -285
- data/website/stylesheets/screen.css +0 -130
- data/website/template.rhtml +0 -48
data/lib/roo/csv.rb
CHANGED
@@ -1,113 +1,120 @@
|
|
1
|
-
require 'csv'
|
2
|
-
require 'time'
|
3
|
-
|
4
|
-
# The CSV class can read csv files (must be separated with commas) which then
|
5
|
-
# can be handled like spreadsheets. This means you can access cells like A5
|
6
|
-
# within these files.
|
7
|
-
# The CSV class provides only string objects. If you want conversions to other
|
8
|
-
# types you have to do it yourself.
|
9
|
-
#
|
10
|
-
# You can pass options to the underlying CSV parse operation, via the
|
11
|
-
# :csv_options option.
|
12
|
-
#
|
13
|
-
|
14
|
-
class Roo::CSV < Roo::Base
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
sheet
|
73
|
-
|
74
|
-
@
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
1
|
+
require 'csv'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
# The CSV class can read csv files (must be separated with commas) which then
|
5
|
+
# can be handled like spreadsheets. This means you can access cells like A5
|
6
|
+
# within these files.
|
7
|
+
# The CSV class provides only string objects. If you want conversions to other
|
8
|
+
# types you have to do it yourself.
|
9
|
+
#
|
10
|
+
# You can pass options to the underlying CSV parse operation, via the
|
11
|
+
# :csv_options option.
|
12
|
+
#
|
13
|
+
|
14
|
+
class Roo::CSV < Roo::Base
|
15
|
+
|
16
|
+
attr_reader :filename
|
17
|
+
|
18
|
+
# Returns an array with the names of the sheets. In CSV class there is only
|
19
|
+
# one dummy sheet, because a csv file cannot have more than one sheet.
|
20
|
+
def sheets
|
21
|
+
['default']
|
22
|
+
end
|
23
|
+
|
24
|
+
def cell(row, col, sheet=nil)
|
25
|
+
sheet ||= default_sheet
|
26
|
+
read_cells(sheet)
|
27
|
+
@cell[normalize(row,col)]
|
28
|
+
end
|
29
|
+
|
30
|
+
def celltype(row, col, sheet=nil)
|
31
|
+
sheet ||= default_sheet
|
32
|
+
read_cells(sheet)
|
33
|
+
@cell_type[normalize(row,col)]
|
34
|
+
end
|
35
|
+
|
36
|
+
def cell_postprocessing(row,col,value)
|
37
|
+
value
|
38
|
+
end
|
39
|
+
|
40
|
+
def csv_options
|
41
|
+
@options[:csv_options] || {}
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
TYPE_MAP = {
|
47
|
+
String => :string,
|
48
|
+
Float => :float,
|
49
|
+
Date => :date,
|
50
|
+
DateTime => :datetime,
|
51
|
+
}
|
52
|
+
|
53
|
+
def celltype_class(value)
|
54
|
+
TYPE_MAP[value.class]
|
55
|
+
end
|
56
|
+
|
57
|
+
def each_row(options, &block)
|
58
|
+
if uri?(filename)
|
59
|
+
make_tmpdir do |tmpdir|
|
60
|
+
tmp_filename = download_uri(filename, tmpdir)
|
61
|
+
CSV.foreach(tmp_filename, options, &block)
|
62
|
+
end
|
63
|
+
else
|
64
|
+
CSV.foreach(filename, options, &block)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def read_cells(sheet = default_sheet)
|
69
|
+
sheet ||= default_sheet
|
70
|
+
return if @cells_read[sheet]
|
71
|
+
@first_row[sheet] = 1
|
72
|
+
@last_row[sheet] = 0
|
73
|
+
@first_column[sheet] = 1
|
74
|
+
@last_column[sheet] = 1
|
75
|
+
rownum = 1
|
76
|
+
each_row csv_options do |row|
|
77
|
+
row.each_with_index do |elem,i|
|
78
|
+
@cell[[rownum,i+1]] = cell_postprocessing rownum,i+1, elem
|
79
|
+
@cell_type[[rownum,i+1]] = celltype_class @cell[[rownum,i+1]]
|
80
|
+
if i+1 > @last_column[sheet]
|
81
|
+
@last_column[sheet] += 1
|
82
|
+
end
|
83
|
+
end
|
84
|
+
rownum += 1
|
85
|
+
@last_row[sheet] += 1
|
86
|
+
end
|
87
|
+
@cells_read[sheet] = true
|
88
|
+
#-- adjust @first_row if neccessary
|
89
|
+
while !row(@first_row[sheet]).any? and @first_row[sheet] < @last_row[sheet]
|
90
|
+
@first_row[sheet] += 1
|
91
|
+
end
|
92
|
+
#-- adjust @last_row if neccessary
|
93
|
+
while !row(@last_row[sheet]).any? and @last_row[sheet] and
|
94
|
+
@last_row[sheet] > @first_row[sheet]
|
95
|
+
@last_row[sheet] -= 1
|
96
|
+
end
|
97
|
+
#-- adjust @first_column if neccessary
|
98
|
+
while !column(@first_column[sheet]).any? and
|
99
|
+
@first_column[sheet] and
|
100
|
+
@first_column[sheet] < @last_column[sheet]
|
101
|
+
@first_column[sheet] += 1
|
102
|
+
end
|
103
|
+
#-- adjust @last_column if neccessary
|
104
|
+
while !column(@last_column[sheet]).any? and
|
105
|
+
@last_column[sheet] and
|
106
|
+
@last_column[sheet] > @first_column[sheet]
|
107
|
+
@last_column[sheet] -= 1
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def clean_sheet(sheet)
|
112
|
+
read_cells(sheet)
|
113
|
+
|
114
|
+
@cell.each_pair do |coord, value|
|
115
|
+
@cell[coord] = sanitize_value(value) if value.is_a?(::String)
|
116
|
+
end
|
117
|
+
|
118
|
+
@cleaned[sheet] = true
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module Roo
|
4
|
+
class Excelx
|
5
|
+
class Cell
|
6
|
+
attr_reader :type, :formula, :value, :excelx_type, :excelx_value, :style, :hyperlink, :coordinate
|
7
|
+
attr_writer :value
|
8
|
+
|
9
|
+
def initialize(value, type, formula, excelx_type, excelx_value, style, hyperlink, base_date, coordinate)
|
10
|
+
@type = type
|
11
|
+
@formula = formula
|
12
|
+
@base_date = base_date if [:date, :datetime].include?(@type)
|
13
|
+
@excelx_type = excelx_type
|
14
|
+
@excelx_value = excelx_value
|
15
|
+
@style = style
|
16
|
+
@value = type_cast_value(value)
|
17
|
+
@value = Roo::Link.new(hyperlink, @value.to_s) if hyperlink
|
18
|
+
@coordinate = coordinate
|
19
|
+
end
|
20
|
+
|
21
|
+
def type
|
22
|
+
case
|
23
|
+
when @formula
|
24
|
+
:formula
|
25
|
+
when @value.is_a?(Roo::Link)
|
26
|
+
:link
|
27
|
+
else
|
28
|
+
@type
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Coordinate
|
33
|
+
attr_accessor :row, :column
|
34
|
+
|
35
|
+
def initialize(row, column)
|
36
|
+
@row, @column = row, column
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def type_cast_value(value)
|
43
|
+
case @type
|
44
|
+
when :float, :percentage
|
45
|
+
value.to_f
|
46
|
+
when :date
|
47
|
+
create_date(@base_date + value.to_i)
|
48
|
+
when :datetime
|
49
|
+
create_datetime(@base_date + value.to_f.round(6))
|
50
|
+
when :time
|
51
|
+
value.to_f * 86_400
|
52
|
+
else
|
53
|
+
value
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def create_date(date)
|
58
|
+
yyyy, mm, dd = date.strftime('%Y-%m-%d').split('-')
|
59
|
+
|
60
|
+
Date.new(yyyy.to_i, mm.to_i, dd.to_i)
|
61
|
+
end
|
62
|
+
|
63
|
+
def create_datetime(date)
|
64
|
+
datetime_string = date.strftime('%Y-%m-%d %H:%M:%S.%N')
|
65
|
+
t = round_datetime(datetime_string)
|
66
|
+
|
67
|
+
DateTime.civil(t.year, t.month, t.day, t.hour, t.min, t.sec)
|
68
|
+
end
|
69
|
+
|
70
|
+
def round_datetime(datetime_string)
|
71
|
+
/(?<yyyy>\d+)-(?<mm>\d+)-(?<dd>\d+) (?<hh>\d+):(?<mi>\d+):(?<ss>\d+.\d+)/ =~ datetime_string
|
72
|
+
|
73
|
+
Time.new(yyyy.to_i, mm.to_i, dd.to_i, hh.to_i, mi.to_i, ss.to_r).round(0)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'roo/excelx/extractor'
|
2
|
+
|
3
|
+
module Roo
|
4
|
+
class Excelx
|
5
|
+
class Comments < Excelx::Extractor
|
6
|
+
def comments
|
7
|
+
@comments ||= extract_comments
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def extract_comments
|
13
|
+
return {} unless doc_exists?
|
14
|
+
|
15
|
+
Hash[doc.xpath('//comments/commentList/comment').map do |comment|
|
16
|
+
value = (comment.at_xpath('./text/r/t') || comment.at_xpath('./text/t')).text
|
17
|
+
[::Roo::Utils.ref_to_key(comment.attributes['ref'].to_s), value]
|
18
|
+
end]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Roo
|
2
|
+
class Excelx
|
3
|
+
class Extractor
|
4
|
+
def initialize(path)
|
5
|
+
@path = path
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def doc
|
11
|
+
@doc ||=
|
12
|
+
if doc_exists?
|
13
|
+
::Roo::Utils.load_xml(@path).remove_namespaces!
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def doc_exists?
|
18
|
+
@path && File.exist?(@path)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'roo/excelx/extractor'
|
2
|
+
|
3
|
+
module Roo
|
4
|
+
class Excelx
|
5
|
+
class Relationships < Excelx::Extractor
|
6
|
+
def [](index)
|
7
|
+
to_a[index]
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_a
|
11
|
+
@relationships ||= extract_relationships
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def extract_relationships
|
17
|
+
return [] unless doc_exists?
|
18
|
+
|
19
|
+
Hash[doc.xpath('/Relationships/Relationship').map do |rel|
|
20
|
+
[rel.attribute('Id').text, rel]
|
21
|
+
end]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'roo/excelx/extractor'
|
2
|
+
|
3
|
+
module Roo
|
4
|
+
class Excelx
|
5
|
+
class SharedStrings < Excelx::Extractor
|
6
|
+
def [](index)
|
7
|
+
to_a[index]
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_a
|
11
|
+
@array ||= extract_shared_strings
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def extract_shared_strings
|
17
|
+
return [] unless doc_exists?
|
18
|
+
|
19
|
+
# read the shared strings xml document
|
20
|
+
doc.xpath('/sst/si').map do |si|
|
21
|
+
shared_string = ''
|
22
|
+
si.children.each do |elem|
|
23
|
+
case elem.name
|
24
|
+
when 'r'
|
25
|
+
elem.children.each do |r_elem|
|
26
|
+
shared_string << r_elem.content if r_elem.name == 't'
|
27
|
+
end
|
28
|
+
when 't'
|
29
|
+
shared_string = elem.content
|
30
|
+
end
|
31
|
+
end
|
32
|
+
shared_string
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Roo
|
2
|
+
class Excelx
|
3
|
+
class Sheet
|
4
|
+
def initialize(name, rels_path, sheet_path, comments_path, styles, shared_strings, workbook, options = {})
|
5
|
+
@name = name
|
6
|
+
@rels = Relationships.new(rels_path)
|
7
|
+
@comments = Comments.new(comments_path)
|
8
|
+
@styles = styles
|
9
|
+
@sheet = SheetDoc.new(sheet_path, @rels, @styles, shared_strings, workbook, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def cells
|
13
|
+
@cells ||= @sheet.cells(@rels)
|
14
|
+
end
|
15
|
+
|
16
|
+
def present_cells
|
17
|
+
@present_cells ||= cells.select { |_, cell| cell && cell.value }
|
18
|
+
end
|
19
|
+
|
20
|
+
# Yield each row as array of Excelx::Cell objects
|
21
|
+
# accepts options max_rows (int) (offset by 1 for header),
|
22
|
+
# pad_cells (boolean) and offset (int)
|
23
|
+
def each_row(options = {}, &block)
|
24
|
+
row_count = 0
|
25
|
+
options[:offset] ||= 0
|
26
|
+
@sheet.each_row_streaming do |row|
|
27
|
+
break if options[:max_rows] && row_count == options[:max_rows] + options[:offset] + 1
|
28
|
+
if block_given? && !(options[:offset] && row_count < options[:offset])
|
29
|
+
block.call(cells_for_row_element(row, options))
|
30
|
+
end
|
31
|
+
row_count += 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def row(row_number)
|
36
|
+
first_column.upto(last_column).map do |col|
|
37
|
+
cells[[row_number, col]]
|
38
|
+
end.map { |cell| cell && cell.value }
|
39
|
+
end
|
40
|
+
|
41
|
+
def column(col_number)
|
42
|
+
first_row.upto(last_row).map do |row|
|
43
|
+
cells[[row, col_number]]
|
44
|
+
end.map { |cell| cell && cell.value }
|
45
|
+
end
|
46
|
+
|
47
|
+
# returns the number of the first non-empty row
|
48
|
+
def first_row
|
49
|
+
@first_row ||= present_cells.keys.map { |row, _| row }.min
|
50
|
+
end
|
51
|
+
|
52
|
+
def last_row
|
53
|
+
@last_row ||= present_cells.keys.map { |row, _| row }.max
|
54
|
+
end
|
55
|
+
|
56
|
+
# returns the number of the first non-empty column
|
57
|
+
def first_column
|
58
|
+
@first_column ||= present_cells.keys.map { |_, col| col }.min
|
59
|
+
end
|
60
|
+
|
61
|
+
# returns the number of the last non-empty column
|
62
|
+
def last_column
|
63
|
+
@last_column ||= present_cells.keys.map { |_, col| col }.max
|
64
|
+
end
|
65
|
+
|
66
|
+
def excelx_format(key)
|
67
|
+
cell = cells[key]
|
68
|
+
@styles.style_format(cell.style).to_s if cell
|
69
|
+
end
|
70
|
+
|
71
|
+
def hyperlinks
|
72
|
+
@hyperlinks ||= @sheet.hyperlinks(@rels)
|
73
|
+
end
|
74
|
+
|
75
|
+
def comments
|
76
|
+
@comments.comments
|
77
|
+
end
|
78
|
+
|
79
|
+
def dimensions
|
80
|
+
@sheet.dimensions
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
# Take an xml row and return an array of Excelx::Cell objects
|
86
|
+
# optionally pad array to header width(assumed 1st row).
|
87
|
+
# takes option pad_cells (boolean) defaults false
|
88
|
+
def cells_for_row_element(row_element, options = {})
|
89
|
+
return [] unless row_element
|
90
|
+
cell_col = 0
|
91
|
+
cells = []
|
92
|
+
@sheet.each_cell(row_element) do |cell|
|
93
|
+
cells.concat(pad_cells(cell, cell_col)) if options[:pad_cells]
|
94
|
+
cells << cell
|
95
|
+
cell_col = cell.coordinate.column
|
96
|
+
end
|
97
|
+
cells
|
98
|
+
end
|
99
|
+
|
100
|
+
def pad_cells(cell, last_column)
|
101
|
+
pad = []
|
102
|
+
(cell.coordinate.column - 1 - last_column).times { pad << nil }
|
103
|
+
pad
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|