excel_to_code 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. data/README +41 -0
  2. data/bin/excel_to_c +63 -0
  3. data/bin/excel_to_ruby +9 -0
  4. data/src/commands.rb +2 -0
  5. data/src/commands/excel_to_c.rb +858 -0
  6. data/src/commands/excel_to_ruby.rb +620 -0
  7. data/src/compile.rb +2 -0
  8. data/src/compile/c.rb +5 -0
  9. data/src/compile/c/compile_to_c.rb +62 -0
  10. data/src/compile/c/compile_to_c_header.rb +26 -0
  11. data/src/compile/c/compile_to_c_unit_test.rb +42 -0
  12. data/src/compile/c/excel_to_c_runtime.c +2029 -0
  13. data/src/compile/c/map_formulae_to_c.rb +184 -0
  14. data/src/compile/c/map_sheet_names_to_c_names.rb +19 -0
  15. data/src/compile/c/map_values_to_c.rb +85 -0
  16. data/src/compile/c/map_values_to_c_structs.rb +37 -0
  17. data/src/compile/ruby.rb +3 -0
  18. data/src/compile/ruby/compile_to_ruby.rb +33 -0
  19. data/src/compile/ruby/compile_to_ruby_unit_test.rb +28 -0
  20. data/src/compile/ruby/excel_to_ruby_runtime.rb +1 -0
  21. data/src/compile/ruby/map_formulae_to_ruby.rb +95 -0
  22. data/src/compile/ruby/map_sheet_names_to_ruby_names.rb +19 -0
  23. data/src/compile/ruby/map_values_to_ruby.rb +65 -0
  24. data/src/excel.rb +5 -0
  25. data/src/excel/area.rb +93 -0
  26. data/src/excel/excel_functions.rb +84 -0
  27. data/src/excel/excel_functions/abs.rb +14 -0
  28. data/src/excel/excel_functions/add.rb +18 -0
  29. data/src/excel/excel_functions/and.rb +30 -0
  30. data/src/excel/excel_functions/apply_to_range.rb +17 -0
  31. data/src/excel/excel_functions/average.rb +12 -0
  32. data/src/excel/excel_functions/choose.rb +18 -0
  33. data/src/excel/excel_functions/cosh.rb +9 -0
  34. data/src/excel/excel_functions/count.rb +9 -0
  35. data/src/excel/excel_functions/counta.rb +8 -0
  36. data/src/excel/excel_functions/divide.rb +23 -0
  37. data/src/excel/excel_functions/excel_equal.rb +20 -0
  38. data/src/excel/excel_functions/excel_if.rb +8 -0
  39. data/src/excel/excel_functions/excel_match.rb +51 -0
  40. data/src/excel/excel_functions/find.rb +39 -0
  41. data/src/excel/excel_functions/iferror.rb +10 -0
  42. data/src/excel/excel_functions/index.rb +48 -0
  43. data/src/excel/excel_functions/left.rb +12 -0
  44. data/src/excel/excel_functions/less_than.rb +26 -0
  45. data/src/excel/excel_functions/less_than_or_equal.rb +26 -0
  46. data/src/excel/excel_functions/max.rb +12 -0
  47. data/src/excel/excel_functions/min.rb +12 -0
  48. data/src/excel/excel_functions/mod.rb +15 -0
  49. data/src/excel/excel_functions/more_than.rb +26 -0
  50. data/src/excel/excel_functions/more_than_or_equal.rb +26 -0
  51. data/src/excel/excel_functions/multiply.rb +24 -0
  52. data/src/excel/excel_functions/negative.rb +12 -0
  53. data/src/excel/excel_functions/not_equal.rb +19 -0
  54. data/src/excel/excel_functions/number_argument.rb +30 -0
  55. data/src/excel/excel_functions/pi.rb +7 -0
  56. data/src/excel/excel_functions/pmt.rb +16 -0
  57. data/src/excel/excel_functions/power.rb +18 -0
  58. data/src/excel/excel_functions/round.rb +13 -0
  59. data/src/excel/excel_functions/rounddown.rb +14 -0
  60. data/src/excel/excel_functions/roundup.rb +17 -0
  61. data/src/excel/excel_functions/string_join.rb +19 -0
  62. data/src/excel/excel_functions/subtotal.rb +13 -0
  63. data/src/excel/excel_functions/subtract.rb +18 -0
  64. data/src/excel/excel_functions/sum.rb +8 -0
  65. data/src/excel/excel_functions/sumif.rb +7 -0
  66. data/src/excel/excel_functions/sumifs.rb +74 -0
  67. data/src/excel/excel_functions/sumproduct.rb +32 -0
  68. data/src/excel/excel_functions/vlookup.rb +49 -0
  69. data/src/excel/formula_peg.rb +238 -0
  70. data/src/excel/formula_peg.txt +45 -0
  71. data/src/excel/reference.rb +56 -0
  72. data/src/excel/table.rb +108 -0
  73. data/src/excel_to_code.rb +7 -0
  74. data/src/extract.rb +13 -0
  75. data/src/extract/check_for_unknown_functions.rb +20 -0
  76. data/src/extract/extract_array_formulae.rb +23 -0
  77. data/src/extract/extract_formulae.rb +36 -0
  78. data/src/extract/extract_named_references.rb +38 -0
  79. data/src/extract/extract_relationships.rb +10 -0
  80. data/src/extract/extract_shared_formulae.rb +23 -0
  81. data/src/extract/extract_shared_strings.rb +20 -0
  82. data/src/extract/extract_simple_formulae.rb +18 -0
  83. data/src/extract/extract_table.rb +24 -0
  84. data/src/extract/extract_values.rb +29 -0
  85. data/src/extract/extract_worksheet_dimensions.rb +11 -0
  86. data/src/extract/extract_worksheet_names.rb +10 -0
  87. data/src/extract/extract_worksheet_table_relationships.rb +10 -0
  88. data/src/extract/simple_extract_from_xml.rb +19 -0
  89. data/src/rewrite.rb +10 -0
  90. data/src/rewrite/ast_copy_formula.rb +42 -0
  91. data/src/rewrite/ast_expand_array_formulae.rb +180 -0
  92. data/src/rewrite/rewrite_array_formulae.rb +71 -0
  93. data/src/rewrite/rewrite_array_formulae_to_arrays.rb +18 -0
  94. data/src/rewrite/rewrite_cell_references_to_include_sheet.rb +56 -0
  95. data/src/rewrite/rewrite_formulae_to_ast.rb +24 -0
  96. data/src/rewrite/rewrite_merge_formulae_and_values.rb +18 -0
  97. data/src/rewrite/rewrite_relationship_id_to_filename.rb +22 -0
  98. data/src/rewrite/rewrite_shared_formulae.rb +38 -0
  99. data/src/rewrite/rewrite_values_to_ast.rb +28 -0
  100. data/src/rewrite/rewrite_whole_row_column_references_to_areas.rb +90 -0
  101. data/src/rewrite/rewrite_worksheet_names.rb +20 -0
  102. data/src/simplify.rb +16 -0
  103. data/src/simplify/count_formula_references.rb +58 -0
  104. data/src/simplify/identify_dependencies.rb +56 -0
  105. data/src/simplify/identify_repeated_formula_elements.rb +37 -0
  106. data/src/simplify/inline_formulae.rb +77 -0
  107. data/src/simplify/map_formulae_to_values.rb +157 -0
  108. data/src/simplify/remove_cells.rb +18 -0
  109. data/src/simplify/replace_arrays_with_single_cells.rb +27 -0
  110. data/src/simplify/replace_blanks.rb +58 -0
  111. data/src/simplify/replace_common_elements_in_formulae.rb +19 -0
  112. data/src/simplify/replace_formulae_with_calculated_values.rb +21 -0
  113. data/src/simplify/replace_indirects_with_references.rb +44 -0
  114. data/src/simplify/replace_named_references.rb +82 -0
  115. data/src/simplify/replace_ranges_with_array_literals.rb +54 -0
  116. data/src/simplify/replace_shared_strings.rb +49 -0
  117. data/src/simplify/replace_table_references.rb +71 -0
  118. data/src/simplify/replace_values_with_constants.rb +47 -0
  119. data/src/simplify/simplify_arithmetic.rb +54 -0
  120. data/src/util.rb +2 -0
  121. data/src/util/not_supported_exception.rb +2 -0
  122. data/src/util/try.rb +9 -0
  123. 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
@@ -0,0 +1,5 @@
1
+ require_relative 'excel/area'
2
+ require_relative 'excel/reference'
3
+ require_relative 'excel/formula_peg'
4
+ require_relative 'excel/table'
5
+ require_relative 'excel/excel_functions'
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,14 @@
1
+ module ExcelFunctions
2
+
3
+ def abs(a)
4
+ case a
5
+ when Numeric; return a.abs
6
+ when Symbol; return a
7
+ when nil; return 0
8
+ when true; return 1
9
+ when false; return 0
10
+ else; return :value
11
+ end
12
+ end
13
+
14
+ end
@@ -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,9 @@
1
+ module ExcelFunctions
2
+
3
+ def cosh(x)
4
+ return x if x.is_a?(Symbol)
5
+ x ||= 0
6
+ Math.cosh(x)
7
+ end
8
+
9
+ end
@@ -0,0 +1,9 @@
1
+ module ExcelFunctions
2
+
3
+ def count(*args)
4
+ args = args.flatten
5
+ args.delete_if { |a| !a.is_a?(Numeric)}
6
+ args.size
7
+ end
8
+
9
+ end
@@ -0,0 +1,8 @@
1
+ module ExcelFunctions
2
+
3
+ def counta(*args)
4
+ args = args.flatten.compact
5
+ args.size
6
+ end
7
+
8
+ 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