roo 1.13.1 → 2.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.codeclimate.yml +17 -0
- data/.github/issue_template.md +16 -0
- data/.github/pull_request_template.md +14 -0
- data/.github/workflows/pull-request.yml +15 -0
- data/.github/workflows/ruby.yml +34 -0
- data/.gitignore +11 -0
- data/.rubocop.yml +186 -0
- data/.simplecov +4 -0
- data/CHANGELOG.md +702 -0
- data/Gemfile +18 -12
- data/Guardfile +23 -0
- data/LICENSE +5 -1
- data/README.md +328 -0
- data/Rakefile +23 -23
- data/examples/roo_soap_client.rb +28 -31
- data/examples/roo_soap_server.rb +4 -6
- data/examples/write_me.rb +9 -10
- data/lib/roo/base.rb +317 -504
- data/lib/roo/constants.rb +7 -0
- data/lib/roo/csv.rb +141 -113
- data/lib/roo/errors.rb +11 -0
- data/lib/roo/excelx/cell/base.rb +108 -0
- data/lib/roo/excelx/cell/boolean.rb +30 -0
- data/lib/roo/excelx/cell/date.rb +28 -0
- data/lib/roo/excelx/cell/datetime.rb +107 -0
- data/lib/roo/excelx/cell/empty.rb +20 -0
- data/lib/roo/excelx/cell/number.rb +99 -0
- data/lib/roo/excelx/cell/string.rb +19 -0
- data/lib/roo/excelx/cell/time.rb +44 -0
- data/lib/roo/excelx/cell.rb +110 -0
- data/lib/roo/excelx/comments.rb +55 -0
- data/lib/roo/excelx/coordinate.rb +19 -0
- data/lib/roo/excelx/extractor.rb +39 -0
- data/lib/roo/excelx/format.rb +71 -0
- data/lib/roo/excelx/images.rb +26 -0
- data/lib/roo/excelx/relationships.rb +33 -0
- data/lib/roo/excelx/shared.rb +39 -0
- data/lib/roo/excelx/shared_strings.rb +151 -0
- data/lib/roo/excelx/sheet.rb +151 -0
- data/lib/roo/excelx/sheet_doc.rb +257 -0
- data/lib/roo/excelx/styles.rb +64 -0
- data/lib/roo/excelx/workbook.rb +64 -0
- data/lib/roo/excelx.rb +407 -601
- data/lib/roo/font.rb +17 -0
- data/lib/roo/formatters/base.rb +15 -0
- data/lib/roo/formatters/csv.rb +84 -0
- data/lib/roo/formatters/matrix.rb +23 -0
- data/lib/roo/formatters/xml.rb +31 -0
- data/lib/roo/formatters/yaml.rb +40 -0
- data/lib/roo/helpers/default_attr_reader.rb +20 -0
- data/lib/roo/helpers/weak_instance_cache.rb +41 -0
- data/lib/roo/libre_office.rb +4 -0
- data/lib/roo/link.rb +34 -0
- data/lib/roo/open_office.rb +631 -0
- data/lib/roo/spreadsheet.rb +28 -23
- data/lib/roo/tempdir.rb +24 -0
- data/lib/roo/utils.rb +128 -0
- data/lib/roo/version.rb +3 -0
- data/lib/roo.rb +26 -24
- data/roo.gemspec +29 -202
- data/spec/helpers.rb +5 -0
- data/spec/lib/roo/base_spec.rb +291 -3
- data/spec/lib/roo/csv_spec.rb +38 -11
- data/spec/lib/roo/excelx/cell/time_spec.rb +15 -0
- data/spec/lib/roo/excelx/format_spec.rb +7 -6
- data/spec/lib/roo/excelx/relationships_spec.rb +43 -0
- data/spec/lib/roo/excelx/sheet_doc_spec.rb +11 -0
- data/spec/lib/roo/excelx_spec.rb +682 -6
- data/spec/lib/roo/libreoffice_spec.rb +16 -6
- data/spec/lib/roo/openoffice_spec.rb +30 -8
- data/spec/lib/roo/spreadsheet_spec.rb +60 -12
- data/spec/lib/roo/strict_spec.rb +43 -0
- data/spec/lib/roo/utils_spec.rb +119 -0
- data/spec/lib/roo/weak_instance_cache_spec.rb +92 -0
- data/spec/lib/roo_spec.rb +0 -0
- data/spec/spec_helper.rb +7 -6
- data/test/all_ss.rb +12 -11
- data/test/excelx/cell/test_attr_reader_default.rb +72 -0
- data/test/excelx/cell/test_base.rb +68 -0
- data/test/excelx/cell/test_boolean.rb +36 -0
- data/test/excelx/cell/test_date.rb +38 -0
- data/test/excelx/cell/test_datetime.rb +45 -0
- data/test/excelx/cell/test_empty.rb +18 -0
- data/test/excelx/cell/test_number.rb +90 -0
- data/test/excelx/cell/test_string.rb +48 -0
- data/test/excelx/cell/test_time.rb +30 -0
- data/test/excelx/test_coordinate.rb +51 -0
- data/test/formatters/test_csv.rb +136 -0
- data/test/formatters/test_matrix.rb +76 -0
- data/test/formatters/test_xml.rb +78 -0
- data/test/formatters/test_yaml.rb +20 -0
- data/test/helpers/test_accessing_files.rb +81 -0
- data/test/helpers/test_comments.rb +43 -0
- data/test/helpers/test_formulas.rb +9 -0
- data/test/helpers/test_labels.rb +103 -0
- data/test/helpers/test_sheets.rb +55 -0
- data/test/helpers/test_styles.rb +62 -0
- data/test/roo/test_base.rb +182 -0
- data/test/roo/test_csv.rb +88 -0
- data/test/roo/test_excelx.rb +360 -0
- data/test/roo/test_libre_office.rb +9 -0
- data/test/roo/test_open_office.rb +289 -0
- data/test/test_helper.rb +123 -59
- data/test/test_roo.rb +392 -2292
- metadata +153 -296
- data/CHANGELOG +0 -412
- data/Gemfile.lock +0 -78
- data/README.markdown +0 -126
- data/VERSION +0 -1
- data/lib/roo/excel.rb +0 -355
- data/lib/roo/excel2003xml.rb +0 -300
- data/lib/roo/google.rb +0 -292
- data/lib/roo/openoffice.rb +0 -496
- data/lib/roo/roo_rails_helper.rb +0 -83
- data/lib/roo/worksheet.rb +0 -18
- data/scripts/txt2html +0 -67
- data/spec/lib/roo/excel2003xml_spec.rb +0 -15
- data/spec/lib/roo/excel_spec.rb +0 -17
- data/spec/lib/roo/google_spec.rb +0 -64
- data/test/files/1900_base.xls +0 -0
- data/test/files/1900_base.xlsx +0 -0
- data/test/files/1904_base.xls +0 -0
- data/test/files/1904_base.xlsx +0 -0
- data/test/files/Bibelbund.csv +0 -3741
- data/test/files/Bibelbund.ods +0 -0
- data/test/files/Bibelbund.xls +0 -0
- data/test/files/Bibelbund.xlsx +0 -0
- data/test/files/Bibelbund.xml +0 -62518
- data/test/files/Bibelbund1.ods +0 -0
- data/test/files/Pfand_from_windows_phone.xlsx +0 -0
- data/test/files/bad_excel_date.xls +0 -0
- data/test/files/bbu.ods +0 -0
- data/test/files/bbu.xls +0 -0
- data/test/files/bbu.xlsx +0 -0
- data/test/files/bbu.xml +0 -152
- data/test/files/bode-v1.ods.zip +0 -0
- data/test/files/bode-v1.xls.zip +0 -0
- data/test/files/boolean.csv +0 -2
- data/test/files/boolean.ods +0 -0
- data/test/files/boolean.xls +0 -0
- data/test/files/boolean.xlsx +0 -0
- data/test/files/boolean.xml +0 -112
- data/test/files/borders.ods +0 -0
- data/test/files/borders.xls +0 -0
- data/test/files/borders.xlsx +0 -0
- data/test/files/borders.xml +0 -144
- data/test/files/bug-numbered-sheet-names.xlsx +0 -0
- data/test/files/bug-row-column-fixnum-float.xls +0 -0
- data/test/files/bug-row-column-fixnum-float.xml +0 -127
- data/test/files/comments.ods +0 -0
- data/test/files/comments.xls +0 -0
- data/test/files/comments.xlsx +0 -0
- data/test/files/csvtypes.csv +0 -1
- data/test/files/datetime.ods +0 -0
- data/test/files/datetime.xls +0 -0
- data/test/files/datetime.xlsx +0 -0
- data/test/files/datetime.xml +0 -142
- data/test/files/datetime_floatconv.xls +0 -0
- data/test/files/datetime_floatconv.xml +0 -148
- data/test/files/dreimalvier.ods +0 -0
- data/test/files/emptysheets.ods +0 -0
- data/test/files/emptysheets.xls +0 -0
- data/test/files/emptysheets.xlsx +0 -0
- data/test/files/emptysheets.xml +0 -105
- data/test/files/excel2003.xml +0 -21140
- data/test/files/false_encoding.xls +0 -0
- data/test/files/false_encoding.xml +0 -132
- data/test/files/file_item_error.xlsx +0 -0
- data/test/files/formula.ods +0 -0
- data/test/files/formula.xls +0 -0
- data/test/files/formula.xlsx +0 -0
- data/test/files/formula.xml +0 -134
- data/test/files/formula_parse_error.xls +0 -0
- data/test/files/formula_parse_error.xml +0 -1833
- data/test/files/formula_string_error.xlsx +0 -0
- data/test/files/html-escape.ods +0 -0
- data/test/files/link.xls +0 -0
- data/test/files/link.xlsx +0 -0
- data/test/files/matrix.ods +0 -0
- data/test/files/matrix.xls +0 -0
- data/test/files/named_cells.ods +0 -0
- data/test/files/named_cells.xls +0 -0
- data/test/files/named_cells.xlsx +0 -0
- data/test/files/no_spreadsheet_file.txt +0 -1
- data/test/files/numbers1.csv +0 -18
- data/test/files/numbers1.ods +0 -0
- data/test/files/numbers1.xls +0 -0
- data/test/files/numbers1.xlsx +0 -0
- data/test/files/numbers1.xml +0 -312
- data/test/files/only_one_sheet.ods +0 -0
- data/test/files/only_one_sheet.xls +0 -0
- data/test/files/only_one_sheet.xlsx +0 -0
- data/test/files/only_one_sheet.xml +0 -67
- data/test/files/paragraph.ods +0 -0
- data/test/files/paragraph.xls +0 -0
- data/test/files/paragraph.xlsx +0 -0
- data/test/files/paragraph.xml +0 -127
- data/test/files/prova.xls +0 -0
- data/test/files/ric.ods +0 -0
- data/test/files/simple_spreadsheet.ods +0 -0
- data/test/files/simple_spreadsheet.xls +0 -0
- data/test/files/simple_spreadsheet.xlsx +0 -0
- data/test/files/simple_spreadsheet.xml +0 -225
- data/test/files/simple_spreadsheet_from_italo.ods +0 -0
- data/test/files/simple_spreadsheet_from_italo.xls +0 -0
- data/test/files/simple_spreadsheet_from_italo.xml +0 -242
- data/test/files/so_datetime.csv +0 -7
- data/test/files/style.ods +0 -0
- data/test/files/style.xls +0 -0
- data/test/files/style.xlsx +0 -0
- data/test/files/style.xml +0 -154
- data/test/files/time-test.csv +0 -2
- data/test/files/time-test.ods +0 -0
- data/test/files/time-test.xls +0 -0
- data/test/files/time-test.xlsx +0 -0
- data/test/files/time-test.xml +0 -131
- data/test/files/type_excel.ods +0 -0
- data/test/files/type_excel.xlsx +0 -0
- data/test/files/type_excelx.ods +0 -0
- data/test/files/type_excelx.xls +0 -0
- data/test/files/type_openoffice.xls +0 -0
- data/test/files/type_openoffice.xlsx +0 -0
- data/test/files/whitespace.ods +0 -0
- data/test/files/whitespace.xls +0 -0
- data/test/files/whitespace.xlsx +0 -0
- data/test/files/whitespace.xml +0 -184
- data/test/rm_sub_test.rb +0 -12
- data/test/rm_test.rb +0 -7
- data/test/test_generic_spreadsheet.rb +0 -259
- data/website/index.html +0 -385
- data/website/index.txt +0 -423
- data/website/javascripts/rounded_corners_lite.inc.js +0 -285
- data/website/stylesheets/screen.css +0 -130
- data/website/template.rhtml +0 -48
@@ -0,0 +1,19 @@
|
|
1
|
+
module Roo
|
2
|
+
class Excelx
|
3
|
+
class Cell
|
4
|
+
class String < Cell::Base
|
5
|
+
attr_reader :value, :formula, :format, :cell_value, :coordinate
|
6
|
+
|
7
|
+
attr_reader_with_default default_type: :string, cell_type: :string
|
8
|
+
|
9
|
+
def initialize(value, formula, style, link, coordinate)
|
10
|
+
super(value, formula, nil, style, link, coordinate)
|
11
|
+
end
|
12
|
+
|
13
|
+
def empty?
|
14
|
+
value.empty?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module Roo
|
4
|
+
class Excelx
|
5
|
+
class Cell
|
6
|
+
class Time < Roo::Excelx::Cell::DateTime
|
7
|
+
attr_reader :value, :formula, :format, :cell_value, :coordinate
|
8
|
+
|
9
|
+
attr_reader_with_default default_type: :time
|
10
|
+
|
11
|
+
def initialize(value, formula, excelx_type, style, link, base_date, coordinate)
|
12
|
+
# NOTE: Pass all arguments to DateTime super class.
|
13
|
+
super
|
14
|
+
@format = excelx_type.last
|
15
|
+
@datetime = create_datetime(base_date, value)
|
16
|
+
@value = link ? Roo::Link.new(link, value) : (value.to_f * 86_400).round.to_i
|
17
|
+
end
|
18
|
+
|
19
|
+
def formatted_value
|
20
|
+
formatter = @format.gsub(/#{TIME_FORMATS.keys.join('|')}/, TIME_FORMATS)
|
21
|
+
@datetime.strftime(formatter)
|
22
|
+
end
|
23
|
+
|
24
|
+
alias_method :to_s, :formatted_value
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# def create_datetime(base_date, value)
|
29
|
+
# date = base_date + value.to_f.round(6)
|
30
|
+
# datetime_string = date.strftime('%Y-%m-%d %H:%M:%S.%N')
|
31
|
+
# t = round_datetime(datetime_string)
|
32
|
+
#
|
33
|
+
# ::DateTime.civil(t.year, t.month, t.day, t.hour, t.min, t.sec)
|
34
|
+
# end
|
35
|
+
|
36
|
+
# def round_datetime(datetime_string)
|
37
|
+
# /(?<yyyy>\d+)-(?<mm>\d+)-(?<dd>\d+) (?<hh>\d+):(?<mi>\d+):(?<ss>\d+.\d+)/ =~ datetime_string
|
38
|
+
#
|
39
|
+
# ::Time.new(yyyy.to_i, mm.to_i, dd.to_i, hh.to_i, mi.to_i, ss.to_r).round(0)
|
40
|
+
# end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'roo/excelx/cell/base'
|
3
|
+
require 'roo/excelx/cell/boolean'
|
4
|
+
require 'roo/excelx/cell/datetime'
|
5
|
+
require 'roo/excelx/cell/date'
|
6
|
+
require 'roo/excelx/cell/empty'
|
7
|
+
require 'roo/excelx/cell/number'
|
8
|
+
require 'roo/excelx/cell/string'
|
9
|
+
require 'roo/excelx/cell/time'
|
10
|
+
|
11
|
+
module Roo
|
12
|
+
class Excelx
|
13
|
+
class Cell
|
14
|
+
attr_reader :formula, :value, :excelx_type, :excelx_value, :style, :hyperlink, :coordinate
|
15
|
+
attr_writer :value
|
16
|
+
|
17
|
+
# DEPRECATED: Please use Cell.create_cell instead.
|
18
|
+
def initialize(value, type, formula, excelx_type, excelx_value, style, hyperlink, base_date, coordinate)
|
19
|
+
warn '[DEPRECATION] `Cell.new` is deprecated. Please use `Cell.create_cell` instead.'
|
20
|
+
@type = type
|
21
|
+
@formula = formula
|
22
|
+
@base_date = base_date if [:date, :datetime].include?(@type)
|
23
|
+
@excelx_type = excelx_type
|
24
|
+
@excelx_value = excelx_value
|
25
|
+
@style = style
|
26
|
+
@value = type_cast_value(value)
|
27
|
+
@value = Roo::Link.new(hyperlink, @value.to_s) if hyperlink
|
28
|
+
@coordinate = coordinate
|
29
|
+
end
|
30
|
+
|
31
|
+
def type
|
32
|
+
case
|
33
|
+
when @formula
|
34
|
+
:formula
|
35
|
+
when @value.is_a?(Roo::Link)
|
36
|
+
:link
|
37
|
+
else
|
38
|
+
@type
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.create_cell(type, *values)
|
43
|
+
cell_class(type)&.new(*values)
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.cell_class(type)
|
47
|
+
case type
|
48
|
+
when :string
|
49
|
+
Cell::String
|
50
|
+
when :boolean
|
51
|
+
Cell::Boolean
|
52
|
+
when :number
|
53
|
+
Cell::Number
|
54
|
+
when :date
|
55
|
+
Cell::Date
|
56
|
+
when :datetime
|
57
|
+
Cell::DateTime
|
58
|
+
when :time
|
59
|
+
Cell::Time
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Deprecated: use Roo::Excelx::Coordinate instead.
|
64
|
+
class Coordinate
|
65
|
+
attr_accessor :row, :column
|
66
|
+
|
67
|
+
def initialize(row, column)
|
68
|
+
warn '[DEPRECATION] `Roo::Excel::Cell::Coordinate` is deprecated. Please use `Roo::Excelx::Coordinate` instead.'
|
69
|
+
@row, @column = row, column
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def type_cast_value(value)
|
76
|
+
case @type
|
77
|
+
when :float, :percentage
|
78
|
+
value.to_f
|
79
|
+
when :date
|
80
|
+
create_date(@base_date + value.to_i)
|
81
|
+
when :datetime
|
82
|
+
create_datetime(@base_date + value.to_f.round(6))
|
83
|
+
when :time
|
84
|
+
value.to_f * 86_400
|
85
|
+
else
|
86
|
+
value
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def create_date(date)
|
91
|
+
yyyy, mm, dd = date.strftime('%Y-%m-%d').split('-')
|
92
|
+
|
93
|
+
::Date.new(yyyy.to_i, mm.to_i, dd.to_i)
|
94
|
+
end
|
95
|
+
|
96
|
+
def create_datetime(date)
|
97
|
+
datetime_string = date.strftime('%Y-%m-%d %H:%M:%S.%N')
|
98
|
+
t = round_datetime(datetime_string)
|
99
|
+
|
100
|
+
::DateTime.civil(t.year, t.month, t.day, t.hour, t.min, t.sec)
|
101
|
+
end
|
102
|
+
|
103
|
+
def round_datetime(datetime_string)
|
104
|
+
/(?<yyyy>\d+)-(?<mm>\d+)-(?<dd>\d+) (?<hh>\d+):(?<mi>\d+):(?<ss>\d+.\d+)/ =~ datetime_string
|
105
|
+
|
106
|
+
::Time.new(yyyy.to_i, mm.to_i, dd.to_i, hh.to_i, mi.to_i, ss.to_r).round(0)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'roo/excelx/extractor'
|
2
|
+
|
3
|
+
module Roo
|
4
|
+
class Excelx
|
5
|
+
class Comments < Excelx::Extractor
|
6
|
+
def comments
|
7
|
+
@comments ||= extract_comments
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def extract_comments
|
13
|
+
return {} unless doc_exists?
|
14
|
+
|
15
|
+
doc.xpath('//comments/commentList/comment').each_with_object({}) do |comment, hash|
|
16
|
+
value = (comment.at_xpath('./text/r/t') || comment.at_xpath('./text/t')).text
|
17
|
+
hash[::Roo::Utils.ref_to_key(comment['ref'].to_s)] = value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
# xl/comments1.xml
|
24
|
+
# <?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
25
|
+
# <comments xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
26
|
+
# <authors>
|
27
|
+
# <author />
|
28
|
+
# </authors>
|
29
|
+
# <commentList>
|
30
|
+
# <comment ref="B4" authorId="0">
|
31
|
+
# <text>
|
32
|
+
# <r>
|
33
|
+
# <rPr>
|
34
|
+
# <sz val="10" />
|
35
|
+
# <rFont val="Arial" />
|
36
|
+
# <family val="2" />
|
37
|
+
# </rPr>
|
38
|
+
# <t>Comment for B4</t>
|
39
|
+
# </r>
|
40
|
+
# </text>
|
41
|
+
# </comment>
|
42
|
+
# <comment ref="B5" authorId="0">
|
43
|
+
# <text>
|
44
|
+
# <r>
|
45
|
+
# <rPr>
|
46
|
+
# <sz val="10" />
|
47
|
+
# <rFont val="Arial" />
|
48
|
+
# <family val="2" />
|
49
|
+
# </rPr>
|
50
|
+
# <t>Comment for B5</t>
|
51
|
+
# </r>
|
52
|
+
# </text>
|
53
|
+
# </comment>
|
54
|
+
# </commentList>
|
55
|
+
# </comments>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "roo/helpers/weak_instance_cache"
|
4
|
+
|
5
|
+
module Roo
|
6
|
+
class Excelx
|
7
|
+
class Extractor
|
8
|
+
include Roo::Helpers::WeakInstanceCache
|
9
|
+
|
10
|
+
COMMON_STRINGS = {
|
11
|
+
t: "t",
|
12
|
+
r: "r",
|
13
|
+
s: "s",
|
14
|
+
ref: "ref",
|
15
|
+
html_tag_open: "<html>",
|
16
|
+
html_tag_closed: "</html>"
|
17
|
+
}
|
18
|
+
|
19
|
+
def initialize(path, options = {})
|
20
|
+
@path = path
|
21
|
+
@options = options
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def doc
|
27
|
+
instance_cache(:@doc) do
|
28
|
+
raise FileNotFound, "#{@path} file not found" unless doc_exists?
|
29
|
+
|
30
|
+
::Roo::Utils.load_xml(@path).remove_namespaces!
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def doc_exists?
|
35
|
+
@path && File.exist?(@path)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Roo
|
4
|
+
class Excelx
|
5
|
+
module Format
|
6
|
+
extend self
|
7
|
+
EXCEPTIONAL_FORMATS = {
|
8
|
+
'h:mm am/pm' => :date,
|
9
|
+
'h:mm:ss am/pm' => :date
|
10
|
+
}
|
11
|
+
|
12
|
+
STANDARD_FORMATS = {
|
13
|
+
0 => 'General',
|
14
|
+
1 => '0',
|
15
|
+
2 => '0.00',
|
16
|
+
3 => '#,##0',
|
17
|
+
4 => '#,##0.00',
|
18
|
+
9 => '0%',
|
19
|
+
10 => '0.00%',
|
20
|
+
11 => '0.00E+00',
|
21
|
+
12 => '# ?/?',
|
22
|
+
13 => '# ??/??',
|
23
|
+
14 => 'mm-dd-yy',
|
24
|
+
15 => 'd-mmm-yy',
|
25
|
+
16 => 'd-mmm',
|
26
|
+
17 => 'mmm-yy',
|
27
|
+
18 => 'h:mm AM/PM',
|
28
|
+
19 => 'h:mm:ss AM/PM',
|
29
|
+
20 => 'h:mm',
|
30
|
+
21 => 'h:mm:ss',
|
31
|
+
22 => 'm/d/yy h:mm',
|
32
|
+
37 => '#,##0 ;(#,##0)',
|
33
|
+
38 => '#,##0 ;[Red](#,##0)',
|
34
|
+
39 => '#,##0.00;(#,##0.00)',
|
35
|
+
40 => '#,##0.00;[Red](#,##0.00)',
|
36
|
+
45 => 'mm:ss',
|
37
|
+
46 => '[h]:mm:ss',
|
38
|
+
47 => 'mmss.0',
|
39
|
+
48 => '##0.0E+0',
|
40
|
+
49 => '@'
|
41
|
+
}
|
42
|
+
|
43
|
+
def to_type(format)
|
44
|
+
@to_type ||= {}
|
45
|
+
@to_type[format] ||= _to_type(format)
|
46
|
+
end
|
47
|
+
|
48
|
+
def _to_type(format)
|
49
|
+
format = format.to_s.downcase
|
50
|
+
if (type = EXCEPTIONAL_FORMATS[format])
|
51
|
+
type
|
52
|
+
elsif format.include?('#')
|
53
|
+
:float
|
54
|
+
elsif format.include?('y') || !format.match(/d+(?![\]])/).nil?
|
55
|
+
if format.include?('h') || format.include?('s')
|
56
|
+
:datetime
|
57
|
+
else
|
58
|
+
:date
|
59
|
+
end
|
60
|
+
elsif format.include?('h') || format.include?('s')
|
61
|
+
:time
|
62
|
+
elsif format.include?('%')
|
63
|
+
:percentage
|
64
|
+
else
|
65
|
+
:float
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'roo/excelx/extractor'
|
2
|
+
|
3
|
+
module Roo
|
4
|
+
class Excelx
|
5
|
+
class Images < Excelx::Extractor
|
6
|
+
|
7
|
+
# Returns: Hash { id1: extracted_file_name1 },
|
8
|
+
# Example: { "rId1"=>"roo_media_image1.png",
|
9
|
+
# "rId2"=>"roo_media_image2.png",
|
10
|
+
# "rId3"=>"roo_media_image3.png" }
|
11
|
+
def list
|
12
|
+
@images ||= extract_images_names
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def extract_images_names
|
18
|
+
return {} unless doc_exists?
|
19
|
+
|
20
|
+
doc.xpath('/Relationships/Relationship').each_with_object({}) do |rel, hash|
|
21
|
+
hash[rel['Id']] = "roo" + rel['Target'].gsub(/\.\.\/|\//, '_')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'roo/excelx/extractor'
|
4
|
+
|
5
|
+
module Roo
|
6
|
+
class Excelx
|
7
|
+
class Relationships < Excelx::Extractor
|
8
|
+
def [](index)
|
9
|
+
to_a[index]
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_a
|
13
|
+
@relationships ||= extract_relationships
|
14
|
+
end
|
15
|
+
|
16
|
+
def include_type?(type)
|
17
|
+
to_a.any? do |_, rel|
|
18
|
+
rel["Type"]&.include? type
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def extract_relationships
|
25
|
+
return {} unless doc_exists?
|
26
|
+
|
27
|
+
doc.xpath('/Relationships/Relationship').each_with_object({}) do |rel, hash|
|
28
|
+
hash[rel['Id']] = rel
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Roo
|
2
|
+
class Excelx
|
3
|
+
# Public: Shared class for allowing sheets to share data. This should
|
4
|
+
# reduce memory usage and reduce the number of objects being passed
|
5
|
+
# to various inititializers.
|
6
|
+
class Shared
|
7
|
+
attr_accessor :comments_files, :sheet_files, :rels_files, :image_rels, :image_files
|
8
|
+
def initialize(dir, options = {})
|
9
|
+
@dir = dir
|
10
|
+
@comments_files = []
|
11
|
+
@sheet_files = []
|
12
|
+
@rels_files = []
|
13
|
+
@options = options
|
14
|
+
@image_rels = []
|
15
|
+
@image_files = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def styles
|
19
|
+
@styles ||= Styles.new(File.join(@dir, 'roo_styles.xml'))
|
20
|
+
end
|
21
|
+
|
22
|
+
def shared_strings
|
23
|
+
@shared_strings ||= SharedStrings.new(File.join(@dir, 'roo_sharedStrings.xml'), @options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def workbook
|
27
|
+
@workbook ||= Workbook.new(File.join(@dir, 'roo_workbook.xml'))
|
28
|
+
end
|
29
|
+
|
30
|
+
def base_date
|
31
|
+
workbook.base_date
|
32
|
+
end
|
33
|
+
|
34
|
+
def base_timestamp
|
35
|
+
workbook.base_timestamp
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'roo/excelx/extractor'
|
4
|
+
|
5
|
+
module Roo
|
6
|
+
class Excelx
|
7
|
+
class SharedStrings < Excelx::Extractor
|
8
|
+
def [](index)
|
9
|
+
to_a[index]
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_a
|
13
|
+
@array ||= extract_shared_strings
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_html
|
17
|
+
@html ||= extract_html
|
18
|
+
end
|
19
|
+
|
20
|
+
# Use to_html or to_a for html returns
|
21
|
+
# See what is happening with commit???
|
22
|
+
def use_html?(index)
|
23
|
+
return false if @options[:disable_html_wrapper]
|
24
|
+
to_html[index][/<([biu]|sup|sub)>/]
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def fix_invalid_shared_strings(doc)
|
30
|
+
invalid = { '_x000D_' => "\n" }
|
31
|
+
xml = doc.to_s
|
32
|
+
return doc unless xml[/#{invalid.keys.join('|')}/]
|
33
|
+
|
34
|
+
::Nokogiri::XML(xml.gsub(/#{invalid.keys.join('|')}/, invalid))
|
35
|
+
end
|
36
|
+
|
37
|
+
def extract_shared_strings
|
38
|
+
return [] unless doc_exists?
|
39
|
+
|
40
|
+
document = fix_invalid_shared_strings(doc)
|
41
|
+
# read the shared strings xml document
|
42
|
+
document.xpath('/sst/si').map do |si|
|
43
|
+
shared_string = +""
|
44
|
+
si.children.each do |elem|
|
45
|
+
case elem.name
|
46
|
+
when 'r'
|
47
|
+
elem.children.each do |r_elem|
|
48
|
+
shared_string << r_elem.content if r_elem.name == 't'
|
49
|
+
end
|
50
|
+
when 't'
|
51
|
+
shared_string = elem.content
|
52
|
+
end
|
53
|
+
end
|
54
|
+
shared_string
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def extract_html
|
59
|
+
return [] unless doc_exists?
|
60
|
+
fix_invalid_shared_strings(doc)
|
61
|
+
# read the shared strings xml document
|
62
|
+
doc.xpath('/sst/si').map do |si|
|
63
|
+
html_string = '<html>'.dup
|
64
|
+
si.children.each do |elem|
|
65
|
+
case elem.name
|
66
|
+
when 'r'
|
67
|
+
html_string << extract_html_r(elem)
|
68
|
+
when 't'
|
69
|
+
html_string << elem.content
|
70
|
+
end # case elem.name
|
71
|
+
end # si.children.each do |elem|
|
72
|
+
html_string << '</html>'
|
73
|
+
end # doc.xpath('/sst/si').map do |si|
|
74
|
+
end # def extract_html
|
75
|
+
|
76
|
+
# The goal of this function is to take the following XML code snippet and create a html tag
|
77
|
+
# r_elem ::: XML Element that is in sharedStrings.xml of excel_book.xlsx
|
78
|
+
# {code:xml}
|
79
|
+
# <r>
|
80
|
+
# <rPr>
|
81
|
+
# <i/>
|
82
|
+
# <b/>
|
83
|
+
# <u/>
|
84
|
+
# <vertAlign val="subscript"/>
|
85
|
+
# <vertAlign val="superscript"/>
|
86
|
+
# </rPr>
|
87
|
+
# <t>TEXT</t>
|
88
|
+
# </r>
|
89
|
+
# {code}
|
90
|
+
#
|
91
|
+
# Expected Output ::: "<html><sub|sup><b><i><u>TEXT</u></i></b></sub|/sup></html>"
|
92
|
+
def extract_html_r(r_elem)
|
93
|
+
str = +""
|
94
|
+
xml_elems = {
|
95
|
+
sub: false,
|
96
|
+
sup: false,
|
97
|
+
b: false,
|
98
|
+
i: false,
|
99
|
+
u: false
|
100
|
+
}
|
101
|
+
r_elem.children.each do |elem|
|
102
|
+
case elem.name
|
103
|
+
when 'rPr'
|
104
|
+
elem.children.each do |rPr_elem|
|
105
|
+
case rPr_elem.name
|
106
|
+
when 'b'
|
107
|
+
# set formatting for Bold to true
|
108
|
+
xml_elems[:b] = true
|
109
|
+
when 'i'
|
110
|
+
# set formatting for Italics to true
|
111
|
+
xml_elems[:i] = true
|
112
|
+
when 'u'
|
113
|
+
# set formatting for Underline to true
|
114
|
+
xml_elems[:u] = true
|
115
|
+
when 'vertAlign'
|
116
|
+
# See if the Vertical Alignment is subscript or superscript
|
117
|
+
case rPr_elem.xpath('@val').first.value
|
118
|
+
when 'subscript'
|
119
|
+
# set formatting for Subscript to true and Superscript to false ... Can't have both
|
120
|
+
xml_elems[:sub] = true
|
121
|
+
xml_elems[:sup] = false
|
122
|
+
when 'superscript'
|
123
|
+
# set formatting for Superscript to true and Subscript to false ... Can't have both
|
124
|
+
xml_elems[:sup] = true
|
125
|
+
xml_elems[:sub] = false
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
when 't'
|
130
|
+
str << create_html(elem.content, xml_elems)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
str
|
134
|
+
end # extract_html_r
|
135
|
+
|
136
|
+
# This will return an html string
|
137
|
+
def create_html(text, formatting)
|
138
|
+
tmp_str = +""
|
139
|
+
formatting.each do |elem, val|
|
140
|
+
tmp_str << "<#{elem}>" if val
|
141
|
+
end
|
142
|
+
tmp_str << text
|
143
|
+
|
144
|
+
formatting.reverse_each do |elem, val|
|
145
|
+
tmp_str << "</#{elem}>" if val
|
146
|
+
end
|
147
|
+
tmp_str
|
148
|
+
end
|
149
|
+
end # class SharedStrings < Excelx::Extractor
|
150
|
+
end # class Excelx
|
151
|
+
end # module Roo
|