spreadsheetx 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/spreadsheetx.rb +1 -0
- data/lib/spreadsheetx/cell_format.rb +19 -0
- data/lib/spreadsheetx/workbook.rb +22 -0
- data/lib/spreadsheetx/worksheet.rb +46 -16
- data/spec/spreadsheetx_spec.rb +30 -1
- data/spreadsheetx.gemspec +2 -1
- data/templates/spec.xlsx +0 -0
- metadata +3 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.1
|
data/lib/spreadsheetx.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
module SpreadsheetX
|
2
|
+
|
3
|
+
# this object represents an existing cell format in the workbook
|
4
|
+
class CellFormat
|
5
|
+
|
6
|
+
attr_reader :id
|
7
|
+
attr_reader :format
|
8
|
+
|
9
|
+
def initialize(id, format)
|
10
|
+
@id = id
|
11
|
+
@format = format
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
id.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -5,6 +5,7 @@ module SpreadsheetX
|
|
5
5
|
|
6
6
|
attr_reader :path
|
7
7
|
attr_reader :worksheets
|
8
|
+
attr_reader :formats
|
8
9
|
|
9
10
|
# return a Workbook object which relates to an existing xlsx file on disk
|
10
11
|
def initialize(path)
|
@@ -33,6 +34,26 @@ module SpreadsheetX
|
|
33
34
|
|
34
35
|
end
|
35
36
|
|
37
|
+
# open the styles, to get the cell formats
|
38
|
+
archive.fopen('xl/styles.xml') do |f|
|
39
|
+
|
40
|
+
# read contents of this file
|
41
|
+
file_contents = f.read
|
42
|
+
|
43
|
+
#parse the XML and build the worksheets
|
44
|
+
@formats = []
|
45
|
+
# parse the XML and hold the doc
|
46
|
+
xml_doc = XML::Document.string(file_contents)
|
47
|
+
# set the default namespace
|
48
|
+
xml_doc.root.namespaces.default_prefix = 'spreadsheetml'
|
49
|
+
|
50
|
+
format_id = 0
|
51
|
+
xml_doc.find('spreadsheetml:numFmts/spreadsheetml:numFmt').each do |node|
|
52
|
+
@formats.push SpreadsheetX::CellFormat.new((format_id+=1), node['formatCode'])
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
36
57
|
end
|
37
58
|
end
|
38
59
|
|
@@ -54,6 +75,7 @@ module SpreadsheetX
|
|
54
75
|
|
55
76
|
end
|
56
77
|
|
78
|
+
|
57
79
|
end
|
58
80
|
|
59
81
|
end
|
@@ -28,19 +28,37 @@ module SpreadsheetX
|
|
28
28
|
end
|
29
29
|
|
30
30
|
# update the value of a particular cell, if the row or cell doesnt exist in the XML, then it will be created
|
31
|
-
def update_cell(col_number, row_number, val)
|
31
|
+
def update_cell(col_number, row_number, val, format=nil)
|
32
32
|
|
33
33
|
cell_id = SpreadsheetX::Worksheet.cell_id(col_number, row_number)
|
34
|
+
|
35
|
+
val_is_a_date = (val.kind_of?(Date) || val.kind_of?(Time) || val.kind_of?(DateTime))
|
36
|
+
|
37
|
+
# if the val is nil or an empty string, then just delete the cell
|
38
|
+
if val.nil? || val == ''
|
39
|
+
if cell = @xml_doc.find_first("spreadsheetml:sheetData/spreadsheetml:row[@r=#{row_number}]/spreadsheetml:c[@r='#{cell_id}']")
|
40
|
+
cell.remove!
|
41
|
+
end
|
42
|
+
return
|
43
|
+
end
|
34
44
|
|
35
45
|
row = @xml_doc.find_first("spreadsheetml:sheetData/spreadsheetml:row[@r=#{row_number}]")
|
36
46
|
|
37
47
|
# was this row found
|
38
48
|
unless row
|
49
|
+
|
39
50
|
# build a new row
|
40
51
|
row = XML::Node.new('row')
|
41
52
|
row['r'] = row_number.to_s
|
42
|
-
|
43
|
-
|
53
|
+
|
54
|
+
# if there are no rows higher than this one, then add this row to the end of the sheetData
|
55
|
+
next_largest = @xml_doc.find_first("spreadsheetml:sheetData/spreadsheetml:row[@r>#{row_number}]")
|
56
|
+
if next_largest
|
57
|
+
next_largest.prev = row
|
58
|
+
else # there are no rows higher than this one
|
59
|
+
# add this row to the end of the sheetData
|
60
|
+
@xml_doc.find_first('spreadsheetml:sheetData') << row
|
61
|
+
end
|
44
62
|
end
|
45
63
|
|
46
64
|
cell = row.find_first("spreadsheetml:c[@r='#{cell_id}']")
|
@@ -49,30 +67,42 @@ module SpreadsheetX
|
|
49
67
|
# build a new cell
|
50
68
|
cell = XML::Node.new('c')
|
51
69
|
cell['r'] = cell_id
|
52
|
-
# add it to the other
|
70
|
+
# add it to the other cells in this row
|
53
71
|
row << cell
|
54
72
|
end
|
55
73
|
|
74
|
+
# are we setting a format
|
75
|
+
cell['s'] = format.to_s
|
76
|
+
|
77
|
+
# reset this attribute
|
78
|
+
cell['t'] = ''
|
79
|
+
|
56
80
|
# create the node which represents the value in the cell
|
57
|
-
|
81
|
+
|
82
|
+
# numeric types
|
83
|
+
if val.kind_of?(Integer) || val.kind_of?(Float) || val.kind_of?(Fixnum)
|
84
|
+
|
85
|
+
cell_value = XML::Node.new('v')
|
86
|
+
cell_value.content = val.to_s
|
87
|
+
|
88
|
+
# if we are using a format, then dates are stored as floats, otherwise they get caught by string use a string
|
89
|
+
elsif format && val_is_a_date
|
58
90
|
|
91
|
+
cell_value = XML::Node.new('v')
|
92
|
+
# dates are stored as flaots, otherwise use a string
|
93
|
+
cell_value.content = (val.to_time.to_f / (60*60*24)).to_s
|
94
|
+
|
95
|
+
else # assume its a string
|
96
|
+
|
59
97
|
# put the strings inline to make life easier
|
60
98
|
cell['t'] = 'inlineStr'
|
61
99
|
|
62
|
-
# the string node
|
100
|
+
# the string node looks like <is><t>string</t></is>
|
63
101
|
is = XML::Node.new('is')
|
64
102
|
t = XML::Node.new('t')
|
65
|
-
t.content = val
|
103
|
+
t.content = val_is_a_date ? val.to_time.strftime('%Y-%m-%d %H:%M:%S') : val.to_s
|
66
104
|
|
67
105
|
cell_value = ( is << t )
|
68
|
-
|
69
|
-
else
|
70
|
-
|
71
|
-
# incase this was an inline string, clear out this attribute
|
72
|
-
cell['t'] = ''
|
73
|
-
|
74
|
-
cell_value = XML::Node.new('v')
|
75
|
-
cell_value.content = val.to_s
|
76
106
|
|
77
107
|
end
|
78
108
|
|
@@ -94,7 +124,7 @@ module SpreadsheetX
|
|
94
124
|
|
95
125
|
# returns the xml representation of this worksheet
|
96
126
|
def to_s
|
97
|
-
@xml_doc.to_s
|
127
|
+
@xml_doc.to_s(:indent => false).gsub(/\n/,"\r\n")
|
98
128
|
end
|
99
129
|
|
100
130
|
# turns a cell address into its excel name, 1,1 = A1 2,3 = C2 etc.
|
data/spec/spreadsheetx_spec.rb
CHANGED
@@ -27,7 +27,7 @@ describe "Spreadsheetx" do
|
|
27
27
|
empty_xlsx_file = "#{File.dirname(__FILE__)}/../templates/spec.xlsx"
|
28
28
|
workbook = SpreadsheetX.open(empty_xlsx_file)
|
29
29
|
|
30
|
-
workbook.worksheets.last.row_count.should ==
|
30
|
+
workbook.worksheets.last.row_count.should == 8
|
31
31
|
|
32
32
|
end
|
33
33
|
|
@@ -107,6 +107,7 @@ describe "Spreadsheetx" do
|
|
107
107
|
workbook = SpreadsheetX.open(empty_xlsx_file)
|
108
108
|
|
109
109
|
workbook.worksheets.last.update_cell(9, 9, Time.now)
|
110
|
+
workbook.worksheets.last.update_cell(1, 4, 'A string')
|
110
111
|
workbook.worksheets.last.update_cell(9, 10, 'A string')
|
111
112
|
workbook.worksheets.last.update_cell(9, 11, 10.3)
|
112
113
|
workbook.worksheets.last.update_cell(9, 12, 53)
|
@@ -116,7 +117,35 @@ describe "Spreadsheetx" do
|
|
116
117
|
workbook.save(new_xlsx_file)
|
117
118
|
|
118
119
|
end
|
120
|
+
|
121
|
+
it "can read and return a list of number formats currently in the document" do
|
122
|
+
|
123
|
+
# a valid xlsx file used for testing
|
124
|
+
empty_xlsx_file = "#{File.dirname(__FILE__)}/../templates/spec.xlsx"
|
125
|
+
workbook = SpreadsheetX.open(empty_xlsx_file)
|
126
|
+
|
127
|
+
workbook.formats.count.should == 3
|
128
|
+
workbook.formats.first.id.to_i.should > 0
|
129
|
+
puts workbook.formats.first.format.should == '[$-F400]h:mm:ss\ AM/PM'
|
130
|
+
|
131
|
+
new_xlsx_file = "#{File.dirname(__FILE__)}/../templates/spec_various_content.xlsx"
|
132
|
+
workbook.save(new_xlsx_file)
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
it "can set formats on cells" do
|
138
|
+
|
139
|
+
# a valid xlsx file used for testing
|
140
|
+
empty_xlsx_file = "#{File.dirname(__FILE__)}/../templates/spec.xlsx"
|
141
|
+
workbook = SpreadsheetX.open(empty_xlsx_file)
|
119
142
|
|
143
|
+
date_format = workbook.formats.first
|
144
|
+
workbook.worksheets.last.update_cell(1, 8, Time.now, date_format)
|
145
|
+
|
146
|
+
new_xlsx_file = "#{File.dirname(__FILE__)}/../templates/spec_cell_format.xlsx"
|
147
|
+
workbook.save(new_xlsx_file)
|
120
148
|
|
149
|
+
end
|
121
150
|
|
122
151
|
end
|
data/spreadsheetx.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{spreadsheetx}
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Craig Ulliott"]
|
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
|
|
26
26
|
"Rakefile",
|
27
27
|
"VERSION",
|
28
28
|
"lib/spreadsheetx.rb",
|
29
|
+
"lib/spreadsheetx/cell_format.rb",
|
29
30
|
"lib/spreadsheetx/workbook.rb",
|
30
31
|
"lib/spreadsheetx/worksheet.rb",
|
31
32
|
"spec/spec_helper.rb",
|
data/templates/spec.xlsx
CHANGED
Binary file
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: spreadsheetx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.2.
|
5
|
+
version: 0.2.1
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Craig Ulliott
|
@@ -98,6 +98,7 @@ files:
|
|
98
98
|
- Rakefile
|
99
99
|
- VERSION
|
100
100
|
- lib/spreadsheetx.rb
|
101
|
+
- lib/spreadsheetx/cell_format.rb
|
101
102
|
- lib/spreadsheetx/workbook.rb
|
102
103
|
- lib/spreadsheetx/worksheet.rb
|
103
104
|
- spec/spec_helper.rb
|
@@ -118,7 +119,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
118
119
|
requirements:
|
119
120
|
- - ">="
|
120
121
|
- !ruby/object:Gem::Version
|
121
|
-
hash:
|
122
|
+
hash: 3923025067229430193
|
122
123
|
segments:
|
123
124
|
- 0
|
124
125
|
version: "0"
|