roo 1.13.2 → 2.0.0beta1
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 +21 -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.rb +18 -24
- data/lib/roo/base.rb +303 -388
- data/lib/roo/csv.rb +120 -113
- data/lib/roo/excelx.rb +452 -484
- data/lib/roo/excelx/comments.rb +24 -0
- data/lib/roo/excelx/extractor.rb +20 -0
- data/lib/roo/excelx/relationships.rb +26 -0
- data/lib/roo/excelx/shared_strings.rb +40 -0
- data/lib/roo/excelx/sheet_doc.rb +202 -0
- data/lib/roo/excelx/styles.rb +62 -0
- data/lib/roo/excelx/workbook.rb +59 -0
- 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} +678 -496
- data/lib/roo/spreadsheet.rb +20 -23
- data/lib/roo/utils.rb +78 -0
- data/lib/roo/version.rb +3 -0
- 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 +388 -11
- data/spec/lib/roo/libreoffice_spec.rb +16 -6
- data/spec/lib/roo/openoffice_spec.rb +2 -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 +19 -67
- data/test/test_helper.rb +9 -56
- data/test/test_roo.rb +252 -477
- metadata +63 -302
- 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/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/Gemfile.lock
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
GEM
|
|
2
|
-
remote: http://rubygems.org/
|
|
3
|
-
specs:
|
|
4
|
-
addressable (2.3.5)
|
|
5
|
-
crack (0.4.1)
|
|
6
|
-
safe_yaml (~> 0.9.0)
|
|
7
|
-
diff-lcs (1.2.1)
|
|
8
|
-
faraday (0.8.7)
|
|
9
|
-
multipart-post (~> 1.1)
|
|
10
|
-
git (1.2.5)
|
|
11
|
-
google_drive (0.3.6)
|
|
12
|
-
nokogiri (>= 1.4.4, != 1.5.2, != 1.5.1)
|
|
13
|
-
oauth (>= 0.3.6)
|
|
14
|
-
oauth2 (>= 0.5.0)
|
|
15
|
-
httpauth (0.2.0)
|
|
16
|
-
jeweler (1.8.3)
|
|
17
|
-
bundler (~> 1.0)
|
|
18
|
-
git (>= 1.2.5)
|
|
19
|
-
rake
|
|
20
|
-
rdoc
|
|
21
|
-
json (1.7.7)
|
|
22
|
-
json (1.7.7-java)
|
|
23
|
-
jwt (0.1.8)
|
|
24
|
-
multi_json (>= 1.5)
|
|
25
|
-
multi_json (1.7.3)
|
|
26
|
-
multi_xml (0.5.3)
|
|
27
|
-
multipart-post (1.2.0)
|
|
28
|
-
nokogiri (1.5.6)
|
|
29
|
-
nokogiri (1.5.6-java)
|
|
30
|
-
oauth (0.4.7)
|
|
31
|
-
oauth2 (0.9.1)
|
|
32
|
-
faraday (~> 0.8)
|
|
33
|
-
httpauth (~> 0.1)
|
|
34
|
-
jwt (~> 0.1.4)
|
|
35
|
-
multi_json (~> 1.0)
|
|
36
|
-
multi_xml (~> 0.5)
|
|
37
|
-
rack (~> 1.2)
|
|
38
|
-
rack (1.5.2)
|
|
39
|
-
rake (0.9.2.2)
|
|
40
|
-
rdoc (3.12.2)
|
|
41
|
-
json (~> 1.4)
|
|
42
|
-
rspec (2.13.0)
|
|
43
|
-
rspec-core (~> 2.13.0)
|
|
44
|
-
rspec-expectations (~> 2.13.0)
|
|
45
|
-
rspec-mocks (~> 2.13.0)
|
|
46
|
-
rspec-core (2.13.1)
|
|
47
|
-
rspec-expectations (2.13.0)
|
|
48
|
-
diff-lcs (>= 1.1.3, < 2.0)
|
|
49
|
-
rspec-mocks (2.13.0)
|
|
50
|
-
ruby-ole (1.2.11.6)
|
|
51
|
-
rubyzip (1.0.0)
|
|
52
|
-
safe_yaml (0.9.4)
|
|
53
|
-
shoulda (3.0.1)
|
|
54
|
-
shoulda-context (~> 1.0.0)
|
|
55
|
-
shoulda-matchers (~> 1.0.0)
|
|
56
|
-
shoulda-context (1.0.0)
|
|
57
|
-
shoulda-matchers (1.0.0)
|
|
58
|
-
spreadsheet (0.8.2)
|
|
59
|
-
ruby-ole (>= 1.0)
|
|
60
|
-
vcr (2.5.0)
|
|
61
|
-
webmock (1.13.0)
|
|
62
|
-
addressable (>= 2.2.7)
|
|
63
|
-
crack (>= 0.3.2)
|
|
64
|
-
|
|
65
|
-
PLATFORMS
|
|
66
|
-
java
|
|
67
|
-
ruby
|
|
68
|
-
|
|
69
|
-
DEPENDENCIES
|
|
70
|
-
google_drive
|
|
71
|
-
jeweler
|
|
72
|
-
nokogiri
|
|
73
|
-
rspec
|
|
74
|
-
rubyzip
|
|
75
|
-
shoulda
|
|
76
|
-
spreadsheet (> 0.6.4)
|
|
77
|
-
vcr
|
|
78
|
-
webmock
|
data/README.markdown
DELETED
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
# README for Roo
|
|
2
|
-
|
|
3
|
-
Roo implements read access for all spreadsheet types and read/write access for
|
|
4
|
-
Google spreadsheets. It can handle
|
|
5
|
-
* OpenOffice
|
|
6
|
-
* Excel
|
|
7
|
-
* Google spreadsheets
|
|
8
|
-
* Excelx
|
|
9
|
-
* LibreOffice
|
|
10
|
-
* CSV
|
|
11
|
-
|
|
12
|
-
## Notes
|
|
13
|
-
|
|
14
|
-
### XLS
|
|
15
|
-
|
|
16
|
-
There is no support for formulas in Roo for .xls files - you can get the result
|
|
17
|
-
of a formula but not the formula itself.
|
|
18
|
-
|
|
19
|
-
### Google Spreadsheet
|
|
20
|
-
|
|
21
|
-
Using Roo to access Google spreadsheets requires you install the 'google-spreadsheet-ruby' gem separately.
|
|
22
|
-
|
|
23
|
-
## License
|
|
24
|
-
|
|
25
|
-
While Roo is licensed under the MIT / Expat license, please note that the 'spreadsheet' gem [is released under](https://github.com/zdavatz/spreadsheet/blob/master/LICENSE.txt) the GPLv3 license.
|
|
26
|
-
|
|
27
|
-
## Usage:
|
|
28
|
-
|
|
29
|
-
```ruby
|
|
30
|
-
require 'roo'
|
|
31
|
-
|
|
32
|
-
s = Roo::OpenOffice.new("myspreadsheet.ods") # loads an OpenOffice Spreadsheet
|
|
33
|
-
s = Roo::Excel.new("myspreadsheet.xls") # loads an Excel Spreadsheet
|
|
34
|
-
s = Roo::Google.new("myspreadsheetkey_at_google") # loads a Google Spreadsheet
|
|
35
|
-
s = Roo::Excelx.new("myspreadsheet.xlsx") # loads an Excel Spreadsheet for Excel .xlsx files
|
|
36
|
-
s = Roo::CSV.new("mycsv.csv") # loads a CSV file
|
|
37
|
-
|
|
38
|
-
# You can use CSV to load TSV files, or files of a certain encoding by passing
|
|
39
|
-
# in options under the :csv_options key
|
|
40
|
-
s = Roo::CSV.new("mytsv.tsv", csv_options: {col_sep: "\t"}) # TSV
|
|
41
|
-
s = Roo::CSV.new("mycsv.csv", csv_options: {encoding: Encoding::ISO_8859_1}) # csv with explicit encoding
|
|
42
|
-
|
|
43
|
-
s.default_sheet = s.sheets.first # first sheet in the spreadsheet file will be used
|
|
44
|
-
|
|
45
|
-
# s.sheets is an array which holds the names of the sheets within
|
|
46
|
-
# a spreadsheet.
|
|
47
|
-
# you can also write
|
|
48
|
-
# s.default_sheet = s.sheets[3] or
|
|
49
|
-
# s.default_sheet = 'Sheet 3'
|
|
50
|
-
|
|
51
|
-
s.cell(1,1) # returns the content of the first row/first cell in the sheet
|
|
52
|
-
s.cell('A',1) # same cell
|
|
53
|
-
s.cell(1,'A') # same cell
|
|
54
|
-
s.cell(1,'A',s.sheets[0]) # same cell
|
|
55
|
-
|
|
56
|
-
# almost all methods have an optional argument 'sheet'.
|
|
57
|
-
# If this parameter is omitted, the default_sheet will be used.
|
|
58
|
-
|
|
59
|
-
s.info # prints infos about the spreadsheet file
|
|
60
|
-
|
|
61
|
-
s.first_row # the number of the first row
|
|
62
|
-
s.last_row # the number of the last row
|
|
63
|
-
s.first_column # the number of the first column
|
|
64
|
-
s.last_column # the number of the last column
|
|
65
|
-
|
|
66
|
-
# limited font information is available
|
|
67
|
-
|
|
68
|
-
s.font(1,1).bold?
|
|
69
|
-
s.font(1,1).italic?
|
|
70
|
-
s.font(1,1).underline?
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
# Spreadsheet.open can accept both files and paths
|
|
74
|
-
|
|
75
|
-
xls = Roo::Spreadsheet.open('./new_prices.xls')
|
|
76
|
-
|
|
77
|
-
# If the File.path or provided path string does not have an extension, you can optionally
|
|
78
|
-
# provide one as a string or symbol
|
|
79
|
-
|
|
80
|
-
xls = Roo::Spreadsheet.open('./rails_temp_upload', extension: :xls)
|
|
81
|
-
|
|
82
|
-
# no more setting xls.default_sheet, just use this
|
|
83
|
-
|
|
84
|
-
xls.sheet('Info').row(1)
|
|
85
|
-
xls.sheet(0).row(1)
|
|
86
|
-
|
|
87
|
-
# excel likes to create random "Data01" sheets for macros
|
|
88
|
-
# use this to find the sheet with the most data to parse
|
|
89
|
-
|
|
90
|
-
xls.longest_sheet
|
|
91
|
-
|
|
92
|
-
# this excel file has multiple worksheets, let's iterate through each of them and process
|
|
93
|
-
|
|
94
|
-
xls.each_with_pagename do |name, sheet|
|
|
95
|
-
p sheet.row(1)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# pull out a hash of exclusive column data (get rid of useless columns and save memory)
|
|
99
|
-
|
|
100
|
-
xls.each(:id => 'UPC',:qty => 'ATS') {|hash| arr << hash}
|
|
101
|
-
#=> hash will appear like {:upc=>727880013358, :qty => 12}
|
|
102
|
-
|
|
103
|
-
# NOTE: .parse does the same as .each, except it returns an array (similar to each vs. map)
|
|
104
|
-
|
|
105
|
-
# not sure exactly what a column will be named? try a wildcard search with the character *
|
|
106
|
-
# regex characters are allowed ('^price\s')
|
|
107
|
-
# case insensitive
|
|
108
|
-
|
|
109
|
-
xls.parse(:id => 'UPC*SKU',:qty => 'ATS*\sATP\s*QTY$')
|
|
110
|
-
|
|
111
|
-
# if you need to locate the header row and assign the header names themselves,
|
|
112
|
-
# use the :header_search option
|
|
113
|
-
|
|
114
|
-
xls.parse(:header_search => ['UPC*SKU','ATS*\sATP\s*QTY$'])
|
|
115
|
-
#=> each element will appear in this fashion:
|
|
116
|
-
#=> {"UPC" => 123456789012, "STYLE" => "987B0", "COLOR" => "blue", "QTY" => 78}
|
|
117
|
-
|
|
118
|
-
# want to strip out annoying unicode characters and surrounding white space?
|
|
119
|
-
|
|
120
|
-
xls.parse(:clean => true)
|
|
121
|
-
|
|
122
|
-
# another bonus feature is a patch to prevent the Spreadsheet gem from parsing
|
|
123
|
-
# thousands and thousands of blank lines. i got fed up after watching my computer
|
|
124
|
-
# nearly catch fire for 4 hours for a spreadsheet with only 200 ACTUAL lines
|
|
125
|
-
# - located in lib/roo/worksheet.rb
|
|
126
|
-
```
|
data/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.13.2
|
data/lib/roo/excel.rb
DELETED
|
@@ -1,355 +0,0 @@
|
|
|
1
|
-
require 'spreadsheet'
|
|
2
|
-
|
|
3
|
-
# Class for handling Excel-Spreadsheets
|
|
4
|
-
class Roo::Excel < Roo::Base
|
|
5
|
-
FORMULAS_MESSAGE = 'the spreadsheet gem does not support forumulas, so roo can not.'
|
|
6
|
-
CHARGUESS =
|
|
7
|
-
begin
|
|
8
|
-
require 'charguess'
|
|
9
|
-
true
|
|
10
|
-
rescue LoadError
|
|
11
|
-
false
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
attr_reader :workbook
|
|
15
|
-
|
|
16
|
-
# Creates a new Excel spreadsheet object.
|
|
17
|
-
# Parameter packed: :zip - File is a zip-file
|
|
18
|
-
def initialize(filename, options = {}, deprecated_file_warning = :error)
|
|
19
|
-
if Hash === options
|
|
20
|
-
packed = options[:packed]
|
|
21
|
-
file_warning = options[:file_warning] || :error
|
|
22
|
-
mode = options[:mode] || "rb+"
|
|
23
|
-
else
|
|
24
|
-
warn 'Supplying `packed` or `file_warning` as separate arguments to `Roo::Excel.new` is deprecated. Use an options hash instead.'
|
|
25
|
-
packed = options
|
|
26
|
-
mode = "rb+"
|
|
27
|
-
file_warning = deprecated_file_warning
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
file_type_check(filename,'.xls','an Excel', file_warning, packed)
|
|
31
|
-
make_tmpdir do |tmpdir|
|
|
32
|
-
filename = download_uri(filename, tmpdir) if uri?(filename)
|
|
33
|
-
filename = open_from_stream(filename[7..-1], tmpdir) if filename[0,7] == "stream:"
|
|
34
|
-
filename = unzip(filename, tmpdir) if packed == :zip
|
|
35
|
-
|
|
36
|
-
@filename = filename
|
|
37
|
-
unless File.file?(@filename)
|
|
38
|
-
raise IOError, "file #{@filename} does not exist"
|
|
39
|
-
end
|
|
40
|
-
@workbook = Spreadsheet.open(filename, mode)
|
|
41
|
-
end
|
|
42
|
-
super(filename, options)
|
|
43
|
-
@formula = Hash.new
|
|
44
|
-
@fonts = Hash.new
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def encoding=(codepage)
|
|
48
|
-
@workbook.encoding = codepage
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# returns an array of sheet names in the spreadsheet
|
|
52
|
-
def sheets
|
|
53
|
-
@workbook.worksheets.collect {|worksheet| normalize_string(worksheet.name)}
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# this method lets you find the worksheet with the most data
|
|
57
|
-
def longest_sheet
|
|
58
|
-
sheet(@workbook.worksheets.inject {|m,o|
|
|
59
|
-
o.row_count > m.row_count ? o : m
|
|
60
|
-
}.name)
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# returns the content of a cell. The upper left corner is (1,1) or ('A',1)
|
|
64
|
-
def cell(row,col,sheet=nil)
|
|
65
|
-
sheet ||= @default_sheet
|
|
66
|
-
validate_sheet!(sheet)
|
|
67
|
-
|
|
68
|
-
read_cells(sheet)
|
|
69
|
-
raise "should be read" unless @cells_read[sheet]
|
|
70
|
-
row,col = normalize(row,col)
|
|
71
|
-
if celltype(row,col,sheet) == :date
|
|
72
|
-
yyyy,mm,dd = @cell[sheet][[row,col]].split('-')
|
|
73
|
-
return Date.new(yyyy.to_i,mm.to_i,dd.to_i)
|
|
74
|
-
end
|
|
75
|
-
if celltype(row,col,sheet) == :string
|
|
76
|
-
return platform_specific_encoding(@cell[sheet][[row,col]])
|
|
77
|
-
else
|
|
78
|
-
if @cell[sheet] and @cell[sheet][[row,col]]
|
|
79
|
-
return @cell[sheet][[row,col]]
|
|
80
|
-
else
|
|
81
|
-
return nil
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# returns the type of a cell:
|
|
87
|
-
# * :float
|
|
88
|
-
# * :string,
|
|
89
|
-
# * :date
|
|
90
|
-
# * :percentage
|
|
91
|
-
# * :formula
|
|
92
|
-
# * :time
|
|
93
|
-
# * :datetime
|
|
94
|
-
def celltype(row,col,sheet=nil)
|
|
95
|
-
sheet ||= @default_sheet
|
|
96
|
-
read_cells(sheet)
|
|
97
|
-
row,col = normalize(row,col)
|
|
98
|
-
begin
|
|
99
|
-
if @formula[sheet] and @formula[sheet][[row,col]]
|
|
100
|
-
:formula
|
|
101
|
-
elsif @cell_type[sheet]
|
|
102
|
-
@cell_type[sheet][[row,col]]
|
|
103
|
-
end
|
|
104
|
-
rescue
|
|
105
|
-
puts "Error in sheet #{sheet}, row #{row}, col #{col}"
|
|
106
|
-
raise
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
# returns NO formula in excel spreadsheets
|
|
111
|
-
def formula(row,col,sheet=nil)
|
|
112
|
-
raise NotImplementedError, FORMULAS_MESSAGE
|
|
113
|
-
end
|
|
114
|
-
alias_method :formula?, :formula
|
|
115
|
-
|
|
116
|
-
# returns NO formulas in excel spreadsheets
|
|
117
|
-
def formulas(sheet=nil)
|
|
118
|
-
raise NotImplementedError, FORMULAS_MESSAGE
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
# Given a cell, return the cell's font
|
|
122
|
-
def font(row, col, sheet=nil)
|
|
123
|
-
sheet ||= @default_sheet
|
|
124
|
-
read_cells(sheet)
|
|
125
|
-
row,col = normalize(row,col)
|
|
126
|
-
@fonts[sheet][[row,col]]
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
# shows the internal representation of all cells
|
|
130
|
-
# mainly for debugging purposes
|
|
131
|
-
def to_s(sheet=nil)
|
|
132
|
-
sheet ||= @default_sheet
|
|
133
|
-
read_cells(sheet)
|
|
134
|
-
@cell[sheet].inspect
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
private
|
|
138
|
-
|
|
139
|
-
# converts name of a sheet to index (0,1,2,..)
|
|
140
|
-
def sheet_no(name)
|
|
141
|
-
return name-1 if name.kind_of?(Fixnum)
|
|
142
|
-
i = 0
|
|
143
|
-
@workbook.worksheets.each do |worksheet|
|
|
144
|
-
return i if name == normalize_string(worksheet.name)
|
|
145
|
-
i += 1
|
|
146
|
-
end
|
|
147
|
-
raise StandardError, "sheet '#{name}' not found"
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
def normalize_string(value)
|
|
151
|
-
value = every_second_null?(value) ? remove_every_second_null(value) : value
|
|
152
|
-
if CHARGUESS && encoding = CharGuess::guess(value)
|
|
153
|
-
encoding.encode Encoding::UTF_8
|
|
154
|
-
else
|
|
155
|
-
platform_specific_encoding(value)
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
def platform_specific_encoding(value)
|
|
160
|
-
result =
|
|
161
|
-
case RUBY_PLATFORM.downcase
|
|
162
|
-
when /darwin|solaris/
|
|
163
|
-
value.encode Encoding::UTF_8
|
|
164
|
-
when /mswin32/
|
|
165
|
-
value.encode Encoding::ISO_8859_1
|
|
166
|
-
else
|
|
167
|
-
value
|
|
168
|
-
end
|
|
169
|
-
if every_second_null?(result)
|
|
170
|
-
result = remove_every_second_null(result)
|
|
171
|
-
end
|
|
172
|
-
result
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
def every_second_null?(str)
|
|
176
|
-
result = true
|
|
177
|
-
return false if str.length < 2
|
|
178
|
-
0.upto(str.length/2-1) do |i|
|
|
179
|
-
if str[i*2+1,1] != "\000"
|
|
180
|
-
result = false
|
|
181
|
-
break
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
result
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
def remove_every_second_null(str)
|
|
188
|
-
result = ''
|
|
189
|
-
0.upto(str.length/2-1) do |i|
|
|
190
|
-
c = str[i*2,1]
|
|
191
|
-
result += c
|
|
192
|
-
end
|
|
193
|
-
result
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
# helper function to set the internal representation of cells
|
|
197
|
-
def set_cell_values(sheet,row,col,i,v,value_type,formula,tr,font)
|
|
198
|
-
#key = "#{y},#{x+i}"
|
|
199
|
-
key = [row,col+i]
|
|
200
|
-
@cell_type[sheet] = {} unless @cell_type[sheet]
|
|
201
|
-
@cell_type[sheet][key] = value_type
|
|
202
|
-
@formula[sheet] = {} unless @formula[sheet]
|
|
203
|
-
@formula[sheet][key] = formula if formula
|
|
204
|
-
@cell[sheet] = {} unless @cell[sheet]
|
|
205
|
-
@fonts[sheet] = {} unless @fonts[sheet]
|
|
206
|
-
@fonts[sheet][key] = font
|
|
207
|
-
|
|
208
|
-
@cell[sheet][key] =
|
|
209
|
-
case value_type
|
|
210
|
-
when :float
|
|
211
|
-
v.to_f
|
|
212
|
-
when :string
|
|
213
|
-
v
|
|
214
|
-
when :date
|
|
215
|
-
v
|
|
216
|
-
when :datetime
|
|
217
|
-
@cell[sheet][key] = DateTime.new(v.year,v.month,v.day,v.hour,v.min,v.sec)
|
|
218
|
-
when :percentage
|
|
219
|
-
v.to_f
|
|
220
|
-
when :time
|
|
221
|
-
v
|
|
222
|
-
else
|
|
223
|
-
v
|
|
224
|
-
end
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
# ruby-spreadsheet has a font object so we're extending it
|
|
228
|
-
# with our own functionality but still providing full access
|
|
229
|
-
# to the user for other font information
|
|
230
|
-
module ExcelFontExtensions
|
|
231
|
-
def bold?(*args)
|
|
232
|
-
#From ruby-spreadsheet doc: 100 <= weight <= 1000, bold => 700, normal => 400
|
|
233
|
-
weight == 700
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
def italic?
|
|
237
|
-
italic
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
def underline?
|
|
241
|
-
underline != :none
|
|
242
|
-
end
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
# read all cells in the selected sheet
|
|
246
|
-
def read_cells(sheet=nil)
|
|
247
|
-
sheet ||= @default_sheet
|
|
248
|
-
validate_sheet!(sheet)
|
|
249
|
-
return if @cells_read[sheet]
|
|
250
|
-
|
|
251
|
-
worksheet = @workbook.worksheet(sheet_no(sheet))
|
|
252
|
-
row_index=1
|
|
253
|
-
worksheet.each(0) do |row|
|
|
254
|
-
(0..row.size).each do |cell_index|
|
|
255
|
-
cell = row.at(cell_index)
|
|
256
|
-
next if cell.nil? #skip empty cells
|
|
257
|
-
next if cell.class == Spreadsheet::Formula && cell.value.nil? # skip empty formula cells
|
|
258
|
-
value_type, v =
|
|
259
|
-
if date_or_time?(row, cell_index)
|
|
260
|
-
read_cell_date_or_time(row, cell_index)
|
|
261
|
-
else
|
|
262
|
-
read_cell(row, cell_index)
|
|
263
|
-
end
|
|
264
|
-
formula = tr = nil #TODO:???
|
|
265
|
-
col_index = cell_index + 1
|
|
266
|
-
font = row.format(cell_index).font
|
|
267
|
-
font.extend(ExcelFontExtensions)
|
|
268
|
-
set_cell_values(sheet,row_index,col_index,0,v,value_type,formula,tr,font)
|
|
269
|
-
end #row
|
|
270
|
-
row_index += 1
|
|
271
|
-
end # worksheet
|
|
272
|
-
@cells_read[sheet] = true
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
# Get the contents of a cell, accounting for the
|
|
276
|
-
# way formula stores the value
|
|
277
|
-
def read_cell_content(row, idx)
|
|
278
|
-
cell = row.at(idx)
|
|
279
|
-
cell = row[idx] if row[idx].class == Spreadsheet::Link
|
|
280
|
-
cell = cell.value if cell.class == Spreadsheet::Formula
|
|
281
|
-
cell
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
# Test the cell to see if it's a valid date/time.
|
|
285
|
-
def date_or_time?(row, idx)
|
|
286
|
-
format = row.format(idx)
|
|
287
|
-
if format.date_or_time?
|
|
288
|
-
cell = read_cell_content(row, idx)
|
|
289
|
-
true if Float(cell) > 0 rescue false
|
|
290
|
-
else
|
|
291
|
-
false
|
|
292
|
-
end
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
# Read the date-time cell and convert to,
|
|
296
|
-
# the date-time values for Roo
|
|
297
|
-
def read_cell_date_or_time(row, idx)
|
|
298
|
-
cell = read_cell_content(row, idx)
|
|
299
|
-
cell = cell.to_s.to_f
|
|
300
|
-
if cell < 1.0
|
|
301
|
-
value_type = :time
|
|
302
|
-
f = cell*24.0*60.0*60.0
|
|
303
|
-
secs = f.round
|
|
304
|
-
h = (secs / 3600.0).floor
|
|
305
|
-
secs = secs - 3600*h
|
|
306
|
-
m = (secs / 60.0).floor
|
|
307
|
-
secs = secs - 60*m
|
|
308
|
-
s = secs
|
|
309
|
-
value = h*3600+m*60+s
|
|
310
|
-
else
|
|
311
|
-
if row.at(idx).class == Spreadsheet::Formula
|
|
312
|
-
datetime = row.send(:_datetime, cell)
|
|
313
|
-
else
|
|
314
|
-
datetime = row.datetime(idx)
|
|
315
|
-
end
|
|
316
|
-
if datetime.hour != 0 or
|
|
317
|
-
datetime.min != 0 or
|
|
318
|
-
datetime.sec != 0
|
|
319
|
-
value_type = :datetime
|
|
320
|
-
value = datetime
|
|
321
|
-
else
|
|
322
|
-
value_type = :date
|
|
323
|
-
if row.at(idx).class == Spreadsheet::Formula
|
|
324
|
-
value = row.send(:_date, cell)
|
|
325
|
-
else
|
|
326
|
-
value = row.date(idx)
|
|
327
|
-
end
|
|
328
|
-
value = sprintf("%04d-%02d-%02d",value.year,value.month,value.day)
|
|
329
|
-
end
|
|
330
|
-
end
|
|
331
|
-
return value_type, value
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
# Read the cell and based on the class,
|
|
335
|
-
# return the values for Roo
|
|
336
|
-
def read_cell(row, idx)
|
|
337
|
-
cell = read_cell_content(row, idx)
|
|
338
|
-
case cell
|
|
339
|
-
when Float, Integer, Fixnum, Bignum
|
|
340
|
-
value_type = :float
|
|
341
|
-
value = cell.to_f
|
|
342
|
-
when Spreadsheet::Link
|
|
343
|
-
value_type = :link
|
|
344
|
-
value = cell
|
|
345
|
-
when String, TrueClass, FalseClass
|
|
346
|
-
value_type = :string
|
|
347
|
-
value = cell.to_s
|
|
348
|
-
else
|
|
349
|
-
value_type = cell.class.to_s.downcase.to_sym
|
|
350
|
-
value = nil
|
|
351
|
-
end # case
|
|
352
|
-
return value_type, value
|
|
353
|
-
end
|
|
354
|
-
|
|
355
|
-
end
|