xsv 1.1.1 → 1.2.1

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
  SHA256:
3
- metadata.gz: b2cc530ad96a5351ea6ab8a8b9d0f2ee9df0e1827a98e4244f239b3658bc2145
4
- data.tar.gz: e286d74163ea3524dfcbd92553c0c4254b667e4ea13adae7468c0d1dc4c8089b
3
+ metadata.gz: 5ba17dfa73b0bb77884f1f95bac715291316aa415c512b5a60b230250395f87d
4
+ data.tar.gz: d5c9ce6ac4b64dc854f6dd133fb139fae13b343b9e08465712d6b0e0189a6628
5
5
  SHA512:
6
- metadata.gz: a89e58bc0447ecbd2eefdd81fe978a5e38438296bcce9dbf18b4dbc3fea5d5740016e35237d229fbab8201bb0e71b208ca66858c9d61e85f4d31d729e9048054
7
- data.tar.gz: 45ddf90be0abe97dcd8aac6b08b9daeac2f68f7634062655efee6f59fbef50c6aad3eb69a461b4f7fcf9dd2751fa735de82e9a0821ec18d2f45cb4bada591698
6
+ metadata.gz: ec2f2bfd10455002aa2ebe8fe661a2b347e5831fde513d57a08fa43a58ea24a8105a2b308d504d5e65f30a5ac5a5c029daf0a6c2ac9c81ca722d6ff456d512ac
7
+ data.tar.gz: 232238fb39c14a4a9fb7d080b0817bd83620f9caeecd812f3058cc473d97506d8b8fbfd5ef74fc25afaf2c46674d230f2292e9b2e1b8e89b2734bb8b1540c679
@@ -19,10 +19,10 @@ jobs:
19
19
  runs-on: ubuntu-latest
20
20
  strategy:
21
21
  matrix:
22
- ruby-version: ['2.6', '2.7', '3.0', '3.1', 'jruby', 'truffleruby']
22
+ ruby-version: ['2.6', '2.7', '3.0', '3.1', '3.2', 'jruby', 'truffleruby']
23
23
 
24
24
  steps:
25
- - uses: actions/checkout@v2
25
+ - uses: actions/checkout@v3
26
26
  - name: Set up Ruby
27
27
  uses: ruby/setup-ruby@v1
28
28
  with:
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Xsv Changelog
2
2
 
3
+ ## 1.2.1 2023-05-09
4
+
5
+ - Handle columns without `r` attribute (issue #48)
6
+ - Access sheets by UTF-8 name (thanks @sebikeller)
7
+
8
+ ## 1.2.0 2023-01-01
9
+
10
+ **This release contains the following minor breaking changes**
11
+
12
+ - Raise an error when entering hash mode on a sheet with duplicate headers to prevent unintentional behaviour (fixes #44)
13
+ - Xsv now returns frozen strings to further improve performance. This means it's no longer possible to call mutating methods on strings read from worksheets without unfreezing them first.
14
+ - Unescape all HTML entities in XML characters (thanks @til)
15
+
3
16
  ## 1.1.1 2022-04-01
4
17
 
5
18
  - Improve compatibility with files generated by the Open XML SDK (#40)
@@ -119,4 +132,4 @@ Fix a Gemfile small Gemfile issue that broke the 0.3.3 and 0.3.4 releases
119
132
 
120
133
  ## 0.3.3 - 2020-03-02
121
134
 
122
- Intial version with a changelog and reasonably complete YARD documentation.
135
+ Initial version with a changelog and reasonably complete YARD documentation.
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # Xsv .xlsx reader
2
2
 
3
3
 
4
- [![Test badge](https://img.shields.io/github/workflow/status/martijn/xsv/Ruby/main)](https://github.com/martijn/xsv/actions/workflows/ruby.yml)
4
+
5
+ [![Test badge](https://img.shields.io/github/actions/workflow/status/martijn/xsv/ruby.yml?branch=main)](https://github.com/martijn/xsv/actions/workflows/ruby.yml)
5
6
  [![Codecov badge](https://img.shields.io/codecov/c/github/martijn/xsv/main)](https://app.codecov.io/gh/martijn/xsv)
6
7
  [![Yard Docs badge](http://img.shields.io/badge/yard-docs-blue.svg)](https://rubydoc.info/github/martijn/xsv)
7
8
  [![Gem Version badge](https://badge.fury.io/rb/xsv.svg)](https://badge.fury.io/rb/xsv)
@@ -36,10 +37,9 @@ Or install it yourself as:
36
37
 
37
38
  $ gem install xsv
38
39
 
39
- Xsv targets ruby >= 2.5 and has a just single dependency, `rubyzip`. It has been
40
- tested successfully with MRI, JRuby, and TruffleRuby. Due to the lack of
41
- native extensions should work well in multi-threaded environments or in Ractor
42
- when that becomes stable.
40
+ Xsv targets ruby >= 2.6 and has a just single dependency, `rubyzip`. It has been
41
+ tested successfully with MRI, JRuby, and TruffleRuby. It has no native extensions
42
+ and is designed to be thread-safe.
43
43
 
44
44
  ## Usage
45
45
 
@@ -85,8 +85,11 @@ sheet.parse_headers!
85
85
  sheet[0] # => {"header1" => "value1", "header2" => "value2"}
86
86
  ```
87
87
 
88
- Be aware that hash mode will lead to unpredictable results if the worksheet
89
- has multiple columns with the same header. `Xsv::Sheet` implements `Enumerable` so along with `#each`
88
+ Because of the way Ruby hashes work will raise `Xsv::DuplicateHeaders` if it detects
89
+ duplicate values in the header row when calling `#parse_headers!` or when opening
90
+ a workbook with `parse_headers: true`.
91
+
92
+ `Xsv::Sheet` implements `Enumerable` so along with `#each`
90
93
  you can call methods like `#first`, `#filter`/`#select`, and `#map` on it.
91
94
 
92
95
  ### Opening a string or buffer instead of filename
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "cgi"
4
+
3
5
  module Xsv
4
6
  class SaxParser
5
7
  ATTR_REGEX = /((\p{Alnum}+)="(.*?)")/mn
@@ -36,14 +38,7 @@ module Xsv
36
38
  chars = pbuf.slice!(0, o + 1).chop!.force_encoding("utf-8")
37
39
 
38
40
  if responds_to_characters && !chars.empty?
39
- if chars.index("&")
40
- chars.gsub!("&", "&")
41
- chars.gsub!("'", "'")
42
- chars.gsub!(">", ">")
43
- chars.gsub!("&lt;", "<")
44
- chars.gsub!("&quot;", '"')
45
- end
46
- characters(chars)
41
+ characters(CGI.unescapeHTML(chars))
47
42
  end
48
43
 
49
44
  state = :look_end
@@ -6,7 +6,7 @@ module Xsv
6
6
  class SharedStringsParser < SaxParser
7
7
  def self.parse(io)
8
8
  strings = []
9
- new { |s| strings << s }.parse(io)
9
+ new { |s| strings << -s }.parse(io)
10
10
  strings
11
11
  end
12
12
 
data/lib/xsv/sheet.rb CHANGED
@@ -83,6 +83,12 @@ module Xsv
83
83
  # @return [self]
84
84
  def parse_headers!
85
85
  @headers = parse_headers
86
+
87
+ # Check for duplicate headers, but don't care about nil columns
88
+ if (duplicate_header = @headers.detect { |h| @headers.count(h) > 1 })
89
+ raise Xsv::DuplicateHeaders, "Duplicate header '#{duplicate_header}' found, consider parsing this sheet in array mode."
90
+ end
91
+
86
92
  @mode = :hash
87
93
 
88
94
  self
@@ -17,6 +17,7 @@ module Xsv
17
17
  @store_characters = false
18
18
 
19
19
  @row_index = 0
20
+ @col_index = 0
20
21
  @current_row = {}
21
22
  @current_row_number = 0
22
23
  @current_cell = {}
@@ -33,7 +34,7 @@ module Xsv
33
34
  when "v", "is", "t"
34
35
  @store_characters = true
35
36
  when "row"
36
- @current_row = @empty_row.dup
37
+ @current_row = @mode == :array ? [] : @empty_row.dup
37
38
  @current_row_number = attrs[:r].to_i
38
39
  end
39
40
  end
@@ -47,19 +48,22 @@ module Xsv
47
48
  when "v", "is", "t"
48
49
  @store_characters = false
49
50
  when "c"
50
- col_index = column_index(@current_cell[:r])
51
+ col_index = @current_cell[:r] ? column_index(@current_cell[:r]) : @col_index
51
52
 
52
53
  if @mode == :array
53
54
  @current_row[col_index] = format_cell
54
55
  else
55
56
  @current_row[@headers[col_index]] = format_cell
56
57
  end
58
+
59
+ @col_index += 1
57
60
  when "row"
58
61
  return if @current_row_number <= @row_skip
59
62
 
60
63
  adjusted_row_number = @current_row_number - @row_skip
61
64
 
62
65
  @row_index += 1
66
+ @col_index = 0
63
67
 
64
68
  # Skip first row if we're in hash mode
65
69
  return if adjusted_row_number == 1 && @mode == :hash
@@ -72,7 +76,14 @@ module Xsv
72
76
  end
73
77
 
74
78
  # Do not return empty trailing rows
75
- @block.call(@current_row) unless @row_index > @last_row
79
+ return if @row_index > @last_row
80
+
81
+ # Add trailing empty columns
82
+ if @mode == :array && @current_row.length < @empty_row.length
83
+ @block.call(@current_row + @empty_row[@current_row.length..])
84
+ else
85
+ @block.call(@current_row)
86
+ end
76
87
  end
77
88
  end
78
89
 
@@ -85,7 +96,7 @@ module Xsv
85
96
  when "s"
86
97
  @workbook.shared_strings[@current_value.to_i]
87
98
  when "str", "inlineStr"
88
- @current_value.strip
99
+ -@current_value.strip
89
100
  when "e" # N/A
90
101
  nil
91
102
  when nil, "n"
@@ -9,7 +9,9 @@ module Xsv
9
9
 
10
10
  new { |sheet_ids| sheets_ids << sheet_ids }.parse(io)
11
11
 
12
- sheets_ids
12
+ sheets_ids.each do |sheet|
13
+ sheet[:name].force_encoding(Encoding::UTF_8)
14
+ end
13
15
  end
14
16
 
15
17
  def initialize(&block)
data/lib/xsv/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Xsv
4
- VERSION = "1.1.1"
4
+ VERSION = "1.2.1"
5
5
  end
data/lib/xsv.rb CHANGED
@@ -21,6 +21,8 @@ require "xsv/workbook"
21
21
  module Xsv
22
22
  class Error < StandardError; end
23
23
 
24
+ class DuplicateHeaders < StandardError; end
25
+
24
26
  # An AssertionFailed error indicates an unexpected condition, meaning a bug
25
27
  # or misinterpreted .xlsx document
26
28
  class AssertionFailed < StandardError; end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xsv
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Martijn Storck
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-04-01 00:00:00.000000000 Z
11
+ date: 2023-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubyzip