simple_xlsx_reader 1.0.2 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
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