excel_to_code 0.0.1
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 +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
|