spreadbase 0.1.3 → 0.1.4
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 +7 -0
- data/.gitignore +3 -2
- data/.rspec +1 -0
- data/.travis.yml +7 -0
- data/Gemfile +3 -0
- data/LICENSE +674 -0
- data/README.md +12 -17
- data/Rakefile +5 -0
- data/docs/STRUCTURE.md +3 -0
- data/docs/TESTING.md +11 -0
- data/lib/spreadbase/cell.rb +19 -0
- data/lib/spreadbase/codecs/open_document_12.rb +19 -41
- data/lib/spreadbase/codecs/open_document_12_modules/decoding.rb +72 -92
- data/lib/spreadbase/codecs/open_document_12_modules/encoding.rb +43 -72
- data/lib/spreadbase/document.rb +12 -33
- data/lib/spreadbase/helpers/helpers.rb +27 -61
- data/lib/spreadbase/table.rb +120 -86
- data/lib/spreadbase/version.rb +1 -3
- data/lib/spreadbase.rb +7 -28
- data/spec/codecs/open_document_12_spec.rb +42 -64
- data/spec/elements/document_spec.rb +33 -55
- data/spec/elements/table_spec.rb +186 -174
- data/spec/spec_helper.rb +100 -0
- data/spec/spec_helpers.rb +10 -30
- data/spreadbase.gemspec +14 -9
- data/utils/convert_sqlite_to_ods.rb +30 -49
- data/utils/test_ods_folder.rb +7 -26
- data/utils/test_recoding_file.rb +11 -27
- data/utils/test_recoding_from_content.rb +10 -29
- data/utils/utils_helpers.rb +19 -33
- metadata +41 -26
- data/COPYING.LESSER +0 -165
- data/utils/prettify_file.rb +0 -46
data/README.md
CHANGED
@@ -1,8 +1,17 @@
|
|
1
|
+
[![Build Status][BS img]](https://travis-ci.org/saveriomiroddi/spreadbase)
|
2
|
+
|
1
3
|
SpreadBase!!
|
2
4
|
============
|
3
5
|
|
4
6
|
... because Excel IS a database.
|
5
7
|
|
8
|
+
Status
|
9
|
+
------
|
10
|
+
|
11
|
+
The library itself is stable, and can be regularly used.
|
12
|
+
|
13
|
+
I plan to add features on request, but if nobody asks for them, I will update the project very infrequently.
|
14
|
+
|
6
15
|
What is SpreadBase©?
|
7
16
|
--------------------
|
8
17
|
|
@@ -132,12 +141,7 @@ Notes
|
|
132
141
|
|
133
142
|
`SpreadBase::Document.new( "Random numbers für alle!.ods", :floats_as_bigdecimal => true )`
|
134
143
|
|
135
|
-
- The
|
136
|
-
|
137
|
-
`SpreadBase::Document.new( "Today's menu.ods", :force_18_strings_encoding => '<encoding>' )`
|
138
|
-
|
139
|
-
in order to override the input encoding.
|
140
|
-
- The gem has been tested on Ruby 1.8.7 and 1.9.3-p125, on Linux and Mac OS X.
|
144
|
+
- The gem has been tested on Ruby 1.9.3-p125, on Linux and Mac OS X.
|
141
145
|
- The column widths are retained (decoding/encoding), but at the current version, they're not [officially] accessible via any API.
|
142
146
|
|
143
147
|
Currently unsupported features
|
@@ -146,18 +150,9 @@ Currently unsupported features
|
|
146
150
|
- Styles; Date and and [Date]Times are formatted as, respectively, '%Y-%m-%d' and '%Y-%m-%d %H:%M:%S %z'
|
147
151
|
- Percentage data type - they're handled using their float value (e.g. 50% = 0.5)
|
148
152
|
|
149
|
-
Supporting SpreadBase
|
150
|
-
---------------------
|
151
|
-
|
152
|
-
If you find SpreadBase useful for any reason, I invite you to join Kiva.org, using this invitation:
|
153
|
-
|
154
|
-
http://www.kiva.org/invitedby/saveriomiroddi
|
155
|
-
|
156
|
-
it will cost you **nothing** (zero/0 €/£/$), it will take three to five minutes of your time, and you will have actively done something for economically disadvantaged countries.
|
157
|
-
|
158
|
-
If you want to do more, in addition to accepting the invitation, you can donate to my Paypal account (saverio.pub2 \<a-hat!\> gmail.com) - I will publish your donation and use the entire amount for making loans using the mentioned website.
|
159
|
-
|
160
153
|
Roadmap/Todo
|
161
154
|
------------
|
162
155
|
|
163
156
|
https://github.com/saveriomiroddi/spreadbase/wiki/Todo-%28roadmap%29
|
157
|
+
|
158
|
+
[BS img]: https://travis-ci.org/saveriomiroddi/spreadbase.svg?branch=master
|
data/Rakefile
ADDED
data/docs/STRUCTURE.md
ADDED
data/docs/TESTING.md
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
Files
|
2
|
+
=====
|
3
|
+
|
4
|
+
- the `elements` suites test the abstract concept classes (document, table, etc.)
|
5
|
+
- the `codecs` suites have functional testing (encode -> decode cycle) of each code, plus UTs for codec-specific functionalities
|
6
|
+
- `spec_helpers.rb` are a few constants and methods useful for testing
|
7
|
+
|
8
|
+
Methodology
|
9
|
+
===========
|
10
|
+
|
11
|
+
The general workflow is to write specific UTs, then extend the functional test(s), then test on files generated with Libreoffice (from Libreoffice-built to spreadbase, from spreadbase-built to Libreoffice, and from Libreoffice-build to spreadbase to Libreoffice), using the `utils` scripts.
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module SpreadBase # :nodoc:
|
2
|
+
|
3
|
+
# Represents the abstraction of a cell; values and their types are merged into a single entity.
|
4
|
+
#
|
5
|
+
class Cell
|
6
|
+
|
7
|
+
attr_accessor :value
|
8
|
+
|
9
|
+
def initialize(value)
|
10
|
+
@value = value
|
11
|
+
end
|
12
|
+
|
13
|
+
def ==(other)
|
14
|
+
other.is_a?(Cell) && @value == other.value
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -1,23 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
=begin
|
4
|
-
Copyright 2012 Saverio Miroddi saverio.pub2 <a-hat!> gmail.com
|
5
|
-
|
6
|
-
This file is part of SpreadBase.
|
7
|
-
|
8
|
-
SpreadBase is free software: you can redistribute it and/or modify it under the
|
9
|
-
terms of the GNU Lesser General Public License as published by the Free Software
|
10
|
-
Foundation, either version 3 of the License, or (at your option) any later
|
11
|
-
version.
|
12
|
-
|
13
|
-
SpreadBase is distributed in the hope that it will be useful, but WITHOUT ANY
|
14
|
-
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
15
|
-
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
16
|
-
|
17
|
-
You should have received a copy of the GNU Lesser General Public License along
|
18
|
-
with SpreadBase. If not, see <http://www.gnu.org/licenses/>.
|
19
|
-
=end
|
20
|
-
|
21
1
|
require 'zipruby'
|
22
2
|
require 'rexml/document'
|
23
3
|
|
@@ -49,20 +29,19 @@ module SpreadBase # :nodoc:
|
|
49
29
|
#
|
50
30
|
# _options_:
|
51
31
|
#
|
52
|
-
# +force_18_strings_encoding+:: ('UTF-8') on ruby 1.8, when converting to UTF-8, assume the strings are using the specified format.
|
53
32
|
# +prettify+:: (false )prettifies the content.xml to be human readable.
|
54
33
|
#
|
55
34
|
# _returns_ the archive as binary string.
|
56
35
|
#
|
57
|
-
def encode_to_archive(
|
58
|
-
document_buffer = encode_to_content_xml(
|
36
|
+
def encode_to_archive(el_document, options={})
|
37
|
+
document_buffer = encode_to_content_xml(el_document, options)
|
59
38
|
zip_buffer = ''
|
60
39
|
|
61
|
-
Zip::Archive.open_buffer(
|
62
|
-
zip_file.add_dir(
|
40
|
+
Zip::Archive.open_buffer(zip_buffer, Zip::CREATE) do | zip_file |
|
41
|
+
zip_file.add_dir('META-INF')
|
63
42
|
|
64
|
-
zip_file.add_buffer(
|
65
|
-
zip_file.add_buffer(
|
43
|
+
zip_file.add_buffer('META-INF/manifest.xml', MANIFEST_XML);
|
44
|
+
zip_file.add_buffer('content.xml', document_buffer);
|
66
45
|
end
|
67
46
|
|
68
47
|
zip_buffer
|
@@ -81,12 +60,12 @@ module SpreadBase # :nodoc:
|
|
81
60
|
#
|
82
61
|
# _returns_ the SpreadBase::Document instance.
|
83
62
|
#
|
84
|
-
def decode_archive(
|
85
|
-
content_xml_data = Zip::Archive.open_buffer(
|
86
|
-
zip_file.fopen(
|
63
|
+
def decode_archive(zip_buffer, options={})
|
64
|
+
content_xml_data = Zip::Archive.open_buffer(zip_buffer) do | zip_file |
|
65
|
+
zip_file.fopen('content.xml') { | file | file.read }
|
87
66
|
end
|
88
67
|
|
89
|
-
decode_content_xml(
|
68
|
+
decode_content_xml(content_xml_data, options)
|
90
69
|
end
|
91
70
|
|
92
71
|
# Utility method; encodes the Document to the content.xml format.
|
@@ -97,18 +76,17 @@ module SpreadBase # :nodoc:
|
|
97
76
|
#
|
98
77
|
# _options_:
|
99
78
|
#
|
100
|
-
# +force_18_strings_encoding+:: ('UTF-8') on ruby 1.8, when converting to UTF-8, assume the strings are using the specified format.
|
101
79
|
# +prettify+:: (false ) prettifies the content.xml to be human readable.
|
102
80
|
#
|
103
81
|
# _returns_ content.xml as string.
|
104
82
|
#--
|
105
83
|
# "utility" is a fancy name for testing/utils helper.
|
106
84
|
#
|
107
|
-
def encode_to_content_xml(
|
108
|
-
prettify = options[
|
85
|
+
def encode_to_content_xml(el_document, options={})
|
86
|
+
prettify = options[:prettify]
|
109
87
|
|
110
|
-
document_xml_root = encode_to_document_node(
|
111
|
-
document_buffer = prettify ? pretty_xml(
|
88
|
+
document_xml_root = encode_to_document_node(el_document)
|
89
|
+
document_buffer = prettify ? pretty_xml(document_xml_root) : document_xml_root.to_s
|
112
90
|
|
113
91
|
document_buffer
|
114
92
|
end
|
@@ -123,20 +101,20 @@ module SpreadBase # :nodoc:
|
|
123
101
|
#--
|
124
102
|
# "utility" is a fancy name for testing/utils helper.
|
125
103
|
#
|
126
|
-
def decode_content_xml(
|
127
|
-
root_node = REXML::Document.new(
|
104
|
+
def decode_content_xml(content_xml_data, options={})
|
105
|
+
root_node = REXML::Document.new(content_xml_data)
|
128
106
|
|
129
|
-
decode_document_node(
|
107
|
+
decode_document_node(root_node, options)
|
130
108
|
end
|
131
109
|
|
132
110
|
private
|
133
111
|
|
134
|
-
def pretty_xml(
|
112
|
+
def pretty_xml(document)
|
135
113
|
buffer = ""
|
136
114
|
|
137
115
|
xml_formatter = REXML::Formatters::Pretty.new
|
138
116
|
xml_formatter.compact = true
|
139
|
-
xml_formatter.write(
|
117
|
+
xml_formatter.write(document, buffer)
|
140
118
|
|
141
119
|
buffer
|
142
120
|
end
|
@@ -1,23 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
=begin
|
4
|
-
Copyright 2012 Saverio Miroddi saverio.pub2 <a-hat!> gmail.com
|
5
|
-
|
6
|
-
This file is part of SpreadBase.
|
7
|
-
|
8
|
-
SpreadBase is free software: you can redistribute it and/or modify it under the
|
9
|
-
terms of the GNU Lesser General Public License as published by the Free Software
|
10
|
-
Foundation, either version 3 of the License, or (at your option) any later
|
11
|
-
version.
|
12
|
-
|
13
|
-
SpreadBase is distributed in the hope that it will be useful, but WITHOUT ANY
|
14
|
-
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
15
|
-
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
16
|
-
|
17
|
-
You should have received a copy of the GNU Lesser General Public License along
|
18
|
-
with SpreadBase. If not, see <http://www.gnu.org/licenses/>.
|
19
|
-
=end
|
20
|
-
|
21
1
|
require 'date'
|
22
2
|
require 'bigdecimal'
|
23
3
|
|
@@ -37,32 +17,32 @@ module SpreadBase # :nodoc:
|
|
37
17
|
|
38
18
|
# Returns a Document instance.
|
39
19
|
#
|
40
|
-
def decode_document_node(
|
20
|
+
def decode_document_node(root_node, options={})
|
41
21
|
document = Document.new
|
42
22
|
|
43
|
-
style_nodes = root_node.elements.to_a(
|
44
|
-
table_nodes = root_node.elements.to_a(
|
23
|
+
style_nodes = root_node.elements.to_a('//office:document-content/office:automatic-styles/style:style')
|
24
|
+
table_nodes = root_node.elements.to_a('//office:document-content/office:body/office:spreadsheet/table:table')
|
45
25
|
|
46
|
-
document.column_width_styles = decode_column_width_styles(
|
26
|
+
document.column_width_styles = decode_column_width_styles(style_nodes)
|
47
27
|
|
48
|
-
document.tables = table_nodes.map { | node | decode_table_node(
|
28
|
+
document.tables = table_nodes.map { | node | decode_table_node(node, options) }
|
49
29
|
|
50
30
|
document
|
51
31
|
end
|
52
32
|
|
53
33
|
# Currently it has only the purpose of decoding the column widths (for this reason it has a different naming convention).
|
54
34
|
#
|
55
|
-
def decode_column_width_styles(
|
56
|
-
style_nodes.inject(
|
57
|
-
column_node = style_node.elements[
|
35
|
+
def decode_column_width_styles(style_nodes)
|
36
|
+
style_nodes.inject({}) do | column_width_styles, style_node |
|
37
|
+
column_node = style_node.elements['style:table-column-properties']
|
58
38
|
|
59
39
|
if column_node
|
60
|
-
column_width = column_node.attributes[
|
40
|
+
column_width = column_node.attributes['style:column-width']
|
61
41
|
|
62
42
|
if column_width
|
63
|
-
style_name = style_node.attributes[
|
43
|
+
style_name = style_node.attributes['style:name']
|
64
44
|
|
65
|
-
column_width_styles[
|
45
|
+
column_width_styles[style_name] = column_width
|
66
46
|
end
|
67
47
|
end
|
68
48
|
|
@@ -70,98 +50,98 @@ module SpreadBase # :nodoc:
|
|
70
50
|
end
|
71
51
|
end
|
72
52
|
|
73
|
-
def decode_table_node(
|
74
|
-
table = Table.new(
|
53
|
+
def decode_table_node(table_node, options)
|
54
|
+
table = Table.new(table_node.attributes['table:name'])
|
75
55
|
|
76
|
-
column_nodes = table_node.elements.to_a(
|
77
|
-
row_nodes = table_node.elements.to_a(
|
56
|
+
column_nodes = table_node.elements.to_a('table:table-column')
|
57
|
+
row_nodes = table_node.elements.to_a('table:table-row')
|
78
58
|
|
79
59
|
# A single column/row can represent multiple columns (table:number-(columns|rows)-repeated)
|
80
60
|
#
|
81
|
-
table.column_width_styles = column_nodes.inject(
|
82
|
-
table.data = row_nodes.inject(
|
61
|
+
table.column_width_styles = column_nodes.inject([]) { | current_styles, node | current_styles + decode_column_width_style(node) }
|
62
|
+
table.data = row_nodes.inject([]) { | current_rows, node | current_rows + decode_row_node(node, options) }
|
83
63
|
|
84
64
|
table
|
85
65
|
end
|
86
66
|
|
87
|
-
def decode_column_width_style(
|
88
|
-
repetitions = (
|
89
|
-
style_name = column_node.attributes[
|
67
|
+
def decode_column_width_style(column_node)
|
68
|
+
repetitions = (column_node.attributes['table:number-columns-repeated'] || '1').to_i
|
69
|
+
style_name = column_node.attributes['table:style-name']
|
90
70
|
|
91
71
|
# WATCH OUT! See module note
|
92
72
|
#
|
93
|
-
make_array_from_repetitions(
|
73
|
+
make_array_from_repetitions(style_name, repetitions)
|
94
74
|
end
|
95
75
|
|
96
|
-
def decode_row_node(
|
97
|
-
repetitions = (
|
98
|
-
cell_nodes = row_node.elements.to_a(
|
76
|
+
def decode_row_node(row_node, options)
|
77
|
+
repetitions = (row_node.attributes['table:number-rows-repeated'] || '1').to_i
|
78
|
+
cell_nodes = row_node.elements.to_a('table:table-cell')
|
99
79
|
|
100
80
|
# Watch out the :flatten; a single cell can represent multiple cells (table:number-columns-repeated)
|
101
81
|
#
|
102
|
-
values = cell_nodes.map { | node | decode_cell_node(
|
82
|
+
values = cell_nodes.map { | node | decode_cell_node(node, options) }.flatten
|
103
83
|
|
104
|
-
make_array_from_repetitions(
|
84
|
+
make_array_from_repetitions(values, repetitions)
|
105
85
|
end
|
106
86
|
|
107
|
-
def decode_cell_node(
|
108
|
-
|
87
|
+
def decode_cell_node(cell_node, options)
|
88
|
+
value = decode_cell_value(cell_node, options)
|
109
89
|
|
110
|
-
|
90
|
+
repetitions = (cell_node.attributes['table:number-columns-repeated'] || '1').to_i
|
111
91
|
|
112
|
-
value
|
113
|
-
|
114
|
-
when 'string'
|
115
|
-
value_node = cell_node.elements[ 'text:p' ]
|
92
|
+
make_array_from_repetitions(value, repetitions)
|
93
|
+
end
|
116
94
|
|
117
|
-
|
118
|
-
|
119
|
-
date_string = cell_node.attributes[ 'office:date-value' ]
|
95
|
+
def decode_cell_value(cell_node, options)
|
96
|
+
floats_as_bigdecimal = options[:floats_as_bigdecimal]
|
120
97
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
when 'true'
|
143
|
-
true
|
144
|
-
when 'false'
|
145
|
-
false
|
98
|
+
value_type = cell_node.attributes['office:value-type']
|
99
|
+
|
100
|
+
case value_type
|
101
|
+
when 'string'
|
102
|
+
value_node = cell_node.elements['text:p']
|
103
|
+
|
104
|
+
value_node.text
|
105
|
+
when 'date'
|
106
|
+
date_string = cell_node.attributes['office:date-value']
|
107
|
+
|
108
|
+
if date_string =~ /T/
|
109
|
+
DateTime.strptime(date_string, '%Y-%m-%dT%H:%M:%S')
|
110
|
+
else
|
111
|
+
Date.strptime(date_string, '%Y-%m-%d')
|
112
|
+
end
|
113
|
+
when 'float', 'percentage'
|
114
|
+
float_string = cell_node.attributes['office:value']
|
115
|
+
|
116
|
+
if float_string.include?('.')
|
117
|
+
if floats_as_bigdecimal
|
118
|
+
BigDecimal(float_string)
|
146
119
|
else
|
147
|
-
|
120
|
+
float_string.to_f
|
148
121
|
end
|
149
|
-
when nil
|
150
|
-
nil
|
151
122
|
else
|
152
|
-
|
123
|
+
float_string.to_i
|
153
124
|
end
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
125
|
+
when 'boolean'
|
126
|
+
boolean_string = cell_node.attributes['office:boolean-value']
|
127
|
+
|
128
|
+
case boolean_string
|
129
|
+
when 'true'
|
130
|
+
true
|
131
|
+
when 'false'
|
132
|
+
false
|
133
|
+
else
|
134
|
+
raise "Invalid boolean value: #{ boolean_string }"
|
135
|
+
end
|
136
|
+
when nil
|
137
|
+
nil
|
138
|
+
else
|
139
|
+
raise "Unrecognized value type found in a cell: #{ value_type }"
|
140
|
+
end
|
158
141
|
end
|
159
142
|
|
160
143
|
end
|
161
144
|
|
162
|
-
private
|
163
|
-
|
164
|
-
|
165
145
|
end
|
166
146
|
|
167
147
|
end
|
@@ -1,27 +1,6 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
|
-
=begin
|
4
|
-
Copyright 2012 Saverio Miroddi saverio.pub2 <a-hat!> gmail.com
|
5
|
-
|
6
|
-
This file is part of SpreadBase.
|
7
|
-
|
8
|
-
SpreadBase is free software: you can redistribute it and/or modify it under the
|
9
|
-
terms of the GNU Lesser General Public License as published by the Free Software
|
10
|
-
Foundation, either version 3 of the License, or (at your option) any later
|
11
|
-
version.
|
12
|
-
|
13
|
-
SpreadBase is distributed in the hope that it will be useful, but WITHOUT ANY
|
14
|
-
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
15
|
-
PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
16
|
-
|
17
|
-
You should have received a copy of the GNU Lesser General Public License along
|
18
|
-
with SpreadBase. If not, see <http://www.gnu.org/licenses/>.
|
19
|
-
=end
|
20
|
-
|
21
1
|
require 'rexml/document'
|
22
2
|
require 'date'
|
23
3
|
require 'bigdecimal'
|
24
|
-
require 'iconv' if RUBY_VERSION < '1.9'
|
25
4
|
|
26
5
|
module SpreadBase # :nodoc:
|
27
6
|
|
@@ -81,17 +60,17 @@ module SpreadBase # :nodoc:
|
|
81
60
|
|
82
61
|
# Returns the XML root node
|
83
62
|
#
|
84
|
-
def encode_to_document_node(
|
85
|
-
root_node = REXML::Document.new(
|
86
|
-
spreadsheet_node = root_node.elements[
|
87
|
-
styles_node = root_node.elements[
|
63
|
+
def encode_to_document_node(el_document)
|
64
|
+
root_node = REXML::Document.new(BASE_CONTENT_XML)
|
65
|
+
spreadsheet_node = root_node.elements['//office:document-content/office:body/office:spreadsheet']
|
66
|
+
styles_node = root_node.elements['//office:document-content/office:automatic-styles']
|
88
67
|
|
89
68
|
el_document.column_width_styles.each do | style_name, column_width |
|
90
|
-
encode_style(
|
69
|
+
encode_style(styles_node, style_name, column_width)
|
91
70
|
end
|
92
71
|
|
93
72
|
el_document.tables.each do | table |
|
94
|
-
encode_table(
|
73
|
+
encode_table(table, spreadsheet_node)
|
95
74
|
end
|
96
75
|
|
97
76
|
root_node
|
@@ -99,91 +78,83 @@ module SpreadBase # :nodoc:
|
|
99
78
|
|
100
79
|
# Currently only encodes column width styles
|
101
80
|
#
|
102
|
-
def encode_style(
|
103
|
-
style_node = styles_node.add_element(
|
81
|
+
def encode_style(styles_node, style_name, column_width)
|
82
|
+
style_node = styles_node.add_element('style:style', 'style:name' => style_name, 'style:family' => 'table-column')
|
104
83
|
|
105
|
-
style_node.add_element(
|
84
|
+
style_node.add_element('style:table-column-properties', 'style:column-width' => column_width)
|
106
85
|
end
|
107
86
|
|
108
|
-
def encode_table(
|
109
|
-
table_node = spreadsheet_node.add_element(
|
87
|
+
def encode_table(table, spreadsheet_node)
|
88
|
+
table_node = spreadsheet_node.add_element('table:table')
|
110
89
|
|
111
|
-
table_node.attributes[
|
90
|
+
table_node.attributes['table:name'] = table.name
|
112
91
|
|
113
92
|
table.column_width_styles.each do | style_name |
|
114
|
-
encode_column(
|
93
|
+
encode_column(table_node, style_name) if style_name
|
115
94
|
end
|
116
95
|
|
117
96
|
# At least one column element is required
|
118
97
|
#
|
119
|
-
table_node.add_element(
|
98
|
+
table_node.add_element('table:table-column') if table.column_width_styles.size == 0
|
120
99
|
|
121
|
-
table.data.each do | row |
|
122
|
-
encode_row(
|
100
|
+
table.data(as_cell: true).each do | row |
|
101
|
+
encode_row(row, table_node)
|
123
102
|
end
|
124
103
|
end
|
125
104
|
|
126
105
|
# Currently only encodes column width styles
|
127
106
|
#
|
128
|
-
def encode_column(
|
129
|
-
table_node.add_element(
|
107
|
+
def encode_column(table_node, style_name)
|
108
|
+
table_node.add_element('table:table-column', 'table:style-name' => style_name)
|
130
109
|
end
|
131
110
|
|
132
|
-
def encode_row(
|
133
|
-
row_node = table_node.add_element(
|
111
|
+
def encode_row(row, table_node)
|
112
|
+
row_node = table_node.add_element('table:table-row')
|
134
113
|
|
135
|
-
row.each do |
|
136
|
-
encode_cell(
|
114
|
+
row.each do | cell |
|
115
|
+
encode_cell(cell.value, row_node)
|
137
116
|
end
|
138
117
|
end
|
139
118
|
|
140
|
-
def encode_cell(
|
141
|
-
|
142
|
-
|
143
|
-
cell_node = row_node.add_element( 'table:table-cell' )
|
119
|
+
def encode_cell(value, row_node)
|
120
|
+
cell_node = row_node.add_element('table:table-cell')
|
144
121
|
|
145
122
|
# WATCH OUT!!! DateTime.new.is_a?( Date )!!!
|
146
123
|
#
|
147
124
|
case value
|
148
125
|
when String
|
149
|
-
cell_node.attributes[
|
150
|
-
|
151
|
-
cell_value_node = cell_node.add_element( 'text:p' )
|
126
|
+
cell_node.attributes['office:value-type'] = 'string'
|
152
127
|
|
153
|
-
|
154
|
-
value = value.encode( 'UTF-8' )
|
155
|
-
else
|
156
|
-
value = Iconv.conv( 'UTF-8', force_18_strings_encoding, value )
|
157
|
-
end
|
128
|
+
cell_value_node = cell_node.add_element('text:p')
|
158
129
|
|
159
|
-
cell_value_node.text = value
|
130
|
+
cell_value_node.text = value.encode('UTF-8')
|
160
131
|
when Time, DateTime
|
161
|
-
cell_node.attributes[
|
162
|
-
cell_node.attributes[
|
132
|
+
cell_node.attributes['office:value-type'] = 'date'
|
133
|
+
cell_node.attributes['table:style-name'] = 'datetime'
|
163
134
|
|
164
|
-
encoded_value = value.strftime(
|
135
|
+
encoded_value = value.strftime('%Y-%m-%dT%H:%M:%S')
|
165
136
|
|
166
|
-
cell_node.attributes[
|
137
|
+
cell_node.attributes['office:date-value'] = encoded_value
|
167
138
|
when Date
|
168
|
-
cell_node.attributes[
|
169
|
-
cell_node.attributes[
|
139
|
+
cell_node.attributes['office:value-type'] = 'date'
|
140
|
+
cell_node.attributes['table:style-name'] = 'date'
|
170
141
|
|
171
|
-
encoded_value = value.strftime(
|
142
|
+
encoded_value = value.strftime('%Y-%m-%d')
|
172
143
|
|
173
|
-
cell_node.attributes[
|
144
|
+
cell_node.attributes['office:date-value'] = encoded_value
|
174
145
|
when BigDecimal
|
175
|
-
cell_node.attributes[
|
146
|
+
cell_node.attributes['office:value-type'] = 'float'
|
176
147
|
|
177
|
-
cell_node.attributes[
|
178
|
-
when Float,
|
179
|
-
cell_node.attributes[
|
148
|
+
cell_node.attributes['office:value'] = value.to_s('F')
|
149
|
+
when Float, Integer
|
150
|
+
cell_node.attributes['office:value-type'] = 'float'
|
180
151
|
|
181
|
-
cell_node.attributes[
|
152
|
+
cell_node.attributes['office:value'] = value.to_s
|
182
153
|
when true, false
|
183
|
-
cell_node.attributes[
|
184
|
-
cell_node.attributes[
|
154
|
+
cell_node.attributes['office:value-type'] = 'boolean'
|
155
|
+
cell_node.attributes['table:style-name'] = 'boolean'
|
185
156
|
|
186
|
-
cell_node.attributes[
|
157
|
+
cell_node.attributes['office:boolean-value'] = value.to_s
|
187
158
|
when nil
|
188
159
|
# do nothing
|
189
160
|
else
|