roo 1.11.2 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,4 +1,29 @@
1
- == 1.11.2 (unreleased)
1
+ == 1.12.0 (unreleased)
2
+
3
+ * 3 deprecations
4
+ * Rename Openoffice -> OpenOffice, Libreoffice -> LibreOffice, Csv -> CSV, and redirect the old names to the new constants
5
+ * Enable Roo::Excel, Excel2003XML, Excelx, OpenOffice to accept an options hash, and deprecate the old method argument based approach to supplying them options
6
+ * Roo's roo_rails_helper, aka the `spreadsheet` html-generating view method is currently deprecated with no replacement. If you find it helpful, tell http://github.com/Empact or extract it yourself.
7
+
8
+ * 9 enhancements
9
+ * Add Roo::Excelx#load_xml so that people can customize to their data, e.g. https://github.com/Empact/roo/pull/23
10
+ * Enable passing csv_options to Roo::CSV, which are passed through to the underlying CSV call.
11
+ * Enable passing options through from Roo::Spreadsheet to any Roo type.
12
+ * Enable passing an :extension option to Roo::Spreadsheet.new, which will override the extension detected on in the path https://github.com/Empact/roo/pull/15
13
+ * Switch from google-spreadsheet-ruby to google_drive for Roo::Google access https://github.com/Empact/roo/pull/40
14
+ * Make all the classes consistent in that #read_cells is only effective if the sheet has not been read.
15
+ * Roo::Google supports login via oauth :access_token. https://github.com/Empact/roo/pull/61
16
+ * Roo::Excel now exposes its Spreadsheet workbook via #workbook
17
+ * Pull #load_xml down into Roo::Base, and use it in Excel2003XML and OpenOffice.
18
+
19
+ * 2 changes
20
+ * #formula? now returns truthy or falsey, rather than true/false.
21
+ * Base#longest_sheet was moved to Excel, as it only worked under Excel
22
+
23
+ * 1 bugfix
24
+ * Fix that Roo::CSV#parse(headers: true) would blow up. https://github.com/Empact/roo/pull/37
25
+
26
+ == 1.11.2 2013-04-10
2
27
 
3
28
  * 4 bugfixes
4
29
  * Fix that Roo::Spreadsheet.open wasn't tolerant to case differences.
data/Gemfile CHANGED
@@ -3,9 +3,9 @@ source 'http://rubygems.org'
3
3
  gem 'spreadsheet', '> 0.6.4'
4
4
  gem 'nokogiri'
5
5
  gem 'rubyzip'
6
- # gem 'google-spreadsheet-ruby'
7
6
 
8
7
  group :development do
8
+ gem 'google_drive'
9
9
  gem 'jeweler'
10
10
  end
11
11
 
@@ -14,4 +14,5 @@ group :test do
14
14
  gem 'webmock'
15
15
  gem 'shoulda'
16
16
  gem 'rspec'
17
+ gem 'vcr'
17
18
  end
@@ -4,14 +4,37 @@ GEM
4
4
  addressable (2.3.2)
5
5
  crack (0.3.1)
6
6
  diff-lcs (1.2.1)
7
+ faraday (0.8.7)
8
+ multipart-post (~> 1.1)
7
9
  git (1.2.5)
10
+ google_drive (0.3.6)
11
+ nokogiri (>= 1.4.4, != 1.5.2, != 1.5.1)
12
+ oauth (>= 0.3.6)
13
+ oauth2 (>= 0.5.0)
14
+ httpauth (0.2.0)
8
15
  jeweler (1.8.3)
9
16
  bundler (~> 1.0)
10
17
  git (>= 1.2.5)
11
18
  rake
12
19
  rdoc
13
20
  json (1.7.7)
21
+ json (1.7.7-java)
22
+ jwt (0.1.8)
23
+ multi_json (>= 1.5)
24
+ multi_json (1.7.3)
25
+ multi_xml (0.5.3)
26
+ multipart-post (1.2.0)
14
27
  nokogiri (1.5.6)
28
+ nokogiri (1.5.6-java)
29
+ oauth (0.4.7)
30
+ oauth2 (0.9.1)
31
+ faraday (~> 0.8)
32
+ httpauth (~> 0.1)
33
+ jwt (~> 0.1.4)
34
+ multi_json (~> 1.0)
35
+ multi_xml (~> 0.5)
36
+ rack (~> 1.2)
37
+ rack (1.5.2)
15
38
  rake (0.9.2.2)
16
39
  rdoc (3.12.2)
17
40
  json (~> 1.4)
@@ -32,6 +55,7 @@ GEM
32
55
  shoulda-matchers (1.0.0)
33
56
  spreadsheet (0.8.2)
34
57
  ruby-ole (>= 1.0)
58
+ vcr (2.5.0)
35
59
  webmock (1.9.0)
36
60
  addressable (>= 2.2.7)
37
61
  crack (>= 0.1.7)
@@ -41,10 +65,12 @@ PLATFORMS
41
65
  ruby
42
66
 
43
67
  DEPENDENCIES
68
+ google_drive
44
69
  jeweler
45
70
  nokogiri
46
71
  rspec
47
72
  rubyzip
48
73
  shoulda
49
74
  spreadsheet (> 0.6.4)
75
+ vcr
50
76
  webmock
@@ -2,108 +2,128 @@
2
2
 
3
3
  Roo implements read access for all spreadsheet types and read/write access for
4
4
  Google spreadsheets. It can handle
5
- * Openoffice
5
+ * OpenOffice
6
6
  * Excel
7
7
  * Google spreadsheets
8
8
  * Excelx
9
- * Libreoffice
9
+ * LibreOffice
10
10
  * CSV
11
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
+
12
21
  Using Roo to access Google spreadsheets requires you install the 'google-spreadsheet-ruby' gem separately.
13
22
 
14
- Unless the underlying 'spreadsheet' gem supports formulas there is no support
15
- for formulas in Roo for .xls files (you get the result of a formula in such a
16
- file but not the formula itself)
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.
17
26
 
18
27
  ## Usage:
19
28
 
20
- require 'roo'
29
+ require 'roo'
30
+
31
+ s = Roo::OpenOffice.new("myspreadsheet.ods") # loads an OpenOffice Spreadsheet
32
+ s = Roo::Excel.new("myspreadsheet.xls") # loads an Excel Spreadsheet
33
+ s = Roo::Google.new("myspreadsheetkey_at_google") # loads a Google Spreadsheet
34
+ s = Roo::Excelx.new("myspreadsheet.xlsx") # loads an Excel Spreadsheet for Excel .xlsx files
35
+ s = Roo::CSV.new("mycsv.csv") # loads a CSV file
21
36
 
22
- s = Roo::Openoffice.new("myspreadsheet.ods") # creates an Openoffice Spreadsheet instance
23
- s = Roo::Excel.new("myspreadsheet.xls") # creates an Excel Spreadsheet instance
24
- s = Roo::Google.new("myspreadsheetkey_at_google") # creates an Google Spreadsheet instance
25
- s = Roo::Excelx.new("myspreadsheet.xlsx") # creates an Excel Spreadsheet instance for Excel .xlsx files
37
+ # You can use CSV to load TSV files, or files of a certain encoding by passing
38
+ # in options under the :csv_options key
39
+ s = Roo::CSV.new("mytsv.tsv", csv_options: {col_sep: "\t"}) # TSV
40
+ s = Roo::CSV.new("mycsv.csv", csv_options: {encoding: Encoding::ISO_8859_1}) # csv with explicit encoding
26
41
 
27
- s.default_sheet = s.sheets.first # first sheet in the spreadsheet file will be used
42
+ s.default_sheet = s.sheets.first # first sheet in the spreadsheet file will be used
28
43
 
29
- # s.sheet is an array which holds the names of the sheets within
30
- # a spreadsheet.
31
- # you can also write
32
- # s.default_sheet = s.sheets[3] or
33
- # s.default_sheet = 'Sheet 3'
44
+ # s.sheets is an array which holds the names of the sheets within
45
+ # a spreadsheet.
46
+ # you can also write
47
+ # s.default_sheet = s.sheets[3] or
48
+ # s.default_sheet = 'Sheet 3'
34
49
 
35
- s.cell(1,1) # returns the content of the first row/first cell in the sheet
36
- s.cell('A',1) # same cell
37
- s.cell(1,'A') # same cell
38
- s.cell(1,'A',s.sheets[0]) # same cell
50
+ s.cell(1,1) # returns the content of the first row/first cell in the sheet
51
+ s.cell('A',1) # same cell
52
+ s.cell(1,'A') # same cell
53
+ s.cell(1,'A',s.sheets[0]) # same cell
39
54
 
40
- # almost all methods have an optional argument 'sheet'.
41
- # If this parameter is omitted, the default_sheet will be used.
55
+ # almost all methods have an optional argument 'sheet'.
56
+ # If this parameter is omitted, the default_sheet will be used.
42
57
 
43
- s.info # prints infos about the spreadsheet file
58
+ s.info # prints infos about the spreadsheet file
44
59
 
45
- s.first_row # the number of the first row
46
- s.last_row # the number of the last row
47
- s.first_column # the number of the first column
48
- s.last_column # the number of the last column
60
+ s.first_row # the number of the first row
61
+ s.last_row # the number of the last row
62
+ s.first_column # the number of the first column
63
+ s.last_column # the number of the last column
49
64
 
50
- # limited font information is available
65
+ # limited font information is available
51
66
 
52
- s.font(1,1).bold?
53
- s.font(1,1).italic?
54
- s.font(1,1).underline?
67
+ s.font(1,1).bold?
68
+ s.font(1,1).italic?
69
+ s.font(1,1).underline?
55
70
 
56
71
 
57
72
  see http://roo.rubyforge.org for a more complete tutorial
58
73
 
59
74
  # Fork Changelog / New Features
60
75
 
61
- # Spreadsheet.open can accept both files and paths
76
+ # Spreadsheet.open can accept both files and paths
77
+
78
+ xls = Roo::Spreadsheet.open('./new_prices.xls')
79
+
80
+ # If the File.path or provided path string does not have an extension, you can optionally
81
+ # provide one as a string or symbol
62
82
 
63
- xls = Roo::Spreadsheet.open('./new_prices.xls')
83
+ xls = Roo::Spreadsheet.open('./rails_temp_upload', extension: :xls)
64
84
 
65
- # no more setting xls.default_sheet, just use this
85
+ # no more setting xls.default_sheet, just use this
66
86
 
67
- xls.sheet('Info').row_count
68
- xls.sheet(0).row_count
87
+ xls.sheet('Info').row(1)
88
+ xls.sheet(0).row(1)
69
89
 
70
- # excel likes to create random "Data01" sheets for macros
71
- # use this to find the sheet with the most data to parse
90
+ # excel likes to create random "Data01" sheets for macros
91
+ # use this to find the sheet with the most data to parse
72
92
 
73
- xls.longest_sheet
93
+ xls.longest_sheet
74
94
 
75
- # this excel file has multiple worksheets, let's iterate through each of them and process
95
+ # this excel file has multiple worksheets, let's iterate through each of them and process
76
96
 
77
- xls.each_with_pagename do |name,sheet|
78
- puts sheet.row_count
79
- end
97
+ xls.each_with_pagename do |name, sheet|
98
+ p sheet.row(1)
99
+ end
80
100
 
81
- # pull out a hash of exclusive column data (get rid of useless columns and save memory)
101
+ # pull out a hash of exclusive column data (get rid of useless columns and save memory)
82
102
 
83
- xls.each(:id => 'UPC',:qty => 'ATS') {|hash| arr << hash}
84
- #=> hash will appear like {:upc=>727880013358, :qty => 12}
103
+ xls.each(:id => 'UPC',:qty => 'ATS') {|hash| arr << hash}
104
+ #=> hash will appear like {:upc=>727880013358, :qty => 12}
85
105
 
86
- # NOTE: .parse does the same as .each, except it returns an array (similar to each vs. map)
106
+ # NOTE: .parse does the same as .each, except it returns an array (similar to each vs. map)
87
107
 
88
- # not sure exactly what a column will be named? try a wildcard search with the character *
89
- # regex characters are allowed ('^price\s')
90
- # case insensitive
108
+ # not sure exactly what a column will be named? try a wildcard search with the character *
109
+ # regex characters are allowed ('^price\s')
110
+ # case insensitive
91
111
 
92
- xls.parse(:id => 'UPC*SKU',:qty => 'ATS*\sATP\s*QTY$')
112
+ xls.parse(:id => 'UPC*SKU',:qty => 'ATS*\sATP\s*QTY$')
93
113
 
94
- # if you need to locate the header row and assign the header names themselves,
95
- # use the :header_search option
114
+ # if you need to locate the header row and assign the header names themselves,
115
+ # use the :header_search option
96
116
 
97
- xls.parse(:header_search => ['UPC*SKU','ATS*\sATP\s*QTY$'])
98
- #=> each element will appear in this fashion:
99
- #=> {"UPC" => 123456789012, "STYLE" => "987B0", "COLOR" => "blue", "QTY" => 78}
117
+ xls.parse(:header_search => ['UPC*SKU','ATS*\sATP\s*QTY$'])
118
+ #=> each element will appear in this fashion:
119
+ #=> {"UPC" => 123456789012, "STYLE" => "987B0", "COLOR" => "blue", "QTY" => 78}
100
120
 
101
- # want to strip out annoying unicode characters and surrounding white space?
121
+ # want to strip out annoying unicode characters and surrounding white space?
102
122
 
103
- xls.parse(:clean => true)
123
+ xls.parse(:clean => true)
104
124
 
105
- # another bonus feature is a patch to prevent the Spreadsheet gem from parsing
106
- # thousands and thousands of blank lines. i got fed up after watching my computer
107
- # nearly catch fire for 4 hours for a spreadsheet with only 200 ACTUAL lines
108
- # - located in lib/roo/worksheet.rb
125
+ # another bonus feature is a patch to prevent the Spreadsheet gem from parsing
126
+ # thousands and thousands of blank lines. i got fed up after watching my computer
127
+ # nearly catch fire for 4 hours for a spreadsheet with only 200 ACTUAL lines
128
+ # - located in lib/roo/worksheet.rb
109
129
 
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ Jeweler::Tasks.new do |gem|
4
4
  # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
5
5
  gem.name = "roo"
6
6
  gem.summary = "Roo can access the contents of various spreadsheet files."
7
- gem.description = "Roo can access the contents of various spreadsheet files. It can handle\n* Openoffice\n* Excel\n* Google spreadsheets\n* Excelx\n* Libreoffice\n* CSV"
7
+ gem.description = "Roo can access the contents of various spreadsheet files. It can handle\n* OpenOffice\n* Excel\n* Google spreadsheets\n* Excelx\n* LibreOffice\n* CSV"
8
8
  gem.email = "ruby.ruby.ruby.roo@gmail.com"
9
9
  gem.homepage = "http://github.com/Empact/roo"
10
10
  gem.authors = ['Thomas Preymesser', 'Hugh McGowan', 'Ben Woosley']
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.11.2
1
+ 1.12.0
@@ -5,7 +5,7 @@ NS = "spreadsheetserver" # name of your service = namespace
5
5
  class Server2 < SOAP::RPC::StandaloneServer
6
6
 
7
7
  def on_init
8
- spreadsheet = Openoffice.new("./Ferien-de.ods")
8
+ spreadsheet = OpenOffice.new("./Ferien-de.ods")
9
9
  add_method(spreadsheet, 'cell', 'row', 'col')
10
10
  add_method(spreadsheet, 'officeversion')
11
11
  add_method(spreadsheet, 'first_row')
data/lib/roo.rb CHANGED
@@ -1,16 +1,34 @@
1
1
  module Roo
2
2
 
3
- VERSION = '1.10.3'
3
+ VERSION = '1.12.0'
4
4
 
5
- autoload :Spreadsheet, 'roo/spreadsheet'
5
+ def self.const_missing(const_name)
6
+ case const_name
7
+ when :Libreoffice
8
+ warn "`Roo::Libreoffice` has been deprecated. Use `Roo::LibreOffice` instead."
9
+ LibreOffice
10
+ when :Openoffice
11
+ warn "`Roo::Openoffice` has been deprecated. Use `Roo::OpenOffice` instead."
12
+ OpenOffice
13
+ when :Csv
14
+ warn "`Roo::Csv` has been deprecated. Use `Roo::CSV` instead."
15
+ CSV
16
+ when :GenericSpreadsheet
17
+ warn "`Roo::GenericSpreadsheet` has been deprecated. Use `Roo::Base` instead."
18
+ Base
19
+ else
20
+ super
21
+ end
22
+ end
6
23
 
7
- autoload :GenericSpreadsheet, 'roo/generic_spreadsheet'
8
- autoload :Openoffice, 'roo/openoffice'
9
- autoload :Excel, 'roo/excel'
10
- autoload :Excelx, 'roo/excelx'
11
- autoload :Google, 'roo/google'
12
- autoload :Csv, 'roo/csv'
24
+ autoload :Spreadsheet, 'roo/spreadsheet'
25
+ autoload :Base, 'roo/base'
13
26
 
14
- autoload :Excel2003XML, 'roo/excel2003xml'
15
- autoload :RooRailsHelper, 'roo/roo_rails_helper'
27
+ autoload :OpenOffice, 'roo/openoffice'
28
+ autoload :LibreOffice, 'roo/openoffice'
29
+ autoload :Excel, 'roo/excel'
30
+ autoload :Excelx, 'roo/excelx'
31
+ autoload :Excel2003XML, 'roo/excel2003xml'
32
+ autoload :Google, 'roo/google'
33
+ autoload :CSV, 'roo/csv'
16
34
  end
@@ -5,7 +5,7 @@ require 'stringio'
5
5
  require 'zip/zipfilesystem'
6
6
 
7
7
  # Base class for all other types of spreadsheets
8
- class Roo::GenericSpreadsheet
8
+ class Roo::Base
9
9
  include Enumerable
10
10
 
11
11
  TEMP_PREFIX = "oo_"
@@ -18,7 +18,7 @@ class Roo::GenericSpreadsheet
18
18
  protected
19
19
 
20
20
  def self.split_coordinate(str)
21
- letter,number = Roo::GenericSpreadsheet.split_coord(str)
21
+ letter,number = Roo::Base.split_coord(str)
22
22
  x = letter_to_number(letter)
23
23
  y = number
24
24
  return y, x
@@ -37,9 +37,12 @@ class Roo::GenericSpreadsheet
37
37
 
38
38
  public
39
39
 
40
- def initialize(filename, packed=nil, file_warning=:error, tmpdir=nil)
41
- @cell = Hash.new{|h,k| h[k] = {}}
42
- @cell_type = Hash.new{|h,k| h[k] = {}}
40
+ def initialize(filename, options={}, file_warning=:error, tmpdir=nil)
41
+ @filename = filename
42
+ @options = options
43
+
44
+ @cell = {}
45
+ @cell_type = {}
43
46
  @cells_read = {}
44
47
 
45
48
  @first_row = {}
@@ -47,12 +50,8 @@ class Roo::GenericSpreadsheet
47
50
  @first_column = {}
48
51
  @last_column = {}
49
52
 
50
- @style = {}
51
- @style_defaults = Hash.new { |h,k| h[k] = [] }
52
- @style_definitions = {}
53
-
53
+ @header_line = 1
54
54
  @default_sheet = self.sheets.first
55
- @formula = {}
56
55
  @header_line = 1
57
56
  end
58
57
 
@@ -67,18 +66,18 @@ class Roo::GenericSpreadsheet
67
66
 
68
67
  # first non-empty column as a letter
69
68
  def first_column_as_letter(sheet=nil)
70
- Roo::GenericSpreadsheet.number_to_letter(first_column(sheet))
69
+ Roo::Base.number_to_letter(first_column(sheet))
71
70
  end
72
71
 
73
72
  # last non-empty column as a letter
74
73
  def last_column_as_letter(sheet=nil)
75
- Roo::GenericSpreadsheet.number_to_letter(last_column(sheet))
74
+ Roo::Base.number_to_letter(last_column(sheet))
76
75
  end
77
76
 
78
77
  # returns the number of the first non-empty row
79
78
  def first_row(sheet=nil)
80
79
  sheet ||= @default_sheet
81
- read_cells(sheet) unless @cells_read[sheet]
80
+ read_cells(sheet)
82
81
  if @first_row[sheet]
83
82
  return @first_row[sheet]
84
83
  end
@@ -96,7 +95,7 @@ class Roo::GenericSpreadsheet
96
95
  # returns the number of the last non-empty row
97
96
  def last_row(sheet=nil)
98
97
  sheet ||= @default_sheet
99
- read_cells(sheet) unless @cells_read[sheet]
98
+ read_cells(sheet)
100
99
  if @last_row[sheet]
101
100
  return @last_row[sheet]
102
101
  end
@@ -114,7 +113,7 @@ class Roo::GenericSpreadsheet
114
113
  # returns the number of the first non-empty column
115
114
  def first_column(sheet=nil)
116
115
  sheet ||= @default_sheet
117
- read_cells(sheet) unless @cells_read[sheet]
116
+ read_cells(sheet)
118
117
  if @first_column[sheet]
119
118
  return @first_column[sheet]
120
119
  end
@@ -132,7 +131,7 @@ class Roo::GenericSpreadsheet
132
131
  # returns the number of the last non-empty column
133
132
  def last_column(sheet=nil)
134
133
  sheet ||= @default_sheet
135
- read_cells(sheet) unless @cells_read[sheet]
134
+ read_cells(sheet)
136
135
  if @last_column[sheet]
137
136
  return @last_column[sheet]
138
137
  end
@@ -166,7 +165,7 @@ class Roo::GenericSpreadsheet
166
165
  result << " col: #{col} \n"
167
166
  result << " celltype: #{self.celltype(row,col,sheet)} \n"
168
167
  if self.celltype(row,col,sheet) == :time
169
- result << " value: #{Roo::GenericSpreadsheet.integer_to_timestring( self.cell(row,col,sheet))} \n"
168
+ result << " value: #{Roo::Base.integer_to_timestring( self.cell(row,col,sheet))} \n"
170
169
  else
171
170
  result << " value: #{self.cell(row,col,sheet)} \n"
172
171
  end
@@ -255,7 +254,7 @@ class Roo::GenericSpreadsheet
255
254
  # row numbers are 1,2,3,... like in the spreadsheet
256
255
  def row(rownumber,sheet=nil)
257
256
  sheet ||= @default_sheet
258
- read_cells(sheet) unless @cells_read[sheet]
257
+ read_cells(sheet)
259
258
  first_column(sheet).upto(last_column(sheet)).map do |col|
260
259
  cell(rownumber,col,sheet)
261
260
  end
@@ -268,7 +267,7 @@ class Roo::GenericSpreadsheet
268
267
  columnnumber = Roo::Excel.letter_to_number(columnnumber)
269
268
  end
270
269
  sheet ||= @default_sheet
271
- read_cells(sheet) unless @cells_read[sheet]
270
+ read_cells(sheet)
272
271
  first_row(sheet).upto(last_row(sheet)).map do |row|
273
272
  cell(row,columnnumber,sheet)
274
273
  end
@@ -278,7 +277,7 @@ class Roo::GenericSpreadsheet
278
277
  # (this will not be saved back to the spreadsheet file!)
279
278
  def set(row,col,value,sheet=nil) #:nodoc:
280
279
  sheet ||= @default_sheet
281
- read_cells(sheet) unless @cells_read[sheet]
280
+ read_cells(sheet)
282
281
  row, col = normalize(row,col)
283
282
  cell_type = case value
284
283
  when Fixnum then :float
@@ -293,21 +292,15 @@ class Roo::GenericSpreadsheet
293
292
 
294
293
  # reopens and read a spreadsheet document
295
294
  def reload
296
- # von Abfrage der Klasse direkt auf .to_s == '..' umgestellt
297
295
  ds = @default_sheet
298
- if self.class.to_s == 'Google'
299
- initialize(@spreadsheetkey,@user,@password)
300
- else
301
- initialize(@filename)
302
- end
296
+ reinitialize
303
297
  self.default_sheet = ds
304
- #@first_row = @last_row = @first_column = @last_column = nil
305
298
  end
306
299
 
307
300
  # true if cell is empty
308
301
  def empty?(row, col, sheet=nil)
309
302
  sheet ||= @default_sheet
310
- read_cells(sheet) unless @cells_read[sheet] or self.class == Roo::Excel
303
+ read_cells(sheet)
311
304
  row,col = normalize(row,col)
312
305
  contents = cell(row, col, sheet)
313
306
  !contents || (celltype(row, col, sheet) == :string && contents.empty?) \
@@ -329,8 +322,8 @@ class Roo::GenericSpreadsheet
329
322
  else
330
323
  result << " First row: #{first_row}\n"
331
324
  result << " Last row: #{last_row}\n"
332
- result << " First column: #{Roo::GenericSpreadsheet.number_to_letter(first_column)}\n"
333
- result << " Last column: #{Roo::GenericSpreadsheet.number_to_letter(last_column)}"
325
+ result << " First column: #{Roo::Base.number_to_letter(first_column)}\n"
326
+ result << " Last column: #{Roo::Base.number_to_letter(last_column)}"
334
327
  end
335
328
  result << "\n" if sheet != sheets.last
336
329
  n += 1
@@ -370,7 +363,7 @@ class Roo::GenericSpreadsheet
370
363
  # #aa42 => #cell('aa',42)
371
364
  # #aa42('Sheet1') => #cell('aa',42,'Sheet1')
372
365
  if m =~ /^([a-z]+)(\d)$/
373
- col = Roo::GenericSpreadsheet.letter_to_number($1)
366
+ col = Roo::Base.letter_to_number($1)
374
367
  row = $2.to_i
375
368
  if args.empty?
376
369
  cell(row,col)
@@ -382,148 +375,120 @@ class Roo::GenericSpreadsheet
382
375
  end
383
376
  end
384
377
 
385
- =begin
386
- #TODO: hier entfernen
387
- # returns each formula in the selected sheet as an array of elements
388
- # [row, col, formula]
389
- def formulas(sheet=nil)
390
- theformulas = Array.new
391
- sheet ||= @default_sheet
392
- read_cells(sheet) unless @cells_read[sheet]
393
- return theformulas unless first_row(sheet) # if there is no first row then
394
- # there can't be formulas
395
- first_row(sheet).upto(last_row(sheet)) {|row|
396
- first_column(sheet).upto(last_column(sheet)) {|col|
397
- if formula?(row,col,sheet)
398
- theformulas << [row, col, formula(row,col,sheet)]
399
- end
400
- }
401
- }
402
- theformulas
378
+ # access different worksheets by calling spreadsheet.sheet(1)
379
+ # or spreadsheet.sheet('SHEETNAME')
380
+ def sheet(index,name=false)
381
+ @default_sheet = String === index ? index : self.sheets[index]
382
+ name ? [@default_sheet,self] : self
403
383
  end
404
- =end
405
-
406
-
407
-
408
- # FestivalBobcats fork changes begin here
409
384
 
410
-
411
-
412
- # access different worksheets by calling spreadsheet.sheet(1)
413
- # or spreadsheet.sheet('SHEETNAME')
414
- def sheet(index,name=false)
415
- @default_sheet = String === index ? index : self.sheets[index]
416
- name ? [@default_sheet,self] : self
385
+ # iterate through all worksheets of a document
386
+ def each_with_pagename
387
+ self.sheets.each do |s|
388
+ yield sheet(s,true)
417
389
  end
390
+ end
418
391
 
419
- # iterate through all worksheets of a document
420
- def each_with_pagename
421
- self.sheets.each do |s|
422
- yield sheet(s,true)
423
- end
424
- end
392
+ # by passing in headers as options, this method returns
393
+ # specific columns from your header assignment
394
+ # for example:
395
+ # xls.sheet('New Prices').parse(:upc => 'UPC', :price => 'Price') would return:
396
+ # [{:upc => 123456789012, :price => 35.42},..]
425
397
 
426
- # by passing in headers as options, this method returns
427
- # specific columns from your header assignment
428
- # for example:
429
- # xls.sheet('New Prices').parse(:upc => 'UPC', :price => 'Price') would return:
430
- # [{:upc => 123456789012, :price => 35.42},..]
398
+ # the queries are matched with regex, so regex options can be passed in
399
+ # such as :price => '^(Cost|Price)'
400
+ # case insensitive by default
431
401
 
432
- # the queries are matched with regex, so regex options can be passed in
433
- # such as :price => '^(Cost|Price)'
434
- # case insensitive by default
435
402
 
403
+ # by using the :header_search option, you can query for headers
404
+ # and return a hash of every row with the keys set to the header result
405
+ # for example:
406
+ # xls.sheet('New Prices').parse(:header_search => ['UPC*SKU','^Price*\sCost\s'])
436
407
 
437
- # by using the :header_search option, you can query for headers
438
- # and return a hash of every row with the keys set to the header result
439
- # for example:
440
- # xls.sheet('New Prices').parse(:header_search => ['UPC*SKU','^Price*\sCost\s'])
408
+ # that example searches for a column titled either UPC or SKU and another
409
+ # column titled either Price or Cost (regex characters allowed)
410
+ # * is the wildcard character
441
411
 
442
- # that example searches for a column titled either UPC or SKU and another
443
- # column titled either Price or Cost (regex characters allowed)
444
- # * is the wildcard character
412
+ # you can also pass in a :clean => true option to strip the sheet of
413
+ # odd unicode characters and white spaces around columns
445
414
 
446
- # you can also pass in a :clean => true option to strip the sheet of
447
- # odd unicode characters and white spaces around columns
415
+ def each(options={})
416
+ if options.empty?
417
+ 1.upto(last_row) do |line|
418
+ yield row(line)
419
+ end
420
+ else
421
+ if options[:clean]
422
+ options.delete(:clean)
423
+ @cleaned ||= {}
424
+ @cleaned[@default_sheet] || clean_sheet(@default_sheet)
425
+ end
448
426
 
449
- def each(options={})
450
- if options.empty?
451
- 1.upto(last_row) do |line|
452
- yield row(line)
453
- end
427
+ if options[:header_search]
428
+ @headers = nil
429
+ @header_line = row_with(options[:header_search])
430
+ elsif [:first_row,true].include?(options[:headers])
431
+ @headers = []
432
+ row(first_row).each_with_index {|x,i| @headers << [x,i + 1]}
454
433
  else
455
- if options[:clean]
456
- options.delete(:clean)
457
- @cleaned ||= {}
458
- @cleaned[@default_sheet] || clean_sheet(@default_sheet)
459
- end
460
-
461
- if options[:header_search]
462
- @headers = nil
463
- @header_line = row_with(options[:header_search])
464
- elsif [:first_row,true].include?(options[:headers])
465
- @headers = []
466
- row(first_row).each_with_index {|x,i| @headers << [x,i + 1]}
467
- else
468
- set_headers(options)
469
- end
434
+ set_headers(options)
435
+ end
470
436
 
471
- headers = @headers ||
472
- Hash[(first_column..last_column).map do |col|
473
- [cell(@header_line,col), col]
474
- end]
437
+ headers = @headers ||
438
+ Hash[(first_column..last_column).map do |col|
439
+ [cell(@header_line,col), col]
440
+ end]
475
441
 
476
- @header_line.upto(last_row) do |line|
477
- yield(Hash[headers.map {|k,v| [k,cell(line,v)]}])
478
- end
442
+ @header_line.upto(last_row) do |line|
443
+ yield(Hash[headers.map {|k,v| [k,cell(line,v)]}])
479
444
  end
480
445
  end
446
+ end
481
447
 
482
- def parse(options={})
483
- ary = []
484
- if block_given?
485
- each(options) {|row| ary << yield(row)}
486
- else
487
- each(options) {|row| ary << row}
488
- end
489
- ary
490
- end
491
-
492
- def row_with(query,return_headers=false)
493
- query.map! {|x| Array(x.split('*'))}
494
- line_no = 0
495
- each do |row|
496
- line_no += 1
497
- # makes sure headers is the first part of wildcard search for priority
498
- # ex. if UPC and SKU exist for UPC*SKU search, UPC takes the cake
499
- headers = query.map do |q|
500
- q.map {|i| row.grep(/#{i}/i)[0]}.compact[0]
501
- end.compact
502
-
503
- if headers.length == query.length
504
- @header_line = line_no
505
- return return_headers ? headers : line_no
506
- elsif line_no > 100
507
- raise "Couldn't find header row."
508
- end
448
+ def parse(options={})
449
+ ary = []
450
+ if block_given?
451
+ each(options) {|row| ary << yield(row)}
452
+ else
453
+ each(options) {|row| ary << row}
454
+ end
455
+ ary
456
+ end
457
+
458
+ def row_with(query,return_headers=false)
459
+ query.map! {|x| Array(x.split('*'))}
460
+ line_no = 0
461
+ each do |row|
462
+ line_no += 1
463
+ # makes sure headers is the first part of wildcard search for priority
464
+ # ex. if UPC and SKU exist for UPC*SKU search, UPC takes the cake
465
+ headers = query.map do |q|
466
+ q.map {|i| row.grep(/#{i}/i)[0]}.compact[0]
467
+ end.compact
468
+
469
+ if headers.length == query.length
470
+ @header_line = line_no
471
+ return return_headers ? headers : line_no
472
+ elsif line_no > 100
473
+ raise "Couldn't find header row."
509
474
  end
510
475
  end
511
-
512
- # this method lets you find the worksheet with the most data
513
- def longest_sheet
514
- sheet(@workbook.worksheets.inject {|m,o|
515
- o.row_count > m.row_count ? o : m
516
- }.name)
517
- end
476
+ end
518
477
 
519
478
  protected
520
479
 
480
+ def load_xml(path)
481
+ File.open(path) do |file|
482
+ Nokogiri::XML(file)
483
+ end
484
+ end
485
+
521
486
  def file_type_check(filename, ext, name, warning_level, packed=nil)
522
487
  new_expression = {
523
- '.ods' => 'Roo::Openoffice.new',
488
+ '.ods' => 'Roo::OpenOffice.new',
524
489
  '.xls' => 'Roo::Excel.new',
525
490
  '.xlsx' => 'Roo::Excelx.new',
526
- '.csv' => 'Roo::Csv.new',
491
+ '.csv' => 'Roo::CSV.new',
527
492
  '.xml' => 'Roo::Excel2003XML.new',
528
493
  }
529
494
  if packed == :zip
@@ -574,6 +539,10 @@ class Roo::GenericSpreadsheet
574
539
 
575
540
  private
576
541
 
542
+ def reinitialize
543
+ initialize(@filename)
544
+ end
545
+
577
546
  def make_tmpdir(tmp_root = nil)
578
547
  Dir.mktmpdir(TEMP_PREFIX, tmp_root || ENV['ROO_TMP']) do |tmpdir|
579
548
  yield tmpdir
@@ -581,7 +550,7 @@ class Roo::GenericSpreadsheet
581
550
  end
582
551
 
583
552
  def clean_sheet(sheet)
584
- read_cells(sheet) unless @cells_read[sheet]
553
+ read_cells(sheet)
585
554
  @cell[sheet].each_pair do |coord,value|
586
555
  if String === value
587
556
  @cell[sheet][coord] = sanitize_value(value)
@@ -627,7 +596,7 @@ class Roo::GenericSpreadsheet
627
596
  end
628
597
  end
629
598
  if col.class == String
630
- col = Roo::GenericSpreadsheet.letter_to_number(col)
599
+ col = Roo::Base.letter_to_number(col)
631
600
  end
632
601
  return row,col
633
602
  end
@@ -636,21 +605,20 @@ class Roo::GenericSpreadsheet
636
605
  filename.start_with?("http://", "https://")
637
606
  end
638
607
 
639
- def open_from_uri(uri, tmpdir)
608
+ def download_uri(uri, tmpdir)
640
609
  require 'open-uri'
610
+ tempfilename = File.join(tmpdir, File.basename(uri))
641
611
  response = ''
642
612
  begin
643
- open(uri, "User-Agent" => "Ruby/#{RUBY_VERSION}") { |net|
644
- response = net.read
645
- tempfilename = File.join(tmpdir, File.basename(uri))
646
- File.open(tempfilename,"wb") do |file|
647
- file.write(response)
648
- end
649
- }
613
+ File.open(tempfilename,"wb") do |file|
614
+ open(uri, "User-Agent" => "Ruby/#{RUBY_VERSION}") { |net|
615
+ file.write(net.read)
616
+ }
617
+ end
650
618
  rescue OpenURI::HTTPError
651
619
  raise "could not open #{uri}"
652
620
  end
653
- File.join(tmpdir, File.basename(uri))
621
+ tempfilename
654
622
  end
655
623
 
656
624
  def open_from_stream(stream, tmpdir)
@@ -790,7 +758,7 @@ class Roo::GenericSpreadsheet
790
758
  when :date, :datetime
791
759
  onecell.to_s
792
760
  when :time
793
- Roo::GenericSpreadsheet.integer_to_timestring(onecell)
761
+ Roo::Base.integer_to_timestring(onecell)
794
762
  else
795
763
  raise "unhandled celltype #{celltype(row,col,sheet)}"
796
764
  end || ""