ooxl 0.0.1.4.26 → 0.0.1.5.0

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: 1713569c7400873f6610528e7e815e1349727506
4
- data.tar.gz: bca84c26d40ca27e771fdb61131e0e8f53c69d29
3
+ metadata.gz: d3da0847d61333cf06c4a9e3212604a6b6f1e1e0
4
+ data.tar.gz: 2b5d30b7c28f88c14adfe0fcbe4e1c0085ccfb61
5
5
  SHA512:
6
- metadata.gz: e6e19c17da54efc9f23311b2799532e4b31d6276582d3c3dc8b84329f509229ee1184413a93921c4626737390dfee53e67da83497703e91270c75dd3b3112a85
7
- data.tar.gz: c217a26675b2c51995b6fcffe553f35077797c06ae1f1948231be53c498cb57c73c047a9c4605a2cee1f78e7d45d49c96a6f141fd83c243f0851ab960fecd5bb
6
+ metadata.gz: cb1e938d50dbfa698605986ae790670f0b2c557438aeb73925baf261326fe8f79b05948d409d06a5fbf620aaa88adba26642206b3beed11ca05e05372487a0ac
7
+ data.tar.gz: e30534d829e6b0ba29388a950cf5743977ee0b73c942c798df26eca177f9e17a70d365515c76bf37d20d6bb42c027ddad937223a75b582143a1cf1cac7c00d82
data/.gitignore CHANGED
File without changes
data/.rspec CHANGED
File without changes
data/.travis.yml CHANGED
File without changes
data/Gemfile CHANGED
File without changes
data/README.md CHANGED
File without changes
data/Rakefile CHANGED
File without changes
data/bin/console CHANGED
File without changes
data/bin/setup CHANGED
File without changes
File without changes
data/lib/ooxl/ooxl.rb CHANGED
File without changes
data/lib/ooxl/util.rb CHANGED
File without changes
data/lib/ooxl/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  class OOXL
2
- VERSION = "0.0.1.4.26"
2
+ VERSION = "0.0.1.5.0"
3
3
  end
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -10,20 +10,18 @@ class OOXL
10
10
  end
11
11
 
12
12
  def [](id)
13
- cell = if id.is_a?(String)
14
- cells.find { |row| row.id == id}
13
+ if id.is_a?(String)
14
+ cell(id)
15
15
  else
16
- cells[id]
16
+ cells[id] || BlankCell.new(id)
17
17
  end
18
- (cell.present?) ? cell : BlankCell.new(id)
19
18
  end
20
19
 
21
20
  def cells
22
21
  if @options[:padded_cells]
23
22
  unless @cells.blank?
24
23
  'A'.upto(@cells.last.column).map do |column_letter|
25
- cell = @cells.find { |cell| cell.column == column_letter}
26
- (cell.blank?) ? BlankCell.new("#{column_letter}#{id}") : cell
24
+ cell(column_letter)
27
25
  end
28
26
  end
29
27
  else
@@ -32,8 +30,14 @@ class OOXL
32
30
  end
33
31
 
34
32
  def cell(cell_id)
35
- cell_final_id = cell_id[/[A-Z]{1,}\d+/] ? cell_id : "#{cell_id}#{id}"
36
- cells.find { |cell| cell.id == cell_final_id}
33
+ cell_final_id = cell_id[/[A-Z]+\d+/] ? cell_id : "#{cell_id}#{id}"
34
+ cell_id_map[cell_final_id]
35
+ end
36
+
37
+ def cell_id_map
38
+ @cell_id_map ||= cells.each_with_object(Hash.new { |_, k| BlankCell.new(k) }) do |cell, result|
39
+ result[cell.id] = cell
40
+ end
37
41
  end
38
42
 
39
43
  def each
@@ -0,0 +1,100 @@
1
+ class OOXL
2
+ class RowCache
3
+ include Enumerable
4
+
5
+ attr_accessor :styles
6
+
7
+ # built on-demand -- use rows instead
8
+ attr_reader :row_cache
9
+
10
+ # built on-demand -- use fetch_row_by_id instead
11
+ attr_reader :row_id_map
12
+
13
+ def initialize(sheet_xml, shared_strings, options = {})
14
+ @shared_strings = shared_strings
15
+ @sheet_xml = sheet_xml
16
+ @options = options
17
+ @row_cache = []
18
+ @row_id_map = {}
19
+ end
20
+
21
+ def [](id)
22
+ fetch_row_by_id(id)
23
+ end
24
+
25
+ alias_method :row, :[]
26
+
27
+ def each(&block)
28
+ if @options[:padded_rows]
29
+ padded_rows(&block)
30
+ else
31
+ rows(&block)
32
+ end
33
+ end
34
+
35
+ def rows(&block)
36
+ # track yield count to know if caller broke out of loop
37
+ rows_yielded = 0
38
+ row_cache.each do |r|
39
+ yield r if block_given?
40
+ rows_yielded += 1
41
+ end
42
+
43
+ if !all_rows_loaded? && rows_yielded == row_cache.count
44
+ parse_more_rows(&block)
45
+ end
46
+
47
+ row_cache
48
+ end
49
+
50
+ private
51
+
52
+ def parse_more_rows
53
+ row_nodes.drop(row_cache.count).each do |row_node|
54
+ row = Row.load_from_node(row_node, @shared_strings, @styles, @options)
55
+ row_cache << row
56
+ row_id_map[row.id] = row
57
+ yield row if block_given?
58
+ end
59
+ end
60
+
61
+ def all_rows_loaded?
62
+ row_cache.count == row_nodes.count
63
+ end
64
+
65
+ def row_nodes
66
+ @row_nodes ||= @sheet_xml.xpath('//sheetData/row')
67
+ end
68
+
69
+ def fetch_row_by_id(row_id)
70
+ row_id = row_id.to_s
71
+ return row_id_map[row_id] if all_rows_loaded? || row_id_map.key?(row_id)
72
+
73
+ parse_more_rows do |row|
74
+ return row if row.id == row_id
75
+ end
76
+
77
+ nil
78
+ end
79
+
80
+ def padded_rows
81
+ real_rows_yielded = 0
82
+ yielded_rows = []
83
+ (1..Float::INFINITY).each do |row_index|
84
+ row = row(row_index)
85
+ if row.blank?
86
+ row = Row.new(id: row_index.to_s, cells: [])
87
+ else
88
+ real_rows_yielded += 1
89
+ end
90
+
91
+ yielded_rows << row
92
+ yield row if block_given?
93
+
94
+ break if real_rows_yielded == row_cache.count && all_rows_loaded?
95
+ end
96
+ yielded_rows
97
+ end
98
+ end
99
+ end
100
+
File without changes
@@ -1,10 +1,14 @@
1
1
  require_relative 'sheet/data_validation'
2
+ require_relative 'row_cache'
3
+
2
4
  class OOXL
3
5
  class Sheet
4
6
  include OOXL::Util
5
7
  include Enumerable
6
- attr_reader :columns, :data_validations, :shared_strings
7
- attr_accessor :comments, :styles, :defined_names, :name
8
+
9
+ attr_reader :columns, :data_validations, :shared_strings, :styles
10
+ attr_accessor :comments, :defined_names, :name
11
+ delegate :[], :each, :rows, :row, to: :@row_cache
8
12
 
9
13
  def initialize(xml, shared_strings, options={})
10
14
  @xml = Nokogiri.XML(xml).remove_namespaces!
@@ -12,8 +16,8 @@ class OOXL
12
16
  @comments = {}
13
17
  @defined_names = {}
14
18
  @styles = []
15
- @loaded_cache = {}
16
19
  @options = options
20
+ @row_cache = RowCache.new(@xml, @shared_strings, options)
17
21
  end
18
22
 
19
23
  def code_name
@@ -41,82 +45,35 @@ class OOXL
41
45
  end
42
46
  end
43
47
 
44
- def [](id)
45
- if id.is_a?(String)
46
- rows.find { |row| row.id == id}
47
- else
48
- rows[id]
49
- end
50
- end
51
-
52
- def row(index, stream: false)
53
- if @loaded_cache[:rows] || !stream
54
- rows.find { |row| row.id == index.to_s}
55
- else
56
- found_row = nil
57
- rows do |row|
58
- if row.id == index.to_s
59
- found_row = row
60
- break
61
- end
62
- end
63
- found_row
64
- end
65
- end
66
48
 
49
+ # DEPRECATED: stream is no longer separate
67
50
  def stream_row(index)
68
- row(index, stream: true)
51
+ row(index)
69
52
  end
70
53
 
71
54
  # test mode
72
55
  def cells_by_column(column_letter)
73
- columns = []
74
- rows.each do |row|
75
- columns << row.cells.find { |cell| to_column_letter(cell.id) == column_letter}
56
+ rows.map do |row|
57
+ row.cells.find { |cell| to_column_letter(cell.id) == column_letter}
76
58
  end
77
- columns
78
59
  end
79
60
 
80
61
  def last_column(row_index=1)
81
62
  @last_column ||= {}
82
63
  @last_column[row_index] ||= begin
83
- cells = stream_row(row_index).try(:cells)
64
+ cells = row(row_index).try(:cells)
84
65
  cells.last.column if cells.present?
85
66
  end
86
67
  end
87
68
 
88
- def cell(cell_id, stream: false)
69
+ def cell(cell_id)
89
70
  column_letter, row_index = cell_id.partition(/\d+/)
90
- current_row = row(row_index, stream: stream)
71
+ current_row = row(row_index)
91
72
  current_row.cell(column_letter) unless current_row.nil?
92
73
  end
93
74
 
94
- def formula(cell_id, stream: false)
95
- cell(cell_id, stream: stream).try(:formula)
96
- end
97
-
98
- def rows
99
- @rows ||= begin
100
- all_rows = @xml.xpath('//sheetData/row').map do |row_node|
101
- row = Row.load_from_node(row_node, @shared_strings, @styles, @options)
102
- yield row if block_given?
103
- row
104
- end
105
- @loaded_cache[:rows] = true
106
- all_rows
107
- end
108
- end
109
-
110
- def each
111
- if @options[:padded_rows]
112
- last_row_index = rows.last.id.to_i
113
- (1.upto(last_row_index)).each do |row_index|
114
- row = row(row_index)
115
- yield (row.blank?) ? Row.new(id: "#{row_index}", cells: []) : row
116
- end
117
- else
118
- rows { |row| yield row }
119
- end
75
+ def formula(cell_id)
76
+ cell(cell_id).try(:formula)
120
77
  end
121
78
 
122
79
  def font(cell_reference)
@@ -127,7 +84,6 @@ class OOXL
127
84
  cell(cell_reference).try(:fill)
128
85
  end
129
86
 
130
-
131
87
  def data_validations
132
88
  @data_validations ||= begin
133
89
 
@@ -146,6 +102,11 @@ class OOXL
146
102
  end
147
103
  end
148
104
 
105
+ def styles=(styles)
106
+ @styles = styles
107
+ @row_cache.styles = styles
108
+ end
109
+
149
110
  # a shortcut for:
150
111
  # formula = data_validation('A1').formula
151
112
  # ooxl.named_range(formula)
@@ -168,40 +129,51 @@ class OOXL
168
129
  if cell_range.include?(":")
169
130
  cell_letters = cell_range.gsub(/[\d]/, '').split(':')
170
131
  start_index, end_index = cell_range[/[A-Z]{1,}\d+/] ? cell_range.gsub(/[^\d:]/, '').split(':').map(&:to_i) : [1, rows.size]
171
- # This will allow values from this pattern
172
- # 'SheetName!A1:C3'
173
- # The number after the cell letter will be the index
174
- # 1 => start_index
175
- # 3 => end_index
176
- # Expected output would be: [['value', 'value', 'value'], ['value', 'value', 'value'], ['value', 'value', 'value']]
177
132
  if cell_letters.uniq.size > 1
178
- start_index.upto(end_index).map do |row_index|
179
- (letter_index(cell_letters.first)..letter_index(cell_letters.last)).map do |cell_index|
180
- row = fetch_row_by_id(row_index.to_s)
181
- next if row.blank?
182
-
183
- cell_letter = letter_equivalent(cell_index)
184
- row["#{cell_letter}#{row_index}"].value
185
- end
186
- end
133
+ list_values_from_rectangle(cell_letters, start_index, end_index)
187
134
  else
188
- cell_letter = cell_letters.uniq.first
189
- (start_index..end_index).to_a.map do |row_index|
190
- row = fetch_row_by_id(row_index.to_s)
191
- next if row.blank?
192
- row["#{cell_letter}#{row_index}"].value
193
- end
135
+ list_values_from_column(cell_letters.uniq.first, start_index, end_index)
194
136
  end
195
137
  else
196
138
  # when only one value: B2
197
- row_index = cell_range.gsub(/[^\d:]/, '').split(':').map(&:to_i).first
198
- row = fetch_row_by_id(row_index.to_s)
199
- return if row.blank?
200
- [row[cell_range].value]
139
+ list_values_from_cell(cell_range)
201
140
  end
202
141
  end
203
142
  alias_method :list_values_from_formula, :list_values_from_cell_range
204
143
 
144
+ # This will allow values from this pattern
145
+ # 'SheetName!A1:C3'
146
+ # The number after the cell letter will be the index
147
+ # 1 => start_index
148
+ # 3 => end_index
149
+ # Expected output would be: [['value', 'value', 'value'], ['value', 'value', 'value'], ['value', 'value', 'value']]
150
+ def list_values_from_rectangle(cell_letters, start_index, end_index)
151
+ start_index.upto(end_index).map do |row_index|
152
+ (letter_index(cell_letters.first)..letter_index(cell_letters.last)).map do |cell_index|
153
+ row = row(row_index)
154
+ next if row.blank?
155
+
156
+ cell_letter = letter_equivalent(cell_index)
157
+ row["#{cell_letter}#{row_index}"].value
158
+ end
159
+ end
160
+ end
161
+
162
+ def list_values_from_column(column_letter, start_index, end_index)
163
+ (start_index..end_index).to_a.map do |row_index|
164
+ row = row(row_index)
165
+ next if row.blank?
166
+ row["#{column_letter}#{row_index}"].value
167
+ end
168
+ end
169
+
170
+ def list_values_from_cell(cell_ref)
171
+ row_index = cell_ref.gsub(/[^\d:]/, '').split(':').map(&:to_i).first
172
+ row = row(row_index)
173
+ return if row.blank?
174
+ [row[cell_ref].value]
175
+ end
176
+
205
177
  def self.load_from_stream(xml_stream, shared_strings)
206
178
  self.new(Nokogiri.XML(xml_stream).remove_namespaces!, shared_strings)
207
179
  end
@@ -213,9 +185,6 @@ class OOXL
213
185
  end
214
186
 
215
187
  private
216
- def fetch_row_by_id(row_id)
217
- rows.find { |row| row.id == row_id.to_s}
218
- end
219
188
 
220
189
  def merged_cells_range
221
190
  @merged_cells ||= @xml.xpath('//mergeCells/mergeCell').map do |merged_cell|
File without changes
File without changes
File without changes
data/lib/ooxl.rb CHANGED
File without changes
data/ooxml_excel.gemspec CHANGED
@@ -28,7 +28,8 @@ Gem::Specification.new do |spec|
28
28
  spec.add_dependency 'nokogiri', '~> 1'
29
29
  spec.add_dependency 'rubyzip', '~> 1.0', '< 2.0.0'
30
30
 
31
- spec.add_development_dependency "bundler", "~> 1.12"
31
+ spec.add_development_dependency "bundler"
32
+ spec.add_development_dependency "pry-byebug"
32
33
  spec.add_development_dependency "rake", "~> 10.0"
33
34
  spec.add_development_dependency "rspec", "~> 3.0"
34
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ooxl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.4.26
4
+ version: 0.0.1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Mones
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-03-31 00:00:00.000000000 Z
11
+ date: 2019-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -62,16 +62,30 @@ dependencies:
62
62
  name: bundler
63
63
  requirement: !ruby/object:Gem::Requirement
64
64
  requirements:
65
- - - "~>"
65
+ - - ">="
66
66
  - !ruby/object:Gem::Version
67
- version: '1.12'
67
+ version: '0'
68
68
  type: :development
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - "~>"
72
+ - - ">="
73
73
  - !ruby/object:Gem::Version
74
- version: '1.12'
74
+ version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: pry-byebug
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
75
89
  - !ruby/object:Gem::Dependency
76
90
  name: rake
77
91
  requirement: !ruby/object:Gem::Requirement
@@ -129,6 +143,7 @@ files:
129
143
  - lib/ooxl/xl_objects/number_formatting.rb
130
144
  - lib/ooxl/xl_objects/relationships.rb
131
145
  - lib/ooxl/xl_objects/row.rb
146
+ - lib/ooxl/xl_objects/row_cache.rb
132
147
  - lib/ooxl/xl_objects/sheet.rb
133
148
  - lib/ooxl/xl_objects/sheet/data_validation.rb
134
149
  - lib/ooxl/xl_objects/styles.rb
@@ -154,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
169
  version: '0'
155
170
  requirements: []
156
171
  rubyforge_project:
157
- rubygems_version: 2.6.8
172
+ rubygems_version: 2.6.12
158
173
  signing_key:
159
174
  specification_version: 4
160
175
  summary: OOXL Excel - Parse Excel Spreadsheets (xlsx, xlsm).