spreadsheetx 0.1.1 → 0.2.0

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.
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"