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,19 @@
|
|
1
|
+
class MapSheetNamesToRubyNames
|
2
|
+
|
3
|
+
def self.rewrite(*args)
|
4
|
+
self.new.rewrite(*args)
|
5
|
+
end
|
6
|
+
|
7
|
+
def rewrite(input,output)
|
8
|
+
ruby_names_assigned = {}
|
9
|
+
input.lines do |line|
|
10
|
+
excel_worksheet_name = line.split("\t").first
|
11
|
+
ruby_name = excel_worksheet_name.downcase.gsub(/[^a-z0-9]+/,'_')
|
12
|
+
ruby_name = "s"+ruby_name if ruby_name[0] !~ /[a-z]/
|
13
|
+
ruby_name = ruby_name + "2" if ruby_names_assigned.has_key?(ruby_name)
|
14
|
+
ruby_name.succ! while ruby_names_assigned.has_key?(ruby_name)
|
15
|
+
output.puts "#{excel_worksheet_name}\t#{ruby_name}"
|
16
|
+
ruby_names_assigned[ruby_name] = excel_worksheet_name
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require_relative '../../util/not_supported_exception'
|
2
|
+
|
3
|
+
class MapValuesToRuby
|
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
|
+
"nil"
|
20
|
+
end
|
21
|
+
|
22
|
+
alias :null :blank
|
23
|
+
|
24
|
+
def number(text)
|
25
|
+
case text
|
26
|
+
when /\./
|
27
|
+
text.to_f.to_s
|
28
|
+
when /e/i
|
29
|
+
text.to_f.to_s
|
30
|
+
else
|
31
|
+
text.to_i.to_s
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def percentage(text)
|
36
|
+
(text.to_f / 100.0).to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
def string(text)
|
40
|
+
text.inspect
|
41
|
+
end
|
42
|
+
|
43
|
+
ERRORS = {
|
44
|
+
"#NAME?" => ":name",
|
45
|
+
"#VALUE!" => ":value",
|
46
|
+
"#DIV/0!" => ":div0",
|
47
|
+
"#REF!" => ":ref",
|
48
|
+
"#N/A" => ":na"
|
49
|
+
}
|
50
|
+
|
51
|
+
REVERSE_ERRORS = ERRORS.invert
|
52
|
+
|
53
|
+
def error(text)
|
54
|
+
ERRORS[text] || (raise NotSupportedException.new("#{text.inspect} error not recognised"))
|
55
|
+
end
|
56
|
+
|
57
|
+
def boolean_true
|
58
|
+
"true"
|
59
|
+
end
|
60
|
+
|
61
|
+
def boolean_false
|
62
|
+
"false"
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
data/src/excel.rb
ADDED
data/src/excel/area.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
require_relative 'reference'
|
2
|
+
|
3
|
+
class Area < String
|
4
|
+
|
5
|
+
# This is so that we only have one instance for a given area
|
6
|
+
@@areas_for_text ||= Hash.new do |hash,text|
|
7
|
+
hash[text] = area = Area.new(text)
|
8
|
+
area
|
9
|
+
end
|
10
|
+
|
11
|
+
# This is so that we only have one instance of a given reference specified by its variables
|
12
|
+
def Area.for(text)
|
13
|
+
@@areas_for_text[text]
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :excel_start, :excel_finish
|
17
|
+
|
18
|
+
def calculate_excel_variables
|
19
|
+
return if @excel_variables_calculated
|
20
|
+
if self =~ /([^:]+):(.*)/
|
21
|
+
@excel_start = Reference.for($1)
|
22
|
+
@excel_finish = Reference.for($2)
|
23
|
+
else
|
24
|
+
@excel_start = @excel_finish = Reference.for(self)
|
25
|
+
end
|
26
|
+
@excel_start.calculate_excel_variables
|
27
|
+
@excel_finish.calculate_excel_variables
|
28
|
+
end
|
29
|
+
|
30
|
+
def offset(row,column)
|
31
|
+
calculate_excel_variables
|
32
|
+
Area.for([
|
33
|
+
@excel_start.offset(row,column),
|
34
|
+
':',
|
35
|
+
@excel_finish.offset(row,column),
|
36
|
+
].join)
|
37
|
+
end
|
38
|
+
|
39
|
+
def offsets
|
40
|
+
Enumerator.new do |yielder|
|
41
|
+
0.upto(width).each do |c|
|
42
|
+
0.upto(height).each do |r|
|
43
|
+
yielder.yield([r,c])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def height
|
50
|
+
calculate_excel_variables
|
51
|
+
@excel_finish.excel_row_number - @excel_start.excel_row_number
|
52
|
+
end
|
53
|
+
|
54
|
+
def width
|
55
|
+
calculate_excel_variables
|
56
|
+
@excel_finish.excel_column_number - @excel_start.excel_column_number
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_array_literal(sheet = nil)
|
60
|
+
calculate_excel_variables
|
61
|
+
unfixed_start = @excel_start.unfix
|
62
|
+
[:array,
|
63
|
+
*(0.upto(height).map do |row|
|
64
|
+
[:row,
|
65
|
+
*(0.upto(width).map do |column|
|
66
|
+
if sheet
|
67
|
+
[:sheet_reference,
|
68
|
+
sheet,
|
69
|
+
[:cell,
|
70
|
+
unfixed_start.offset(row,column)
|
71
|
+
]
|
72
|
+
]
|
73
|
+
else
|
74
|
+
[:cell,
|
75
|
+
unfixed_start.offset(row,column)
|
76
|
+
]
|
77
|
+
end
|
78
|
+
end)
|
79
|
+
]
|
80
|
+
end)
|
81
|
+
]
|
82
|
+
end
|
83
|
+
|
84
|
+
def includes?(reference)
|
85
|
+
calculate_excel_variables
|
86
|
+
r = Reference.for(reference)
|
87
|
+
r.calculate_excel_variables
|
88
|
+
return false if r.excel_row_number < @excel_start.excel_row_number || r.excel_row_number > @excel_finish.excel_row_number
|
89
|
+
return false if r.excel_column_number < @excel_start.excel_column_number || r.excel_column_number > @excel_finish.excel_column_number
|
90
|
+
true
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module ExcelFunctions
|
2
|
+
end
|
3
|
+
|
4
|
+
# Support functions
|
5
|
+
require_relative 'excel_functions/number_argument'
|
6
|
+
|
7
|
+
# Constants
|
8
|
+
require_relative 'excel_functions/pi'
|
9
|
+
|
10
|
+
# Comparators
|
11
|
+
require_relative 'excel_functions/excel_equal'
|
12
|
+
require_relative 'excel_functions/less_than'
|
13
|
+
require_relative 'excel_functions/more_than'
|
14
|
+
require_relative 'excel_functions/less_than_or_equal'
|
15
|
+
require_relative 'excel_functions/more_than_or_equal'
|
16
|
+
require_relative 'excel_functions/not_equal'
|
17
|
+
|
18
|
+
require_relative 'excel_functions/excel_if'
|
19
|
+
require_relative 'excel_functions/iferror'
|
20
|
+
|
21
|
+
# Basic arithmetic
|
22
|
+
require_relative 'excel_functions/add'
|
23
|
+
require_relative 'excel_functions/subtract'
|
24
|
+
require_relative 'excel_functions/multiply'
|
25
|
+
require_relative 'excel_functions/divide'
|
26
|
+
require_relative 'excel_functions/power'
|
27
|
+
|
28
|
+
# More advanced arithmetic
|
29
|
+
require_relative 'excel_functions/abs'
|
30
|
+
require_relative 'excel_functions/and'
|
31
|
+
require_relative 'excel_functions/mod'
|
32
|
+
|
33
|
+
# Array arithmetic
|
34
|
+
require_relative 'excel_functions/sum'
|
35
|
+
require_relative 'excel_functions/average'
|
36
|
+
require_relative 'excel_functions/max'
|
37
|
+
require_relative 'excel_functions/min'
|
38
|
+
|
39
|
+
# Financial functions
|
40
|
+
require_relative 'excel_functions/pmt'
|
41
|
+
|
42
|
+
# Geometry functions
|
43
|
+
require_relative 'excel_functions/cosh'
|
44
|
+
|
45
|
+
# String functions
|
46
|
+
require_relative 'excel_functions/string_join'
|
47
|
+
require_relative 'excel_functions/excel_match'
|
48
|
+
require_relative 'excel_functions/find'
|
49
|
+
|
50
|
+
# Search functions
|
51
|
+
require_relative 'excel_functions/choose'
|
52
|
+
|
53
|
+
# Other functions
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
require_relative 'excel_functions/round'
|
61
|
+
|
62
|
+
require_relative 'excel_functions/subtotal'
|
63
|
+
|
64
|
+
require_relative 'excel_functions/count'
|
65
|
+
|
66
|
+
require_relative 'excel_functions/counta'
|
67
|
+
|
68
|
+
require_relative 'excel_functions/sumif'
|
69
|
+
|
70
|
+
require_relative 'excel_functions/sumifs'
|
71
|
+
|
72
|
+
require_relative 'excel_functions/sumproduct'
|
73
|
+
|
74
|
+
require_relative 'excel_functions/vlookup'
|
75
|
+
|
76
|
+
require_relative 'excel_functions/index'
|
77
|
+
|
78
|
+
require_relative 'excel_functions/left'
|
79
|
+
|
80
|
+
require_relative 'excel_functions/roundup'
|
81
|
+
|
82
|
+
require_relative 'excel_functions/rounddown'
|
83
|
+
|
84
|
+
require_relative 'excel_functions/negative'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'number_argument'
|
2
|
+
require_relative 'apply_to_range'
|
3
|
+
|
4
|
+
module ExcelFunctions
|
5
|
+
|
6
|
+
def add(a,b)
|
7
|
+
# return apply_to_range(a,b) { |a,b| add(a,b) } if a.is_a?(Array) || b.is_a?(Array)
|
8
|
+
|
9
|
+
a = number_argument(a)
|
10
|
+
b = number_argument(b)
|
11
|
+
|
12
|
+
return a if a.is_a?(Symbol)
|
13
|
+
return b if b.is_a?(Symbol)
|
14
|
+
|
15
|
+
a + b
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ExcelFunctions
|
2
|
+
|
3
|
+
def excel_and(*args)
|
4
|
+
# Flatten arrays
|
5
|
+
args = args.flatten
|
6
|
+
|
7
|
+
# If an argument is an error, return that
|
8
|
+
error = args.find {|a| a.is_a?(Symbol)}
|
9
|
+
return error if error
|
10
|
+
|
11
|
+
# Replace 1 and 0 with true and false
|
12
|
+
args.map! do |a|
|
13
|
+
case a
|
14
|
+
when 1; true
|
15
|
+
when 0; false
|
16
|
+
else; a
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Remove anything not boolean
|
21
|
+
args.delete_if { |a| !(a.is_a?(TrueClass) || a.is_a?(FalseClass)) }
|
22
|
+
|
23
|
+
# Return an error if nothing less
|
24
|
+
return :value if args.empty?
|
25
|
+
|
26
|
+
# Now calculate and return
|
27
|
+
args.all? {|a| a == true }
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ExcelFunctions
|
2
|
+
|
3
|
+
def apply_to_range(a,b)
|
4
|
+
a = Array.new(b.length,Array.new(b.first.length,a)) unless a.is_a?(Array)
|
5
|
+
b = Array.new(a.length,Array.new(a.first.length,b)) unless b.is_a?(Array)
|
6
|
+
|
7
|
+
return :value unless b.length == a.length
|
8
|
+
return :value unless b.first.length == a.first.length
|
9
|
+
|
10
|
+
a.map.with_index do |row,i|
|
11
|
+
row.map.with_index do |cell,j|
|
12
|
+
yield cell, b[i][j]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module ExcelFunctions
|
2
|
+
|
3
|
+
def average(*args)
|
4
|
+
args = args.flatten
|
5
|
+
error = args.find {|a| a.is_a?(Symbol)}
|
6
|
+
return error if error
|
7
|
+
args.delete_if { |a| !a.is_a?(Numeric) }
|
8
|
+
return :div0 if args.empty?
|
9
|
+
args.inject(0.0) { |m,i| m + i.to_f } / args.size.to_f
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module ExcelFunctions
|
2
|
+
|
3
|
+
def choose(index,*args)
|
4
|
+
# If an argument is an error, return that
|
5
|
+
return index if index.is_a?(Symbol)
|
6
|
+
error = args.find {|a| a.is_a?(Symbol)}
|
7
|
+
return error if error
|
8
|
+
|
9
|
+
# If the index is out of bounds, return an error
|
10
|
+
return :value unless index
|
11
|
+
return :value if index < 1
|
12
|
+
return :value if index > args.length
|
13
|
+
|
14
|
+
return args[index-1] || 0
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative 'number_argument'
|
2
|
+
require_relative 'apply_to_range'
|
3
|
+
|
4
|
+
module ExcelFunctions
|
5
|
+
|
6
|
+
def divide(a,b)
|
7
|
+
# return apply_to_range(a,b) { |a,b| divide(a,b) } if a.is_a?(Array) || b.is_a?(Array)
|
8
|
+
|
9
|
+
a = number_argument(a)
|
10
|
+
b = number_argument(b)
|
11
|
+
|
12
|
+
return a if a.is_a?(Symbol)
|
13
|
+
return b if b.is_a?(Symbol)
|
14
|
+
|
15
|
+
return :div0 if b == 0
|
16
|
+
|
17
|
+
a / b.to_f
|
18
|
+
|
19
|
+
rescue ZeroDivisionError
|
20
|
+
:div0
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|