ooxml_excel 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f763147398129f0ac41335c8ddf647bb2540917e
4
+ data.tar.gz: e9f93a0c9ee5ec07cdcd8269f77b49b9480e7980
5
+ SHA512:
6
+ metadata.gz: d3a06ce3169938a146da26eb347ffbc812b7b15627b04d237407fb25ed7138a2b31f298293a12e231a54e9a0756ab18092b9b24ac393e580b2bfb8c16727cbe0
7
+ data.tar.gz: cb765ec3f0bb940938f7a4ba968b7f8aa54549f0f7040eb6c4e60dd1165804ec72466c91649d24558903c7914e188ec7ecee93dd2cecac33399ed624b51eb424
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.2.3
5
+ before_install: gem install bundler -v 1.12.5
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in moon_xl.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # OOXML Excel
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/ooxml_excel`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'ooxml_excel'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install ooxml_excel
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/ooxml_excel.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "ooxml_excel"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,10 @@
1
+ require 'nokogiri'
2
+ require 'active_support/all'
3
+ require 'zip'
4
+ require "ooxml_excel/version"
5
+ require "ooxml_excel/helper/list"
6
+ require "ooxml_excel/excel"
7
+ require "ooxml_excel/styles"
8
+ require "ooxml_excel/comments"
9
+ require "ooxml_excel/workbook"
10
+ require "ooxml_excel/sheet"
@@ -0,0 +1,26 @@
1
+ module OOXML
2
+ class Excel
3
+ class Comments
4
+ attr_reader :comments
5
+
6
+ def initialize(comments)
7
+ @comments = comments
8
+ end
9
+
10
+ def [](id)
11
+ @comments[id]
12
+ end
13
+
14
+ def self.load_from_stream(comment_xml)
15
+ comment_xml =Nokogiri.XML(comment_xml).remove_namespaces!
16
+
17
+ comments = comment_xml.xpath("//comments/commentList/comment").map do |comment_node|
18
+ value = (comment_node.xpath('./text/r/t').last || comment_node.at_xpath('./text/r/t') || comment_node.at_xpath('./text/t')).text
19
+ id = comment_node.attributes["ref"].to_s
20
+ [id, value]
21
+ end.to_h
22
+ new(comments)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,63 @@
1
+ module OOXML
2
+ class Excel
3
+ include OOXML::Helper::List
4
+ attr_reader :comments
5
+ def initialize(spreadsheet, load_only_sheet:nil)
6
+ @spreadsheet = spreadsheet
7
+ @sheets = {}
8
+ @comments = {}
9
+ # @themes = []
10
+ @workbook = nil
11
+ @load_only_sheet = nil
12
+ @styles = nil
13
+ load_xml_contents
14
+ end
15
+
16
+ def sheets
17
+ @workbook.sheets.map { |sheet| sheet[:name]}
18
+ end
19
+
20
+ def sheet(sheet_name)
21
+ sheet_from_workbook = @workbook.sheets.find { |sheet| sheet[:name] == sheet_name}
22
+ raise "No #{sheet_name} in workbook." if sheet_from_workbook.blank?
23
+ sheet = @sheets.fetch(sheet_from_workbook[:relationship_id])
24
+
25
+ # shared variables
26
+ sheet.name = sheet_name
27
+ sheet.comments = @comments[sheet_from_workbook[:relationship_id]]
28
+ sheet.styles = @styles
29
+ sheet.defined_names = @workbook.defined_names
30
+ sheet
31
+ end
32
+
33
+ private
34
+
35
+ # Currently supports DataValidation (comment), columns (check if hidden)
36
+ # TODO: list values, Font styles (if bold, colored in red etc..), background color
37
+ def load_xml_contents
38
+ shared_strings = []
39
+ Zip::File.open(@spreadsheet) do |spreadsheet_zip|
40
+ spreadsheet_zip.each do |entry|
41
+ stream_xml = entry.get_input_stream.read
42
+ if entry.name[/xl\/worksheets\/sheet(\d+)?\.xml/]
43
+ sheet_id = entry.name.scan(/xl\/worksheets\/sheet(\d+)?\.xml/).flatten.first
44
+ @sheets[sheet_id] = Excel::Sheet.load_from_stream(stream_xml, shared_strings)
45
+ elsif entry.name[/xl\/styles\.xml/]
46
+ @styles = Excel::Styles.load_from_stream(stream_xml)
47
+ # elsif entry.name[/xl\/theme(\d+)?\.xml/]
48
+ # @themes << Excel::Theme.load_from_stream(stream_xml)
49
+ elsif entry.name[/xl\/comments(\d+)?\.xml/]
50
+ comment_id = entry.name.scan(/xl\/comments(\d+)\.xml/).flatten.first
51
+ @comments[comment_id] = Excel::Comments.load_from_stream(stream_xml)
52
+ elsif entry.name == "xl/sharedStrings.xml"
53
+ Nokogiri.XML(stream_xml).remove_namespaces!.xpath('sst/si').each do |shared_string_node|
54
+ shared_strings << shared_string_node.at('t').text
55
+ end
56
+ elsif entry.name == "xl/workbook.xml"
57
+ @workbook = Workbook.load_from_stream(stream_xml)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,67 @@
1
+ module OOXML
2
+ module Helper
3
+ module List
4
+
5
+ # excel.rb
6
+ # fetch dropdown values based on given data validation formula
7
+ def list_values(formula)
8
+ # "Lists!$J$2:$J$4"
9
+ # transform into useful info
10
+
11
+ # for list values explicitly stated
12
+ if formula.include?(',')
13
+ formula.gsub('"', '').split(',')
14
+ # invalid format
15
+ elsif !formula.include?('!') && formula[/$/]
16
+ puts "Warning: This formula is not yet supported: #{formula} in your Data Validation's formula."
17
+ []
18
+ else
19
+ # # required for fetching values
20
+ sheet_name = formula.gsub(/[\$\']/, '').scan(/^[^!]*/).first
21
+ cell_range_formula = formula.gsub(/\$/, '').scan(/(?<=!).+/).first
22
+
23
+ # fetch the sheet of the cell reference
24
+ working_sheet = sheet(sheet_name)
25
+
26
+ # gather values
27
+ list_values = working_sheet.list_values_from_formula(cell_range_formula)
28
+ end
29
+ end
30
+
31
+ # Used in sheet.rb
32
+ def list_value_formula(cell_ref)
33
+ data_validation = data_validations.find { |data_validation| data_validation.sqref_range.include?(cell_ref)}
34
+ if data_validation.respond_to?(:type) && data_validation.type == "list"
35
+ if data_validation.formula[/[\s\$\,\:]/]
36
+ (data_validation.formula[/\$/].present?) ? "#{name}!#{data_validation.formula}" : data_validation.formula
37
+ else
38
+ @defined_names.fetch(data_validation.formula)
39
+ end
40
+ end
41
+ end
42
+
43
+ def list_values_from_formula(formula)
44
+ return [] if formula.blank?
45
+
46
+ # Formula values separated by comma
47
+ if formula.include?(":")
48
+ cell_letters = formula.gsub(/[\d]/, '').split(':')
49
+ start_index, end_index = formula.gsub(/[^\d:]/, '').split(':').map(&:to_i)
50
+
51
+ cell_letter = cell_letters.uniq.first
52
+ (start_index..end_index).to_a.map do |row_index|
53
+ row = rows[row_index-1]
54
+ next if row.blank?
55
+ row["#{cell_letter}#{row_index}"].value
56
+ end
57
+ else
58
+ # when only one value: B2
59
+ row_index = formula.gsub(/[^\d:]/, '').split(':').map(&:to_i).first
60
+ row = rows[row_index-1]
61
+ return if row.blank?
62
+ [row[formula].value]
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,249 @@
1
+ module OOXML
2
+ class Excel
3
+ class Sheet
4
+ include OOXML::Helper::List
5
+ attr_reader :columns, :data_validations, :shared_strings
6
+ attr_accessor :comments, :styles, :defined_names, :name
7
+
8
+ def initialize(xml, shared_strings)
9
+ @xml = xml
10
+ @shared_strings = shared_strings
11
+ @comments = {}
12
+ @defined_names = {}
13
+ @styles = []
14
+ end
15
+
16
+ def code_name
17
+ @code_name ||= @xml.xpath('//sheetPr').attribute('codeName').try(:value)
18
+ end
19
+
20
+ def data_validation_for_cell(cell_ref)
21
+ data_validations.find { |data_validation| data_validation.sqref_range.include?(cell_ref)}
22
+ end
23
+
24
+
25
+ def column(id)
26
+ columns.select { |column| column.id_range.include?(id)}
27
+ end
28
+
29
+ def columns
30
+ @columns ||= begin
31
+ @xml.xpath('//cols/col').map do |column_node|
32
+ Excel::Sheet::Column.load_from_node(column_node)
33
+ end
34
+ end
35
+ end
36
+
37
+ def [](id)
38
+ if id.is_a?(String)
39
+ rows.find { |row| row.id == id}
40
+ else
41
+ rows[id]
42
+ end
43
+ end
44
+
45
+ def rows
46
+ @rows ||= begin
47
+ # TODO: get the value of merged cells
48
+ # merged_cells = @xml.xpath('//mergeCells/mergeCell').map { |merged_cell| merged_cell.attributes["ref"].try(:value) }
49
+ @xml.xpath('//sheetData/row').map do |row_node|
50
+ Excel::Sheet::Row.load_from_node(row_node, shared_strings)
51
+ end
52
+ end
53
+ end
54
+
55
+ def font(cell_reference)
56
+ style_id = fetch_style_style_id(cell_reference)
57
+ if style_id.present?
58
+ style = @styles.by_id(style_id.to_i)
59
+
60
+ (style.present?) ? style[:font] : nil
61
+ end
62
+ end
63
+
64
+ def fill(cell_reference)
65
+ style_id = fetch_style_style_id(cell_reference)
66
+ if style_id.present?
67
+ style = @styles.by_id(style_id.to_i)
68
+ (style.present?) ? style[:fill] : nil
69
+ end
70
+ end
71
+
72
+ def each_row
73
+ rows.each_with_index do |row, row_index|
74
+ yield row.cells.map(&:value), row_index
75
+ end
76
+ end
77
+
78
+ def each_row_as_object
79
+ 0.upto(rows.size).each do |row_index|
80
+ yield rows[row_index]
81
+ end
82
+ end
83
+
84
+ def data_validations
85
+ @data_validations ||= begin
86
+ @xml.xpath('//dataValidations/dataValidation').map do |data_validation_node|
87
+ Excel::Sheet::DataValidation.load_from_node(data_validation_node)
88
+ end
89
+ end
90
+ end
91
+
92
+ def self.load_from_stream(xml_stream, shared_strings)
93
+ self.new(Nokogiri.XML(xml_stream).remove_namespaces!, shared_strings)
94
+ end
95
+
96
+ private
97
+ def fetch_style_style_id(cell_reference)
98
+ raise 'Invalid Cell Reference!' if cell_reference[/[A-Z]{1,}\d+/].blank?
99
+ row_index = cell_reference.scan(/[A-Z{1,}](\d+)/).flatten.first.to_i - 1
100
+ return if rows[row_index].blank? || rows[row_index][cell_reference].blank?
101
+ rows[row_index][cell_reference].s
102
+ end
103
+
104
+ end
105
+ end
106
+ end
107
+
108
+ module OOXML
109
+ class Excel
110
+ class Sheet
111
+ class Column
112
+ attr_accessor :id, :width, :custom_width, :id_range, :hidden
113
+ alias_method :hidden?, :hidden
114
+ def initialize(**attrs)
115
+ attrs.each { |property, value| send("#{property}=", value)}
116
+ end
117
+
118
+ def self.load_from_node(column_node)
119
+ hidden_attr = column_node.attributes["hidden"]
120
+ new(id: column_node.attributes["min"].try(:value),
121
+ width: column_node.attributes["width"].try(:value),
122
+ custom_width: column_node.attributes["custom_width"].try(:value),
123
+ id_range: (column_node.attributes["min"].value.to_i..column_node.attributes["max"].value.to_i).to_a,
124
+ hidden: (hidden_attr.present?) ? hidden_attr.value == "1" : false)
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ module OOXML
132
+ class Excel
133
+ class Sheet
134
+ class Row
135
+ attr_accessor :id, :spans, :cells
136
+
137
+ def initialize(**attrs)
138
+ attrs.each { |property, value| send("#{property}=", value)}
139
+ end
140
+
141
+ def [](id)
142
+ if id.is_a?(String)
143
+ cells.find { |row| row.id == id}
144
+ else
145
+ cells[id]
146
+ end
147
+ end
148
+
149
+ def self.load_from_node(row_node, shared_strings)
150
+ new(id: row_node.attributes["r"].try(:value),
151
+ spans: row_node.attributes["spans"].try(:value),
152
+ cells: row_node.xpath('c').map { |cell_node| Row::Cell.load_from_node(cell_node, shared_strings) } )
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+ module OOXML
160
+ class Excel
161
+ class Sheet
162
+ class Row
163
+ class Cell
164
+ attr_accessor :id, :t, :s, :v, :shared_strings
165
+ # t = type
166
+ # v = value
167
+ # s = ??
168
+ def initialize(**attrs)
169
+ attrs.each { |property, value| send("#{property}=", value)}
170
+ end
171
+
172
+ def value
173
+ (v.present?) ? shared_strings[v.to_i] : nil
174
+ end
175
+
176
+ def self.load_from_node(cell_node, shared_strings)
177
+ new(id: cell_node.attributes["r"].try(:value),
178
+ t: cell_node.attributes["t"].try(:value),
179
+ s: cell_node.attributes["s"].try(:value),
180
+ v: cell_node.at('v').try(:text),
181
+ shared_strings: shared_strings )
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end
187
+ end
188
+
189
+
190
+ module OOXML
191
+ class Excel
192
+ class Sheet
193
+ class DataValidation
194
+ attr_accessor :allow_blank, :prompt, :type, :sqref, :formula
195
+
196
+ def sqref_range
197
+ @sqref_range ||= begin
198
+ # "BH5:BH271 BI5:BI271"
199
+ sqref.split( ' ').map do |splitted_by_space_sqref|
200
+ # ["BH5:BH271, "BI5:BI271"]
201
+ if splitted_by_space_sqref.is_a?(Array)
202
+ splitted_by_space_sqref.map do |sqref|
203
+ split_sqref(sqref)
204
+ end
205
+ else
206
+ # "BH5:BH271"
207
+ split_sqref(splitted_by_space_sqref)
208
+ end
209
+ end.flatten.uniq
210
+ end
211
+ end
212
+
213
+ def self.load_from_node(data_validation_node)
214
+ allow_blank = data_validation_node.attribute('allowBlank').try(:value)
215
+ prompt = data_validation_node.attribute('prompt').try(:value)
216
+ type = data_validation_node.attribute('type').try(:value)
217
+ sqref = data_validation_node.attribute('sqref').try(:value)
218
+ formula = data_validation_node.at('formula1').try(:content)
219
+
220
+ self.new(allow_blank: allow_blank,
221
+ prompt: prompt,
222
+ type: type,
223
+ sqref: sqref,
224
+ formula: formula)
225
+ end
226
+
227
+ private
228
+ def initialize(**attrs)
229
+ attrs.each { |property, value| send("#{property}=", value)}
230
+ end
231
+
232
+ def split_sqref(sqref)
233
+ # Example: "BH5:BH271"
234
+ # starting_reference: BH5
235
+ # ending_reference: BH271
236
+ starting_reference, ending_reference = sqref.split(":")
237
+
238
+ # if the starting_reference column letters are the same with ending_reference
239
+ # use the first one otherwise use both
240
+ if ending_reference.blank? || starting_reference[/A-Z{1,}/] == ending_reference[/A-Z{1,}/]
241
+ starting_reference
242
+ else
243
+ [starting_reference, ending_reference]
244
+ end
245
+ end
246
+ end
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,127 @@
1
+ module OOXML
2
+ class Excel
3
+ class Styles
4
+ attr_accessor :fonts, :fills, :cell_style_xfs
5
+ def initialize(**attrs)
6
+ attrs.each { |property, value| send("#{property}=", value)}
7
+ end
8
+
9
+ def by_id(id)
10
+ cell_style = cell_style_xfs.fetch(id)
11
+ {
12
+ font: fonts_by_index(cell_style.font_id),
13
+ fill: fills_by_index(cell_style.fill_id)
14
+ }
15
+ end
16
+
17
+ def fonts_by_index(font_index)
18
+ @fonts[font_index]
19
+ end
20
+
21
+ def fills_by_index(fill_index)
22
+ @fills[fill_index]
23
+ end
24
+
25
+ def self.load_from_stream(xml_stream)
26
+ style_doc = Nokogiri.XML(xml_stream).remove_namespaces!
27
+ fonts = style_doc.xpath('//fonts/font')
28
+ fills = style_doc.xpath('//fills/fill')
29
+
30
+ # This element contains the master formatting records (xf) which
31
+ # define the formatting applied to cells in this workbook.
32
+ # link: https://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.cellformats(v=office.14).aspx
33
+ cell_style_xfs = style_doc.xpath('//cellXfs/xf')
34
+
35
+ self.new(
36
+ fonts: fonts.map { |font_node| Excel::Styles::Font.load_from_node(font_node)},
37
+ fills: fills.map { |fill_node| Excel::Styles::Fill.load_from_node(fill_node)},
38
+ cell_style_xfs: cell_style_xfs.map { |cell_style_xfs_node| Excel::Styles::CellStyleXfs.load_from_node(cell_style_xfs_node)}
39
+ )
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ module OOXML
46
+ class Excel
47
+ class Styles
48
+ class Font
49
+ attr_accessor :size, :name, :rgb_color, :theme, :bold
50
+ alias_method :bold?, :bold
51
+ def initialize(**attrs)
52
+ attrs.each { |property, value| send("#{property}=", value)}
53
+ end
54
+ def self.load_from_node(font_node)
55
+ font_size_node = font_node.at('sz')
56
+ font_color_node = font_node.at('color')
57
+ font_name_node = font_node.at('name')
58
+ font_bold_node = font_node.at('b')
59
+ self.new(
60
+ size: font_size_node.attributes["val"].value,
61
+ name: font_name_node.attributes["val"].value,
62
+ rgb_color: (font_color_node.present?) ? font_color_node.attributes["rgb"].try(:value) : nil,
63
+ theme: (font_color_node.present?) ? font_color_node.attributes["theme"].try(:value) : nil,
64
+ bold: font_bold_node.present?
65
+ )
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ # <xf numFmtId="0" borderId="0" fillId="0" fontId="0" applyAlignment="1" applyFont="1" xfId="0"/>
73
+ module OOXML
74
+ class Excel
75
+ class Styles
76
+ class CellStyleXfs
77
+ attr_accessor :id, :number_formatting_id, :fill_id, :font_id
78
+ def initialize(**attrs)
79
+ attrs.each { |property, value| send("#{property}=", value)}
80
+ end
81
+ def self.load_from_node(cell_style_xfs_node)
82
+ attributes = cell_style_xfs_node.attributes
83
+
84
+
85
+ self.new(
86
+ id: attributes["xfId"].value.to_i,
87
+ number_formatting_id: attributes["numFmtId"].value.to_i,
88
+ fill_id: attributes["fillId"].value.to_i,
89
+ font_id: attributes["fontId"].value.to_i
90
+ )
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+
98
+ module OOXML
99
+ class Excel
100
+ class Styles
101
+ class Fill
102
+ attr_accessor :pattern_type, :fg_color, :fg_color_theme, :fg_color_tint, :bg_color_index, :bg_color
103
+
104
+ def initialize(**attrs)
105
+ attrs.each { |property, value| send("#{property}=", value)}
106
+ end
107
+ def self.load_from_node(fill_node)
108
+ pattern_fill = fill_node.at('patternFill')
109
+
110
+ pattern_type = pattern_fill.attributes["patternType"].value
111
+ if pattern_type == "solid"
112
+ fg_color = pattern_fill.at('fgColor')
113
+ bg_color = pattern_fill.at('bgColor')
114
+ self.new(pattern_type: pattern_type,
115
+ fg_color: (fg_color.present?) ? fg_color.attributes["rgb"].try(:value) : nil,
116
+ fg_color_theme: (fg_color.present?) ? fg_color.attributes["theme"].try(:value) : nil,
117
+ fg_color_tint: (fg_color.present?) ? fg_color.attributes["tint"].try(:value) : nil,
118
+ bg_color: (bg_color.present?) ? bg_color.attributes["rgb"].try(:value) : nil,
119
+ bg_color_index: (bg_color.present?) ? bg_color.attributes["index"].try(:value) : nil)
120
+ else
121
+ self.new(pattern_type: pattern_type)
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,5 @@
1
+ module OOXML
2
+ class Excel
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,35 @@
1
+ module OOXML
2
+ class Excel
3
+ class Workbook
4
+ def initialize(xml)
5
+ @xml = xml
6
+ end
7
+
8
+ def sheets
9
+ @sheets ||= begin
10
+ @xml.xpath('//sheets/sheet').map do |sheet_node|
11
+ name = sheet_node.attribute('name').value
12
+ rel_id = sheet_node.attribute('id').value.gsub(/[^\d+]/, '')
13
+ sheet_id = sheet_node.attribute('sheetId').value
14
+ { name: name, sheet_id: sheet_id, relationship_id: rel_id}
15
+ end
16
+ end
17
+ end
18
+
19
+ def defined_names
20
+ @defined_names ||= begin
21
+ @xml.xpath('//definedNames/definedName').map do |defined_names_node|
22
+ name = defined_names_node.attribute('name').value
23
+ reference = defined_names_node.text
24
+ [name, reference]
25
+ end.to_h
26
+ end
27
+ end
28
+
29
+
30
+ def self.load_from_stream(xml_stream)
31
+ self.new (Nokogiri.XML(xml_stream).remove_namespaces!)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ooxml_excel/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ooxml_excel"
8
+ spec.version = OOXML::Excel::VERSION
9
+ spec.authors = ["James Mones"]
10
+ spec.email = ["bajong009@gmail.com"]
11
+ spec.summary = %q{OOXML Excel - Parse Excel Spreadsheets (xlsx, xlsm).}
12
+ spec.description = %q{A Ruby spreadsheet parser for Excel (xlsx, xlsm).}
13
+ spec.homepage = "https://github.com/halcjames/ooxml_excel"
14
+
15
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
16
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
17
+ # if spec.respond_to?(:metadata)
18
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
19
+ # else
20
+ # raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
21
+ # end
22
+
23
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ spec.bindir = "exe"
25
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ["lib"]
27
+ spec.add_dependency 'activesupport'
28
+ spec.add_dependency 'nokogiri', '~> 1'
29
+ spec.add_dependency 'rubyzip', '~> 1.1', '< 2.0.0'
30
+
31
+ spec.add_development_dependency "bundler", "~> 1.12"
32
+ spec.add_development_dependency "rake", "~> 10.0"
33
+ spec.add_development_dependency "rspec", "~> 3.0"
34
+ end
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ooxml_excel
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - James Mones
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-08-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: nokogiri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubyzip
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.1'
48
+ - - "<"
49
+ - !ruby/object:Gem::Version
50
+ version: 2.0.0
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '1.1'
58
+ - - "<"
59
+ - !ruby/object:Gem::Version
60
+ version: 2.0.0
61
+ - !ruby/object:Gem::Dependency
62
+ name: bundler
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.12'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.12'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rake
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '10.0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '10.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rspec
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '3.0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '3.0'
103
+ description: A Ruby spreadsheet parser for Excel (xlsx, xlsm).
104
+ email:
105
+ - bajong009@gmail.com
106
+ executables: []
107
+ extensions: []
108
+ extra_rdoc_files: []
109
+ files:
110
+ - ".gitignore"
111
+ - ".rspec"
112
+ - ".travis.yml"
113
+ - Gemfile
114
+ - README.md
115
+ - Rakefile
116
+ - bin/console
117
+ - bin/setup
118
+ - lib/ooxml_excel.rb
119
+ - lib/ooxml_excel/comments.rb
120
+ - lib/ooxml_excel/excel.rb
121
+ - lib/ooxml_excel/helper/list.rb
122
+ - lib/ooxml_excel/sheet.rb
123
+ - lib/ooxml_excel/styles.rb
124
+ - lib/ooxml_excel/version.rb
125
+ - lib/ooxml_excel/workbook.rb
126
+ - ooxml_excel.gemspec
127
+ homepage: https://github.com/halcjames/ooxml_excel
128
+ licenses: []
129
+ metadata: {}
130
+ post_install_message:
131
+ rdoc_options: []
132
+ require_paths:
133
+ - lib
134
+ required_ruby_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ required_rubygems_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '0'
144
+ requirements: []
145
+ rubyforge_project:
146
+ rubygems_version: 2.6.4
147
+ signing_key:
148
+ specification_version: 4
149
+ summary: OOXML Excel - Parse Excel Spreadsheets (xlsx, xlsm).
150
+ test_files: []