spreadsheetx 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -2,6 +2,7 @@ source "http://rubygems.org"
2
2
  # Add dependencies required to use your gem here.
3
3
  # Example:
4
4
  gem "zipruby", "~> 0.3.6"
5
+ gem "libxml-ruby", "~> 2.0.9"
5
6
 
6
7
  # Add dependencies to develop your gem here.
7
8
  # Include everything needed to run rake, tests, features, etc.
data/Gemfile.lock CHANGED
@@ -3,10 +3,11 @@ GEM
3
3
  specs:
4
4
  diff-lcs (1.1.2)
5
5
  git (1.2.5)
6
- jeweler (1.6.3)
6
+ jeweler (1.6.4)
7
7
  bundler (~> 1.0)
8
8
  git (>= 1.2.5)
9
9
  rake
10
+ libxml-ruby (2.0.9)
10
11
  rake (0.9.2)
11
12
  rcov (0.9.9)
12
13
  rspec (2.3.0)
@@ -25,6 +26,7 @@ PLATFORMS
25
26
  DEPENDENCIES
26
27
  bundler (~> 1.0.0)
27
28
  jeweler (~> 1.6.2)
29
+ libxml-ruby (~> 2.0.9)
28
30
  rcov
29
31
  rspec (~> 2.3.0)
30
32
  zipruby (~> 0.3.6)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.2.0
data/lib/spreadsheetx.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # zipruby is nice as it can modify an existing zip file, perfect for our usecase
2
2
  require 'zipruby'
3
- # we use this because it comes with ruby
4
- require 'rexml/document'
3
+ # we use this because it is WAY faster than rexml
4
+ require 'xml'
5
5
  # for copying files
6
6
  require 'fileutils'
7
7
  #
@@ -19,10 +19,15 @@ module SpreadsheetX
19
19
 
20
20
  #parse the XML and build the worksheets
21
21
  @worksheets = []
22
- REXML::Document.new(file_contents).elements.each('workbook/sheets/sheet') do |node|
23
- sheet_id = node.attributes['sheetId'].to_i
24
- r_id = node.attributes['r:id'].gsub('rId','').to_i
25
- name = node.attributes['name'].to_s
22
+ # parse the XML and hold the doc
23
+ xml_doc = XML::Document.string(file_contents)
24
+ # set the default namespace
25
+ xml_doc.root.namespaces.default_prefix = 'spreadsheetml'
26
+
27
+ xml_doc.find('spreadsheetml:sheets/spreadsheetml:sheet').each do |node|
28
+ sheet_id = node['sheetId'].to_i
29
+ r_id = node['id'].gsub('rId','').to_i
30
+ name = node['name'].to_s
26
31
  @worksheets.push SpreadsheetX::Worksheet.new(archive, sheet_id, r_id, name)
27
32
  end
28
33
 
@@ -18,8 +18,10 @@ module SpreadsheetX
18
18
 
19
19
  # read contents of this file
20
20
  file_contents = f.read
21
- #parse the XML and hold the doc
22
- @xml_doc = REXML::Document.new(file_contents)
21
+ # parse the XML and hold the doc
22
+ @xml_doc = XML::Document.string(file_contents)
23
+ # set the default namespace
24
+ @xml_doc.root.namespaces.default_prefix = 'spreadsheetml'
23
25
 
24
26
  end
25
27
 
@@ -30,35 +32,55 @@ module SpreadsheetX
30
32
 
31
33
  cell_id = SpreadsheetX::Worksheet.cell_id(col_number, row_number)
32
34
 
33
- rows = @xml_doc.get_elements("worksheet/sheetData/row[@r=#{row_number}]")
35
+ row = @xml_doc.find_first("spreadsheetml:sheetData/spreadsheetml:row[@r=#{row_number}]")
36
+
34
37
  # was this row found
35
- if rows.empty?
38
+ unless row
36
39
  # build a new row
37
- row = @xml_doc.elements['worksheet'].elements['sheetData'].add_element('row', {'r' => row_number})
38
- else
39
- # x path returns an array, but we know there is only one row with this number
40
- row = rows.first
40
+ row = XML::Node.new('row')
41
+ row['r'] = row_number.to_s
42
+ # add it to the other rows
43
+ @xml_doc.find_first('spreadsheetml:sheetData') << row
41
44
  end
42
45
 
43
- cells = row.get_elements("c[@r='#{cell_id}']")
44
- if cells.empty?
45
- cell = row.add_element('c', {'r' => cell_id})
46
- else
47
- # x path returns an array, but we know there is only one row with this number
48
- cell = cells.first
46
+ cell = row.find_first("spreadsheetml:c[@r='#{cell_id}']")
47
+ # was this row found
48
+ unless cell
49
+ # build a new cell
50
+ cell = XML::Node.new('c')
51
+ cell['r'] = cell_id
52
+ # add it to the other rows
53
+ row << cell
49
54
  end
50
55
 
51
- # first clear out any existing values
52
- cell.delete_element('*')
53
-
54
- # now we put the value in the cell
56
+ # create the node which represents the value in the cell
55
57
  if val.kind_of? String
56
- cell.attributes['t'] = 'inlineStr'
57
- cell.add_element('is').add_element('t').add_text(val)
58
+
59
+ # put the strings inline to make life easier
60
+ cell['t'] = 'inlineStr'
61
+
62
+ # the string node looke like <is><t>string</t></is>
63
+ is = XML::Node.new('is')
64
+ t = XML::Node.new('t')
65
+ t.content = val
66
+
67
+ cell_value = ( is << t )
68
+
58
69
  else
59
- cell.attributes['t'] = nil
60
- cell.add_element('v').add_text(val.to_s)
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
+
61
77
  end
78
+
79
+ # first clear out any existing values (nodes)
80
+ cell.find('*').each{|n| n.remove! }
81
+
82
+ # now we put the value in the cell
83
+ cell << cell_value
62
84
 
63
85
  end
64
86
 
@@ -66,8 +88,8 @@ module SpreadsheetX
66
88
  # NOTE: this is the count of those rows, not the length of the document
67
89
  def row_count
68
90
  count = 0
69
- @xml_doc.elements.each('worksheet/sheetData/row'){ count+=1 }
70
- count
91
+ # target the sheetData rows
92
+ @xml_doc.find('spreadsheetml:sheetData/spreadsheetml:row').count
71
93
  end
72
94
 
73
95
  # returns the xml representation of this worksheet
@@ -77,6 +99,7 @@ module SpreadsheetX
77
99
 
78
100
  # turns a cell address into its excel name, 1,1 = A1 2,3 = C2 etc.
79
101
  def self.cell_id(col_number, row_number)
102
+ raise 'There is no row 0, start at 1 instead' if row_number < 1
80
103
  letter = 'A'
81
104
  # some day, speed this up
82
105
  (col_number.to_i-1).times{letter = letter.succ}
@@ -50,7 +50,6 @@ describe "Spreadsheetx" do
50
50
  SpreadsheetX::Worksheet.cell_id(26, 4).should == 'Z4'
51
51
  SpreadsheetX::Worksheet.cell_id(820, 496).should == 'AEN496'
52
52
 
53
-
54
53
  end
55
54
 
56
55
  it "allows cell values to be updated" do
@@ -81,5 +80,43 @@ describe "Spreadsheetx" do
81
80
  workbook.save(new_xlsx_file)
82
81
 
83
82
  end
83
+
84
+ it "handles large numbers of rows and cols" do
85
+
86
+ # a valid xlsx file used for testing
87
+ empty_xlsx_file = "#{File.dirname(__FILE__)}/../templates/spec.xlsx"
88
+ workbook = SpreadsheetX.open(empty_xlsx_file)
89
+
90
+ 500.times do |row|
91
+ 6.times do |col|
92
+ random_string = (0...30).map{65.+(rand(25)).chr}.join
93
+ # ump the row because there is no row 0
94
+ workbook.worksheets.last.update_cell(col, (row+1), random_string)
95
+ end
96
+ end
97
+
98
+ new_xlsx_file = "#{File.dirname(__FILE__)}/../templates/spec_large_data.xlsx"
99
+ workbook.save(new_xlsx_file)
100
+
101
+ end
102
+
103
+ it "handles various types of content" do
104
+
105
+ # a valid xlsx file used for testing
106
+ empty_xlsx_file = "#{File.dirname(__FILE__)}/../templates/spec.xlsx"
107
+ workbook = SpreadsheetX.open(empty_xlsx_file)
108
+
109
+ workbook.worksheets.last.update_cell(9, 9, Time.now)
110
+ workbook.worksheets.last.update_cell(9, 10, 'A string')
111
+ workbook.worksheets.last.update_cell(9, 11, 10.3)
112
+ workbook.worksheets.last.update_cell(9, 12, 53)
113
+ workbook.worksheets.last.update_cell(9, 13, nil)
114
+
115
+ new_xlsx_file = "#{File.dirname(__FILE__)}/../templates/spec_various_content.xlsx"
116
+ workbook.save(new_xlsx_file)
117
+
118
+ end
119
+
120
+
84
121
 
85
122
  end
data/spreadsheetx.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{spreadsheetx}
8
- s.version = "0.1.1"
8
+ s.version = "0.2.0"
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"]
12
- s.date = %q{2011-07-02}
12
+ s.date = %q{2011-07-09}
13
13
  s.description = %q{Using an existing xlsx file as a template, it allows you to modify cell values and add rows and columns. Facilitating a templateized approach to creating a new xlsx spreadsheet}
14
14
  s.email = %q{craigulliott@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -44,12 +44,14 @@ Gem::Specification.new do |s|
44
44
 
45
45
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
46
46
  s.add_runtime_dependency(%q<zipruby>, ["~> 0.3.6"])
47
+ s.add_runtime_dependency(%q<libxml-ruby>, ["~> 2.0.9"])
47
48
  s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
48
49
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
49
50
  s.add_development_dependency(%q<jeweler>, ["~> 1.6.2"])
50
51
  s.add_development_dependency(%q<rcov>, [">= 0"])
51
52
  else
52
53
  s.add_dependency(%q<zipruby>, ["~> 0.3.6"])
54
+ s.add_dependency(%q<libxml-ruby>, ["~> 2.0.9"])
53
55
  s.add_dependency(%q<rspec>, ["~> 2.3.0"])
54
56
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
55
57
  s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
@@ -57,6 +59,7 @@ Gem::Specification.new do |s|
57
59
  end
58
60
  else
59
61
  s.add_dependency(%q<zipruby>, ["~> 0.3.6"])
62
+ s.add_dependency(%q<libxml-ruby>, ["~> 2.0.9"])
60
63
  s.add_dependency(%q<rspec>, ["~> 2.3.0"])
61
64
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
62
65
  s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: spreadsheetx
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.1
5
+ version: 0.2.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Craig Ulliott
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-07-02 00:00:00 -05:00
13
+ date: 2011-07-09 00:00:00 -05:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -25,8 +25,19 @@ dependencies:
25
25
  prerelease: false
26
26
  version_requirements: *id001
27
27
  - !ruby/object:Gem::Dependency
28
- name: rspec
28
+ name: libxml-ruby
29
29
  requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ~>
33
+ - !ruby/object:Gem::Version
34
+ version: 2.0.9
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: *id002
38
+ - !ruby/object:Gem::Dependency
39
+ name: rspec
40
+ requirement: &id003 !ruby/object:Gem::Requirement
30
41
  none: false
31
42
  requirements:
32
43
  - - ~>
@@ -34,10 +45,10 @@ dependencies:
34
45
  version: 2.3.0
35
46
  type: :development
36
47
  prerelease: false
37
- version_requirements: *id002
48
+ version_requirements: *id003
38
49
  - !ruby/object:Gem::Dependency
39
50
  name: bundler
40
- requirement: &id003 !ruby/object:Gem::Requirement
51
+ requirement: &id004 !ruby/object:Gem::Requirement
41
52
  none: false
42
53
  requirements:
43
54
  - - ~>
@@ -45,10 +56,10 @@ dependencies:
45
56
  version: 1.0.0
46
57
  type: :development
47
58
  prerelease: false
48
- version_requirements: *id003
59
+ version_requirements: *id004
49
60
  - !ruby/object:Gem::Dependency
50
61
  name: jeweler
51
- requirement: &id004 !ruby/object:Gem::Requirement
62
+ requirement: &id005 !ruby/object:Gem::Requirement
52
63
  none: false
53
64
  requirements:
54
65
  - - ~>
@@ -56,10 +67,10 @@ dependencies:
56
67
  version: 1.6.2
57
68
  type: :development
58
69
  prerelease: false
59
- version_requirements: *id004
70
+ version_requirements: *id005
60
71
  - !ruby/object:Gem::Dependency
61
72
  name: rcov
62
- requirement: &id005 !ruby/object:Gem::Requirement
73
+ requirement: &id006 !ruby/object:Gem::Requirement
63
74
  none: false
64
75
  requirements:
65
76
  - - ">="
@@ -67,7 +78,7 @@ dependencies:
67
78
  version: "0"
68
79
  type: :development
69
80
  prerelease: false
70
- version_requirements: *id005
81
+ version_requirements: *id006
71
82
  description: Using an existing xlsx file as a template, it allows you to modify cell values and add rows and columns. Facilitating a templateized approach to creating a new xlsx spreadsheet
72
83
  email: craigulliott@gmail.com
73
84
  executables: []
@@ -107,7 +118,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
107
118
  requirements:
108
119
  - - ">="
109
120
  - !ruby/object:Gem::Version
110
- hash: -680141844261039746
121
+ hash: -772800674702882304
111
122
  segments:
112
123
  - 0
113
124
  version: "0"