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