simple_xlsx_reader 1.0.2 → 1.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d3b2fbcc0148d773ed19a266e64877600863730c
4
- data.tar.gz: 61be9bbca611e49dc7ca725dd33d1560eec98018
3
+ metadata.gz: 1dd4b96753ca2dafcfadf59469c3a9357742ab7e
4
+ data.tar.gz: ffb23c6b020a55b893743206c236fea2abb07b65
5
5
  SHA512:
6
- metadata.gz: 041cd7eb5b2ebeeb310da52c0e173ff7c04ac95b55ae1c35cc510280c7d10e9ea6af703d10f2bed1f5f5678c77465fdd5807de2d8b3e4ccf7f1a01475178f487
7
- data.tar.gz: 8587c21a003e2bf4af53b2c67348102d85713e997bc15e248f2b806d4d7388b078bb7a5315c503931a0f287e1a7771d990913878d916d010c36040b6777b98ab
6
+ metadata.gz: 01a2326f942c455c665d5c135aa4115edd87a307e4aa5dff5e1d177ef61dcd326bcc33ad342f3b164ac7996731f0e31e97a9471973b98682757624f44052f6a2
7
+ data.tar.gz: b5371713dd232d5f1134ab810ea69447a3ad59bb781f917df2bc3a49e7b1c86c765ab0a074b1ddce021390f1b1d54e1507326abf22a65f1d83de1cf568ce7896
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ cache: bundler
3
+ before_install:
4
+ - gem update bundler
5
+ rvm:
6
+ - 1.9.3
7
+ - 2.3.0
@@ -1,3 +1,13 @@
1
+ ### 1.0.4
2
+
3
+ * Fix Windows + RubyZip 1.2.1 bug preventing files from being read
4
+ * Add ability to parse hyperlinks
5
+ * Support files exported from Google Docs (@Strnadj)
6
+
7
+ ### 1.0.3
8
+
9
+ Broken on Ruby 1.9; yanked.
10
+
1
11
  ### 1.0.2
2
12
 
3
13
  * Fix Ruby 1.9.3-specific bug preventing parsing most sheets [middagj, eritiro]
@@ -5,6 +15,7 @@
5
15
  * You don't always have a numFmtId column, and that's OK
6
16
  * Sometimes 'sharedStrings.xml' can be 'sharedstrings.xml'
7
17
  * Fixed parsing times very close to 12/30/1899 [Valeriy Utyaganov]
18
+ * Be more flexible with custom formats using a numFmtId < 164
8
19
 
9
20
  ### 1.0.1
10
21
 
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # SimpleXlsxReader
1
+ # SimpleXlsxReader [![Build Status](https://travis-ci.org/woahdae/simple_xlsx_reader.svg?branch=master)](https://travis-ci.org/woahdae/simple_xlsx_reader)
2
2
 
3
3
  An xlsx reader for Ruby that parses xlsx cell values into plain ruby
4
4
  primitives and dates/times.
@@ -19,6 +19,33 @@ end
19
19
  module SimpleXlsxReader
20
20
  class CellLoadError < StandardError; end
21
21
 
22
+ # We support hyperlinks as a "type" even though they're technically
23
+ # represented either as a function or an external reference in the xlsx spec.
24
+ #
25
+ # Since having hyperlink data in our sheet usually means we might want to do
26
+ # something primarily with the URL (store it in the database, download it, etc),
27
+ # we go through extra effort to parse the function or follow the reference
28
+ # to represent the hyperlink primarily as a URL. However, maybe we do want
29
+ # the hyperlink "friendly name" part (as MS calls it), so here we've subclassed
30
+ # string to tack on the friendly name. This means 80% of us that just want
31
+ # the URL value will have to do nothing extra, but the 20% that might want the
32
+ # friendly name can access it.
33
+ #
34
+ # Note, by default, the value we would get by just asking the cell would
35
+ # be the "friendly name" and *not* the URL, which is tucked away in the
36
+ # function definition or a separate "relationships" meta-document.
37
+ #
38
+ # See MS documentation on the HYPERLINK function for some background:
39
+ # https://support.office.com/en-us/article/HYPERLINK-function-333c7ce6-c5ae-4164-9c47-7de9b76f577f
40
+ class Hyperlink < String
41
+ attr_reader :friendly_name
42
+
43
+ def initialize(url, friendly_name = nil)
44
+ @friendly_name = friendly_name
45
+ super(url)
46
+ end
47
+ end
48
+
22
49
  def self.configuration
23
50
  @configuration ||= Struct.new(:catch_cell_load_errors).new.tap do |c|
24
51
  c.catch_cell_load_errors = false
@@ -69,29 +96,54 @@ module SimpleXlsxReader
69
96
  ##
70
97
  # For internal use; stores source xml in nokogiri documents
71
98
  class Xml
72
- attr_accessor :workbook, :shared_strings, :sheets, :styles
99
+ attr_accessor :workbook, :shared_strings, :sheets, :sheet_rels, :styles
73
100
 
74
101
  def self.load(file_path)
75
102
  self.new.tap do |xml|
76
103
  SimpleXlsxReader::Zip.open(file_path) do |zip|
77
- xml.workbook = Nokogiri::XML(zip.read('xl/workbook.xml')).remove_namespaces!
78
- xml.styles = Nokogiri::XML(zip.read('xl/styles.xml')).remove_namespaces!
79
-
80
- # optional feature used by excel, but not often used by xlsx
81
- # generation libraries
82
- ss_file = (zip.to_a.map(&:name) & ['xl/sharedStrings.xml','xl/sharedstrings.xml'])[0]
83
- if ss_file
84
- xml.shared_strings = Nokogiri::XML(zip.read(ss_file)).remove_namespaces!
85
- end
86
-
87
104
  xml.sheets = []
88
- i = 0
89
- loop do
90
- i += 1
91
- break if !zip.file.file?("xl/worksheets/sheet#{i}.xml")
105
+ xml.sheet_rels = []
106
+
107
+ # This weird style of enumerating over the entries lets us
108
+ # concisely assign entries in a case insensitive and
109
+ # slash insensitive ('/' vs '\') manner.
110
+ #
111
+ # RubyZip used to normalize the slashes, but doesn't now:
112
+ # https://github.com/rubyzip/rubyzip/issues/324
113
+ zip.entries.each do |entry|
114
+ if entry.name.match(/^xl.workbook\.xml$/) # xl/workbook.xml
115
+ xml.workbook = Nokogiri::XML(zip.read(entry)).remove_namespaces!
116
+ elsif entry.name.match(/^xl.styles\.xml$/) # xl/styles.xml
117
+ xml.styles = Nokogiri::XML(zip.read(entry)).remove_namespaces!
118
+ elsif entry.name.match(/^xl.sharedStrings\.xml$/i) # xl/sharedStrings.xml
119
+ # optional feature used by excel, but not often used by xlsx
120
+ # generation libraries. Path name is sometimes lowercase, too.
121
+ xml.shared_strings = Nokogiri::XML(zip.read(entry)).remove_namespaces!
122
+ elsif match = entry.name.match(/^xl.worksheets.sheet([0-9]*)\.xml$/)
123
+ sheet_number = match.captures.first.to_i
124
+ xml.sheets[sheet_number] =
125
+ Nokogiri::XML(zip.read(entry)).remove_namespaces!
126
+ elsif match = entry.name.match(/^xl.worksheets._rels.sheet([0-9]*)\.xml\.rels$/)
127
+ sheet_number = match.captures.first.to_i
128
+ xml.sheet_rels[sheet_number] =
129
+ Nokogiri::XML(zip.read(entry)).remove_namespaces!
130
+ end
131
+ end
92
132
 
93
- xml.sheets <<
94
- Nokogiri::XML(zip.read("xl/worksheets/sheet#{i}.xml")).remove_namespaces!
133
+ # Sometimes there's a zero-index sheet.xml, ex.
134
+ # Google Docs creates:
135
+ #
136
+ # xl/worksheets/sheet.xml
137
+ # xl/worksheets/sheet1.xml
138
+ # xl/worksheets/sheet2.xml
139
+ # While Excel creates:
140
+ # xl/worksheets/sheet1.xml
141
+ # xl/worksheets/sheet2.xml
142
+ #
143
+ # So, for the latter case, let's shift [null, <Sheet 1>, <Sheet 2>]
144
+ if !xml.sheets[0]
145
+ xml.sheets.shift
146
+ xml.sheet_rels.shift
95
147
  end
96
148
  end
97
149
  end
@@ -106,7 +158,7 @@ module SimpleXlsxReader
106
158
 
107
159
  def load_sheets
108
160
  sheet_toc.each_with_index.map do |(sheet_name, _sheet_number), i|
109
- parse_sheet(sheet_name, xml.sheets[i]) # sheet_number is *not* the index into xml.sheets
161
+ parse_sheet(sheet_name, xml.sheets[i], xml.sheet_rels[i]) # sheet_number is *not* the index into xml.sheets
110
162
  end
111
163
  end
112
164
 
@@ -122,9 +174,10 @@ module SimpleXlsxReader
122
174
  end
123
175
  end
124
176
 
125
- def parse_sheet(sheet_name, xsheet)
177
+ def parse_sheet(sheet_name, xsheet, xrels)
126
178
  sheet = Sheet.new(sheet_name)
127
179
  sheet_width, sheet_height = *sheet_dimensions(xsheet)
180
+ cells_w_links = xsheet.xpath('//hyperlinks/hyperlink').inject({}) {|acc, e| acc[e.attr(:ref)] = e.attr(:id); acc}
128
181
 
129
182
  sheet.rows = Array.new(sheet_height) { Array.new(sheet_width) }
130
183
  xsheet.xpath("/worksheet/sheetData/row/c").each do |xcell|
@@ -149,10 +202,21 @@ module SimpleXlsxReader
149
202
  # by about 60%. Odd.
150
203
  xvalue = type == 'inlineStr' ?
151
204
  (xis = xcell.children.find {|c| c.name == 'is'}) && xis.children.find {|c| c.name == 't'} :
152
- xcell.children.find {|c| c.name == 'v'}
205
+ xcell.children.find {|c| c.name == 'f' && c.text.start_with?('HYPERLINK(') || c.name == 'v'}
206
+
207
+ if xvalue
208
+ value = xvalue.text.strip
209
+
210
+ if rel_id = cells_w_links[xcell.attr('r')] # a hyperlink made via GUI
211
+ url = xrels.at_xpath(%(//*[@Id="#{rel_id}"])).attr('Target')
212
+ elsif xvalue.name == 'f' # only time we have a function is if it's a hyperlink
213
+ url = value.slice(/HYPERLINK\("(.*?)"/, 1)
214
+ end
215
+ end
153
216
 
154
217
  cell = begin
155
- self.class.cast(xvalue && xvalue.text.strip, type, style,
218
+ self.class.cast(value, type, style,
219
+ :url => url,
156
220
  :shared_strings => shared_strings,
157
221
  :base_date => base_date)
158
222
  rescue => e
@@ -328,7 +392,7 @@ module SimpleXlsxReader
328
392
  type = style
329
393
  end
330
394
 
331
- case type
395
+ casted = case type
332
396
 
333
397
  ##
334
398
  # There are few built-in types
@@ -361,7 +425,7 @@ module SimpleXlsxReader
361
425
  # the trickiest. note that all these formats can vary on
362
426
  # whether they actually contain a date, time, or datetime.
363
427
  when :date, :time, :date_time
364
- value = value.to_f
428
+ value = Float(value)
365
429
  days_since_date_system_start = value.to_i
366
430
  fraction_of_24 = value - days_since_date_system_start
367
431
 
@@ -388,6 +452,12 @@ module SimpleXlsxReader
388
452
  else
389
453
  value
390
454
  end
455
+
456
+ if options[:url]
457
+ Hyperlink.new(options[:url], casted)
458
+ else
459
+ casted
460
+ end
391
461
  end
392
462
 
393
463
  ## Returns the base_date from which to calculate dates.
@@ -1,3 +1,3 @@
1
1
  module SimpleXlsxReader
2
- VERSION = "1.0.2"
2
+ VERSION = "1.0.4"
3
3
  end
@@ -7,19 +7,21 @@ Gem::Specification.new do |gem|
7
7
  gem.name = "simple_xlsx_reader"
8
8
  gem.version = SimpleXlsxReader::VERSION
9
9
  gem.authors = ["Woody Peterson"]
10
- gem.email = ["woody@sigby.com"]
10
+ gem.email = ["woody.peterson@gmail.com"]
11
11
  gem.description = %q{Read xlsx data the Ruby way}
12
12
  gem.summary = %q{Read xlsx data the Ruby way}
13
13
  gem.homepage = ""
14
+ gem.license = "MIT"
14
15
 
15
16
  gem.add_dependency 'nokogiri'
16
17
  gem.add_dependency 'rubyzip'
17
18
 
18
19
  gem.add_development_dependency 'minitest', '>= 5.0'
20
+ gem.add_development_dependency 'rake'
19
21
  gem.add_development_dependency 'pry'
20
22
 
21
23
  gem.files = `git ls-files`.split($/)
22
24
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
23
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
25
+ gem.test_files = gem.files.grep(%r{^test/})
24
26
  gem.require_paths = ["lib"]
25
27
  end
Binary file
@@ -0,0 +1,15 @@
1
+ require_relative 'test_helper'
2
+ require 'time'
3
+
4
+ describe SimpleXlsxReader do
5
+ let(:one_sheet_file) { File.join(File.dirname(__FILE__), 'gdocs_sheet.xlsx') }
6
+ let(:subject) { SimpleXlsxReader::Document.new(one_sheet_file) }
7
+
8
+ it 'able to load file from google docs' do
9
+ subject.to_hash.must_equal({
10
+ "List 1" => [["Empty gdocs list 1"]],
11
+ "List 2" => [["Empty gdocs list 2"]]
12
+ })
13
+ end
14
+
15
+ end
@@ -96,13 +96,13 @@ describe 'SimpleXlsxReader Benchmark' do
96
96
  bench_exp(1,10000)
97
97
  end
98
98
 
99
- bench_performance_linear 'parses sheets in linear time', 0.9999 do |n|
99
+ bench_performance_linear 'parses sheets in linear time', 0.999 do |n|
100
100
 
101
101
  raise "not enough sample data; asked for #{n}, only have #{@xml.sheets.size}"\
102
102
  if @xml.sheets[n].nil?
103
103
 
104
104
  sheet = SimpleXlsxReader::Document::Mapper.new(@xml).
105
- parse_sheet('test', @xml.sheets[n])
105
+ parse_sheet('test', @xml.sheets[n], nil)
106
106
 
107
107
  raise "sheet didn't parse correctly; expected #{n + 1} rows, got #{sheet.rows.size}"\
108
108
  if sheet.rows.size != n + 1
Binary file
@@ -1,6 +1,8 @@
1
1
  require_relative 'test_helper'
2
2
  require 'time'
3
3
 
4
+ SXR = SimpleXlsxReader
5
+
4
6
  describe SimpleXlsxReader do
5
7
  let(:sesame_street_blog_file) { File.join(File.dirname(__FILE__),
6
8
  'sesame_street_blog.xlsx') }
@@ -15,11 +17,11 @@ describe SimpleXlsxReader do
15
17
  ["Big Bird", "Teacher"]],
16
18
 
17
19
  "Posts"=>
18
- [["Author Name", "Title", "Body", "Created At", "Comment Count"],
19
- ["Big Bird", "The Number 1", "The Greatest", Time.parse("2002-01-01 11:00:00 UTC"), 1],
20
- ["Big Bird", "The Number 2", "Second Best", Time.parse("2002-01-02 14:00:00 UTC"), 2],
21
- ["Big Bird", "Formula Dates", "Tricky tricky", Time.parse("2002-01-03 14:00:00 UTC"), 0],
22
- ["Empty Eagress", nil, "The title, date, and comment have types, but no values", nil, nil]]
20
+ [["Author Name", "Title", "Body", "Created At", "Comment Count", "URL"],
21
+ ["Big Bird", "The Number 1", "The Greatest", Time.parse("2002-01-01 11:00:00 UTC"), 1, SXR::Hyperlink.new("http://www.example.com/hyperlink-function", "This uses the HYPERLINK() function")],
22
+ ["Big Bird", "The Number 2", "Second Best", Time.parse("2002-01-02 14:00:00 UTC"), 2, SXR::Hyperlink.new("http://www.example.com/hyperlink-gui", "This uses the hyperlink GUI option")],
23
+ ["Big Bird", "Formula Dates", "Tricky tricky", Time.parse("2002-01-03 14:00:00 UTC"), 0, nil],
24
+ ["Empty Eagress", nil, "The title, date, and comment have types, but no values", nil, nil, nil]]
23
25
  })
24
26
  end
25
27
  end
@@ -63,10 +65,33 @@ describe SimpleXlsxReader do
63
65
  must_equal Time.parse('2013-08-19 18:30 UTC')
64
66
  end
65
67
 
68
+ it 'reads less-than-zero complex number types styled as times' do
69
+ described_class.cast('6.25E-2', 'n', :time).
70
+ must_equal Time.parse('1899-12-30 01:30:00 UTC')
71
+ end
72
+
66
73
  it 'reads number types styled as date_times' do
67
74
  described_class.cast('41505.77083', 'n', :date_time).
68
75
  must_equal Time.parse('2013-08-19 18:30 UTC')
69
76
  end
77
+
78
+ it 'raises when date-styled values are not numerical' do
79
+ lambda { described_class.cast('14 is not a valid date', nil, :date) }.
80
+ must_raise(ArgumentError)
81
+ end
82
+
83
+ describe "with the url option" do
84
+ let(:url) { "http://www.example.com/hyperlink" }
85
+ it 'creates a hyperlink with a string type' do
86
+ described_class.cast("A link", 'str', :string, url: url).
87
+ must_equal SXR::Hyperlink.new(url, "A link")
88
+ end
89
+
90
+ it 'creates a hyperlink with a shared string type' do
91
+ described_class.cast("2", 's', nil, shared_strings: ['a','b','c'], url: url).
92
+ must_equal SXR::Hyperlink.new(url, 'c')
93
+ end
94
+ end
70
95
  end
71
96
 
72
97
  describe '#shared_strings' do
@@ -253,15 +278,15 @@ describe SimpleXlsxReader do
253
278
  it 'raises if configuration.catch_cell_load_errors' do
254
279
  SimpleXlsxReader.configuration.catch_cell_load_errors = false
255
280
 
256
- lambda { described_class.new(xml).parse_sheet('test', xml.sheets.first) }.
281
+ lambda { described_class.new(xml).parse_sheet('test', xml.sheets.first, nil) }.
257
282
  must_raise(SimpleXlsxReader::CellLoadError)
258
283
  end
259
284
 
260
285
  it 'records a load error if not configuration.catch_cell_load_errors' do
261
286
  SimpleXlsxReader.configuration.catch_cell_load_errors = true
262
287
 
263
- sheet = described_class.new(xml).parse_sheet('test', xml.sheets.first)
264
- sheet.load_errors[[0,0]].must_include 'invalid value for Integer'
288
+ sheet = described_class.new(xml).parse_sheet('test', xml.sheets.first, nil)
289
+ sheet.load_errors[[0,0]].must_include 'invalid value for Float'
265
290
  end
266
291
  end
267
292
 
@@ -295,7 +320,7 @@ describe SimpleXlsxReader do
295
320
  end
296
321
 
297
322
  before do
298
- @row = described_class.new(xml).parse_sheet('test', xml.sheets.first).rows[0]
323
+ @row = described_class.new(xml).parse_sheet('test', xml.sheets.first, nil).rows[0]
299
324
  end
300
325
 
301
326
  it 'continues even when cells are missing numFmtId attributes ' do
@@ -330,8 +355,21 @@ describe SimpleXlsxReader do
330
355
  <c r='G1' t='inlineStr' s='0'>
331
356
  <is><t>Cell G1</t></is>
332
357
  </c>
358
+
359
+ <c r='H1' s='0'>
360
+ <f>HYPERLINK("http://www.example.com/hyperlink-function", "HYPERLINK function")</f>
361
+ <v>HYPERLINK function</v>
362
+ </c>
363
+
364
+ <c r='I1' s='0'>
365
+ <v>GUI-made hyperlink</v>
366
+ </c>
333
367
  </row>
334
368
  </sheetData>
369
+
370
+ <hyperlinks>
371
+ <hyperlink ref="I1" id="rId1"/>
372
+ </hyperlinks>
335
373
  </worksheet>
336
374
  XML
337
375
  ).remove_namespaces!]
@@ -349,11 +387,28 @@ describe SimpleXlsxReader do
349
387
  </styleSheet>
350
388
  XML
351
389
  ).remove_namespaces!
390
+
391
+ # Although not a "type" or "style" according to xlsx spec,
392
+ # it sure could/should be, so let's test it with the rest of our
393
+ # typecasting code.
394
+ xml.sheet_rels = [Nokogiri::XML(
395
+ <<-XML
396
+ <Relationships>
397
+ <Relationship
398
+ Id="rId1"
399
+ Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
400
+ Target="http://www.example.com/hyperlink-gui"
401
+ TargetMode="External"
402
+ />
403
+ </Relationships>
404
+ XML
405
+ ).remove_namespaces!]
406
+
352
407
  end
353
408
  end
354
409
 
355
410
  before do
356
- @row = described_class.new(xml).parse_sheet('test', xml.sheets.first).rows[0]
411
+ @row = described_class.new(xml).parse_sheet('test', xml.sheets.first, xml.sheet_rels.first).rows[0]
357
412
  end
358
413
 
359
414
  it "reads 'Generic' cells as strings" do
@@ -387,6 +442,18 @@ describe SimpleXlsxReader do
387
442
  it "reads strings formatted as inlineStr" do
388
443
  @row[6].must_equal 'Cell G1'
389
444
  end
445
+
446
+ it "reads hyperlinks created via HYPERLINK()" do
447
+ @row[7].must_equal(
448
+ SXR::Hyperlink.new(
449
+ "http://www.example.com/hyperlink-function", "HYPERLINK function"))
450
+ end
451
+
452
+ it "reads hyperlinks created via the GUI" do
453
+ @row[8].must_equal(
454
+ SXR::Hyperlink.new(
455
+ "http://www.example.com/hyperlink-gui", "GUI-made hyperlink"))
456
+ end
390
457
  end
391
458
 
392
459
  describe 'parsing documents with blank rows' do
@@ -435,7 +502,7 @@ describe SimpleXlsxReader do
435
502
  end
436
503
 
437
504
  before do
438
- @rows = described_class.new(xml).parse_sheet('test', xml.sheets.first).rows
505
+ @rows = described_class.new(xml).parse_sheet('test', xml.sheets.first, nil).rows
439
506
  end
440
507
 
441
508
  it "reads row data despite gaps in row numbering" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simple_xlsx_reader
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Woody Peterson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-24 00:00:00.000000000 Z
11
+ date: 2018-07-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '5.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: pry
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -68,12 +82,13 @@ dependencies:
68
82
  version: '0'
69
83
  description: Read xlsx data the Ruby way
70
84
  email:
71
- - woody@sigby.com
85
+ - woody.peterson@gmail.com
72
86
  executables: []
73
87
  extensions: []
74
88
  extra_rdoc_files: []
75
89
  files:
76
90
  - ".gitignore"
91
+ - ".travis.yml"
77
92
  - CHANGELOG.md
78
93
  - Gemfile
79
94
  - LICENSE.txt
@@ -86,6 +101,8 @@ files:
86
101
  - test/date1904_test.rb
87
102
  - test/datetime_test.rb
88
103
  - test/datetimes.xlsx
104
+ - test/gdocs_sheet.xlsx
105
+ - test/gdocs_sheet_test.rb
89
106
  - test/lower_case_sharedstrings.xlsx
90
107
  - test/lower_case_sharedstrings_test.rb
91
108
  - test/performance_test.rb
@@ -95,7 +112,8 @@ files:
95
112
  - test/styles.xml
96
113
  - test/test_helper.rb
97
114
  homepage: ''
98
- licenses: []
115
+ licenses:
116
+ - MIT
99
117
  metadata: {}
100
118
  post_install_message:
101
119
  rdoc_options: []
@@ -113,7 +131,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
131
  version: '0'
114
132
  requirements: []
115
133
  rubyforge_project:
116
- rubygems_version: 2.2.2
134
+ rubygems_version: 2.5.2
117
135
  signing_key:
118
136
  specification_version: 4
119
137
  summary: Read xlsx data the Ruby way
@@ -122,6 +140,8 @@ test_files:
122
140
  - test/date1904_test.rb
123
141
  - test/datetime_test.rb
124
142
  - test/datetimes.xlsx
143
+ - test/gdocs_sheet.xlsx
144
+ - test/gdocs_sheet_test.rb
125
145
  - test/lower_case_sharedstrings.xlsx
126
146
  - test/lower_case_sharedstrings_test.rb
127
147
  - test/performance_test.rb