xsv 0.2.1 → 0.2.2

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
  SHA256:
3
- metadata.gz: ace53a58655a50f4de2f10c4a2d68819774e3e74625595353290502299630b30
4
- data.tar.gz: 8278ea7b26ac261781ae71328762104db9d14de0cbc05be1b0551a3cb876ea35
3
+ metadata.gz: 2b097ec44b4cee4a7f6331a3a94f15e24f33c88258d375923f965dafe88ee13e
4
+ data.tar.gz: c2da68b26d04cb6bd28496d810f7721e327a655c1c96b695d9b091e569767d21
5
5
  SHA512:
6
- metadata.gz: 31ccd6261073893e0a0873997d7befa39fc0f8088f5f4d9d1ec3f97b7d90f48d1153714cff4f124a4be853976ce714326a6ec8634e646f15ecf6cf428c245a39
7
- data.tar.gz: eed43d77052870dc45bc009719b130096a05a6add11576a349ca027ff93b428bfe64813dd83a8ea58a1a7da94aa8b490b4394efa65bbb175ae09dd74c77ee20a
6
+ metadata.gz: b0a7b30c258e16d391990881f4574577eeee6ec3424524cdc360901ffa62033102c518b005d3b181d0b6e7887f52afa7dfc9415cb2cd762f3f0779d9801aaf5a
7
+ data.tar.gz: 32ab543df470d94eb4a81e2b271a18ba9295c0d7d9fd63cf918a18baa02b6c01e6bcfb35e6d6e42021d36f773affce5ace52fb07dd7d2ea4110b4a0cbe22fc9c
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- xsv (0.2.0)
4
+ xsv (0.2.1)
5
5
  nokogiri (~> 1.10)
6
6
  rubyzip (~> 2.2)
7
7
 
data/lib/xsv/helpers.rb CHANGED
@@ -32,14 +32,14 @@ module Xsv
32
32
  47 => "mm:ss.0",
33
33
  48 => "##0.0E+0",
34
34
  49 => "@",
35
- }
35
+ }.freeze
36
36
 
37
- MINUTE = 60
38
- HOUR = 3600
37
+ MINUTE = 60.freeze
38
+ HOUR = 3600.freeze
39
39
 
40
40
  # Return the index number for the given Excel column name
41
41
  def column_index(col)
42
- col = col.scan(/^[A-Z]+/).first
42
+ col = col[/^[A-Z]+/]
43
43
 
44
44
  val = 0
45
45
  while col.length > 0
data/lib/xsv/sheet.rb CHANGED
@@ -14,24 +14,14 @@ module Xsv
14
14
  @mode = :array
15
15
  @row_skip = 0
16
16
 
17
- dimension = xml.css("dimension").first
17
+ @has_cells = !xml.at_css("sheetData c").nil?
18
18
 
19
- if dimension
20
- _firstCell, lastCell = dimension["ref"].split(":")
21
- end
22
-
23
- if lastCell
24
- # Assume the dimension reflects the content
25
- @column_count = column_index(lastCell) + 1
19
+ if @has_cells
20
+ @column_count, @last_row = get_sheet_dimensions
26
21
  else
27
- # Find the last cell in every row that has a value
28
- rightmost_cells = @xml.xpath("//xmlns:row/xmlns:c[*[local-name() = 'v']][last()]").map { |c| column_index(c["r"]) }
29
- @column_count = rightmost_cells.max + 1
30
-
22
+ @column_count = 0
23
+ @last_row = 0
31
24
  end
32
-
33
- # Find the last row that contains actual values
34
- @last_row = @xml.xpath("//xmlns:row[*[xmlns:v]][last()]").first["r"].to_i
35
25
  end
36
26
 
37
27
  def inspect
@@ -69,7 +59,7 @@ module Xsv
69
59
 
70
60
  # Get row by number, starting at 0
71
61
  def [](number)
72
- row_xml = xml.css("sheetData row[r=#{number + @row_skip + 1}]").first
62
+ row_xml = xml.at_css("sheetData row[r=#{number + @row_skip + 1}]")
73
63
 
74
64
  if row_xml
75
65
  parse_row(row_xml)
@@ -81,18 +71,24 @@ module Xsv
81
71
  # Load headers in the top row of the worksheet. After parsing of headers
82
72
  # all methods return hashes instead of arrays
83
73
  def parse_headers!
84
- @mode = :array
85
74
  @headers = parse_headers
86
-
87
75
  @mode = :hash
88
76
 
89
77
  true
90
78
  end
91
79
 
80
+ def headers
81
+ if @headers.any?
82
+ @headers
83
+ else
84
+ parse_headers
85
+ end
86
+ end
87
+
92
88
  private
93
89
 
94
90
  def parse_headers
95
- parse_row(@xml.css("sheetData row")[@row_skip])
91
+ parse_row(@xml.css("sheetData row")[@row_skip], :array)
96
92
  end
97
93
 
98
94
  def empty_row
@@ -104,7 +100,8 @@ module Xsv
104
100
  end
105
101
  end
106
102
 
107
- def parse_row(xml)
103
+ def parse_row(xml, mode = nil)
104
+ mode ||= @mode
108
105
  row = empty_row
109
106
 
110
107
  xml.css("c").first(@column_count).each do |c_xml|
@@ -116,7 +113,7 @@ module Xsv
116
113
  when "e" # N/A
117
114
  nil
118
115
  when nil
119
- v = c_xml.css("v").first
116
+ v = c_xml.at_css("v")
120
117
 
121
118
  if v.nil?
122
119
  nil
@@ -147,7 +144,7 @@ module Xsv
147
144
  # Determine column position and pad row with nil values
148
145
  col_index = column_index(c_xml["r"])
149
146
 
150
- case @mode
147
+ case mode
151
148
  when :array
152
149
  row[col_index] = value
153
150
  when :hash
@@ -157,5 +154,28 @@ module Xsv
157
154
 
158
155
  row
159
156
  end
157
+
158
+ # Read or estimate outer bounds of sheet
159
+ def get_sheet_dimensions
160
+ dimension = xml.at_css("dimension")
161
+
162
+ if dimension
163
+ _firstCell, lastCell = dimension["ref"].split(":")
164
+ end
165
+
166
+ if lastCell
167
+ # Assume the dimension reflects the content
168
+ column_count = column_index(lastCell) + 1
169
+ else
170
+ # Find the last cell in every row that has a value
171
+ rightmost_cells = @xml.xpath("//xmlns:row/xmlns:c[*[local-name() = 'v']][last()]").map { |c| column_index(c["r"]) }
172
+ column_count = rightmost_cells.max + 1
173
+ end
174
+
175
+ # Find the last row that contains actual values
176
+ last_row = @xml.at_xpath("//xmlns:row[*[xmlns:v]][last()]")["r"].to_i
177
+
178
+ return [column_count, last_row]
179
+ end
160
180
  end
161
181
  end
data/lib/xsv/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Xsv
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
3
3
  end
data/lib/xsv/workbook.rb CHANGED
@@ -17,7 +17,7 @@ module Xsv
17
17
 
18
18
  @sheets = []
19
19
  @xfs = []
20
- @numFmts = Xsv::Helpers::BUILT_IN_NUMBER_FORMATS
20
+ @numFmts = Xsv::Helpers::BUILT_IN_NUMBER_FORMATS.dup
21
21
 
22
22
  fetch_shared_strings
23
23
  fetch_styles
@@ -33,11 +33,11 @@ module Xsv
33
33
  def fetch_shared_strings
34
34
  stream = @zip.glob("xl/sharedStrings.xml").first.get_input_stream
35
35
  xml = Nokogiri::XML(stream)
36
- expected_count = xml.css("sst").first["uniqueCount"].to_i
37
- @shared_strings = xml.css("sst si t").map(&:inner_text)
36
+ expected_count = xml.at_css("sst")["uniqueCount"].to_i
37
+ @shared_strings = xml.css("sst si").map { |si| si.css("t").map(&:inner_text).join }
38
38
 
39
39
  if @shared_strings.count != expected_count
40
- raise Xsv::Error, "Mismatch in shared strings count! #{expected_count} <> #{@shared_strings.count}"
40
+ raise Xsv::AssertionFailed, "Mismatch in shared strings count! #{expected_count} <> #{@shared_strings.count}"
41
41
  end
42
42
 
43
43
  stream.close
@@ -58,7 +58,7 @@ module Xsv
58
58
 
59
59
  def fetch_sheets
60
60
  @zip.glob("xl/worksheets/sheet*.xml").sort do |a, b|
61
- a.name.scan(/\d+/).first.to_i <=> b.name.scan(/\d+/).first.to_i
61
+ a.name[/\d+/].to_i <=> b.name[/\d+/].to_i
62
62
  end.each do |entry|
63
63
  @sheets << Xsv::Sheet.new(self, Nokogiri::XML(entry.get_input_stream))
64
64
  end
data/lib/xsv.rb CHANGED
@@ -7,4 +7,7 @@ require "xsv/workbook"
7
7
 
8
8
  module Xsv
9
9
  class Error < StandardError; end
10
+ # An AssertionFailed error indicates an unexpected condition, meaning a bug
11
+ # or misinterpreted .xlsx document
12
+ class AssertionFailed < StandardError; end
10
13
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xsv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martijn Storck