excel_to_code 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +41 -0
- data/bin/excel_to_c +63 -0
- data/bin/excel_to_ruby +9 -0
- data/src/commands.rb +2 -0
- data/src/commands/excel_to_c.rb +858 -0
- data/src/commands/excel_to_ruby.rb +620 -0
- data/src/compile.rb +2 -0
- data/src/compile/c.rb +5 -0
- data/src/compile/c/compile_to_c.rb +62 -0
- data/src/compile/c/compile_to_c_header.rb +26 -0
- data/src/compile/c/compile_to_c_unit_test.rb +42 -0
- data/src/compile/c/excel_to_c_runtime.c +2029 -0
- data/src/compile/c/map_formulae_to_c.rb +184 -0
- data/src/compile/c/map_sheet_names_to_c_names.rb +19 -0
- data/src/compile/c/map_values_to_c.rb +85 -0
- data/src/compile/c/map_values_to_c_structs.rb +37 -0
- data/src/compile/ruby.rb +3 -0
- data/src/compile/ruby/compile_to_ruby.rb +33 -0
- data/src/compile/ruby/compile_to_ruby_unit_test.rb +28 -0
- data/src/compile/ruby/excel_to_ruby_runtime.rb +1 -0
- data/src/compile/ruby/map_formulae_to_ruby.rb +95 -0
- data/src/compile/ruby/map_sheet_names_to_ruby_names.rb +19 -0
- data/src/compile/ruby/map_values_to_ruby.rb +65 -0
- data/src/excel.rb +5 -0
- data/src/excel/area.rb +93 -0
- data/src/excel/excel_functions.rb +84 -0
- data/src/excel/excel_functions/abs.rb +14 -0
- data/src/excel/excel_functions/add.rb +18 -0
- data/src/excel/excel_functions/and.rb +30 -0
- data/src/excel/excel_functions/apply_to_range.rb +17 -0
- data/src/excel/excel_functions/average.rb +12 -0
- data/src/excel/excel_functions/choose.rb +18 -0
- data/src/excel/excel_functions/cosh.rb +9 -0
- data/src/excel/excel_functions/count.rb +9 -0
- data/src/excel/excel_functions/counta.rb +8 -0
- data/src/excel/excel_functions/divide.rb +23 -0
- data/src/excel/excel_functions/excel_equal.rb +20 -0
- data/src/excel/excel_functions/excel_if.rb +8 -0
- data/src/excel/excel_functions/excel_match.rb +51 -0
- data/src/excel/excel_functions/find.rb +39 -0
- data/src/excel/excel_functions/iferror.rb +10 -0
- data/src/excel/excel_functions/index.rb +48 -0
- data/src/excel/excel_functions/left.rb +12 -0
- data/src/excel/excel_functions/less_than.rb +26 -0
- data/src/excel/excel_functions/less_than_or_equal.rb +26 -0
- data/src/excel/excel_functions/max.rb +12 -0
- data/src/excel/excel_functions/min.rb +12 -0
- data/src/excel/excel_functions/mod.rb +15 -0
- data/src/excel/excel_functions/more_than.rb +26 -0
- data/src/excel/excel_functions/more_than_or_equal.rb +26 -0
- data/src/excel/excel_functions/multiply.rb +24 -0
- data/src/excel/excel_functions/negative.rb +12 -0
- data/src/excel/excel_functions/not_equal.rb +19 -0
- data/src/excel/excel_functions/number_argument.rb +30 -0
- data/src/excel/excel_functions/pi.rb +7 -0
- data/src/excel/excel_functions/pmt.rb +16 -0
- data/src/excel/excel_functions/power.rb +18 -0
- data/src/excel/excel_functions/round.rb +13 -0
- data/src/excel/excel_functions/rounddown.rb +14 -0
- data/src/excel/excel_functions/roundup.rb +17 -0
- data/src/excel/excel_functions/string_join.rb +19 -0
- data/src/excel/excel_functions/subtotal.rb +13 -0
- data/src/excel/excel_functions/subtract.rb +18 -0
- data/src/excel/excel_functions/sum.rb +8 -0
- data/src/excel/excel_functions/sumif.rb +7 -0
- data/src/excel/excel_functions/sumifs.rb +74 -0
- data/src/excel/excel_functions/sumproduct.rb +32 -0
- data/src/excel/excel_functions/vlookup.rb +49 -0
- data/src/excel/formula_peg.rb +238 -0
- data/src/excel/formula_peg.txt +45 -0
- data/src/excel/reference.rb +56 -0
- data/src/excel/table.rb +108 -0
- data/src/excel_to_code.rb +7 -0
- data/src/extract.rb +13 -0
- data/src/extract/check_for_unknown_functions.rb +20 -0
- data/src/extract/extract_array_formulae.rb +23 -0
- data/src/extract/extract_formulae.rb +36 -0
- data/src/extract/extract_named_references.rb +38 -0
- data/src/extract/extract_relationships.rb +10 -0
- data/src/extract/extract_shared_formulae.rb +23 -0
- data/src/extract/extract_shared_strings.rb +20 -0
- data/src/extract/extract_simple_formulae.rb +18 -0
- data/src/extract/extract_table.rb +24 -0
- data/src/extract/extract_values.rb +29 -0
- data/src/extract/extract_worksheet_dimensions.rb +11 -0
- data/src/extract/extract_worksheet_names.rb +10 -0
- data/src/extract/extract_worksheet_table_relationships.rb +10 -0
- data/src/extract/simple_extract_from_xml.rb +19 -0
- data/src/rewrite.rb +10 -0
- data/src/rewrite/ast_copy_formula.rb +42 -0
- data/src/rewrite/ast_expand_array_formulae.rb +180 -0
- data/src/rewrite/rewrite_array_formulae.rb +71 -0
- data/src/rewrite/rewrite_array_formulae_to_arrays.rb +18 -0
- data/src/rewrite/rewrite_cell_references_to_include_sheet.rb +56 -0
- data/src/rewrite/rewrite_formulae_to_ast.rb +24 -0
- data/src/rewrite/rewrite_merge_formulae_and_values.rb +18 -0
- data/src/rewrite/rewrite_relationship_id_to_filename.rb +22 -0
- data/src/rewrite/rewrite_shared_formulae.rb +38 -0
- data/src/rewrite/rewrite_values_to_ast.rb +28 -0
- data/src/rewrite/rewrite_whole_row_column_references_to_areas.rb +90 -0
- data/src/rewrite/rewrite_worksheet_names.rb +20 -0
- data/src/simplify.rb +16 -0
- data/src/simplify/count_formula_references.rb +58 -0
- data/src/simplify/identify_dependencies.rb +56 -0
- data/src/simplify/identify_repeated_formula_elements.rb +37 -0
- data/src/simplify/inline_formulae.rb +77 -0
- data/src/simplify/map_formulae_to_values.rb +157 -0
- data/src/simplify/remove_cells.rb +18 -0
- data/src/simplify/replace_arrays_with_single_cells.rb +27 -0
- data/src/simplify/replace_blanks.rb +58 -0
- data/src/simplify/replace_common_elements_in_formulae.rb +19 -0
- data/src/simplify/replace_formulae_with_calculated_values.rb +21 -0
- data/src/simplify/replace_indirects_with_references.rb +44 -0
- data/src/simplify/replace_named_references.rb +82 -0
- data/src/simplify/replace_ranges_with_array_literals.rb +54 -0
- data/src/simplify/replace_shared_strings.rb +49 -0
- data/src/simplify/replace_table_references.rb +71 -0
- data/src/simplify/replace_values_with_constants.rb +47 -0
- data/src/simplify/simplify_arithmetic.rb +54 -0
- data/src/util.rb +2 -0
- data/src/util/not_supported_exception.rb +2 -0
- data/src/util/try.rb +9 -0
- metadata +207 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative 'simple_extract_from_xml'
|
2
|
+
|
3
|
+
class ExtractValues < SimpleExtractFromXML
|
4
|
+
|
5
|
+
attr_accessor :ref, :type
|
6
|
+
|
7
|
+
def start_element(name,attributes)
|
8
|
+
if name == "v"
|
9
|
+
self.parsing = true
|
10
|
+
output.write "#{@ref}\t#{@type}\t"
|
11
|
+
elsif name == "c"
|
12
|
+
@ref = attributes.assoc('r').last
|
13
|
+
type = attributes.assoc('t')
|
14
|
+
@type = type ? type.last : "n"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def end_element(name)
|
19
|
+
return unless name == "v"
|
20
|
+
self.parsing = false
|
21
|
+
output.putc "\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
def characters(string)
|
25
|
+
return unless parsing
|
26
|
+
output.write string
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require_relative 'simple_extract_from_xml'
|
2
|
+
|
3
|
+
class ExtractWorksheetDimensions < SimpleExtractFromXML
|
4
|
+
|
5
|
+
# FIXME: Is there an elegant way to abort once we have found the dimension tag?
|
6
|
+
def start_element(name,attributes)
|
7
|
+
return false unless name == "dimension"
|
8
|
+
output.puts "#{attributes.assoc('ref').last}"
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require_relative 'simple_extract_from_xml'
|
2
|
+
|
3
|
+
class ExtractWorksheetNames < SimpleExtractFromXML
|
4
|
+
|
5
|
+
def start_element(name,attributes)
|
6
|
+
return false unless name == "sheet"
|
7
|
+
output.puts "#{attributes.assoc('r:id').last}\t#{attributes.assoc('name').last}"
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
class SimpleExtractFromXML < Nokogiri::XML::SAX::Document
|
4
|
+
|
5
|
+
attr_accessor :parsing, :input, :output
|
6
|
+
|
7
|
+
def self.extract(input,output)
|
8
|
+
self.new.extract(input,output)
|
9
|
+
end
|
10
|
+
|
11
|
+
def extract(input,output)
|
12
|
+
@input, @output = input, output
|
13
|
+
parsing = false
|
14
|
+
parser = Nokogiri::XML::SAX::Parser.new(self)
|
15
|
+
parser.parse(input)
|
16
|
+
output
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
data/src/rewrite.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require_relative "rewrite/rewrite_formulae_to_ast"
|
2
|
+
require_relative "rewrite/rewrite_worksheet_names"
|
3
|
+
require_relative "rewrite/rewrite_whole_row_column_references_to_areas"
|
4
|
+
require_relative "rewrite/rewrite_shared_formulae"
|
5
|
+
require_relative "rewrite/rewrite_array_formulae_to_arrays"
|
6
|
+
require_relative "rewrite/rewrite_array_formulae"
|
7
|
+
require_relative "rewrite/rewrite_values_to_ast"
|
8
|
+
require_relative "rewrite/rewrite_relationship_id_to_filename"
|
9
|
+
require_relative "rewrite/rewrite_merge_formulae_and_values"
|
10
|
+
require_relative "rewrite/rewrite_cell_references_to_include_sheet"
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative '../excel'
|
2
|
+
require_relative '../util/not_supported_exception'
|
3
|
+
|
4
|
+
class AstCopyFormula
|
5
|
+
attr_accessor :rows_to_move
|
6
|
+
attr_accessor :columns_to_move
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
self.rows_to_move = 0
|
10
|
+
self.columns_to_move = 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def copy(ast)
|
14
|
+
return ast unless ast.is_a?(Array)
|
15
|
+
operator = ast[0]
|
16
|
+
if respond_to?(operator)
|
17
|
+
send(operator,*ast[1..-1])
|
18
|
+
else
|
19
|
+
[operator,*ast[1..-1].map {|a| copy(a) }]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def cell(reference)
|
24
|
+
r = Reference.for(reference)
|
25
|
+
[:cell,r.offset(rows_to_move,columns_to_move)]
|
26
|
+
end
|
27
|
+
|
28
|
+
def area(start,finish)
|
29
|
+
s = Reference.for(start).offset(rows_to_move,columns_to_move)
|
30
|
+
f = Reference.for(finish).offset(rows_to_move,columns_to_move)
|
31
|
+
[:area,s,f]
|
32
|
+
end
|
33
|
+
|
34
|
+
def column_range(reference)
|
35
|
+
raise NotSupportedException.new("Column ranges not suported in AstCopyFormula")
|
36
|
+
end
|
37
|
+
|
38
|
+
def row_range(reference)
|
39
|
+
raise NotSupportedException.new("Row ranges not suported in AstCopyFormula")
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require_relative '../excel'
|
2
|
+
|
3
|
+
class AstExpandArrayFormulae
|
4
|
+
|
5
|
+
def map(ast)
|
6
|
+
return ast unless ast.is_a?(Array)
|
7
|
+
operator = ast[0]
|
8
|
+
if respond_to?(operator)
|
9
|
+
send(operator,*ast[1..-1])
|
10
|
+
else
|
11
|
+
[operator,*ast[1..-1].map {|a| map(a) }]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def arithmetic(left,operator,right)
|
16
|
+
left = map(left)
|
17
|
+
right = map(right)
|
18
|
+
return [:arithmetic, left, operator, right] unless array?(left,right)
|
19
|
+
|
20
|
+
map_arrays([left,right]) do |arrayed|
|
21
|
+
[:arithmetic,arrayed[0],operator,arrayed[1]]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def comparison(left,operator,right)
|
26
|
+
left = map(left)
|
27
|
+
right = map(right)
|
28
|
+
return [:comparison, left, operator, right] unless array?(left,right)
|
29
|
+
|
30
|
+
map_arrays([left,right]) do |arrayed|
|
31
|
+
[:comparison,arrayed[0],operator,arrayed[1]]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def string_join(*strings)
|
36
|
+
strings = strings.map { |s| map(s) }
|
37
|
+
return [:string_join, *strings] unless array?(*strings)
|
38
|
+
map_arrays(strings) do |arrayed_strings|
|
39
|
+
[:string_join, *arrayed_strings]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def map_arrays(arrays, &block)
|
44
|
+
# Turn them into ruby arrays
|
45
|
+
arrays = arrays.map { |a| array_ast_to_ruby_array(a) }
|
46
|
+
|
47
|
+
# Find the largest one
|
48
|
+
max_rows = arrays.max { |a,b| a.length <=> b.length }.length
|
49
|
+
max_columns = arrays.max { |a,b| a.first.length <=> b.first.length }.first.length
|
50
|
+
|
51
|
+
# Convert any single rows into an array of the right size
|
52
|
+
arrays = arrays.map { |a| a.length == 1 ? Array.new(max_rows,a.first) : a }
|
53
|
+
|
54
|
+
# Convert any single columns into an array of the right size
|
55
|
+
arrays = arrays.map { |a| a.first.length == 1 ? Array.new(max_columns,a.flatten(1)).transpose : a }
|
56
|
+
|
57
|
+
# Now iterate through
|
58
|
+
return [:array, *max_rows.times.map do |row|
|
59
|
+
[:row, *max_columns.times.map do |column|
|
60
|
+
block.call(arrays.map do |a|
|
61
|
+
a[row][column] || [:error, "#N/A"]
|
62
|
+
end)
|
63
|
+
end]
|
64
|
+
end]
|
65
|
+
end
|
66
|
+
|
67
|
+
FUNCTIONS_THAT_ACCEPT_RANGES_FOR_ALL_ARGUMENTS = %w{AVERAGE COUNT COUNTA MAX MIN SUM SUMPRODUCT}
|
68
|
+
|
69
|
+
def function(name,*arguments)
|
70
|
+
if FUNCTIONS_THAT_ACCEPT_RANGES_FOR_ALL_ARGUMENTS.include?(name)
|
71
|
+
[:function, name, *arguments.map { |a| map(a) }]
|
72
|
+
elsif respond_to?("map_#{name.downcase}")
|
73
|
+
send("map_#{name.downcase}",*arguments)
|
74
|
+
else
|
75
|
+
function_that_does_not_accept_ranges(name,arguments)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def function_that_does_not_accept_ranges(name,arguments)
|
80
|
+
return [:function, name] if arguments.empty?
|
81
|
+
array_map arguments, name, *Array.new(arguments.length,false)
|
82
|
+
end
|
83
|
+
|
84
|
+
def map_match(*args)
|
85
|
+
$DEBUGN = true
|
86
|
+
a = array_map args, 'MATCH', false, true, false
|
87
|
+
$DEBUGN = false
|
88
|
+
a
|
89
|
+
end
|
90
|
+
|
91
|
+
def map_subtotal(*args)
|
92
|
+
array_map args, 'SUBTOTAL', false, *Array.new(args.length-1,true)
|
93
|
+
end
|
94
|
+
|
95
|
+
def map_index(*args)
|
96
|
+
array_map args, 'INDEX', true, false, false
|
97
|
+
end
|
98
|
+
|
99
|
+
def map_sumif(*args)
|
100
|
+
array_map args, 'SUMIF', true, false, true
|
101
|
+
end
|
102
|
+
|
103
|
+
def map_sumifs(*args)
|
104
|
+
if args.length > 3
|
105
|
+
array_map args, 'SUMIFS', true, true, false, *([true,false]*((args.length-3)/2))
|
106
|
+
else
|
107
|
+
array_map args, 'SUMIFS', true, true, false
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def map_vlookup(*args)
|
112
|
+
array_map args, "VLOOKUP", false, true, false, false
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
|
117
|
+
def no_need_to_array?(args,ok_to_be_an_array)
|
118
|
+
ok_to_be_an_array.each_with_index do |array_ok,i|
|
119
|
+
unless array_ok
|
120
|
+
if args[i].first == :array
|
121
|
+
return false
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
true
|
126
|
+
end
|
127
|
+
|
128
|
+
def array_map(args,function,*ok_to_be_an_array)
|
129
|
+
args = args.map { |a| map(a) }
|
130
|
+
return [:function, function, *args ] if no_need_to_array?(args,ok_to_be_an_array)
|
131
|
+
|
132
|
+
# Turn the relevant arguments into ruby arrays and store the dimensions
|
133
|
+
# Enumerable#max and Enumerable#min don't return Enumerators, so can't do it using those methods
|
134
|
+
max_rows = 1
|
135
|
+
max_columns = 1
|
136
|
+
args = args.map.with_index do |a,i|
|
137
|
+
unless ok_to_be_an_array[i]
|
138
|
+
a = array_ast_to_ruby_array(a)
|
139
|
+
r = a.length
|
140
|
+
c = a.first.length
|
141
|
+
max_rows = r if r > max_rows
|
142
|
+
max_columns = c if c > max_columns
|
143
|
+
end
|
144
|
+
a
|
145
|
+
end
|
146
|
+
|
147
|
+
# Convert any single rows into an array of the right size
|
148
|
+
args = args.map.with_index { |a,i| (!ok_to_be_an_array[i] && a.length == 1) ? Array.new(max_rows,a.first) : a }
|
149
|
+
|
150
|
+
# Convert any single columns into an array of the right size
|
151
|
+
args = args.map.with_index { |a,i| (!ok_to_be_an_array[i] && a.first.length == 1) ? Array.new(max_columns,a.flatten(1)).transpose : a }
|
152
|
+
|
153
|
+
# Now iterate through
|
154
|
+
return [:array, *max_rows.times.map do |row|
|
155
|
+
[:row, *max_columns.times.map do |column|
|
156
|
+
[:function, function, *args.map.with_index do |a,i|
|
157
|
+
if ok_to_be_an_array[i]
|
158
|
+
a
|
159
|
+
else
|
160
|
+
a[row][column] || [:error, "#N/A"]
|
161
|
+
end
|
162
|
+
end]
|
163
|
+
end]
|
164
|
+
end]
|
165
|
+
end
|
166
|
+
|
167
|
+
def array?(*args)
|
168
|
+
args.any? { |a| a.first == :array }
|
169
|
+
end
|
170
|
+
|
171
|
+
def array_ast_to_ruby_array(array_ast)
|
172
|
+
return [[array_ast]] unless array_ast.first == :array
|
173
|
+
array_ast[1..-1].map do |row_ast|
|
174
|
+
row_ast[1..-1].map do |cell|
|
175
|
+
cell
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
class ExtractArrayFormulaForCell
|
2
|
+
|
3
|
+
attr_accessor :row_offset, :column_offset
|
4
|
+
|
5
|
+
def map(ast)
|
6
|
+
case ast.first
|
7
|
+
when :array; map_array(ast)
|
8
|
+
when :function; map_function(ast)
|
9
|
+
else return ast
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def map_array(ast)
|
14
|
+
if (@row_offset + 1) >= ast.length
|
15
|
+
if ast.length == 2
|
16
|
+
@row_offset = 0
|
17
|
+
else
|
18
|
+
return [:error, "#N/A"]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
if (@column_offset + 1) >= ast[1].length
|
23
|
+
if ast[1].length == 2
|
24
|
+
@column_offset = 0
|
25
|
+
else
|
26
|
+
return [:error, "#N/A"]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
ast[@row_offset+1][@column_offset+1] # plus ones to skip tthe [:array,[:row,"cell"]] symbols
|
31
|
+
end
|
32
|
+
|
33
|
+
FUNCTIONS_THAT_CAN_RETURN_ARRAYS = %w{INDEX}
|
34
|
+
|
35
|
+
def map_function(ast)
|
36
|
+
return ast unless FUNCTIONS_THAT_CAN_RETURN_ARRAYS.include?(ast[1])
|
37
|
+
[:function, "INDEX", ast, [:number, (@row_offset+1).to_s], [:number, (column_offset+1).to_s]]
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
class RewriteArrayFormulae
|
43
|
+
def self.rewrite(input,output)
|
44
|
+
new.rewrite(input,output)
|
45
|
+
end
|
46
|
+
|
47
|
+
def rewrite(input,output)
|
48
|
+
input.lines do |line|
|
49
|
+
ref, array_range, formula = line.split("\t")
|
50
|
+
array_formula(formula,array_range,output)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def array_formula(formula,array_range,output)
|
55
|
+
array_ast = eval(formula)
|
56
|
+
array_range = "#{array_range}:#{array_range}" unless array_range.include?(':')
|
57
|
+
array_range = Area.for(array_range)
|
58
|
+
array_range.calculate_excel_variables
|
59
|
+
start_reference = array_range.excel_start
|
60
|
+
mapper = ExtractArrayFormulaForCell.new
|
61
|
+
|
62
|
+
# Then we rewrite each of the subsidiaries
|
63
|
+
array_range.offsets.each do |row,column|
|
64
|
+
mapper.row_offset = row
|
65
|
+
mapper.column_offset = column
|
66
|
+
ref = start_reference.offset(row,column)
|
67
|
+
output.puts "#{ref}\t#{mapper.map(array_ast).inspect}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative "ast_expand_array_formulae"
|
2
|
+
|
3
|
+
class RewriteArrayFormulaeToArrays
|
4
|
+
|
5
|
+
def self.rewrite(*args)
|
6
|
+
new.rewrite(*args)
|
7
|
+
end
|
8
|
+
|
9
|
+
def rewrite(input,output)
|
10
|
+
mapper = AstExpandArrayFormulae.new
|
11
|
+
input.lines do |line|
|
12
|
+
content = line.split("\t")
|
13
|
+
ast = eval(content.pop)
|
14
|
+
output.puts "#{content.join("\t")}\t#{mapper.map(ast).inspect}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require_relative '../excel'
|
2
|
+
|
3
|
+
class RewriteCellReferencesToIncludeSheetAst
|
4
|
+
|
5
|
+
attr_accessor :worksheet
|
6
|
+
|
7
|
+
def map(ast)
|
8
|
+
if ast.is_a?(Array)
|
9
|
+
operator = ast.shift
|
10
|
+
if respond_to?(operator)
|
11
|
+
send(operator,*ast)
|
12
|
+
else
|
13
|
+
[operator,*ast.map {|a| map(a) }]
|
14
|
+
end
|
15
|
+
else
|
16
|
+
return ast
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def cell(ref)
|
21
|
+
[:sheet_reference, worksheet, [:cell, ref]]
|
22
|
+
end
|
23
|
+
|
24
|
+
def area(start,finish)
|
25
|
+
[:sheet_reference, worksheet, [:area, start, finish]]
|
26
|
+
end
|
27
|
+
|
28
|
+
def sheet_reference(sheet_name,reference)
|
29
|
+
[:sheet_reference, sheet_name, reference]
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
class RewriteCellReferencesToIncludeSheet
|
35
|
+
|
36
|
+
def self.rewrite(*args)
|
37
|
+
new.rewrite(*args)
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_accessor :worksheet
|
41
|
+
|
42
|
+
def rewrite(input,output)
|
43
|
+
mapper = RewriteCellReferencesToIncludeSheetAst.new
|
44
|
+
mapper.worksheet = worksheet
|
45
|
+
input.lines do |line|
|
46
|
+
if line =~ /(:area|:cell)/
|
47
|
+
content = line.split("\t")
|
48
|
+
ast = eval(content.pop)
|
49
|
+
output.puts "#{content.join("\t")}\t#{mapper.map(ast).inspect}"
|
50
|
+
else
|
51
|
+
output.puts line
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|