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,184 @@
|
|
1
|
+
require_relative 'map_values_to_c'
|
2
|
+
|
3
|
+
class MapFormulaeToC < MapValuesToC
|
4
|
+
|
5
|
+
attr_accessor :sheet_names
|
6
|
+
attr_accessor :worksheet
|
7
|
+
attr_reader :initializers
|
8
|
+
attr_reader :counter
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
reset
|
12
|
+
end
|
13
|
+
|
14
|
+
def reset
|
15
|
+
@initializers = []
|
16
|
+
@counter = 0
|
17
|
+
end
|
18
|
+
|
19
|
+
FUNCTIONS = {
|
20
|
+
'*' => 'multiply',
|
21
|
+
'+' => 'add',
|
22
|
+
'-' => 'subtract',
|
23
|
+
'/' => 'divide',
|
24
|
+
'<' => 'less_than',
|
25
|
+
'<=' => 'less_than_or_equal',
|
26
|
+
'<>' => 'not_equal',
|
27
|
+
'=' => 'excel_equal',
|
28
|
+
'>' => 'more_than',
|
29
|
+
'>=' => 'more_than_or_equal',
|
30
|
+
'ABS' => 'excel_abs',
|
31
|
+
'AND' => 'excel_and',
|
32
|
+
'AVERAGE' => 'average',
|
33
|
+
'CHOOSE' => 'choose',
|
34
|
+
'COSH' => 'cosh',
|
35
|
+
'COUNT' => 'count',
|
36
|
+
'COUNTA' => 'counta',
|
37
|
+
'FIND2' => 'find_2',
|
38
|
+
'FIND3' => 'find',
|
39
|
+
'IF2' => 'excel_if_2',
|
40
|
+
'IF3' => 'excel_if',
|
41
|
+
'IFERROR' => 'iferror',
|
42
|
+
'INDEX2' => 'excel_index_2',
|
43
|
+
'INDEX3' => 'excel_index',
|
44
|
+
'LEFT1' => 'left_1',
|
45
|
+
'LEFT2' => 'left',
|
46
|
+
'MATCH2' => 'excel_match_2',
|
47
|
+
'MATCH3' => 'excel_match',
|
48
|
+
'MAX' => 'max',
|
49
|
+
'MIN' => 'min',
|
50
|
+
'MOD' => 'mod',
|
51
|
+
'PMT' => 'pmt',
|
52
|
+
'ROUND' => 'excel_round',
|
53
|
+
'ROUNDDOWN' => 'rounddown',
|
54
|
+
'ROUNDUP' => 'roundup',
|
55
|
+
'string_join' => 'string_join',
|
56
|
+
'SUBTOTAL' => 'subtotal',
|
57
|
+
'SUM' => 'sum',
|
58
|
+
'SUMIF2' => 'sumif_2',
|
59
|
+
'SUMIF3' => 'sumif',
|
60
|
+
'SUMIFS' => 'sumifs',
|
61
|
+
'SUMPRODUCT' => 'sumproduct',
|
62
|
+
'VLOOKUP3' => 'vlookup_3',
|
63
|
+
'VLOOKUP4' => 'vlookup',
|
64
|
+
'^' => 'power'
|
65
|
+
}
|
66
|
+
|
67
|
+
def prefix(symbol,ast)
|
68
|
+
return map(ast) if symbol == "+"
|
69
|
+
return "negative(#{map(ast)})"
|
70
|
+
end
|
71
|
+
|
72
|
+
def brackets(*contents)
|
73
|
+
"(#{contents.map { |a| map(a) }.join(',')})"
|
74
|
+
end
|
75
|
+
|
76
|
+
def arithmetic(left,operator,right)
|
77
|
+
"#{FUNCTIONS[operator.last]}(#{map(left)},#{map(right)})"
|
78
|
+
end
|
79
|
+
|
80
|
+
def string_join(*strings)
|
81
|
+
any_number_of_argument_function('string_join',strings)
|
82
|
+
end
|
83
|
+
|
84
|
+
def comparison(left,operator,right)
|
85
|
+
"#{FUNCTIONS[operator.last]}(#{map(left)},#{map(right)})"
|
86
|
+
end
|
87
|
+
|
88
|
+
def function(function_name,*arguments)
|
89
|
+
# Some functions are special cases
|
90
|
+
if self.respond_to?("function_#{function_name.downcase}")
|
91
|
+
send("function_#{function_name.downcase}",*arguments)
|
92
|
+
# Some arguments can take any number of arguments, which we need to treat separately
|
93
|
+
elsif FUNCTIONS_WITH_ANY_NUMBER_OF_ARGUMENTS.include?(function_name)
|
94
|
+
any_number_of_argument_function(function_name,arguments)
|
95
|
+
|
96
|
+
# Check for whether this function has variants based on the number of arguments
|
97
|
+
elsif FUNCTIONS.has_key?("#{function_name}#{arguments.size}")
|
98
|
+
"#{FUNCTIONS["#{function_name}#{arguments.size}"]}(#{arguments.map { |a| map(a) }.join(",")})"
|
99
|
+
|
100
|
+
# Then check for whether it is just a standard type
|
101
|
+
elsif FUNCTIONS.has_key?(function_name)
|
102
|
+
"#{FUNCTIONS[function_name]}(#{arguments.map { |a| map(a) }.join(",")})"
|
103
|
+
|
104
|
+
else
|
105
|
+
raise NotSupportedException.new("Function #{function_name} with #{arguments.size} arguments not supported")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
FUNCTIONS_WITH_ANY_NUMBER_OF_ARGUMENTS = %w{SUM AND AVERAGE COUNT COUNTA MAX MIN SUMPRODUCT}
|
110
|
+
|
111
|
+
def function_pi()
|
112
|
+
"M_PI"
|
113
|
+
end
|
114
|
+
|
115
|
+
def function_choose(index,*arguments)
|
116
|
+
"#{FUNCTIONS["CHOOSE"]}(#{map(index)}, #{map_arguments_to_array(arguments)})"
|
117
|
+
end
|
118
|
+
|
119
|
+
def function_subtotal(type,*arguments)
|
120
|
+
"#{FUNCTIONS["SUBTOTAL"]}(#{map(type)}, #{map_arguments_to_array(arguments)})"
|
121
|
+
end
|
122
|
+
|
123
|
+
def function_sumifs(sum_range,*criteria)
|
124
|
+
"#{FUNCTIONS["SUMIFS"]}(#{map(sum_range)}, #{map_arguments_to_array(criteria)})"
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
def any_number_of_argument_function(function_name,arguments)
|
129
|
+
"#{FUNCTIONS[function_name]}(#{map_arguments_to_array(arguments)})"
|
130
|
+
end
|
131
|
+
|
132
|
+
def map_arguments_to_array(arguments)
|
133
|
+
# First we have to create an excel array
|
134
|
+
array_name = "array#{@counter}"
|
135
|
+
@counter +=1
|
136
|
+
arguments_size = arguments.size
|
137
|
+
arguments = arguments.map { |a| map(a) }.join(',')
|
138
|
+
initializers << "ExcelValue #{array_name}[] = {#{arguments}};"
|
139
|
+
"#{arguments_size}, #{array_name}"
|
140
|
+
end
|
141
|
+
|
142
|
+
def cell(reference)
|
143
|
+
# FIXME: What a cludge.
|
144
|
+
if reference =~ /common\d+/
|
145
|
+
"_#{reference}()"
|
146
|
+
else
|
147
|
+
reference.downcase.gsub('$','')
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def sheet_reference(sheet,reference)
|
152
|
+
"#{sheet_names[sheet]}_#{map(reference).downcase}()"
|
153
|
+
end
|
154
|
+
|
155
|
+
def array(*rows)
|
156
|
+
# Make sure we get the right dimensions
|
157
|
+
number_of_rows = rows.size
|
158
|
+
number_of_columns = rows.max { |r| r.size }.size - 1
|
159
|
+
|
160
|
+
# First we have to create an excel array
|
161
|
+
array_name = "array#{@counter}"
|
162
|
+
@counter +=1
|
163
|
+
|
164
|
+
cells = rows.map do |r|
|
165
|
+
r.shift if r.first == :row
|
166
|
+
r.map do |c|
|
167
|
+
map(c)
|
168
|
+
end
|
169
|
+
end.flatten
|
170
|
+
|
171
|
+
initializers << "static ExcelValue #{array_name}[#{cells.size}];"
|
172
|
+
cells.each_with_index do |c,i|
|
173
|
+
initializers << "#{array_name}[#{i}] = #{c};"
|
174
|
+
end
|
175
|
+
|
176
|
+
# Then we need to assign it to an excel value
|
177
|
+
range_name = array_name+"_ev"
|
178
|
+
initializers << "ExcelValue #{range_name} = new_excel_range(#{array_name},#{number_of_rows},#{number_of_columns});"
|
179
|
+
|
180
|
+
range_name
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class MapSheetNamesToCNames
|
2
|
+
|
3
|
+
def self.rewrite(*args)
|
4
|
+
self.new.rewrite(*args)
|
5
|
+
end
|
6
|
+
|
7
|
+
def rewrite(input,output)
|
8
|
+
c_names_assigned = {}
|
9
|
+
input.lines do |line|
|
10
|
+
excel_worksheet_name = line.split("\t").first
|
11
|
+
c_name = excel_worksheet_name.downcase.gsub(/[^a-z0-9]+/,'_')
|
12
|
+
c_name = "s"+c_name if c_name[0] !~ /[a-z]/
|
13
|
+
c_name = ruby_name + "2" if c_names_assigned.has_key?(c_name)
|
14
|
+
c_name.succ! while c_names_assigned.has_key?(c_name)
|
15
|
+
output.puts "#{excel_worksheet_name}\t#{c_name}"
|
16
|
+
c_names_assigned[c_name] = excel_worksheet_name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require_relative '../../util/not_supported_exception'
|
2
|
+
|
3
|
+
class MapValuesToC
|
4
|
+
|
5
|
+
def map(ast)
|
6
|
+
if ast.is_a?(Array)
|
7
|
+
operator = ast[0]
|
8
|
+
if respond_to?(operator)
|
9
|
+
send(operator,*ast[1..-1])
|
10
|
+
else
|
11
|
+
raise NotSupportedException.new("#{operator} in #{ast.inspect} not supported")
|
12
|
+
end
|
13
|
+
else
|
14
|
+
raise NotSupportedException.new("#{ast} not supported")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def blank
|
19
|
+
"BLANK"
|
20
|
+
end
|
21
|
+
|
22
|
+
def constant(name)
|
23
|
+
name
|
24
|
+
end
|
25
|
+
|
26
|
+
alias :null :blank
|
27
|
+
|
28
|
+
def number(text)
|
29
|
+
n = case text
|
30
|
+
when /\./
|
31
|
+
text.to_f.to_s
|
32
|
+
when /e/i
|
33
|
+
text.to_f.to_s
|
34
|
+
else
|
35
|
+
text.to_i.to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
case n
|
39
|
+
when 0; "ZERO"
|
40
|
+
when 1; "ONE"
|
41
|
+
when 2; "TWO"
|
42
|
+
when 3; "THREE"
|
43
|
+
when 4; "FOUR"
|
44
|
+
when 5; "FIVE"
|
45
|
+
when 6; "SIX"
|
46
|
+
when 7; "SEVEN"
|
47
|
+
when 8; "EIGHT"
|
48
|
+
when 9; "NINE"
|
49
|
+
when 10; "TEN"
|
50
|
+
else
|
51
|
+
"new_excel_number(#{n})"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def percentage(text)
|
56
|
+
"new_excel_number(#{(text.to_f / 100.0).to_s})"
|
57
|
+
end
|
58
|
+
|
59
|
+
def string(text)
|
60
|
+
"new_excel_string(#{text.inspect})"
|
61
|
+
end
|
62
|
+
|
63
|
+
ERRORS = {
|
64
|
+
"#NAME?" => "NAME",
|
65
|
+
"#VALUE!" => "VALUE",
|
66
|
+
"#DIV/0!" => "DIV0",
|
67
|
+
"#REF!" => "REF",
|
68
|
+
"#N/A" => "NA"
|
69
|
+
}
|
70
|
+
|
71
|
+
REVERSE_ERRORS = ERRORS.invert
|
72
|
+
|
73
|
+
def error(text)
|
74
|
+
ERRORS[text] || (raise NotSupportedException.new("#{text.inspect} error not recognised"))
|
75
|
+
end
|
76
|
+
|
77
|
+
def boolean_true
|
78
|
+
"TRUE"
|
79
|
+
end
|
80
|
+
|
81
|
+
def boolean_false
|
82
|
+
"FALSE"
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative '../../util/not_supported_exception'
|
2
|
+
|
3
|
+
class MapValuesToCStructs
|
4
|
+
|
5
|
+
def map(ast)
|
6
|
+
if ast.is_a?(Array)
|
7
|
+
operator = ast[0]
|
8
|
+
if respond_to?(operator)
|
9
|
+
send(operator,*ast[1..-1])
|
10
|
+
else
|
11
|
+
raise NotSupportedException.new("#{operator} in #{ast.inspect} not supported")
|
12
|
+
end
|
13
|
+
else
|
14
|
+
raise NotSupportedException.new("#{ast} not supported")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def number(text)
|
19
|
+
n = case text
|
20
|
+
when /\./
|
21
|
+
text.to_f.to_s
|
22
|
+
when /e/i
|
23
|
+
text.to_f.to_s
|
24
|
+
else
|
25
|
+
text.to_i.to_s
|
26
|
+
end
|
27
|
+
"{.type = ExcelNumber, .number = #{n}}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def percentage(text)
|
31
|
+
"{.type = ExcelNumber, .number = #{(text.to_f / 100.0).to_s}}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def string(text)
|
35
|
+
"{.type = ExcelString, .string = #{text.inspect}}"
|
36
|
+
end
|
37
|
+
end
|
data/src/compile/ruby.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative 'map_formulae_to_ruby'
|
2
|
+
|
3
|
+
class CompileToRuby
|
4
|
+
|
5
|
+
attr_accessor :settable
|
6
|
+
attr_accessor :worksheet
|
7
|
+
|
8
|
+
def self.rewrite(*args)
|
9
|
+
self.new.rewrite(*args)
|
10
|
+
end
|
11
|
+
|
12
|
+
def rewrite(input,sheet_names_file,output,defaults = nil)
|
13
|
+
self.settable ||= lambda { |ref| false }
|
14
|
+
mapper = MapFormulaeToRuby.new
|
15
|
+
mapper.worksheet = worksheet
|
16
|
+
mapper.sheet_names = Hash[sheet_names_file.readlines.map { |line| line.strip.split("\t")}]
|
17
|
+
input.lines do |line|
|
18
|
+
begin
|
19
|
+
ref, formula = line.split("\t")
|
20
|
+
if settable.call(ref)
|
21
|
+
output.puts " attr_accessor :#{ref.downcase} # Default: #{mapper.map(eval(formula))}"
|
22
|
+
defaults.puts " @#{ref.downcase} = #{mapper.map(eval(formula))}" if defaults
|
23
|
+
else
|
24
|
+
output.puts " def #{ref.downcase}; @#{ref.downcase} ||= #{mapper.map(eval(formula))}; end"
|
25
|
+
end
|
26
|
+
rescue Exception => e
|
27
|
+
puts "Exception at line #{line}"
|
28
|
+
raise
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require_relative "map_values_to_ruby"
|
2
|
+
|
3
|
+
class CompileToRubyUnitTest
|
4
|
+
|
5
|
+
def self.rewrite(*args)
|
6
|
+
self.new.rewrite(*args)
|
7
|
+
end
|
8
|
+
|
9
|
+
def rewrite(input,output)
|
10
|
+
mapper = MapValuesToRuby.new
|
11
|
+
input.lines do |line|
|
12
|
+
ref, formula = line.split("\t")
|
13
|
+
ast = eval(formula)
|
14
|
+
value = mapper.map(ast)
|
15
|
+
full_reference = "worksheet.#{ref.downcase}"
|
16
|
+
if ast.first == :number
|
17
|
+
if value == "0" # Need to do a slightly different test, because needs to pass if nil returned, as well as zero
|
18
|
+
output.puts " def test_#{ref.downcase}; assert_in_epsilon(#{value},#{full_reference} || 0); end"
|
19
|
+
else
|
20
|
+
output.puts " def test_#{ref.downcase}; assert_in_epsilon(#{value},#{full_reference}); end"
|
21
|
+
end
|
22
|
+
else
|
23
|
+
output.puts " def test_#{ref.downcase}; assert_equal(#{value},#{full_reference}); end"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative '../../excel/excel_functions'
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require_relative 'map_values_to_ruby'
|
2
|
+
|
3
|
+
class MapFormulaeToRuby < MapValuesToRuby
|
4
|
+
|
5
|
+
attr_accessor :sheet_names
|
6
|
+
attr_accessor :worksheet
|
7
|
+
|
8
|
+
FUNCTIONS = {
|
9
|
+
'*' => 'multiply',
|
10
|
+
'+' => 'add',
|
11
|
+
'-' => 'subtract',
|
12
|
+
'/' => 'divide',
|
13
|
+
'<' => 'less_than?',
|
14
|
+
'<=' => 'less_than_or_equal?',
|
15
|
+
'<>' => 'not_equal?',
|
16
|
+
'=' => 'excel_equal?',
|
17
|
+
'>' => 'more_than?',
|
18
|
+
'>=' => 'more_than_or_equal?',
|
19
|
+
'ABS' => 'abs',
|
20
|
+
'AND' => 'excel_and',
|
21
|
+
'AVERAGE' => 'average',
|
22
|
+
'CHOOSE' => 'choose',
|
23
|
+
'COSH' => 'cosh',
|
24
|
+
'COUNT' => 'count',
|
25
|
+
'COUNTA' => 'counta',
|
26
|
+
'FIND' => 'find',
|
27
|
+
'IF' => 'excel_if',
|
28
|
+
'IFERROR' => 'iferror',
|
29
|
+
'INDEX' => 'index',
|
30
|
+
'LEFT' => 'left',
|
31
|
+
'MATCH' => 'excel_match',
|
32
|
+
'MAX' => 'max',
|
33
|
+
'MIN' => 'min',
|
34
|
+
'MOD' => 'mod',
|
35
|
+
'PI' => 'pi',
|
36
|
+
'PMT' => 'pmt',
|
37
|
+
'ROUND' => 'round',
|
38
|
+
'ROUNDDOWN' => 'rounddown',
|
39
|
+
'ROUNDUP' => 'roundup',
|
40
|
+
'SUBTOTAL' => 'subtotal',
|
41
|
+
'SUM' => 'sum',
|
42
|
+
'SUMIF' => 'sumif',
|
43
|
+
'SUMIFS' => 'sumifs',
|
44
|
+
'SUMPRODUCT' => 'sumproduct',
|
45
|
+
'VLOOKUP' => 'vlookup',
|
46
|
+
'^' => 'power'
|
47
|
+
}
|
48
|
+
|
49
|
+
def prefix(symbol,ast)
|
50
|
+
return map(ast) if symbol == "+"
|
51
|
+
return "negative(#{map(ast)})"
|
52
|
+
end
|
53
|
+
|
54
|
+
def brackets(*contents)
|
55
|
+
"(#{contents.map { |a| map(a) }.join(',')})"
|
56
|
+
end
|
57
|
+
|
58
|
+
def arithmetic(left,operator,right)
|
59
|
+
"#{FUNCTIONS[operator.last]}(#{map(left)},#{map(right)})"
|
60
|
+
end
|
61
|
+
|
62
|
+
def string_join(*strings)
|
63
|
+
"string_join(#{strings.map {|a| map(a)}.join(',')})"
|
64
|
+
end
|
65
|
+
|
66
|
+
def comparison(left,operator,right)
|
67
|
+
"#{FUNCTIONS[operator.last]}(#{map(left)},#{map(right)})"
|
68
|
+
end
|
69
|
+
|
70
|
+
def function(function_name,*arguments)
|
71
|
+
if FUNCTIONS.has_key?(function_name)
|
72
|
+
"#{FUNCTIONS[function_name]}(#{arguments.map { |a| map(a) }.join(",")})"
|
73
|
+
else
|
74
|
+
raise NotSupportedException.new("Function #{function_name} not supported")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def cell(reference)
|
79
|
+
reference.downcase.gsub('$','')
|
80
|
+
end
|
81
|
+
|
82
|
+
def sheet_reference(sheet,reference)
|
83
|
+
return map(reference) if worksheet && worksheet == sheet
|
84
|
+
"#{sheet_names[sheet]}.#{map(reference)}"
|
85
|
+
end
|
86
|
+
|
87
|
+
def array(*rows)
|
88
|
+
"[#{rows.map {|r| map(r)}.join(",")}]"
|
89
|
+
end
|
90
|
+
|
91
|
+
def row(*cells)
|
92
|
+
"[#{cells.map {|r| map(r)}.join(",")}]"
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|