workbook 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.codeclimate.yml +21 -0
- data/.gitignore +4 -1
- data/.ruby-version +1 -1
- data/.travis.yml +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile +2 -2
- data/README.md +9 -7
- data/Rakefile +6 -6
- data/lib/workbook/book.rb +73 -62
- data/lib/workbook/cell.rb +58 -13
- data/lib/workbook/column.rb +31 -28
- data/lib/workbook/format.rb +23 -24
- data/lib/workbook/generatetypes.rb +4 -4
- data/lib/workbook/modules/cache.rb +6 -7
- data/lib/workbook/modules/cell.rb +77 -100
- data/lib/workbook/modules/diff_sort.rb +92 -83
- data/lib/workbook/modules/raw_objects_storage.rb +6 -8
- data/lib/workbook/modules/type_parser.rb +30 -22
- data/lib/workbook/nil_value.rb +4 -9
- data/lib/workbook/readers/csv_reader.rb +7 -10
- data/lib/workbook/readers/ods_reader.rb +48 -50
- data/lib/workbook/readers/txt_reader.rb +6 -8
- data/lib/workbook/readers/xls_reader.rb +21 -33
- data/lib/workbook/readers/xls_shared.rb +106 -117
- data/lib/workbook/readers/xlsx_reader.rb +45 -46
- data/lib/workbook/row.rb +99 -84
- data/lib/workbook/sheet.rb +47 -38
- data/lib/workbook/table.rb +96 -72
- data/lib/workbook/template.rb +12 -15
- data/lib/workbook/types/false.rb +0 -1
- data/lib/workbook/types/nil.rb +0 -1
- data/lib/workbook/types/nil_class.rb +1 -1
- data/lib/workbook/types/numeric.rb +1 -1
- data/lib/workbook/types/string.rb +1 -1
- data/lib/workbook/types/time.rb +1 -1
- data/lib/workbook/types/true.rb +0 -1
- data/lib/workbook/types/true_class.rb +1 -1
- data/lib/workbook/version.rb +2 -3
- data/lib/workbook/writers/csv_table_writer.rb +10 -13
- data/lib/workbook/writers/html_writer.rb +34 -38
- data/lib/workbook/writers/json_table_writer.rb +8 -11
- data/lib/workbook/writers/xls_writer.rb +30 -36
- data/lib/workbook/writers/xlsx_writer.rb +45 -29
- data/lib/workbook.rb +16 -15
- data/test/helper.rb +6 -5
- data/test/test_book.rb +41 -38
- data/test/test_column.rb +26 -24
- data/test/test_format.rb +51 -55
- data/test/test_functional.rb +7 -8
- data/test/test_modules_cache.rb +18 -17
- data/test/test_modules_cell.rb +47 -46
- data/test/test_modules_table_diff_sort.rb +55 -64
- data/test/test_modules_type_parser.rb +61 -31
- data/test/test_readers_csv_reader.rb +48 -42
- data/test/test_readers_ods_reader.rb +28 -31
- data/test/test_readers_txt_reader.rb +21 -23
- data/test/test_readers_xls_reader.rb +20 -23
- data/test/test_readers_xls_shared.rb +2 -3
- data/test/test_readers_xlsx_reader.rb +44 -37
- data/test/test_row.rb +105 -109
- data/test/test_sheet.rb +41 -35
- data/test/test_table.rb +82 -60
- data/test/test_template.rb +16 -15
- data/test/test_types_date.rb +4 -6
- data/test/test_writers_csv_writer.rb +24 -0
- data/test/test_writers_html_writer.rb +42 -41
- data/test/test_writers_json_writer.rb +9 -9
- data/test/test_writers_xls_writer.rb +50 -35
- data/test/test_writers_xlsx_writer.rb +62 -34
- data/workbook.gemspec +26 -27
- metadata +92 -27
@@ -1,34 +1,36 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# -*- encoding : utf-8 -*-
|
4
|
-
# frozen_string_literal: true
|
5
3
|
module Workbook
|
6
4
|
module Readers
|
7
5
|
module OdsReader
|
8
6
|
# reads self with and ods-type content.xml
|
9
7
|
# @param [String,File] file_obj a file or file reference
|
10
8
|
# @return [Workbook::Book] self
|
11
|
-
def load_ods file_obj, options={}
|
9
|
+
def load_ods file_obj, options = {}
|
12
10
|
file_obj = file_obj.path if file_obj.is_a? File
|
13
11
|
content = ""
|
14
12
|
styles = ""
|
13
|
+
|
15
14
|
Zip::File.open(file_obj) do |zipfile|
|
16
15
|
zipfile.entries.each do |file|
|
17
16
|
styles = zipfile.read(file.name) if file.name == "styles.xml"
|
18
17
|
content = zipfile.read(file.name) if file.name == "content.xml"
|
19
18
|
end
|
20
19
|
end
|
20
|
+
|
21
21
|
content = Nokogiri.XML(content)
|
22
22
|
styles = Nokogiri.XML(styles)
|
23
|
+
|
23
24
|
template.add_raw content
|
24
25
|
parse_ods_style styles
|
25
26
|
parse_ods content, options
|
26
|
-
|
27
|
+
|
28
|
+
self
|
27
29
|
end
|
28
30
|
|
29
31
|
def set_format_property format, property, value
|
30
32
|
value.strip!
|
31
|
-
format[property] = value if value
|
33
|
+
format[property] = value if value && (value != "")
|
32
34
|
end
|
33
35
|
|
34
36
|
def parse_ods_style parse_ods_style
|
@@ -37,14 +39,14 @@ module Workbook
|
|
37
39
|
if style_family == "table-cell"
|
38
40
|
format = Workbook::Format.new
|
39
41
|
format.name = style.xpath("@style:name").to_s
|
40
|
-
format.parent =
|
42
|
+
format.parent = template.formats[style.xpath("@style:parent-style-name").to_s]
|
41
43
|
set_format_property format, :border, style.xpath("style:table-cell-properties/@fo:border").to_s
|
42
|
-
set_format_property format, :vertical_align, style.xpath("style:table-cell-properties/@style:vertical-align").to_s.gsub("automatic","auto")
|
43
|
-
set_format_property format, :padding, style.xpath("style:table-cell-properties/@fo:padding").to_s.gsub("automatic","auto")
|
44
|
+
set_format_property format, :vertical_align, style.xpath("style:table-cell-properties/@style:vertical-align").to_s.gsub("automatic", "auto")
|
45
|
+
set_format_property format, :padding, style.xpath("style:table-cell-properties/@fo:padding").to_s.gsub("automatic", "auto")
|
44
46
|
set_format_property format, :font, style.xpath("style:text-properties/style:font-name").to_s + " " + style.xpath("style:text-properties/fo:font-size").to_s + " " + style.xpath("style:text-properties/fo:font-weight").to_s
|
45
47
|
set_format_property format, :color, style.xpath("style:text-properties/@fo:color").to_s
|
46
48
|
set_format_property format, :background_color, style.xpath("style:table-cell-properties/@fo:background-color").to_s
|
47
|
-
|
49
|
+
template.add_format(format)
|
48
50
|
end
|
49
51
|
end
|
50
52
|
end
|
@@ -52,105 +54,101 @@ module Workbook
|
|
52
54
|
# updates self with and ods-type content.xml
|
53
55
|
# @param [Nokogiri::XML::Document] ods_spreadsheet nokogirified content.xml
|
54
56
|
# @return [Workbook::Book] self
|
55
|
-
def parse_ods ods_spreadsheet=template.raws[Nokogiri::XML::Document], options={}
|
56
|
-
require
|
57
|
+
def parse_ods ods_spreadsheet = template.raws[Nokogiri::XML::Document], options = {}
|
58
|
+
require "cgi"
|
57
59
|
|
58
|
-
options = {:additional_type_parsing=>false}.merge options
|
59
|
-
# styles
|
60
|
-
#puts ods_spreadsheet
|
61
60
|
parse_ods_style ods_spreadsheet
|
62
61
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
parse_local_table(workbook_sheet,table,tableindex)
|
62
|
+
ods_spreadsheet.xpath("//office:body/office:spreadsheet").each_with_index do |sheet, sheetindex|
|
63
|
+
workbook_sheet = create_or_open_sheet_at(sheetindex)
|
64
|
+
sheet.xpath("table:table").each_with_index do |table, tableindex|
|
65
|
+
parse_local_table(workbook_sheet, table, tableindex)
|
68
66
|
end
|
69
67
|
end
|
70
|
-
|
68
|
+
self
|
71
69
|
end
|
72
70
|
|
73
|
-
#parse the contents of an entire table by parsing every row in it and adding it to the table
|
74
|
-
def parse_local_table(sheet,table,tableindex)
|
75
|
-
local_table = sheet
|
71
|
+
# parse the contents of an entire table by parsing every row in it and adding it to the table
|
72
|
+
def parse_local_table(sheet, table, tableindex)
|
73
|
+
local_table = sheet[tableindex]
|
76
74
|
local_table.name = table.xpath("@table:name").to_s
|
77
|
-
|
75
|
+
|
78
76
|
table.xpath("table:table-row").each do |row|
|
79
77
|
local_table << parse_local_row(row)
|
80
78
|
end
|
79
|
+
|
81
80
|
local_table.trim!
|
82
81
|
end
|
83
82
|
|
84
|
-
#set column count
|
83
|
+
# set column count
|
85
84
|
def get_column_count(table)
|
86
85
|
first_row = table.xpath("table:table-row").first
|
87
86
|
cells = first_row.xpath("table:table-cell|table:covered-table-cell")
|
88
87
|
column_count = 0
|
89
88
|
cells.each do |cell|
|
90
|
-
if cell.xpath(
|
91
|
-
|
89
|
+
column_count += if cell.xpath("@table:number-columns-spanned").children.size > 0
|
90
|
+
cell.xpath("@table:number-columns-spanned").children[0].inner_text.to_i
|
92
91
|
else
|
93
|
-
|
92
|
+
1
|
94
93
|
end
|
95
94
|
end
|
96
95
|
column_count
|
97
96
|
end
|
98
97
|
|
99
|
-
#parse the contents of an entire row by parsing every cell in it and adding it to the row
|
98
|
+
# parse the contents of an entire row by parsing every cell in it and adding it to the row
|
100
99
|
def parse_local_row(row)
|
101
100
|
cells = row.xpath("table:table-cell|table:covered-table-cell")
|
102
101
|
workbook_row = Workbook::Row.new
|
103
102
|
cells.each do |cell|
|
104
103
|
@cell = cell
|
105
|
-
repeat =
|
106
|
-
workbook_cell = Workbook::Cell.new
|
104
|
+
repeat = cell_repeat
|
105
|
+
workbook_cell = Workbook::Cell.new
|
107
106
|
workbook_cell.value = @cell.nil? ? nil : parse_local_cell(workbook_cell)
|
108
107
|
repeat.times do
|
109
108
|
workbook_row << workbook_cell
|
110
109
|
end
|
111
110
|
end
|
112
|
-
|
111
|
+
workbook_row
|
113
112
|
end
|
114
113
|
|
115
|
-
def
|
116
|
-
pre_set = @cell.xpath(
|
117
|
-
return 1 if
|
118
|
-
return 1 unless
|
114
|
+
def cell_repeat
|
115
|
+
pre_set = @cell.xpath("@table:number-columns-repeated").to_s
|
116
|
+
return 1 if pre_set.nil? || pre_set == "" # if not present, don't repeat.
|
117
|
+
return 1 unless pre_set.to_i.to_s == pre_set.to_s # return 1 if it's not a valid integer
|
119
118
|
return 1 if pre_set.to_i < 1 # return 1, negative repeats make no sense
|
120
|
-
|
119
|
+
pre_set.to_i
|
121
120
|
end
|
122
121
|
|
123
|
-
#parse the contents of a single cell
|
122
|
+
# parse the contents of a single cell
|
124
123
|
def parse_local_cell(workbook_cell)
|
125
124
|
return Workbook::NilValue.new(:covered) if @cell.name == "covered-table-cell"
|
126
|
-
|
127
|
-
valuetype = @cell.xpath(
|
125
|
+
configure_cell_attributes(workbook_cell)
|
126
|
+
valuetype = @cell.xpath("@office:value-type").to_s
|
128
127
|
parse_local_value(valuetype)
|
129
128
|
end
|
130
129
|
|
131
130
|
# Sets cell attributes for rowspan, colspan and format
|
132
|
-
def
|
133
|
-
workbook_cell.format =
|
134
|
-
workbook_cell.colspan= @cell.xpath(
|
135
|
-
workbook_cell.rowspan= @cell.xpath(
|
131
|
+
def configure_cell_attributes(workbook_cell)
|
132
|
+
workbook_cell.format = template.formats[@cell.xpath("@table:style-name").to_s]
|
133
|
+
workbook_cell.colspan = @cell.xpath("@table:number-columns-spanned").to_s
|
134
|
+
workbook_cell.rowspan = @cell.xpath("@table:number-rows-spanned").to_s
|
136
135
|
end
|
137
136
|
|
138
137
|
# Sets value in right context type
|
139
138
|
def parse_local_value(valuetype)
|
140
139
|
value = CGI.unescapeHTML(@cell.xpath("text:p//text()").to_s)
|
141
|
-
value =
|
140
|
+
value = value == "" ? nil : value
|
142
141
|
case valuetype
|
143
|
-
when
|
142
|
+
when "integer"
|
144
143
|
value = @cell.xpath("@office:value").to_s.to_i
|
145
|
-
when
|
144
|
+
when "float"
|
146
145
|
value = @cell.xpath("@office:value").to_s.to_f
|
147
|
-
value = value.to_i unless @cell.xpath("@office:value").to_s
|
148
|
-
when
|
146
|
+
value = value.to_i unless /\./.match?(@cell.xpath("@office:value").to_s) # sadly most integers are typed as floats...
|
147
|
+
when "date"
|
149
148
|
value = DateTime.parse(@cell.xpath("@office:date-value").to_s)
|
150
149
|
end
|
151
150
|
value
|
152
151
|
end
|
153
|
-
|
154
152
|
end
|
155
153
|
end
|
156
154
|
end
|
@@ -1,19 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# -*- encoding : utf-8 -*-
|
4
2
|
# frozen_string_literal: true
|
3
|
+
|
5
4
|
module Workbook
|
6
5
|
module Readers
|
7
6
|
module TxtReader
|
8
|
-
def load_txt text, options={}
|
7
|
+
def load_txt text, options = {}
|
9
8
|
csv = text
|
10
|
-
parse_txt
|
9
|
+
parse_txt(csv, options)
|
11
10
|
end
|
12
11
|
|
13
|
-
def parse_txt
|
14
|
-
csv =
|
15
|
-
|
16
|
-
self[0]=Workbook::Sheet.new(csv,self,{:parse_cells_on_batch_creation=>true, :cell_parse_options=>{:detect_date=>true}}) unless sheet.has_contents?
|
12
|
+
def parse_txt(csv_raw, options = {})
|
13
|
+
csv = csv_raw.split("\n").collect { |l| CSV.parse_line(l, col_sep: "\t") }
|
14
|
+
self[0] = Workbook::Sheet.new(csv, self, parse_cells_on_batch_creation: true, cell_parse_options: {detect_date: true}) unless sheet.has_contents?
|
17
15
|
end
|
18
16
|
end
|
19
17
|
end
|
@@ -1,9 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# -*- encoding : utf-8 -*-
|
4
2
|
# frozen_string_literal: true
|
5
|
-
|
6
|
-
require
|
3
|
+
|
4
|
+
require "spreadsheet"
|
5
|
+
require "workbook/readers/xls_shared"
|
7
6
|
|
8
7
|
module Workbook
|
9
8
|
module Readers
|
@@ -11,20 +10,11 @@ module Workbook
|
|
11
10
|
include Workbook::Readers::XlsShared
|
12
11
|
|
13
12
|
def load_xls file_obj, options
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
begin
|
20
|
-
# Assuming it is a tab separated txt inside .xls
|
21
|
-
import(file_obj.path, 'txt')
|
22
|
-
rescue Exception => ef
|
23
|
-
|
24
|
-
raise ef
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
13
|
+
sp = Spreadsheet.open(file_obj, "rb")
|
14
|
+
template.add_raw sp
|
15
|
+
parse_xls sp, options
|
16
|
+
rescue Ole::Storage::FormatError
|
17
|
+
import(file_obj.path, "txt")
|
28
18
|
end
|
29
19
|
|
30
20
|
def parse_xls_cell xls_cell, xls_row, ci
|
@@ -33,9 +23,9 @@ module Workbook
|
|
33
23
|
rv = Workbook::Cell.new xls_cell
|
34
24
|
rv.parse!
|
35
25
|
rescue ArgumentError => e
|
36
|
-
if e.message.match(
|
26
|
+
if e.message.match?("not a Spreadsheet::Formula")
|
37
27
|
v = xls_cell.value
|
38
|
-
if v.
|
28
|
+
if v.instance_of?(Float) && xls_row.format(ci).date?
|
39
29
|
xls_row[ci] = v
|
40
30
|
v = xls_row.datetime(ci)
|
41
31
|
end
|
@@ -43,14 +33,12 @@ module Workbook
|
|
43
33
|
v = "----!"
|
44
34
|
end
|
45
35
|
rv = Workbook::Cell.new v
|
46
|
-
elsif e.message.match(
|
36
|
+
elsif e.message.match?("not a Spreadsheet::Link")
|
47
37
|
rv = Workbook::Cell.new xls_cell.to_s
|
48
|
-
elsif e.message.match(
|
49
|
-
rv = Workbook::Cell.new xls_cell.to_s
|
50
|
-
elsif e.message.match('not a Spreadsheet::Excel::Error')
|
38
|
+
elsif e.message.match?("not a Spreadsheet::Excel::Error")
|
51
39
|
rv = "._."
|
52
40
|
else
|
53
|
-
rv = "._."
|
41
|
+
rv = "._." # raise e (we're going to be silent for now)
|
54
42
|
end
|
55
43
|
end
|
56
44
|
rv
|
@@ -64,8 +52,8 @@ module Workbook
|
|
64
52
|
col_width = col_widths[ci]
|
65
53
|
end
|
66
54
|
|
67
|
-
f = template.create_or_find_format_by "object_id_#{xls_format.object_id}",col_width
|
68
|
-
f[:width]= col_width
|
55
|
+
f = template.create_or_find_format_by "object_id_#{xls_format.object_id}", col_width
|
56
|
+
f[:width] = col_width
|
69
57
|
f[:rotation] = xls_format.rotation if xls_format.rotation
|
70
58
|
f[:background_color] = xls_color_to_html_hex(xls_format.pattern_fg_color)
|
71
59
|
f[:number_format] = ms_formatting_to_strftime(xls_format.number_format)
|
@@ -81,15 +69,14 @@ module Workbook
|
|
81
69
|
def parse_xls_row ri, s, xls_sheet
|
82
70
|
xls_row = xls_sheet.row(ri)
|
83
71
|
r = s.table.create_or_open_row_at(ri)
|
84
|
-
col_widths = xls_sheet.columns.collect{|c| c
|
85
|
-
xls_row.each_with_index do |xls_cell,ci|
|
72
|
+
col_widths = xls_sheet.columns.collect { |c| c&.width }
|
73
|
+
xls_row.each_with_index do |xls_cell, ci|
|
86
74
|
r[ci] = parse_xls_cell xls_cell, xls_row, ci
|
87
75
|
r[ci].format = parse_xls_format xls_row, ci, ri, col_widths
|
88
76
|
end
|
89
77
|
end
|
90
78
|
|
91
|
-
def parse_xls xls_spreadsheet=template.raws[Spreadsheet::Excel::Workbook], options={}
|
92
|
-
options = {:additional_type_parsing=>true}.merge options
|
79
|
+
def parse_xls xls_spreadsheet = template.raws[Spreadsheet::Excel::Workbook], options = {}
|
93
80
|
number_of_worksheets = xls_spreadsheet.worksheets.count
|
94
81
|
number_of_worksheets.times do |si|
|
95
82
|
xls_sheet = xls_spreadsheet.worksheets[si]
|
@@ -103,15 +90,16 @@ module Workbook
|
|
103
90
|
end
|
104
91
|
rescue TypeError
|
105
92
|
puts "WARNING: Failed at worksheet (#{si})... ignored"
|
106
|
-
#ignore SpreadsheetGem can be buggy...
|
93
|
+
# ignore SpreadsheetGem can be buggy...
|
107
94
|
end
|
108
95
|
end
|
109
96
|
end
|
110
97
|
end
|
111
98
|
|
112
99
|
private
|
100
|
+
|
113
101
|
def xls_color_to_html_hex color_sym
|
114
|
-
Workbook::Book::XLS_COLORS[color_sym]
|
102
|
+
Workbook::Book::XLS_COLORS[color_sym] || "#000000"
|
115
103
|
end
|
116
104
|
end
|
117
105
|
end
|
@@ -1,13 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# -*- encoding : utf-8 -*-
|
4
2
|
# frozen_string_literal: true
|
5
|
-
|
3
|
+
|
4
|
+
require "date"
|
6
5
|
|
7
6
|
module Workbook
|
8
7
|
module Readers
|
9
8
|
module XlsShared
|
10
|
-
|
11
9
|
# Converts standard (ruby/C++/unix/...) strftime formatting to MS's formatting
|
12
10
|
#
|
13
11
|
# @param [String, nil] ms_nr_format (nil returns nil)
|
@@ -16,26 +14,26 @@ module Workbook
|
|
16
14
|
ms_nr_format = num_fmt_id_to_ms_formatting(ms_nr_format) if ms_nr_format.is_a? Integer
|
17
15
|
if ms_nr_format
|
18
16
|
ms_nr_format = ms_nr_format.to_s.downcase
|
19
|
-
return nil if ms_nr_format ==
|
17
|
+
return nil if (ms_nr_format == "general") || (ms_nr_format == "")
|
20
18
|
translation_table = {
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
19
|
+
"yyyy" => "%Y",
|
20
|
+
"dddd" => "%A",
|
21
|
+
"mmmm" => "%B",
|
22
|
+
"ddd" => "%a",
|
23
|
+
"mmm" => "%b",
|
24
|
+
"yy" => "%y",
|
25
|
+
"dd" => "%d",
|
26
|
+
"mm" => "%m",
|
27
|
+
"y" => "%y",
|
28
|
+
"%%y" => "%y",
|
29
|
+
"d" => "%e",
|
30
|
+
"%%e" => "%d",
|
31
|
+
"m" => "%m",
|
32
|
+
"%%m" => "%m",
|
33
|
+
";@" => "",
|
34
|
+
"\\" => ""
|
37
35
|
}
|
38
|
-
translation_table.each{|k,v| ms_nr_format.gsub!(k,v) }
|
36
|
+
translation_table.each { |k, v| ms_nr_format.gsub!(k, v) }
|
39
37
|
ms_nr_format
|
40
38
|
end
|
41
39
|
end
|
@@ -45,37 +43,30 @@ module Workbook
|
|
45
43
|
# @return [String] number format (excel markup)
|
46
44
|
def num_fmt_id_to_ms_formatting num_fmt_id
|
47
45
|
# from: https://stackoverflow.com/questions/4730152/what-indicates-an-office-open-xml-cell-contains-a-date-time-value
|
48
|
-
{
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
46
|
+
{"0" => nil, "1" => "0", "2" => "0.00", "3" => "#,##0", "4" => "#,##0.00",
|
47
|
+
"9" => "0%", "10" => "0.00%", "11" => "0.00E+00", "12" => "# ?/?",
|
48
|
+
"13" => "# ??/??", "14" => "mm-dd-yy", "15" => "d-mmm-yy", "16" => "d-mmm",
|
49
|
+
"17" => "mmm-yy", "18" => "h:mm AM/PM", "19" => "h:mm:ss AM/PM",
|
50
|
+
"20" => "h:mm", "21" => "h:mm:ss", "22" => "m/d/yy h:mm",
|
51
|
+
"37" => "#,##0 ;(#,##0)", "38" => "#,##0 ;[Red](#,##0)",
|
52
|
+
"39" => "#,##0.00;(#,##0.00)", "40" => "#,##0.00;[Red](#,##0.00)",
|
53
|
+
"44" => '_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)',
|
54
|
+
"45" => "mm:ss", "46" => "[h]:mm:ss", "47" => "mmss.0", "48" => "##0.0E+0",
|
55
|
+
"49" => "@", "27" => "[$-404]e/m/d", "30" => "m/d/yy", "36" => "[$-404]e/m/d",
|
56
|
+
"50" => "[$-404]e/m/d", "57" => "[$-404]e/m/d", "59" => "t0", "60" => "t0.00",
|
57
|
+
"61" => "t#,##0", "62" => "t#,##0.00", "67" => "t0%", "68" => "t0.00%",
|
58
|
+
"69" => "t# ?/?", "70" => "t# ??/??"}[num_fmt_id.to_s]
|
61
59
|
end
|
62
60
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
61
|
# Attempt to convert html-hex color value to xls color number
|
71
62
|
#
|
72
63
|
# @param [String] hex color
|
73
64
|
# @return [String] xls color
|
74
65
|
def html_color_to_xls_color hex
|
75
|
-
Workbook::Readers::XlsShared::XLS_COLORS.each do |k,v|
|
76
|
-
return k if (v == hex
|
66
|
+
Workbook::Readers::XlsShared::XLS_COLORS.each do |k, v|
|
67
|
+
return k if (v == hex) || (hex && (hex != "") && (k == hex.to_sym))
|
77
68
|
end
|
78
|
-
|
69
|
+
nil
|
79
70
|
end
|
80
71
|
|
81
72
|
# Converts standard (ruby/C++/unix/...) strftime formatting to MS's formatting
|
@@ -84,86 +75,84 @@ module Workbook
|
|
84
75
|
# @return [String, nil]
|
85
76
|
def strftime_to_ms_format numberformat
|
86
77
|
return nil if numberformat.nil?
|
87
|
-
|
78
|
+
numberformat.gsub("%Y", "yyyy").gsub("%A", "dddd").gsub("%B", "mmmm").gsub("%a", "ddd").gsub("%b", "mmm").gsub("%y", "yy").gsub("%d", "dd").gsub("%m", "mm").gsub("%y", "y").gsub("%y", "%%y").gsub("%e", "d")
|
88
79
|
end
|
89
80
|
|
90
|
-
def xls_number_to_time number, base_date = DateTime.new(1899,12,30)
|
81
|
+
def xls_number_to_time number, base_date = DateTime.new(1899, 12, 30)
|
91
82
|
base_date + number.to_f
|
92
83
|
end
|
93
84
|
|
94
|
-
def xls_number_to_date number, base_date = Date.new(1899,12,30)
|
85
|
+
def xls_number_to_date number, base_date = Date.new(1899, 12, 30)
|
95
86
|
base_date + number.to_i
|
96
87
|
end
|
97
88
|
|
98
|
-
XLS_COLORS = {:
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
}
|
89
|
+
XLS_COLORS = {xls_color_1: "#000000",
|
90
|
+
xls_color_2: "#FFFFFF",
|
91
|
+
xls_color_3: "#FF0000",
|
92
|
+
xls_color_4: "#00FF00",
|
93
|
+
xls_color_5: "#0000FF",
|
94
|
+
xls_color_6: "#FFFF00",
|
95
|
+
xls_color_7: "#FF00FF",
|
96
|
+
xls_color_8: "#00FFFF",
|
97
|
+
xls_color_9: "#800000",
|
98
|
+
xls_color_10: "#008000",
|
99
|
+
xls_color_11: "#000080",
|
100
|
+
xls_color_12: "#808000",
|
101
|
+
xls_color_13: "#800080",
|
102
|
+
xls_color_14: "#008080",
|
103
|
+
xls_color_15: "#C0C0C0",
|
104
|
+
xls_color_16: "#808080",
|
105
|
+
xls_color_17: "#9999FF",
|
106
|
+
xls_color_18: "#993366",
|
107
|
+
xls_color_19: "#FFFFCC",
|
108
|
+
xls_color_20: "#CCFFFF",
|
109
|
+
xls_color_21: "#660066",
|
110
|
+
xls_color_22: "#FF8080",
|
111
|
+
xls_color_23: "#0066CC",
|
112
|
+
xls_color_24: "#CCCCFF",
|
113
|
+
xls_color_25: "#000080",
|
114
|
+
xls_color_26: "#FF00FF",
|
115
|
+
xls_color_27: "#FFFF00",
|
116
|
+
xls_color_28: "#00FFFF",
|
117
|
+
xls_color_29: "#800080",
|
118
|
+
xls_color_30: "#800000",
|
119
|
+
xls_color_31: "#008080",
|
120
|
+
xls_color_32: "#0000FF",
|
121
|
+
xls_color_33: "#00CCFF",
|
122
|
+
xls_color_34: "#CCFFFF",
|
123
|
+
xls_color_35: "#CCFFCC",
|
124
|
+
xls_color_36: "#FFFF99",
|
125
|
+
xls_color_37: "#99CCFF",
|
126
|
+
xls_color_38: "#FF99CC",
|
127
|
+
xls_color_39: "#CC99FF",
|
128
|
+
xls_color_40: "#FFCC99",
|
129
|
+
xls_color_41: "#3366FF",
|
130
|
+
xls_color_42: "#33CCCC",
|
131
|
+
xls_color_43: "#99CC00",
|
132
|
+
xls_color_44: "#FFCC00",
|
133
|
+
xls_color_45: "#FF9900",
|
134
|
+
xls_color_46: "#FF6600",
|
135
|
+
xls_color_47: "#666699",
|
136
|
+
xls_color_48: "#969696",
|
137
|
+
xls_color_49: "#003366",
|
138
|
+
xls_color_50: "#339966",
|
139
|
+
xls_color_51: "#003300",
|
140
|
+
xls_color_52: "#333300",
|
141
|
+
xls_color_53: "#993300",
|
142
|
+
xls_color_54: "#993366",
|
143
|
+
xls_color_55: "#333399",
|
144
|
+
xls_color_56: "#333333",
|
145
|
+
black: "#000000",
|
146
|
+
white: "#FFFFFF",
|
147
|
+
red: "#FF0000",
|
148
|
+
green: "#00FF00",
|
149
|
+
blue: "#0000FF",
|
150
|
+
yellow: "#FFFF00",
|
151
|
+
magenta: "#FF00FF",
|
152
|
+
cyan: "#00FFFF",
|
153
|
+
border: "#FFFFFF",
|
154
|
+
text: "#000000",
|
155
|
+
lime: "#00f94c"}
|
166
156
|
end
|
167
157
|
end
|
168
158
|
end
|
169
|
-
|