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,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
|