creek 2.5.3 → 2.6.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: 0d90975898b7d260d37f6543755f8c2f4d5931d6e387a56c343bce23eee7e3b1
4
- data.tar.gz: 0c381e483070a0e883f128e1a03147a5acf60c4a1095b42ef0d3106af7889f8b
3
+ metadata.gz: d6c8bd9467a3772e8b09ecfce4dbef12d530cc094e44a0a9de3806d92930a46f
4
+ data.tar.gz: de59455bb37db21574fb55f269dd12faa3c4aeecbb52139ce5fdb6b0a7bb740a
5
5
  SHA512:
6
- metadata.gz: 1f23c318b54b45c2d1732c874e3f6519e7d528175a395b888e3352f302fb1f0b8625cdde965f16540081163282751dd410a712281651b9b3d3b91c9e89bec800
7
- data.tar.gz: e601060be6ba35b3bc3ded42865bce8b46fc3ca92feec1439dc2e719f132bb2359d06129f1110dc6676d07f7707364fead716f8f584a5851388a1d183c6e6825
6
+ metadata.gz: c0d5f95b17cd1e3cd7f0fb1286aa6a3a57875949b8a1c55c7eb34e0afe6f9bb34c373126273e5b20f77553c4e350fa8089c0398dfe23c55757a9c43a5ebd141c
7
+ data.tar.gz: ff1771e65a5add043080fa4ebb63c5b90a4e91d40ee7566996ae9e33a83dc0f6b54d327ee825a5759ee874a7219c4bcd2097b2e78e27374e5c7fc6d69fcccebd
@@ -0,0 +1,35 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [ "*" ]
13
+ pull_request:
14
+ branches: [ "*" ]
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ test:
21
+
22
+ runs-on: ubuntu-latest
23
+ strategy:
24
+ matrix:
25
+ ruby-version: ['2.6', '2.7', '3.0', '3.1']
26
+
27
+ steps:
28
+ - uses: actions/checkout@v3
29
+ - name: Set up Ruby
30
+ uses: ruby/setup-ruby@v1
31
+ with:
32
+ ruby-version: ${{ matrix.ruby-version }}
33
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
34
+ - name: Run tests
35
+ run: bundle exec rake
data/creek.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.required_ruby_version = '>= 2.0.0'
22
22
 
23
- spec.add_development_dependency "bundler", "~> 2.1.2"
23
+ spec.add_development_dependency "bundler"
24
24
  spec.add_development_dependency "rake"
25
25
  spec.add_development_dependency 'rspec', '~> 3.6.0'
26
26
  spec.add_development_dependency 'pry-byebug'
data/lib/creek/drawing.rb CHANGED
@@ -66,7 +66,7 @@ module Creek
66
66
  # Drawing xml contains relationships ID's and coordinates (row, col).
67
67
  # Drawing relationships xml contains images' locations.
68
68
  def load_drawings_and_rels
69
- @drawings = parse_xml(@drawing_filepath).css('xdr|twoCellAnchor')
69
+ @drawings = parse_xml(@drawing_filepath).css('xdr|twoCellAnchor', 'xdr|oneCellAnchor' )
70
70
  drawing_rels_filepath = expand_to_rels_path(@drawing_filepath)
71
71
  @drawings_rels = parse_xml(drawing_rels_filepath).css('Relationships')
72
72
  end
@@ -82,7 +82,7 @@ module Creek
82
82
  col_from_selector = 'xdr:from/xdr:col'.freeze
83
83
  col_to_selector = 'xdr:to/xdr:col'.freeze
84
84
 
85
- @drawings.xpath('//xdr:twoCellAnchor').each do |drawing|
85
+ @drawings.xpath('//xdr:twoCellAnchor', '//xdr:oneCellAnchor').each do |drawing|
86
86
  # embed = drawing.xpath(image_selector).first.attributes['embed']
87
87
  temp = drawing.xpath(image_selector).first
88
88
  embed = temp.attributes['embed'] if temp
@@ -93,12 +93,17 @@ module Creek
93
93
 
94
94
  row_from = drawing.xpath(row_from_selector).text.to_i
95
95
  col_from = drawing.xpath(col_from_selector).text.to_i
96
- row_to = drawing.xpath(row_to_selector).text.to_i
97
- col_to = drawing.xpath(col_to_selector).text.to_i
98
96
 
99
- (col_from..col_to).each do |col|
100
- (row_from..row_to).each do |row|
101
- @images_pathnames[[row, col]].push(path)
97
+ if drawing.name == 'oneCellAnchor'
98
+ @images_pathnames[[row_from , col_from ]].push(path)
99
+ else
100
+ row_to = drawing.xpath(row_to_selector).text.to_i
101
+ col_to = drawing.xpath(col_to_selector).text.to_i
102
+
103
+ (col_from..col_to).each do |col|
104
+ (row_from..row_to).each do |row|
105
+ @images_pathnames[[row, col]].push(path)
106
+ end
102
107
  end
103
108
  end
104
109
  end
@@ -5,6 +5,8 @@ module Creek
5
5
 
6
6
  class Creek::SharedStrings
7
7
 
8
+ SPREADSHEETML_URI = 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'
9
+
8
10
  attr_reader :book, :dictionary
9
11
 
10
12
  def initialize book
@@ -27,9 +29,17 @@ module Creek
27
29
 
28
30
  def self.parse_shared_string_from_document(xml)
29
31
  dictionary = Hash.new
30
-
31
- xml.css('si').each_with_index do |si, idx|
32
- text_nodes = si.css('>t, r t')
32
+ namespace = xml.namespaces.detect{|_key, uri| uri == SPREADSHEETML_URI }
33
+ prefix = if namespace && namespace[0].start_with?('xmlns:')
34
+ namespace[0].delete_prefix('xmlns:') + '|'
35
+ else
36
+ ''
37
+ end
38
+ node_selector = "#{prefix}si"
39
+ text_selector = ">#{prefix}t, #{prefix}r #{prefix}t"
40
+
41
+ xml.css(node_selector).each_with_index do |si, idx|
42
+ text_nodes = si.css(text_selector)
33
43
  if text_nodes.count == 1 # plain text node
34
44
  dictionary[idx] = Creek::Styles::Converter.unescape_string(text_nodes.first.content)
35
45
  else # rich text nodes with text fragments
data/lib/creek/sheet.rb CHANGED
@@ -8,6 +8,7 @@ module Creek
8
8
  include Creek::Utils
9
9
 
10
10
  HEADERS_ROW_NUMBER = '1'
11
+ SPREADSHEETML_URI = 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'
11
12
 
12
13
  attr_accessor :with_headers
13
14
  attr_reader :book,
@@ -97,13 +98,22 @@ module Creek
97
98
  cell_type = nil
98
99
  cell_style_idx = nil
99
100
  @book.files.file.open(path) do |xml|
101
+ prefix = ''
100
102
  Nokogiri::XML::Reader.from_io(xml).each do |node|
101
- if node.name == 'row' && node.node_type == opener
103
+ if prefix.empty? && node.namespaces.any?
104
+ namespace = node.namespaces.detect{|_key, uri| uri == SPREADSHEETML_URI }
105
+ prefix = if namespace && namespace[0].start_with?('xmlns:')
106
+ namespace[0].delete_prefix('xmlns:') + ':'
107
+ else
108
+ ''
109
+ end
110
+ end
111
+ if node.name == "#{prefix}row" && node.node_type == opener
102
112
  row = node.attributes
103
113
  row['cells'] = {}
104
114
  cells = {}
105
115
  y << (include_meta_data ? row : cells) if node.self_closing?
106
- elsif node.name == 'row' && node.node_type == closer
116
+ elsif node.name == "#{prefix}row" && node.node_type == closer
107
117
  processed_cells = fill_in_empty_cells(cells, row['r'], cell, use_simple_rows_format)
108
118
  @headers = processed_cells if with_headers && row['r'] == HEADERS_ROW_NUMBER
109
119
 
@@ -117,11 +127,11 @@ module Creek
117
127
 
118
128
  row['cells'] = processed_cells
119
129
  y << (include_meta_data ? row : processed_cells)
120
- elsif node.name == 'c' && node.node_type == opener
130
+ elsif node.name == "#{prefix}c" && node.node_type == opener
121
131
  cell_type = node.attributes['t']
122
132
  cell_style_idx = node.attributes['s']
123
133
  cell = node.attributes['r']
124
- elsif %w[v t].include?(node.name) && node.node_type == opener
134
+ elsif ["#{prefix}v", "#{prefix}t"].include?(node.name) && node.node_type == opener
125
135
  unless cell.nil?
126
136
  node.read
127
137
  cells[cell] = convert(node.value, cell_type, cell_style_idx)
data/lib/creek/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Creek
2
- VERSION = "2.5.3"
2
+ VERSION = "2.6.2"
3
3
  end
data/spec/drawing_spec.rb CHANGED
@@ -3,9 +3,11 @@ require './spec/spec_helper'
3
3
  describe 'drawing' do
4
4
  let(:book) { Creek::Book.new('spec/fixtures/sample-with-images.xlsx') }
5
5
  let(:book_no_images) { Creek::Book.new('spec/fixtures/sample.xlsx') }
6
+ let(:book_with_one_cell_anchored_images) { Creek::Book.new('spec/fixtures/sample-with-one-cell-anchored-images.xlsx') }
6
7
  let(:drawingfile) { 'xl/drawings/drawing1.xml' }
7
8
  let(:drawing) { Creek::Drawing.new(book, drawingfile) }
8
9
  let(:drawing_without_images) { Creek::Drawing.new(book_no_images, drawingfile) }
10
+ let(:drawing_with_one_cell_anchored_images) { Creek::Drawing.new(book_with_one_cell_anchored_images, drawingfile) }
9
11
 
10
12
  describe '#has_images?' do
11
13
  it 'has' do
@@ -48,5 +50,21 @@ describe 'drawing' do
48
50
  expect(image1).to eq(image2)
49
51
  end
50
52
  end
53
+
54
+ context 'when one cell anchored images in cell' do
55
+ it 'returns image for anchored cell' do
56
+ image = drawing_with_one_cell_anchored_images.images_at('A2')[0]
57
+ expect(image.class).to eq(Pathname)
58
+ expect(image.exist?).to eq(true)
59
+ end
60
+
61
+ it 'returns nil for non-anchored cell' do
62
+ image = drawing_with_one_cell_anchored_images.images_at('A3')[0]
63
+ # Image can be seen present on cell A4 in `sample-with-one-cell-anchored-images.xlsx`
64
+ image_at_non_anchored_cell = drawing_with_one_cell_anchored_images.images_at('A4')
65
+ expect(image.class).to eq(Pathname)
66
+ expect(image_at_non_anchored_cell).to eq(nil)
67
+ end
68
+ end
51
69
  end
52
70
  end
@@ -0,0 +1,91 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2
+ <sst xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="6" uniqueCount="5">
3
+ <x:si>
4
+ <x:t>Cell A1</x:t>
5
+ </x:si>
6
+ <x:si>
7
+ <x:t>Cell B1</x:t>
8
+ </x:si>
9
+ <x:si>
10
+ <x:t>My Cell</x:t>
11
+ </x:si>
12
+ <x:si>
13
+ <x:r>
14
+ <x:rPr>
15
+ <x:sz val="11"/>
16
+ <x:color rgb="FFFF0000"/>
17
+ <x:rFont val="Calibri"/>
18
+ <x:family val="2"/>
19
+ <x:scheme val="minor"/>
20
+ </x:rPr>
21
+ <x:t>Cell</x:t>
22
+ </x:r>
23
+ <x:r>
24
+ <x:rPr>
25
+ <x:sz val="11"/>
26
+ <x:color theme="1"/>
27
+ <x:rFont val="Calibri"/>
28
+ <x:family val="2"/>
29
+ <x:scheme val="minor"/>
30
+ </x:rPr>
31
+ <x:t xml:space="preserve"> </x:t>
32
+ </x:r>
33
+ <x:r>
34
+ <x:rPr>
35
+ <x:b/>
36
+ <x:sz val="11"/>
37
+ <x:color theme="1"/>
38
+ <x:rFont val="Calibri"/>
39
+ <x:family val="2"/>
40
+ <x:scheme val="minor"/>
41
+ </x:rPr>
42
+ <x:t>A2</x:t>
43
+ </x:r>
44
+ </x:si>
45
+ <x:si>
46
+ <x:r>
47
+ <x:rPr>
48
+ <x:sz val="11"/>
49
+ <x:color rgb="FF00B0F0"/>
50
+ <x:rFont val="Calibri"/>
51
+ <x:family val="2"/>
52
+ <x:scheme val="minor"/>
53
+ </x:rPr>
54
+ <x:t>Cell</x:t>
55
+ </x:r>
56
+ <x:r>
57
+ <x:rPr>
58
+ <x:sz val="11"/>
59
+ <x:color theme="1"/>
60
+ <x:rFont val="Calibri"/>
61
+ <x:family val="2"/>
62
+ <x:scheme val="minor"/>
63
+ </x:rPr>
64
+ <x:t xml:space="preserve"> </x:t>
65
+ </x:r>
66
+ <x:r>
67
+ <x:rPr>
68
+ <x:i/>
69
+ <x:sz val="11"/>
70
+ <x:color theme="1"/>
71
+ <x:rFont val="Calibri"/>
72
+ <x:family val="2"/>
73
+ <x:scheme val="minor"/>
74
+ </x:rPr>
75
+ <x:t>B2</x:t>
76
+ </x:r>
77
+ </x:si>
78
+ <x:si>
79
+ <x:t>Cell with_x000D_escaped_x000D_characters</x:t>
80
+ </x:si>
81
+ <x:si>
82
+ <x:t>吉田兼好</x:t>
83
+ <x:rPh sb="0" eb="2">
84
+ <x:t xml:space="preserve">ヨシダ </x:t>
85
+ </x:rPh>
86
+ <x:rPh sb="2" eb="4">
87
+ <x:t xml:space="preserve">ケンコウ </x:t>
88
+ </x:rPh>
89
+ <x:phoneticPr fontId="1"/>
90
+ </x:si>
91
+ </x:sst>
@@ -17,4 +17,21 @@ describe 'shared strings' do
17
17
  expect(dictionary[6]).to eq('吉田兼好')
18
18
  end
19
19
 
20
- end
20
+ context 'when the nodes are namespaced' do
21
+ it 'parses the dictionary correctly' do
22
+ shared_strings_xml_file = File.open('spec/fixtures/sst_namespaced.xml')
23
+ doc = Nokogiri::XML(shared_strings_xml_file)
24
+ dictionary = Creek::SharedStrings.parse_shared_string_from_document(doc)
25
+
26
+ expect(dictionary.keys.size).to eq(7)
27
+ expect(dictionary[0]).to eq('Cell A1')
28
+ expect(dictionary[1]).to eq('Cell B1')
29
+ expect(dictionary[2]).to eq('My Cell')
30
+ expect(dictionary[3]).to eq('Cell A2')
31
+ expect(dictionary[4]).to eq('Cell B2')
32
+ expect(dictionary[5]).to eq("Cell with\rescaped\rcharacters")
33
+ expect(dictionary[6]).to eq('吉田兼好')
34
+ end
35
+
36
+ end
37
+ end
data/spec/sheet_spec.rb CHANGED
@@ -65,6 +65,20 @@ describe 'sheet' do
65
65
  end
66
66
  end
67
67
 
68
+ context 'when one cell anchored images in cell' do
69
+ let(:book_with_one_cell_anchored_images) { Creek::Book.new('spec/fixtures/sample-with-one-cell-anchored-images.xlsx') }
70
+ let(:sheet_with_one_cell_anchored_images) { Creek::Sheet.new(book_with_one_cell_anchored_images, 'Sheet 1', 1, '', '', '1', sheetfile) }
71
+ let(:rows) { sheet_with_one_cell_anchored_images.with_images.rows.map { |r| r } }
72
+
73
+ it 'returns image for anchored cell' do
74
+ expect(load_cell(rows, 'A2').size).to eq(1)
75
+ end
76
+
77
+ it 'returns nil for non-anchored cell' do
78
+ expect(load_cell(rows, 'A4')).to eq(nil)
79
+ end
80
+ end
81
+
68
82
  context 'with excel without images' do
69
83
  let(:book_no_images) { Creek::Book.new('spec/fixtures/sample.xlsx') }
70
84
  let(:sheet_no_images) { Creek::Sheet.new(book_no_images, 'Sheet 1', 1, '', '', '1', sheetfile) }
@@ -74,6 +88,16 @@ describe 'sheet' do
74
88
  expect(load_cell(rows, 'A10')).to eq(0.15)
75
89
  end
76
90
  end
91
+
92
+ context 'when nodes are namespaced' do
93
+ let(:namespaced_book) { Creek::Book.new('spec/fixtures/sample_namespaced.xlsx') }
94
+ let(:namespaced_sheet) { Creek::Sheet.new(namespaced_book, 'Sheet 1', 1, '', '', '1', sheetfile) }
95
+
96
+ it 'parses rows correctly' do
97
+ rows = namespaced_sheet.rows.map { |r| r }
98
+ expect(load_cell(rows, 'A10')).to eq(0.15)
99
+ end
100
+ end
77
101
  end
78
102
 
79
103
  describe '#images_at' do
@@ -130,5 +154,37 @@ describe 'sheet' do
130
154
  expect(row['HeaderC']).to eq 'value3'
131
155
  end
132
156
  end
157
+
158
+ context 'when nodes are namespaced' do
159
+ let(:namespaced_book) { Creek::Book.new('spec/fixtures/sample-with-headers_namespaced.xlsx') }
160
+ let(:sheet) { Creek::Sheet.new(namespaced_book, 'Sheet 1', 1, '', '', '1', sheetfile) }
161
+
162
+ it 'returns values by letters' do
163
+ expect(subject['A']).to eq 'value1'
164
+ expect(subject['B']).to eq 'value2'
165
+ end
166
+
167
+ context 'when enable with_headers property' do
168
+ before { sheet.with_headers = true }
169
+
170
+ it 'returns values by headers name' do
171
+ expect(subject['HeaderA']).to eq 'value1'
172
+ expect(subject['HeaderB']).to eq 'value2'
173
+ expect(subject['HeaderC']).to eq 'value3'
174
+ end
175
+
176
+ it 'returns headers correctly when called multiple times' do
177
+ row = sheet.simple_rows.to_a[1]
178
+ expect(row['HeaderA']).to eq 'value1'
179
+ expect(row['HeaderB']).to eq 'value2'
180
+ expect(row['HeaderC']).to eq 'value3'
181
+
182
+ row = sheet.simple_rows.to_a[1]
183
+ expect(row['HeaderA']).to eq 'value1'
184
+ expect(row['HeaderB']).to eq 'value2'
185
+ expect(row['HeaderC']).to eq 'value3'
186
+ end
187
+ end
188
+ end
133
189
  end
134
190
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: creek
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.3
4
+ version: 2.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - pythonicrubyist
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-12 00:00:00.000000000 Z
11
+ date: 2022-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 2.1.2
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 2.1.2
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -103,6 +103,7 @@ extensions: []
103
103
  extra_rdoc_files: []
104
104
  files:
105
105
  - ".DS_Store"
106
+ - ".github/workflows/test.yml"
106
107
  - ".gitignore"
107
108
  - Gemfile
108
109
  - LICENSE.txt
@@ -128,13 +129,17 @@ files:
128
129
  - spec/fixtures/large_numbers.xlsx
129
130
  - spec/fixtures/sample-as-zip.zip
130
131
  - spec/fixtures/sample-with-headers.xlsx
132
+ - spec/fixtures/sample-with-headers_namespaced.xlsx
131
133
  - spec/fixtures/sample-with-images.xlsx
134
+ - spec/fixtures/sample-with-one-cell-anchored-images.xlsx
132
135
  - spec/fixtures/sample.xlsx
133
136
  - spec/fixtures/sample_dates.xlsx
137
+ - spec/fixtures/sample_namespaced.xlsx
134
138
  - spec/fixtures/sheets/sample_dates.xlsx
135
139
  - spec/fixtures/sheets/sheet1.xml
136
140
  - spec/fixtures/sheets/single_data_programme.xlsx
137
141
  - spec/fixtures/sst.xml
142
+ - spec/fixtures/sst_namespaced.xml
138
143
  - spec/fixtures/styles/first.xml
139
144
  - spec/fixtures/temp_string_io_file_path_with_no_extension
140
145
  - spec/shared_string_spec.rb
@@ -162,7 +167,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
162
167
  - !ruby/object:Gem::Version
163
168
  version: '0'
164
169
  requirements: []
165
- rubygems_version: 3.0.3
170
+ rubygems_version: 3.0.3.1
166
171
  signing_key:
167
172
  specification_version: 4
168
173
  summary: A Ruby gem for parsing large Excel(xlsx and xlsm) files.
@@ -175,13 +180,17 @@ test_files:
175
180
  - spec/fixtures/large_numbers.xlsx
176
181
  - spec/fixtures/sample-as-zip.zip
177
182
  - spec/fixtures/sample-with-headers.xlsx
183
+ - spec/fixtures/sample-with-headers_namespaced.xlsx
178
184
  - spec/fixtures/sample-with-images.xlsx
185
+ - spec/fixtures/sample-with-one-cell-anchored-images.xlsx
179
186
  - spec/fixtures/sample.xlsx
180
187
  - spec/fixtures/sample_dates.xlsx
188
+ - spec/fixtures/sample_namespaced.xlsx
181
189
  - spec/fixtures/sheets/sample_dates.xlsx
182
190
  - spec/fixtures/sheets/sheet1.xml
183
191
  - spec/fixtures/sheets/single_data_programme.xlsx
184
192
  - spec/fixtures/sst.xml
193
+ - spec/fixtures/sst_namespaced.xml
185
194
  - spec/fixtures/styles/first.xml
186
195
  - spec/fixtures/temp_string_io_file_path_with_no_extension
187
196
  - spec/shared_string_spec.rb