rubyfromexcel 0.0.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.
- data/README +22 -0
- data/bin/rubyfromexcel +20 -0
- data/examples/create_and_test_examples.rb +37 -0
- data/examples/ruby-versions/array-formulas-ruby/sheets/sheet1.rb +59 -0
- data/examples/ruby-versions/array-formulas-ruby/sheets/sheet2.rb +9 -0
- data/examples/ruby-versions/array-formulas-ruby/specs/sheet1_rspec.rb +156 -0
- data/examples/ruby-versions/array-formulas-ruby/specs/sheet2_rspec.rb +8 -0
- data/examples/ruby-versions/array-formulas-ruby/spreadsheet.rb +9 -0
- data/examples/ruby-versions/complex-test-ruby/sheets/sheet1.rb +305 -0
- data/examples/ruby-versions/complex-test-ruby/sheets/sheet2.rb +147 -0
- data/examples/ruby-versions/complex-test-ruby/specs/sheet1_rspec.rb +876 -0
- data/examples/ruby-versions/complex-test-ruby/specs/sheet2_rspec.rb +412 -0
- data/examples/ruby-versions/complex-test-ruby/spreadsheet.rb +9 -0
- data/examples/ruby-versions/namedReferenceTest-ruby/sheets/sheet1.rb +9 -0
- data/examples/ruby-versions/namedReferenceTest-ruby/sheets/sheet2.rb +8 -0
- data/examples/ruby-versions/namedReferenceTest-ruby/specs/sheet1_rspec.rb +16 -0
- data/examples/ruby-versions/namedReferenceTest-ruby/specs/sheet2_rspec.rb +16 -0
- data/examples/ruby-versions/namedReferenceTest-ruby/spreadsheet.rb +9 -0
- data/examples/ruby-versions/pruning-ruby/sheets/sheet1.rb +11 -0
- data/examples/ruby-versions/pruning-ruby/sheets/sheet2.rb +14 -0
- data/examples/ruby-versions/pruning-ruby/sheets/sheet3.rb +7 -0
- data/examples/ruby-versions/pruning-ruby/specs/sheet1_rspec.rb +20 -0
- data/examples/ruby-versions/pruning-ruby/specs/sheet2_rspec.rb +20 -0
- data/examples/ruby-versions/pruning-ruby/specs/sheet3_rspec.rb +8 -0
- data/examples/ruby-versions/pruning-ruby/spreadsheet.rb +9 -0
- data/examples/ruby-versions/sharedFormulaTest-ruby/sheets/sheet1.rb +15 -0
- data/examples/ruby-versions/sharedFormulaTest-ruby/specs/sheet1_rspec.rb +44 -0
- data/examples/ruby-versions/sharedFormulaTest-ruby/spreadsheet.rb +9 -0
- data/examples/ruby-versions/table-test-ruby/sheets/sheet1.rb +17 -0
- data/examples/ruby-versions/table-test-ruby/sheets/sheet2.rb +5 -0
- data/examples/ruby-versions/table-test-ruby/sheets/sheet3.rb +5 -0
- data/examples/ruby-versions/table-test-ruby/specs/sheet1_rspec.rb +20 -0
- data/examples/ruby-versions/table-test-ruby/specs/sheet2_rspec.rb +8 -0
- data/examples/ruby-versions/table-test-ruby/specs/sheet3_rspec.rb +8 -0
- data/examples/ruby-versions/table-test-ruby/spreadsheet.rb +9 -0
- data/examples/sheets/array-formulas.xlsx +0 -0
- data/examples/sheets/complex-test.xlsx +0 -0
- data/examples/sheets/namedReferenceTest.xlsx +0 -0
- data/examples/sheets/pruning.xlsx +0 -0
- data/examples/sheets/sharedFormulaTest.xlsx +0 -0
- data/examples/sheets/table-test.xlsx +0 -0
- data/examples/sheets/~$array-formulas.xlsx +0 -0
- data/examples/unzipped-sheets/array-formulas/[Content_Types].xml +2 -0
- data/examples/unzipped-sheets/array-formulas/docProps/app.xml +2 -0
- data/examples/unzipped-sheets/array-formulas/docProps/core.xml +2 -0
- data/examples/unzipped-sheets/array-formulas/docProps/thumbnail.jpeg +0 -0
- data/examples/unzipped-sheets/array-formulas/xl/_rels/workbook.xml.rels +2 -0
- data/examples/unzipped-sheets/array-formulas/xl/calcChain.xml +2 -0
- data/examples/unzipped-sheets/array-formulas/xl/sharedStrings.xml +2 -0
- data/examples/unzipped-sheets/array-formulas/xl/styles.xml +2 -0
- data/examples/unzipped-sheets/array-formulas/xl/theme/theme1.xml +2 -0
- data/examples/unzipped-sheets/array-formulas/xl/workbook.xml +2 -0
- data/examples/unzipped-sheets/array-formulas/xl/worksheets/sheet1.xml +2 -0
- data/examples/unzipped-sheets/array-formulas/xl/worksheets/sheet2.xml +2 -0
- data/examples/unzipped-sheets/complex-test/[Content_Types].xml +2 -0
- data/examples/unzipped-sheets/complex-test/docProps/app.xml +2 -0
- data/examples/unzipped-sheets/complex-test/docProps/core.xml +2 -0
- data/examples/unzipped-sheets/complex-test/xl/_rels/workbook.xml.rels +2 -0
- data/examples/unzipped-sheets/complex-test/xl/calcChain.xml +2 -0
- data/examples/unzipped-sheets/complex-test/xl/charts/chart1.xml +2 -0
- data/examples/unzipped-sheets/complex-test/xl/charts/chart2.xml +2 -0
- data/examples/unzipped-sheets/complex-test/xl/comments1.xml +5 -0
- data/examples/unzipped-sheets/complex-test/xl/comments2.xml +5 -0
- data/examples/unzipped-sheets/complex-test/xl/drawings/_rels/drawing1.xml.rels +2 -0
- data/examples/unzipped-sheets/complex-test/xl/drawings/_rels/drawing2.xml.rels +2 -0
- data/examples/unzipped-sheets/complex-test/xl/drawings/drawing1.xml +2 -0
- data/examples/unzipped-sheets/complex-test/xl/drawings/drawing2.xml +2 -0
- data/examples/unzipped-sheets/complex-test/xl/drawings/vmlDrawing1.vml +46 -0
- data/examples/unzipped-sheets/complex-test/xl/drawings/vmlDrawing2.vml +46 -0
- data/examples/unzipped-sheets/complex-test/xl/sharedStrings.xml +2 -0
- data/examples/unzipped-sheets/complex-test/xl/styles.xml +2 -0
- data/examples/unzipped-sheets/complex-test/xl/theme/theme1.xml +2 -0
- data/examples/unzipped-sheets/complex-test/xl/workbook.xml +2 -0
- data/examples/unzipped-sheets/complex-test/xl/worksheets/_rels/sheet1.xml.rels +2 -0
- data/examples/unzipped-sheets/complex-test/xl/worksheets/_rels/sheet2.xml.rels +2 -0
- data/examples/unzipped-sheets/complex-test/xl/worksheets/sheet1.xml +2 -0
- data/examples/unzipped-sheets/complex-test/xl/worksheets/sheet2.xml +2 -0
- data/examples/unzipped-sheets/namedReferenceTest/[Content_Types].xml +2 -0
- data/examples/unzipped-sheets/namedReferenceTest/docProps/app.xml +2 -0
- data/examples/unzipped-sheets/namedReferenceTest/docProps/core.xml +2 -0
- data/examples/unzipped-sheets/namedReferenceTest/docProps/thumbnail.jpeg +0 -0
- data/examples/unzipped-sheets/namedReferenceTest/xl/_rels/workbook.xml.rels +2 -0
- data/examples/unzipped-sheets/namedReferenceTest/xl/calcChain.xml +2 -0
- data/examples/unzipped-sheets/namedReferenceTest/xl/styles.xml +2 -0
- data/examples/unzipped-sheets/namedReferenceTest/xl/theme/theme1.xml +2 -0
- data/examples/unzipped-sheets/namedReferenceTest/xl/workbook.xml +2 -0
- data/examples/unzipped-sheets/namedReferenceTest/xl/worksheets/sheet1.xml +2 -0
- data/examples/unzipped-sheets/namedReferenceTest/xl/worksheets/sheet2.xml +2 -0
- data/examples/unzipped-sheets/pruning/[Content_Types].xml +2 -0
- data/examples/unzipped-sheets/pruning/docProps/app.xml +2 -0
- data/examples/unzipped-sheets/pruning/docProps/core.xml +2 -0
- data/examples/unzipped-sheets/pruning/docProps/thumbnail.jpeg +0 -0
- data/examples/unzipped-sheets/pruning/xl/_rels/workbook.xml.rels +2 -0
- data/examples/unzipped-sheets/pruning/xl/calcChain.xml +2 -0
- data/examples/unzipped-sheets/pruning/xl/sharedStrings.xml +2 -0
- data/examples/unzipped-sheets/pruning/xl/styles.xml +2 -0
- data/examples/unzipped-sheets/pruning/xl/theme/theme1.xml +2 -0
- data/examples/unzipped-sheets/pruning/xl/workbook.xml +2 -0
- data/examples/unzipped-sheets/pruning/xl/worksheets/sheet1.xml +2 -0
- data/examples/unzipped-sheets/pruning/xl/worksheets/sheet2.xml +2 -0
- data/examples/unzipped-sheets/pruning/xl/worksheets/sheet3.xml +2 -0
- data/examples/unzipped-sheets/sharedFormulaTest/[Content_Types].xml +2 -0
- data/examples/unzipped-sheets/sharedFormulaTest/docProps/app.xml +2 -0
- data/examples/unzipped-sheets/sharedFormulaTest/docProps/core.xml +2 -0
- data/examples/unzipped-sheets/sharedFormulaTest/docProps/thumbnail.jpeg +0 -0
- data/examples/unzipped-sheets/sharedFormulaTest/xl/_rels/workbook.xml.rels +2 -0
- data/examples/unzipped-sheets/sharedFormulaTest/xl/calcChain.xml +2 -0
- data/examples/unzipped-sheets/sharedFormulaTest/xl/styles.xml +2 -0
- data/examples/unzipped-sheets/sharedFormulaTest/xl/theme/theme1.xml +2 -0
- data/examples/unzipped-sheets/sharedFormulaTest/xl/workbook.xml +2 -0
- data/examples/unzipped-sheets/sharedFormulaTest/xl/worksheets/sheet1.xml +2 -0
- data/examples/unzipped-sheets/table-test/[Content_Types].xml +2 -0
- data/examples/unzipped-sheets/table-test/docProps/app.xml +2 -0
- data/examples/unzipped-sheets/table-test/docProps/core.xml +2 -0
- data/examples/unzipped-sheets/table-test/xl/_rels/workbook.xml.rels +2 -0
- data/examples/unzipped-sheets/table-test/xl/calcChain.xml +2 -0
- data/examples/unzipped-sheets/table-test/xl/printerSettings/printerSettings1.bin +0 -0
- data/examples/unzipped-sheets/table-test/xl/sharedStrings.xml +2 -0
- data/examples/unzipped-sheets/table-test/xl/styles.xml +2 -0
- data/examples/unzipped-sheets/table-test/xl/tables/table1.xml +2 -0
- data/examples/unzipped-sheets/table-test/xl/theme/theme1.xml +2 -0
- data/examples/unzipped-sheets/table-test/xl/workbook.xml +2 -0
- data/examples/unzipped-sheets/table-test/xl/worksheets/_rels/sheet1.xml.rels +2 -0
- data/examples/unzipped-sheets/table-test/xl/worksheets/sheet1.xml +2 -0
- data/examples/unzipped-sheets/table-test/xl/worksheets/sheet2.xml +2 -0
- data/examples/unzipped-sheets/table-test/xl/worksheets/sheet3.xml +2 -0
- data/lib/cells/array/array_formula_builder.rb +58 -0
- data/lib/cells/array/array_formula_cell.rb +27 -0
- data/lib/cells/array/arraying_formula_cell.rb +67 -0
- data/lib/cells/array/single_cell_array_formula_builder.rb +9 -0
- data/lib/cells/array/single_cell_array_formula_cell.rb +11 -0
- data/lib/cells/cell.rb +98 -0
- data/lib/cells/cells.rb +9 -0
- data/lib/cells/formula/formula_cell.rb +18 -0
- data/lib/cells/formula/simple_formula_cell.rb +4 -0
- data/lib/cells/shared/shared_formula_builder.rb +15 -0
- data/lib/cells/shared/shared_formula_cell.rb +20 -0
- data/lib/cells/shared/sharing_formula_cell.rb +36 -0
- data/lib/cells/value/value_cell.rb +24 -0
- data/lib/excelfile/excelfile.rb +6 -0
- data/lib/excelfile/relationships.rb +24 -0
- data/lib/excelfile/shared_strings.rb +21 -0
- data/lib/excelfile/sheet_names.rb +6 -0
- data/lib/excelfile/table.rb +116 -0
- data/lib/excelfile/workbook.rb +108 -0
- data/lib/excelfile/worksheet.rb +122 -0
- data/lib/formulae/compile/formula_builder.rb +316 -0
- data/lib/formulae/formulae.rb +6 -0
- data/lib/formulae/parse/formula_peg.rb +213 -0
- data/lib/formulae/parse/formula_peg.txt +40 -0
- data/lib/formulae/run/excel_functions.rb +375 -0
- data/lib/formulae/run/excel_matrix.rb +114 -0
- data/lib/formulae/run/excel_range.rb +256 -0
- data/lib/formulae/run/reference.rb +79 -0
- data/lib/optimiser/dependency_builder.rb +86 -0
- data/lib/optimiser/optimiser.rb +3 -0
- data/lib/optimiser/shared_formula_dependency_builder.rb +43 -0
- data/lib/optimiser/workbook_pruner.rb +80 -0
- data/lib/rubyfromexcel.rb +105 -0
- data/lib/runtime/runtime_formula_builder.rb +32 -0
- data/spec/array_formula_builder_spec.rb +35 -0
- data/spec/array_formula_cell_spec.rb +17 -0
- data/spec/arraying_formula_cell_spec.rb +38 -0
- data/spec/dependency_builder_spec.rb +71 -0
- data/spec/excel_functions_spec.rb +381 -0
- data/spec/excel_matrix_spec.rb +92 -0
- data/spec/excel_range_spec.rb +161 -0
- data/spec/formula_builder_spec.rb +230 -0
- data/spec/formula_peg_spec.rb +165 -0
- data/spec/reference_spec.rb +72 -0
- data/spec/relationships_spec.rb +51 -0
- data/spec/runtime_formula_builder_spec.rb +55 -0
- data/spec/shared_formula_builder_spec.rb +29 -0
- data/spec/shared_formula_cell_spec.rb +23 -0
- data/spec/shared_formula_dependency_builder_spec.rb +48 -0
- data/spec/shared_strings_spec.rb +14 -0
- data/spec/sharing_formula_cell_spec.rb +79 -0
- data/spec/simple_formula_cell_spec.rb +78 -0
- data/spec/single_cell_array_formula_builder_spec.rb +19 -0
- data/spec/single_cell_array_formula_cell_spec.rb +25 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/table_spec.rb +100 -0
- data/spec/value_cell_spec.rb +49 -0
- data/spec/workbook_pruner_spec.rb +27 -0
- data/spec/workbook_spec.rb +283 -0
- data/spec/worksheet_failiures_spec.rb +41 -0
- data/spec/worksheet_spec.rb +486 -0
- metadata +291 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
require_relative 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Reference do
|
|
4
|
+
it "converts excel A1 style references to ruby method calls" do
|
|
5
|
+
Reference.new("A1").to_ruby.should == "a1"
|
|
6
|
+
Reference.new("$AA$103").to_ruby.should == "aa103"
|
|
7
|
+
Reference.new("ZZ1").to_ruby.should == "zz1"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "offsets references if required, dealing with any absolute constraints" do
|
|
11
|
+
Reference.new("A1").shift!([1,1]).to_ruby.should == "b2"
|
|
12
|
+
Reference.new("A$1").shift!([1,1]).to_ruby.should == "b1"
|
|
13
|
+
Reference.new("$A1").shift!([1,1]).to_ruby.should == "a2"
|
|
14
|
+
Reference.new("$A$1").shift!([1,1]).to_ruby.should == "a1"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "manages wrap on column numbering when offsetting" do
|
|
18
|
+
Reference.new("Z1").shift!([1,1]).to_ruby.should == "aa2"
|
|
19
|
+
Reference.new("ZZ1").shift!([1,1]).to_ruby.should == "aaa2"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "deals with a nil value as an offset, treating it as offset [0,0]" do
|
|
23
|
+
Reference.new("A1").shift!(nil).to_ruby.should == "a1"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "converts columns to integers" do
|
|
27
|
+
Reference.column_to_integer("A").should == 1
|
|
28
|
+
Reference.column_to_integer("B").should == 2
|
|
29
|
+
Reference.column_to_integer("Z").should == 26
|
|
30
|
+
Reference.column_to_integer("AA").should == 27
|
|
31
|
+
Reference.column_to_integer("AB").should == 28
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "converts integers to columns" do
|
|
35
|
+
Reference.integer_to_column(1).should == "a"
|
|
36
|
+
Reference.integer_to_column(2).should == "b"
|
|
37
|
+
Reference.integer_to_column(26).should == "z"
|
|
38
|
+
Reference.integer_to_column(27).should == "aa"
|
|
39
|
+
Reference.integer_to_column(28).should == "ab"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "raises an exception if asked for a column number < 1 (Excel column numbering starts at 1)" do
|
|
43
|
+
lambda { Reference.integer_to_column(0) }.should raise_error(Exception)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "can return the column_number and row_number for a reference" do
|
|
47
|
+
Reference.new("AB1").column_number.should == 28
|
|
48
|
+
Reference.new("AB1").row_number.should == 1
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "converts column and row numbers into ruby versions of cell references" do
|
|
52
|
+
Reference.ruby_for(28,1).should == "ab1"
|
|
53
|
+
Reference.ruby_for(16384,16384).should == "xfd16384"
|
|
54
|
+
Reference.ruby_for(26,10).should == "z10"
|
|
55
|
+
Reference.ruby_for(701,10).should == "zy10"
|
|
56
|
+
Reference.ruby_for(702,10).should == "zz10"
|
|
57
|
+
Reference.ruby_for(703,10).should == "aaa10"
|
|
58
|
+
Reference.ruby_for(704,10).should == "aab10"
|
|
59
|
+
Reference.ruby_for(1378,10).should == "azz10"
|
|
60
|
+
Reference.ruby_for(2054,10).should == "bzz10"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "returns its value as a ruby_method style reference when to_s is called" do
|
|
64
|
+
Reference.new("$AB$1").to_s.should == "ab1"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "returns an array with [row_offset,column_offset] when subtracted from another reference" do
|
|
68
|
+
(Reference.new("A1") - Reference.new("A1")).should == [0,0]
|
|
69
|
+
(Reference.new("B2") - Reference.new("A1")).should == [1,1]
|
|
70
|
+
(Reference.new("AA10") - Reference.new("Z9")).should == [1,1]
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require_relative 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Relationships do
|
|
4
|
+
|
|
5
|
+
relationship_xml =<<END
|
|
6
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
7
|
+
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
8
|
+
<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet3.xml"/>
|
|
9
|
+
<Relationship Id="rId7" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/calcChain" Target="calcChain.xml"/>
|
|
10
|
+
<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet2.xml"/>
|
|
11
|
+
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>
|
|
12
|
+
<Relationship Id="rId6" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/>
|
|
13
|
+
<Relationship Id="rId5" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
|
|
14
|
+
<Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Target="theme/theme1.xml"/>
|
|
15
|
+
</Relationships>
|
|
16
|
+
END
|
|
17
|
+
|
|
18
|
+
it "it should be created from xml be equivalent to a Hash where the keys are the relationship ids and the values are the target files" do
|
|
19
|
+
wr = Relationships.new(Nokogiri::XML(relationship_xml).root)
|
|
20
|
+
wr['rId3'].should == 'worksheets/sheet3.xml'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "when given a root_directory will prepend that to the target files" do
|
|
24
|
+
wr = Relationships.new(Nokogiri::XML(relationship_xml).root, root_directory = '/usr/local')
|
|
25
|
+
wr['rId3'].should == '/usr/local/worksheets/sheet3.xml'
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "should have a Relationships.for_file(path_to_workkbook) that loads the xml automatically" do
|
|
29
|
+
File.should_receive(:open).with('/usr/local/excel_dir/xl/_rels/workbook.xml.rels').and_yield(StringIO.new(relationship_xml))
|
|
30
|
+
File.should_receive(:exist?).with('/usr/local/excel_dir/xl/_rels/workbook.xml.rels').and_return(true)
|
|
31
|
+
|
|
32
|
+
wr = Relationships.for_file('/usr/local/excel_dir/xl/workbook.xml')
|
|
33
|
+
wr['rId3'].should == '/usr/local/excel_dir/xl/worksheets/sheet3.xml'
|
|
34
|
+
|
|
35
|
+
File.should_receive(:open).with('/usr/local/excel_dir/xl/worksheets/_rels/sheet1.xml.rels').and_yield(StringIO.new(relationship_xml))
|
|
36
|
+
File.should_receive(:exist?).with('/usr/local/excel_dir/xl/worksheets/_rels/sheet1.xml.rels').and_return(true)
|
|
37
|
+
wr = Relationships.for_file('/usr/local/excel_dir/xl/worksheets/sheet1.xml')
|
|
38
|
+
wr['rId3'].should == '/usr/local/excel_dir/xl/worksheets/worksheets/sheet3.xml'
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should return an empty Relationships if relationships xml file doesn't exist" do
|
|
43
|
+
wr = Relationships.for_file('missing_file')
|
|
44
|
+
wr.size.should == 0
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "should pick out the sharedStrings relationship and put in an accessor" do
|
|
48
|
+
wr = Relationships.new(Nokogiri::XML(relationship_xml).root)
|
|
49
|
+
wr.shared_strings.should == 'sharedStrings.xml'
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require_relative 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe RuntimeFormulaBuilder, "For parsing indirect references" do
|
|
4
|
+
|
|
5
|
+
before(:each) do
|
|
6
|
+
@worksheet = mock(:worksheet)
|
|
7
|
+
@builder = RuntimeFormulaBuilder.new(@worksheet)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def ruby_for(formula)
|
|
11
|
+
ast = Formula.parse(formula)
|
|
12
|
+
ast.visit(@builder)
|
|
13
|
+
end
|
|
14
|
+
# These are the new conversions
|
|
15
|
+
it "should convert sheet names to ruby methods" do
|
|
16
|
+
ruby_for("asheetname!A3:B20").should == "s('asheetname').a('a3','b20')"
|
|
17
|
+
ruby_for("'a long sheet name with spaces'!A3:B20").should == "s('a long sheet name with spaces').a('a3','b20')"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should convert table names to references" do
|
|
21
|
+
table = mock(:table)
|
|
22
|
+
table.should_receive('reference_for').with('[#totals],[Description]',nil).and_return("cell reference")
|
|
23
|
+
@worksheet.should_receive('t').with('Vectors').and_return(table)
|
|
24
|
+
ruby_for("Vectors[[#totals],[Description]]").should == "cell reference"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# All these are the standard conversions
|
|
28
|
+
it "Should convert simple references to ruby method calls" do
|
|
29
|
+
ruby_for("AA1").should == "aa1"
|
|
30
|
+
ruby_for("$AA$100").should == "aa100"
|
|
31
|
+
ruby_for("A$1").should == "a1"
|
|
32
|
+
ruby_for("$A1").should == "a1"
|
|
33
|
+
ruby_for("I9+J9+K9+P9+Q9").should == "i9+j9+k9+p9+q9"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "Should convert area references to a(start,end) functions" do
|
|
37
|
+
ruby_for('$A$1:BZ$2000').should == "a('a1','bz2000')"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "Should convert column references to c(start,end) functions" do
|
|
41
|
+
ruby_for('A:ZZ').should == "c('a','zz')"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "should convert row references to r(start,end) functions" do
|
|
45
|
+
ruby_for('1:1000').should == 'r(1,1000)'
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "should convert named references to ruby methods" do
|
|
49
|
+
ruby_for("SUM(OneAnd2)").should == "sum(one_and2)"
|
|
50
|
+
ruby_for("ReferenceOne").should == "reference_one"
|
|
51
|
+
ruby_for("Reference.2").should == "reference_2"
|
|
52
|
+
ruby_for("-($AG70+$X70)*EF.NaturalGas.N2O").should == "-(ag70+x70)*ef_natural_gas_n2o"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require_relative 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe SharedFormulaBuilder, "Formulas with shared_formula_offsets" do
|
|
4
|
+
|
|
5
|
+
before(:each) do
|
|
6
|
+
@builder = SharedFormulaBuilder.new
|
|
7
|
+
@builder.shared_formula_offset = [1,1]
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def ruby_for(formula)
|
|
11
|
+
ast = Formula.parse(formula)
|
|
12
|
+
ast.visit(@builder)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "should move individual references appropriately" do
|
|
16
|
+
ruby_for("A1").should == "b2"
|
|
17
|
+
ruby_for("A$1").should == "b1"
|
|
18
|
+
ruby_for("$A1").should == "a2"
|
|
19
|
+
ruby_for("$A$1").should == "a1"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "should move several references in the same formula" do
|
|
23
|
+
ruby_for("A1+B2").should == "b2+c3"
|
|
24
|
+
ruby_for("A$1+B$1").should == "b1+c1"
|
|
25
|
+
ruby_for("$A1+$B1").should == "a2+b2"
|
|
26
|
+
ruby_for("$A$1+$B$1").should == "a1+b1"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require_relative 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe SharedFormulaCell do
|
|
4
|
+
|
|
5
|
+
before do
|
|
6
|
+
@cell = SharedFormulaCell.new(
|
|
7
|
+
mock(:worksheet,:class_name => 'Sheet1', :to_s => 'sheet1'),
|
|
8
|
+
Nokogiri::XML('<c r="W8" s="49"><f t="shared" si="2"/><v>1</v></c>').root
|
|
9
|
+
)
|
|
10
|
+
@cell.shared_formula = Formula.parse("$A$1+B2")
|
|
11
|
+
@cell.shared_formula_offset = [1,1]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "it is given a pre-parsed formula and offsets its references by the amount of its shared_formula_offset" do
|
|
15
|
+
@cell.to_ruby.should == "def w8; @w8 ||= a1+c3; end\n"
|
|
16
|
+
@cell.to_test.should == "it 'cell w8 should equal 1.0' do\n sheet1.w8.should be_close(1.0,0.1)\nend\n\n"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "knows what it depends on" do
|
|
20
|
+
@cell.work_out_dependencies
|
|
21
|
+
@cell.dependencies.should == ['sheet1.a1','sheet1.c3']
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require_relative 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe SharedFormulaDependencyBuilder do
|
|
4
|
+
|
|
5
|
+
before(:each) do
|
|
6
|
+
SheetNames.instance.clear
|
|
7
|
+
SheetNames.instance['Other Sheet'] = 'sheet2'
|
|
8
|
+
@workbook = mock(:workbook, :named_references => {'named_cell' => 'sheet2.z10', 'named_cell2' => "sheet2.a('z10','ab10')"})
|
|
9
|
+
@worksheet1 = mock(:worksheet, :to_s => 'sheet1', :workbook => @workbook, :named_references => {'named_cell' => 'sheet1.a1'})
|
|
10
|
+
@worksheet2 = mock(:worksheet, :to_s => 'sheet2', :workbook => @workbook, :named_references => {})
|
|
11
|
+
@workbook.stub!(:worksheets => {'sheet1' => @worksheet1, 'sheet2' => @worksheet2 })
|
|
12
|
+
@cell = mock(:cell,:worksheet => @worksheet1, :reference => Reference.new('c30',@worksheet1))
|
|
13
|
+
@builder = SharedFormulaDependencyBuilder.new(@cell)
|
|
14
|
+
@builder.shared_formula_offset = [1,1]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def ruby_for(formula)
|
|
18
|
+
ast = Formula.parse(formula)
|
|
19
|
+
ast.visit(@builder)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "should offset single cell dependencies appropriately" do
|
|
23
|
+
ruby_for("A1").should == ['sheet1.b2']
|
|
24
|
+
ruby_for("$A1").should == ['sheet1.a2']
|
|
25
|
+
ruby_for("A$1").should == ['sheet1.b1']
|
|
26
|
+
ruby_for("$A$1").should == ['sheet1.a1']
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should offset dependences on other worksheets" do
|
|
30
|
+
ruby_for("A1+'Other Sheet'!A1").should == ['sheet1.b2','sheet2.b2']
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should offset dependences in ranges" do
|
|
34
|
+
ruby_for("A1:A3").should == ['sheet1.b2','sheet1.b3','sheet1.b4']
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should not offset dependencies in named_cells" do
|
|
38
|
+
ruby_for("named_cell").should == ['sheet1.a1']
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should not offset dependencies created by table references" do
|
|
42
|
+
Table.new(@worksheet2,'Vectors','a1:b2',['ColA','Description'],1)
|
|
43
|
+
ruby_for("Vectors[#all]").should == ["sheet2.a1","sheet2.a2",'sheet2.b1','sheet2.b2']
|
|
44
|
+
Table.new(@worksheet1,'Vectors','a1:d41',['ColA','Description','ColC'],1)
|
|
45
|
+
ruby_for("[Description]").should == ["sheet1.b30"]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
require_relative 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe SharedStrings do
|
|
4
|
+
|
|
5
|
+
it "should return a shared string when provided with an index" do
|
|
6
|
+
xml = Nokogiri::XML('<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
7
|
+
<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="2" uniqueCount="2"><si><t>This a second shared string</t><phoneticPr fontId="3" type="noConversion"/></si><si><r><t>This is, h</t></r><r><rPr><b/><sz val="10"/><rFont val="Verdana"/></rPr><t>opefully, the first</t></r><r><rPr><sz val="10"/><rFont val="Verdana"/></rPr><t xml:space="preserve"> shared string</t></r><phoneticPr fontId="3" type="noConversion"/></si></sst>')
|
|
8
|
+
shared_strings = SharedStrings.instance
|
|
9
|
+
shared_strings.clear
|
|
10
|
+
shared_strings.load_strings_from_xml xml
|
|
11
|
+
SharedStrings.shared_string_for(0).should == "This a second shared string"
|
|
12
|
+
SharedStrings.shared_string_for(1).should == "This is, hopefully, the first shared string"
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
require_relative 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe SharingFormulaCell do
|
|
4
|
+
it "it is given a pre-parsed formula and offsets its references by the amount of its shared_formula_offset" do
|
|
5
|
+
worksheet = mock(:worksheet,:class_name => 'Sheet1',:to_s => 'sheet1')
|
|
6
|
+
sharing_cell = SharingFormulaCell.new(
|
|
7
|
+
worksheet,
|
|
8
|
+
Nokogiri::XML('<c r="W7" s="49"><f t="shared" ref="W7:W8" si="2">A1+B2</f><v>1</v></c>').root
|
|
9
|
+
)
|
|
10
|
+
shared_cell = SharedFormulaCell.new(
|
|
11
|
+
worksheet,
|
|
12
|
+
Nokogiri::XML('<c r="W8" s="49"><f t="shared" si="2"></f><v>2</v></c>').root
|
|
13
|
+
)
|
|
14
|
+
worksheet.should_receive(:cell).with('w8').and_return(shared_cell)
|
|
15
|
+
|
|
16
|
+
sharing_cell.alter_other_cells_if_required
|
|
17
|
+
sharing_cell.to_ruby.should == "def w7; @w7 ||= a1+b2; end\n"
|
|
18
|
+
shared_cell.to_ruby.should == "def w8; @w8 ||= a2+b3; end\n"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "knows what it depends upon" do
|
|
22
|
+
worksheet = mock(:worksheet,:class_name => 'Sheet1',:to_s => 'sheet1')
|
|
23
|
+
sharing_cell = SharingFormulaCell.new(
|
|
24
|
+
worksheet,
|
|
25
|
+
Nokogiri::XML('<c r="W7" s="49"><f t="shared" ref="W7:W8" si="2">A1+B2</f><v>1</v></c>').root
|
|
26
|
+
)
|
|
27
|
+
shared_cell = SharedFormulaCell.new(
|
|
28
|
+
worksheet,
|
|
29
|
+
Nokogiri::XML('<c r="W8" s="49"><f t="shared" si="2"></f><v>2</v></c>').root
|
|
30
|
+
)
|
|
31
|
+
worksheet.should_receive(:cell).with('w8').and_return(shared_cell)
|
|
32
|
+
|
|
33
|
+
sharing_cell.alter_other_cells_if_required
|
|
34
|
+
sharing_cell.work_out_dependencies
|
|
35
|
+
shared_cell.work_out_dependencies
|
|
36
|
+
sharing_cell.dependencies.should == ['sheet1.a1','sheet1.b2']
|
|
37
|
+
shared_cell.dependencies.should == ['sheet1.a2','sheet1.b3']
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "it should cope if it is sharing only with itself" do
|
|
41
|
+
worksheet = mock(:worksheet,:class_name => 'Sheet1')
|
|
42
|
+
sharing_cell = SharingFormulaCell.new(
|
|
43
|
+
worksheet,
|
|
44
|
+
Nokogiri::XML('<c r="W7" s="49"><f t="shared" ref="W7" si="2">A1+B2</f><v>1</v></c>').root
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
sharing_cell.alter_other_cells_if_required
|
|
48
|
+
sharing_cell.to_ruby.should == "def w7; @w7 ||= a1+b2; end\n"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "it should cope if it is sharing to a formula that doesn't exist" do
|
|
52
|
+
worksheet = mock(:worksheet,:class_name => 'Sheet1')
|
|
53
|
+
sharing_cell = SharingFormulaCell.new(
|
|
54
|
+
worksheet,
|
|
55
|
+
Nokogiri::XML('<c r="W7" s="49"><f t="shared" ref="W7:W8" si="2">A1+B2</f><v>1</v></c>').root
|
|
56
|
+
)
|
|
57
|
+
worksheet.should_receive(:cell).with('w8').and_return(nil)
|
|
58
|
+
|
|
59
|
+
sharing_cell.alter_other_cells_if_required
|
|
60
|
+
sharing_cell.to_ruby.should == "def w7; @w7 ||= a1+b2; end\n"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "it should cope if it is sharing with a cell that has its own formula" do
|
|
64
|
+
worksheet = mock(:worksheet,:class_name => 'Sheet1')
|
|
65
|
+
sharing_cell = SharingFormulaCell.new(
|
|
66
|
+
worksheet,
|
|
67
|
+
Nokogiri::XML('<c r="W7" s="49"><f t="shared" ref="W7:W8" si="2">A1+B2</f><v>1</v></c>').root
|
|
68
|
+
)
|
|
69
|
+
shared_cell = SimpleFormulaCell.new(
|
|
70
|
+
worksheet,
|
|
71
|
+
Nokogiri::XML('<c r="W8" s="49"><f>AND(1,2)</f><v>1</v></c>').root
|
|
72
|
+
)
|
|
73
|
+
worksheet.should_receive(:cell).with('w8').and_return(shared_cell)
|
|
74
|
+
|
|
75
|
+
sharing_cell.alter_other_cells_if_required
|
|
76
|
+
sharing_cell.to_ruby.should == "def w7; @w7 ||= a1+b2; end\n"
|
|
77
|
+
shared_cell.to_ruby.should == "def w8; @w8 ||= excel_and(1.0,2.0); end\n"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require_relative 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe SimpleFormulaCell, "when result is a number" do
|
|
4
|
+
|
|
5
|
+
before do
|
|
6
|
+
@cell = SimpleFormulaCell.new(
|
|
7
|
+
mock(:worksheet,:class_name => 'Sheet1', :to_s => 'sheet1'),
|
|
8
|
+
Nokogiri::XML("<c r=\"C3\"><f>1+2</f><v>3</v></c>").root
|
|
9
|
+
)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should use the FormulaPeg to create ruby code for a formula and turn that into a method" do
|
|
13
|
+
@cell.to_ruby.should == "def c3; @c3 ||= 1.0+2.0; end\n"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "should create a test for the ruby code" do
|
|
17
|
+
@cell.to_test.should == %Q{it 'cell c3 should equal 3.0' do\n sheet1.c3.should be_close(3.0,0.3)\nend\n\n}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "has a method that says it cannot be replaced with its value" do
|
|
21
|
+
@cell.can_be_replaced_with_value?.should be_false
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe SimpleFormulaCell, "when result is a boolean" do
|
|
27
|
+
|
|
28
|
+
before do
|
|
29
|
+
@cell = SimpleFormulaCell.new(
|
|
30
|
+
mock(:worksheet,:class_name => 'Sheet1', :to_s => 'sheet1'),
|
|
31
|
+
Nokogiri::XML('<c r="C3" t="b"><f>AND(1,2)</f><v>TRUE</v></c>').root
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "should use the FormulaPeg to create ruby code for a formula and turn that into a method" do
|
|
36
|
+
@cell.to_ruby.should == "def c3; @c3 ||= excel_and(1.0,2.0); end\n"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "should create a test for the ruby code" do
|
|
40
|
+
@cell.to_test.should == %Q{it 'cell c3 should equal true' do\n sheet1.c3.should == true\nend\n\n}
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe SimpleFormulaCell, "when result is a string" do
|
|
46
|
+
|
|
47
|
+
before do
|
|
48
|
+
@cell = SimpleFormulaCell.new(
|
|
49
|
+
mock(:worksheet,:class_name => 'Sheet1', :to_s => 'sheet1'),
|
|
50
|
+
Nokogiri::XML('<c r="C3" t="str"><f>"Hello "&A1</f><v>Hello Bob</v></c>').root
|
|
51
|
+
)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "should use the FormulaPeg to create ruby code for a formula and turn that into a method" do
|
|
55
|
+
@cell.to_ruby.should == %Q{def c3; @c3 ||= "Hello "+a1.to_s; end\n}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "should create a test for the ruby code" do
|
|
59
|
+
@cell.to_test.should == %Q{it 'cell c3 should equal "Hello Bob"' do\n sheet1.c3.should == "Hello Bob"\nend\n\n}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe SimpleFormulaCell, "can list the cells upon which it depends" do
|
|
65
|
+
|
|
66
|
+
before do
|
|
67
|
+
@cell = SimpleFormulaCell.new(
|
|
68
|
+
mock(:worksheet,:class_name => 'Sheet1', :to_s => 'sheet1'),
|
|
69
|
+
Nokogiri::XML("<c r=\"C3\" t=\"str\"><f>A1</f><v>Hello Bob</v></c>").root
|
|
70
|
+
)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "in simple cases knows what it depends upon" do
|
|
74
|
+
@cell.work_out_dependencies
|
|
75
|
+
@cell.dependencies.should == ['sheet1.a1']
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require_relative 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe SingleCellArrayFormulaBuilder, "Single cell array formulas" do
|
|
4
|
+
|
|
5
|
+
before(:each) do
|
|
6
|
+
@builder = SingleCellArrayFormulaBuilder.new
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def ruby_for(formula)
|
|
10
|
+
ast = Formula.parse(formula)
|
|
11
|
+
ast.visit(@builder)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "should wrap operations in an array_operation(left,operation,right) methods" do
|
|
15
|
+
ruby_for("SUM(F$437:F$449/$M$150:$M$162*($B454=$F$149:$N$149)*($F$150:$N$162))").should == "sum(m(a('f437','f449'),a('m150','m162'),(m(b454,a('f149','n149')) { |r1,r2| r1==r2 }),(a('f150','n162'))) { |r1,r2,r3,r4| r1/r2*r3*r4 })"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require_relative 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe SingleCellArrayFormulaCell do
|
|
4
|
+
|
|
5
|
+
before do
|
|
6
|
+
@cell = SingleCellArrayFormulaCell.new(
|
|
7
|
+
mock(:worksheet,:class_name => 'Sheet1', :to_s => 'sheet1'),
|
|
8
|
+
Nokogiri::XML("<c r=\"C3\"><f t=\"array\" ref=\"C3\">SUM(F$437:F$449/$M$150:$M$162*($B454=$F$149:$N$149)*($F$150:$N$162))</f><v>3</v></c>").root
|
|
9
|
+
)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should use the FormulaPeg to create ruby code for a formula and turn that into a method" do
|
|
13
|
+
@cell.to_ruby.should == "def c3; @c3 ||= sum(m(a('f437','f449'),a('m150','m162'),(m(b454,a('f149','n149')) { |r1,r2| r1==r2 }),(a('f150','n162'))) { |r1,r2,r3,r4| r1/r2*r3*r4 }); end\n"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "should create a test for the ruby code" do
|
|
17
|
+
@cell.to_test.should == %Q{it 'cell c3 should equal 3.0' do\n sheet1.c3.should be_close(3.0,0.3)\nend\n\n}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "in can list the cells upon which it depends" do
|
|
21
|
+
@cell.work_out_dependencies
|
|
22
|
+
dependencies = @cell.dependencies
|
|
23
|
+
dependencies.include?('sheet1.g151').should be_true
|
|
24
|
+
end
|
|
25
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/spec/table_spec.rb
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
require_relative 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Table do
|
|
4
|
+
|
|
5
|
+
def table
|
|
6
|
+
table_xml =<<-END
|
|
7
|
+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
8
|
+
<table xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" id="1" name="FirstTable" displayName="FirstTable" ref="B3:D7" totalsRowCount="1">
|
|
9
|
+
<autoFilter ref="B3:D6"/>
|
|
10
|
+
<tableColumns count="3">
|
|
11
|
+
<tableColumn id="1" name="ColA" totalsRowLabel="Total"/>
|
|
12
|
+
<tableColumn id="2" name="ColB" totalsRowFunction="custom" dataDxfId="1">
|
|
13
|
+
<calculatedColumnFormula>FirstTable[[#This Row],[ColA]]+FirstTable[[#This Row],[ColC]]</calculatedColumnFormula>
|
|
14
|
+
<totalsRowFormula>AVERAGE(FirstTable[ColB])</totalsRowFormula>
|
|
15
|
+
</tableColumn>
|
|
16
|
+
<tableColumn id="3" name="ColC" totalsRowFunction="count" dataDxfId="0">
|
|
17
|
+
<calculatedColumnFormula>3*FirstTable[[#This Row],[ColA]]</calculatedColumnFormula>
|
|
18
|
+
</tableColumn>
|
|
19
|
+
</tableColumns>
|
|
20
|
+
<tableStyleInfo name="TableStyleLight16" showFirstColumn="1" showLastColumn="1" showRowStripes="1" showColumnStripes="1"/>
|
|
21
|
+
</table>
|
|
22
|
+
END
|
|
23
|
+
@worksheet ||= mock(:worksheet,:to_s => 'sheet1')
|
|
24
|
+
@table ||= Table.from_xml(@worksheet, Nokogiri::XML(table_xml).root)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should know its name" do
|
|
28
|
+
table.name.should == 'FirstTable'
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should know the area (returned in #all) that it covers" do
|
|
32
|
+
table.all.start_cell.to_s.should == 'b3'
|
|
33
|
+
table.all.end_cell.to_s.should == 'd7'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "should know the area (returned in #data) covered by its data" do
|
|
37
|
+
table.data.start_cell.to_s.should == 'b4'
|
|
38
|
+
table.data.end_cell.to_s.should == 'd6'
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should know the area covered by its headers" do
|
|
42
|
+
table.headers.start_cell.to_s.should == 'b3'
|
|
43
|
+
table.headers.end_cell.to_s.should == 'd3'
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "should know the area covered by its totals" do
|
|
47
|
+
table.totals.start_cell.to_s.should == 'b7'
|
|
48
|
+
table.totals.end_cell.to_s.should == 'd7'
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "should know the area covered by each of its columns (excluding the headers and the totals)" do
|
|
52
|
+
table.column('ColA').start_cell.to_s.should == 'b4'
|
|
53
|
+
table.column('ColA').end_cell.to_s.should == 'b6'
|
|
54
|
+
table.column('ColC').start_cell.to_s.should == 'd4'
|
|
55
|
+
table.column('ColC').end_cell.to_s.should == 'd6'
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "should be able to translate structured references into normal references" do
|
|
59
|
+
table.reference_for('ColA').start_cell.to_s.should == 'b4'
|
|
60
|
+
table.reference_for('ColA').end_cell.to_s.should == 'b6'
|
|
61
|
+
table.reference_for('#All').start_cell.to_s.should == 'b3'
|
|
62
|
+
table.reference_for('#All').end_cell.to_s.should == 'd7'
|
|
63
|
+
table.reference_for('#Data').start_cell.to_s.should == 'b4'
|
|
64
|
+
table.reference_for('#Data').end_cell.to_s.should == 'd6'
|
|
65
|
+
table.reference_for('#Headers').start_cell.to_s.should == 'b3'
|
|
66
|
+
table.reference_for('#Headers').end_cell.to_s.should == 'd3'
|
|
67
|
+
table.reference_for('#Totals').start_cell.to_s.should == 'b7'
|
|
68
|
+
table.reference_for('#Totals').end_cell.to_s.should == 'd7'
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "should be able to translate structured references that are intersections into normal references" do
|
|
72
|
+
table.reference_for('[#Totals],[ColA]').to_s.should == 'sheet1.b7'
|
|
73
|
+
table.reference_for('[#Headers],[ColC]').to_s.should == 'sheet1.d3'
|
|
74
|
+
table.reference_for('[#All],[ColB]').start_cell.to_s.should == 'c3'
|
|
75
|
+
table.reference_for('[#All],[ColB]').end_cell.to_s.should == 'c7'
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "should be able to translate structured references that include the special variable #This Row" do
|
|
79
|
+
table.reference_for('[#This Row],[ColA]', Reference.new('e5')).to_s.should == 'sheet1.b5'
|
|
80
|
+
table.reference_for('#This Row',Reference.new('e5')).start_cell.to_s.should == 'b5'
|
|
81
|
+
table.reference_for('#This Row',Reference.new('e5')).end_cell.to_s.should == 'd5'
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "should be able to translate structured references from cells that are in the table, treating them as if they had indicated [#This row] as part of the reference" do
|
|
85
|
+
table.reference_for('ColA', Reference.new('e5',@worksheet)).to_s.should == "sheet1.a('b4','b6')"
|
|
86
|
+
table.reference_for('ColA', Reference.new('c5',@worksheet)).to_s.should == 'sheet1.b5'
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "should be able to access structured references by providing the table name to Table.reference_for(table_name,structured_reference,referring_cell)" do
|
|
90
|
+
table
|
|
91
|
+
Table.reference_for('FirstTable','#Data').start_cell.to_s.should == 'b4'
|
|
92
|
+
Table.reference_for('Not a known table','#Data').should == ":ref"
|
|
93
|
+
Table.reference_for('FirstTable','[#This Row],[ColA]', Reference.new('e5')).to_s.should == 'sheet1.b5'
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "#inspect should create a string that can be used to recreate the table" do
|
|
97
|
+
table.inspect.should == %Q{'Table.new(sheet1,"FirstTable","B3:D7",["ColA", "ColB", "ColC"],1)'}
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require_relative 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe ValueCell do
|
|
4
|
+
|
|
5
|
+
it "creates a ruby method that returns the cell's value as a float if it is a number" do
|
|
6
|
+
cell = ValueCell.new(mock('worksheet',:ruby_name => 'sheet1'),Nokogiri::XML('<c r="C22"><v>24</v></c>').root)
|
|
7
|
+
cell.to_ruby.should == "def c22; 24.0; end\n"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "creates a ruby method that returns the cell's value as a ruby boolean if it is a boolean" do
|
|
11
|
+
cell = ValueCell.new(mock('worksheet',:ruby_name => 'sheet1'),Nokogiri::XML('<c r="C22" t="b"><v>TRUE</v></c>').root)
|
|
12
|
+
cell.to_ruby.should == "def c22; true; end\n"
|
|
13
|
+
cell = ValueCell.new(mock('worksheet',:ruby_name => 'sheet1'),Nokogiri::XML('<c r="C22" t="b"><v>1</v></c>').root)
|
|
14
|
+
cell.to_ruby.should == "def c22; true; end\n"
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "creates a ruby method that returns the cell's value as a ruby string if it is a string" do
|
|
19
|
+
cell = ValueCell.new(mock('worksheet',:ruby_name => 'sheet1'),Nokogiri::XML('<c r="B6" t="str"><v>hello</v></c>').root)
|
|
20
|
+
cell.to_ruby.should == %Q{def b6; "hello"; end\n}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "creates a ruby method that returns the cell's value as a ruby string if it is a shared string" do
|
|
24
|
+
cell = ValueCell.new(mock('worksheet',:ruby_name => 'sheet1'),Nokogiri::XML('<c r="B6" t="s"><v>7</v></c>').root)
|
|
25
|
+
SharedStrings.should_receive(:shared_string_for).with(7).and_return('hello')
|
|
26
|
+
cell.to_ruby.should == %Q{def b6; "hello"; end\n}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "creates a ruby method that returns an appropriate symbol if it is an error" do
|
|
30
|
+
cell = ValueCell.new(mock('worksheet',:ruby_name => 'sheet1'),Nokogiri::XML('<c r="B6" t="e"><v>#N/A</v></c>').root)
|
|
31
|
+
cell.to_ruby.should == "def b6; :na; end\n"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "has a method that confirms it can be replaced with its value" do
|
|
35
|
+
cell = ValueCell.new(mock('worksheet',:ruby_name => 'sheet1'),Nokogiri::XML('<c r="B6" t="str"><v>hello</v></c>').root)
|
|
36
|
+
cell.can_be_replaced_with_value?.should be_true
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe ValueCell, "can list the cells upon which it depends" do
|
|
42
|
+
|
|
43
|
+
it "in simple cases knows what it depends upon" do
|
|
44
|
+
cell = ValueCell.new(mock('worksheet',:ruby_name => 'sheet1'),Nokogiri::XML('<c r="B6" t="s"><v>7</v></c>').root)
|
|
45
|
+
cell.work_out_dependencies
|
|
46
|
+
cell.dependencies.should == []
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|