roo 1.13.2 → 2.10.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.
Files changed (236) hide show
  1. checksums.yaml +5 -5
  2. data/.codeclimate.yml +17 -0
  3. data/.github/issue_template.md +16 -0
  4. data/.github/pull_request_template.md +14 -0
  5. data/.github/workflows/pull-request.yml +15 -0
  6. data/.github/workflows/ruby.yml +34 -0
  7. data/.gitignore +11 -0
  8. data/.rubocop.yml +186 -0
  9. data/.simplecov +4 -0
  10. data/CHANGELOG.md +702 -0
  11. data/Gemfile +18 -12
  12. data/Guardfile +23 -0
  13. data/LICENSE +5 -1
  14. data/README.md +328 -0
  15. data/Rakefile +23 -23
  16. data/examples/roo_soap_client.rb +28 -31
  17. data/examples/roo_soap_server.rb +4 -6
  18. data/examples/write_me.rb +9 -10
  19. data/lib/roo/base.rb +317 -504
  20. data/lib/roo/constants.rb +7 -0
  21. data/lib/roo/csv.rb +141 -113
  22. data/lib/roo/errors.rb +11 -0
  23. data/lib/roo/excelx/cell/base.rb +108 -0
  24. data/lib/roo/excelx/cell/boolean.rb +30 -0
  25. data/lib/roo/excelx/cell/date.rb +28 -0
  26. data/lib/roo/excelx/cell/datetime.rb +107 -0
  27. data/lib/roo/excelx/cell/empty.rb +20 -0
  28. data/lib/roo/excelx/cell/number.rb +99 -0
  29. data/lib/roo/excelx/cell/string.rb +19 -0
  30. data/lib/roo/excelx/cell/time.rb +44 -0
  31. data/lib/roo/excelx/cell.rb +110 -0
  32. data/lib/roo/excelx/comments.rb +55 -0
  33. data/lib/roo/excelx/coordinate.rb +19 -0
  34. data/lib/roo/excelx/extractor.rb +39 -0
  35. data/lib/roo/excelx/format.rb +71 -0
  36. data/lib/roo/excelx/images.rb +26 -0
  37. data/lib/roo/excelx/relationships.rb +33 -0
  38. data/lib/roo/excelx/shared.rb +39 -0
  39. data/lib/roo/excelx/shared_strings.rb +151 -0
  40. data/lib/roo/excelx/sheet.rb +151 -0
  41. data/lib/roo/excelx/sheet_doc.rb +257 -0
  42. data/lib/roo/excelx/styles.rb +64 -0
  43. data/lib/roo/excelx/workbook.rb +64 -0
  44. data/lib/roo/excelx.rb +407 -601
  45. data/lib/roo/font.rb +17 -0
  46. data/lib/roo/formatters/base.rb +15 -0
  47. data/lib/roo/formatters/csv.rb +84 -0
  48. data/lib/roo/formatters/matrix.rb +23 -0
  49. data/lib/roo/formatters/xml.rb +31 -0
  50. data/lib/roo/formatters/yaml.rb +40 -0
  51. data/lib/roo/helpers/default_attr_reader.rb +20 -0
  52. data/lib/roo/helpers/weak_instance_cache.rb +41 -0
  53. data/lib/roo/libre_office.rb +4 -0
  54. data/lib/roo/link.rb +34 -0
  55. data/lib/roo/open_office.rb +631 -0
  56. data/lib/roo/spreadsheet.rb +28 -23
  57. data/lib/roo/tempdir.rb +24 -0
  58. data/lib/roo/utils.rb +128 -0
  59. data/lib/roo/version.rb +3 -0
  60. data/lib/roo.rb +26 -24
  61. data/roo.gemspec +29 -203
  62. data/spec/helpers.rb +5 -0
  63. data/spec/lib/roo/base_spec.rb +291 -3
  64. data/spec/lib/roo/csv_spec.rb +38 -11
  65. data/spec/lib/roo/excelx/cell/time_spec.rb +15 -0
  66. data/spec/lib/roo/excelx/format_spec.rb +7 -6
  67. data/spec/lib/roo/excelx/relationships_spec.rb +43 -0
  68. data/spec/lib/roo/excelx/sheet_doc_spec.rb +11 -0
  69. data/spec/lib/roo/excelx_spec.rb +672 -11
  70. data/spec/lib/roo/libreoffice_spec.rb +16 -6
  71. data/spec/lib/roo/openoffice_spec.rb +30 -8
  72. data/spec/lib/roo/spreadsheet_spec.rb +60 -12
  73. data/spec/lib/roo/strict_spec.rb +43 -0
  74. data/spec/lib/roo/utils_spec.rb +119 -0
  75. data/spec/lib/roo/weak_instance_cache_spec.rb +92 -0
  76. data/spec/lib/roo_spec.rb +0 -0
  77. data/spec/spec_helper.rb +7 -6
  78. data/test/all_ss.rb +12 -11
  79. data/test/excelx/cell/test_attr_reader_default.rb +72 -0
  80. data/test/excelx/cell/test_base.rb +68 -0
  81. data/test/excelx/cell/test_boolean.rb +36 -0
  82. data/test/excelx/cell/test_date.rb +38 -0
  83. data/test/excelx/cell/test_datetime.rb +45 -0
  84. data/test/excelx/cell/test_empty.rb +18 -0
  85. data/test/excelx/cell/test_number.rb +90 -0
  86. data/test/excelx/cell/test_string.rb +48 -0
  87. data/test/excelx/cell/test_time.rb +30 -0
  88. data/test/excelx/test_coordinate.rb +51 -0
  89. data/test/formatters/test_csv.rb +136 -0
  90. data/test/formatters/test_matrix.rb +76 -0
  91. data/test/formatters/test_xml.rb +78 -0
  92. data/test/formatters/test_yaml.rb +20 -0
  93. data/test/helpers/test_accessing_files.rb +81 -0
  94. data/test/helpers/test_comments.rb +43 -0
  95. data/test/helpers/test_formulas.rb +9 -0
  96. data/test/helpers/test_labels.rb +103 -0
  97. data/test/helpers/test_sheets.rb +55 -0
  98. data/test/helpers/test_styles.rb +62 -0
  99. data/test/roo/test_base.rb +182 -0
  100. data/test/roo/test_csv.rb +88 -0
  101. data/test/roo/test_excelx.rb +360 -0
  102. data/test/roo/test_libre_office.rb +9 -0
  103. data/test/roo/test_open_office.rb +289 -0
  104. data/test/test_helper.rb +123 -59
  105. data/test/test_roo.rb +392 -2292
  106. metadata +153 -298
  107. data/CHANGELOG +0 -417
  108. data/Gemfile.lock +0 -78
  109. data/README.markdown +0 -126
  110. data/VERSION +0 -1
  111. data/lib/roo/excel.rb +0 -355
  112. data/lib/roo/excel2003xml.rb +0 -300
  113. data/lib/roo/google.rb +0 -292
  114. data/lib/roo/openoffice.rb +0 -496
  115. data/lib/roo/roo_rails_helper.rb +0 -83
  116. data/lib/roo/worksheet.rb +0 -18
  117. data/scripts/txt2html +0 -67
  118. data/spec/lib/roo/excel2003xml_spec.rb +0 -15
  119. data/spec/lib/roo/excel_spec.rb +0 -17
  120. data/spec/lib/roo/google_spec.rb +0 -64
  121. data/test/files/1900_base.xls +0 -0
  122. data/test/files/1900_base.xlsx +0 -0
  123. data/test/files/1904_base.xls +0 -0
  124. data/test/files/1904_base.xlsx +0 -0
  125. data/test/files/Bibelbund.csv +0 -3741
  126. data/test/files/Bibelbund.ods +0 -0
  127. data/test/files/Bibelbund.xls +0 -0
  128. data/test/files/Bibelbund.xlsx +0 -0
  129. data/test/files/Bibelbund.xml +0 -62518
  130. data/test/files/Bibelbund1.ods +0 -0
  131. data/test/files/Pfand_from_windows_phone.xlsx +0 -0
  132. data/test/files/bad_excel_date.xls +0 -0
  133. data/test/files/bbu.ods +0 -0
  134. data/test/files/bbu.xls +0 -0
  135. data/test/files/bbu.xlsx +0 -0
  136. data/test/files/bbu.xml +0 -152
  137. data/test/files/bode-v1.ods.zip +0 -0
  138. data/test/files/bode-v1.xls.zip +0 -0
  139. data/test/files/boolean.csv +0 -2
  140. data/test/files/boolean.ods +0 -0
  141. data/test/files/boolean.xls +0 -0
  142. data/test/files/boolean.xlsx +0 -0
  143. data/test/files/boolean.xml +0 -112
  144. data/test/files/borders.ods +0 -0
  145. data/test/files/borders.xls +0 -0
  146. data/test/files/borders.xlsx +0 -0
  147. data/test/files/borders.xml +0 -144
  148. data/test/files/bug-numbered-sheet-names.xlsx +0 -0
  149. data/test/files/bug-row-column-fixnum-float.xls +0 -0
  150. data/test/files/bug-row-column-fixnum-float.xml +0 -127
  151. data/test/files/comments.ods +0 -0
  152. data/test/files/comments.xls +0 -0
  153. data/test/files/comments.xlsx +0 -0
  154. data/test/files/csvtypes.csv +0 -1
  155. data/test/files/datetime.ods +0 -0
  156. data/test/files/datetime.xls +0 -0
  157. data/test/files/datetime.xlsx +0 -0
  158. data/test/files/datetime.xml +0 -142
  159. data/test/files/datetime_floatconv.xls +0 -0
  160. data/test/files/datetime_floatconv.xml +0 -148
  161. data/test/files/dreimalvier.ods +0 -0
  162. data/test/files/emptysheets.ods +0 -0
  163. data/test/files/emptysheets.xls +0 -0
  164. data/test/files/emptysheets.xlsx +0 -0
  165. data/test/files/emptysheets.xml +0 -105
  166. data/test/files/excel2003.xml +0 -21140
  167. data/test/files/false_encoding.xls +0 -0
  168. data/test/files/false_encoding.xml +0 -132
  169. data/test/files/file_item_error.xlsx +0 -0
  170. data/test/files/formula.ods +0 -0
  171. data/test/files/formula.xls +0 -0
  172. data/test/files/formula.xlsx +0 -0
  173. data/test/files/formula.xml +0 -134
  174. data/test/files/formula_parse_error.xls +0 -0
  175. data/test/files/formula_parse_error.xml +0 -1833
  176. data/test/files/formula_string_error.xlsx +0 -0
  177. data/test/files/html-escape.ods +0 -0
  178. data/test/files/link.xls +0 -0
  179. data/test/files/link.xlsx +0 -0
  180. data/test/files/matrix.ods +0 -0
  181. data/test/files/matrix.xls +0 -0
  182. data/test/files/named_cells.ods +0 -0
  183. data/test/files/named_cells.xls +0 -0
  184. data/test/files/named_cells.xlsx +0 -0
  185. data/test/files/no_spreadsheet_file.txt +0 -1
  186. data/test/files/numbers1.csv +0 -18
  187. data/test/files/numbers1.ods +0 -0
  188. data/test/files/numbers1.xls +0 -0
  189. data/test/files/numbers1.xlsx +0 -0
  190. data/test/files/numbers1.xml +0 -312
  191. data/test/files/numeric-link.xlsx +0 -0
  192. data/test/files/only_one_sheet.ods +0 -0
  193. data/test/files/only_one_sheet.xls +0 -0
  194. data/test/files/only_one_sheet.xlsx +0 -0
  195. data/test/files/only_one_sheet.xml +0 -67
  196. data/test/files/paragraph.ods +0 -0
  197. data/test/files/paragraph.xls +0 -0
  198. data/test/files/paragraph.xlsx +0 -0
  199. data/test/files/paragraph.xml +0 -127
  200. data/test/files/prova.xls +0 -0
  201. data/test/files/ric.ods +0 -0
  202. data/test/files/simple_spreadsheet.ods +0 -0
  203. data/test/files/simple_spreadsheet.xls +0 -0
  204. data/test/files/simple_spreadsheet.xlsx +0 -0
  205. data/test/files/simple_spreadsheet.xml +0 -225
  206. data/test/files/simple_spreadsheet_from_italo.ods +0 -0
  207. data/test/files/simple_spreadsheet_from_italo.xls +0 -0
  208. data/test/files/simple_spreadsheet_from_italo.xml +0 -242
  209. data/test/files/so_datetime.csv +0 -7
  210. data/test/files/style.ods +0 -0
  211. data/test/files/style.xls +0 -0
  212. data/test/files/style.xlsx +0 -0
  213. data/test/files/style.xml +0 -154
  214. data/test/files/time-test.csv +0 -2
  215. data/test/files/time-test.ods +0 -0
  216. data/test/files/time-test.xls +0 -0
  217. data/test/files/time-test.xlsx +0 -0
  218. data/test/files/time-test.xml +0 -131
  219. data/test/files/type_excel.ods +0 -0
  220. data/test/files/type_excel.xlsx +0 -0
  221. data/test/files/type_excelx.ods +0 -0
  222. data/test/files/type_excelx.xls +0 -0
  223. data/test/files/type_openoffice.xls +0 -0
  224. data/test/files/type_openoffice.xlsx +0 -0
  225. data/test/files/whitespace.ods +0 -0
  226. data/test/files/whitespace.xls +0 -0
  227. data/test/files/whitespace.xlsx +0 -0
  228. data/test/files/whitespace.xml +0 -184
  229. data/test/rm_sub_test.rb +0 -12
  230. data/test/rm_test.rb +0 -7
  231. data/test/test_generic_spreadsheet.rb +0 -259
  232. data/website/index.html +0 -385
  233. data/website/index.txt +0 -423
  234. data/website/javascripts/rounded_corners_lite.inc.js +0 -285
  235. data/website/stylesheets/screen.css +0 -130
  236. 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,19 @@
1
+ module Roo
2
+ class Excelx
3
+ class Coordinate < ::Array
4
+
5
+ def initialize(row, column)
6
+ super() << row << column
7
+ freeze
8
+ end
9
+
10
+ def row
11
+ self[0]
12
+ end
13
+
14
+ def column
15
+ self[1]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -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