excel_to_code 0.1.23 → 0.2.0

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/src/commands/excel_to_c.rb +39 -92
  3. data/src/commands/excel_to_ruby.rb +9 -35
  4. data/src/commands/excel_to_x.rb +515 -536
  5. data/src/compile/c/a.out +0 -0
  6. data/src/compile/c/compile_named_reference_setters.rb +4 -6
  7. data/src/compile/c/compile_to_c.rb +34 -21
  8. data/src/compile/c/compile_to_c_header.rb +7 -7
  9. data/src/compile/c/excel_to_c_runtime.c +8 -4
  10. data/src/compile/c/map_formulae_to_c.rb +85 -86
  11. data/src/compile/c/map_values_to_c.rb +7 -1
  12. data/src/compile/c/map_values_to_c_structs.rb +1 -1
  13. data/src/compile/ruby/compile_to_ruby.rb +14 -11
  14. data/src/compile/ruby/compile_to_ruby_unit_test.rb +17 -10
  15. data/src/compile/ruby/map_formulae_to_ruby.rb +56 -56
  16. data/src/compile/ruby/map_values_to_ruby.rb +14 -2
  17. data/src/excel/area.rb +6 -8
  18. data/src/excel/excel_functions/hlookup.rb +1 -1
  19. data/src/excel/excel_functions/vlookup.rb +1 -1
  20. data/src/excel/formula_peg.rb +1 -1
  21. data/src/excel/formula_peg.txt +1 -1
  22. data/src/excel/reference.rb +4 -3
  23. data/src/excel/table.rb +4 -4
  24. data/src/extract.rb +1 -0
  25. data/src/extract/check_for_unknown_functions.rb +2 -2
  26. data/src/extract/extract_array_formulae.rb +9 -9
  27. data/src/extract/extract_everything.rb +140 -0
  28. data/src/extract/extract_formulae.rb +30 -20
  29. data/src/extract/extract_named_references.rb +37 -22
  30. data/src/extract/extract_relationships.rb +16 -3
  31. data/src/extract/extract_shared_formulae.rb +8 -11
  32. data/src/extract/extract_shared_formulae_targets.rb +1 -6
  33. data/src/extract/extract_shared_strings.rb +21 -8
  34. data/src/extract/extract_simple_formulae.rb +11 -6
  35. data/src/extract/extract_table.rb +26 -13
  36. data/src/extract/extract_values.rb +35 -11
  37. data/src/extract/extract_worksheet_dimensions.rb +13 -3
  38. data/src/extract/extract_worksheet_names.rb +16 -3
  39. data/src/extract/extract_worksheet_table_relationships.rb +16 -4
  40. data/src/extract/simple_extract_from_xml.rb +9 -11
  41. data/src/rewrite.rb +3 -0
  42. data/src/rewrite/ast_copy_formula.rb +5 -1
  43. data/src/rewrite/ast_expand_array_formulae.rb +71 -59
  44. data/src/rewrite/caching_formula_parser.rb +110 -0
  45. data/src/rewrite/rewrite_array_formulae.rb +21 -14
  46. data/src/rewrite/rewrite_cell_references_to_include_sheet.rb +41 -13
  47. data/src/rewrite/rewrite_shared_formulae.rb +17 -18
  48. data/src/rewrite/rewrite_values_to_ast.rb +2 -0
  49. data/src/rewrite/rewrite_whole_row_column_references_to_areas.rb +28 -25
  50. data/src/simplify.rb +1 -0
  51. data/src/simplify/count_formula_references.rb +22 -23
  52. data/src/simplify/emergency_array_formula_replace_indirect_bodge.rb +44 -0
  53. data/src/simplify/identify_dependencies.rb +7 -8
  54. data/src/simplify/identify_repeated_formula_elements.rb +5 -6
  55. data/src/simplify/inline_formulae.rb +48 -48
  56. data/src/simplify/map_formulae_to_values.rb +197 -79
  57. data/src/simplify/remove_cells.rb +13 -6
  58. data/src/simplify/replace_arithmetic_on_ranges.rb +42 -28
  59. data/src/simplify/replace_arrays_with_single_cells.rb +11 -5
  60. data/src/simplify/replace_column_with_column_number.rb +31 -23
  61. data/src/simplify/replace_common_elements_in_formulae.rb +16 -17
  62. data/src/simplify/replace_indirects_with_references.rb +26 -21
  63. data/src/simplify/replace_named_references.rb +26 -31
  64. data/src/simplify/replace_offsets_with_references.rb +33 -34
  65. data/src/simplify/replace_ranges_with_array_literals.rb +48 -20
  66. data/src/simplify/replace_shared_strings.rb +15 -13
  67. data/src/simplify/replace_string_join_on_ranges.rb +7 -9
  68. data/src/simplify/replace_table_references.rb +16 -11
  69. data/src/simplify/replace_values_with_constants.rb +6 -4
  70. data/src/simplify/simplify_arithmetic.rb +33 -19
  71. data/src/simplify/sort_into_calculation_order.rb +13 -13
  72. data/src/simplify/wrap_formulae_that_return_arrays_and_are_not_in_arrays.rb +21 -13
  73. metadata +19 -2
data/src/compile/c/a.out CHANGED
Binary file
@@ -25,7 +25,7 @@ class MapNamedReferenceToCSetter
25
25
  end
26
26
 
27
27
  def cell(reference)
28
- reference.downcase.gsub('$','')
28
+ Reference.for(reference).unfix.downcase.to_s
29
29
  end
30
30
 
31
31
  def sheet_reference(sheet,reference)
@@ -56,7 +56,7 @@ class MapNamedReferenceToCSetter
56
56
  settable_refs = cells_that_can_be_set_at_runtime[sheet]
57
57
  return false unless settable_refs
58
58
  return true if settable_refs == :all
59
- settable_refs.include?(reference.upcase)
59
+ settable_refs.include?(reference.upcase.to_sym)
60
60
  end
61
61
 
62
62
  end
@@ -71,12 +71,10 @@ class CompileNamedReferenceSetters
71
71
 
72
72
  def rewrite(named_references, sheet_names, output)
73
73
  mapper = MapNamedReferenceToCSetter.new
74
- mapper.sheet_names = Hash[sheet_names.readlines.map { |line| line.strip.split("\t")}]
74
+ mapper.sheet_names = sheet_names
75
75
  mapper.cells_that_can_be_set_at_runtime = cells_that_can_be_set_at_runtime
76
76
 
77
- named_references.each_line do |line|
78
- name, reference = line.split("\t")
79
- ast = eval(reference)
77
+ named_references.each do |name, ast|
80
78
  output.puts "void set_#{name}(ExcelValue newValue) {"
81
79
  output.puts mapper.map(ast)
82
80
  output.puts "}"
@@ -4,28 +4,32 @@ class CompileToC
4
4
 
5
5
  attr_accessor :settable
6
6
  attr_accessor :gettable
7
- attr_accessor :worksheet
8
7
  attr_accessor :variable_set_counter
9
8
 
10
9
  def self.rewrite(*args)
11
10
  self.new.rewrite(*args)
12
11
  end
13
12
 
14
- def rewrite(input,sheet_names_file,output)
13
+ def rewrite(formulae, sheet_names, output)
15
14
  self.settable ||= lambda { |ref| false }
16
15
  self.gettable ||= lambda { |ref| true }
17
16
  @variable_set_counter ||= 0
17
+
18
18
  mapper = MapFormulaeToC.new
19
- mapper.worksheet = worksheet
20
- mapper.sheet_names = Hash[sheet_names_file.readlines.map { |line| line.strip.split("\t")}]
21
- c_name = mapper.sheet_names[worksheet] || worksheet
22
- input.each_line do |line|
19
+ mapper.sheet_names = sheet_names
20
+ formulae.each do |ref, ast|
23
21
  begin
24
- ref, formula = line.split("\t")
25
- ast = eval(formula)
22
+ worksheet = ref.first
23
+ cell = ref.last
24
+ mapper.worksheet = worksheet
25
+ worksheet_c_name = mapper.sheet_names[worksheet.to_s] || worksheet.to_s
26
26
  calculation = mapper.map(ast)
27
- name = c_name ? "#{c_name}_#{ref.downcase}" : ref.downcase
27
+ name = worksheet_c_name.length > 0 ? "#{worksheet_c_name}_#{cell.downcase}" : cell.downcase
28
+
29
+ # Declare function as static so it can be inlined where possible
28
30
  static_or_not = gettable.call(ref) ? "" : "static "
31
+
32
+ # Settable functions need a default value and then a function for getting and setting
29
33
  if settable.call(ref)
30
34
  output.puts "ExcelValue #{name}_default() {"
31
35
  mapper.initializers.each do |i|
@@ -34,25 +38,34 @@ class CompileToC
34
38
  output.puts " return #{calculation};"
35
39
  output.puts "}"
36
40
  output.puts "static ExcelValue #{name}_variable;"
37
- output.puts "ExcelValue #{name}() { if(variable_set[#{@variable_set_counter}] == 1) { return #{name}_variable; } else { return #{c_name}_#{ref.downcase}_default(); } }"
41
+ output.puts "ExcelValue #{name}() { if(variable_set[#{@variable_set_counter}] == 1) { return #{name}_variable; } else { return #{name}_default(); } }"
38
42
  output.puts "void set_#{name}(ExcelValue newValue) { variable_set[#{@variable_set_counter}] = 1; #{name}_variable = newValue; }"
43
+ output.puts
44
+ # Other functions just have a getter
39
45
  else
40
- output.puts "#{static_or_not}ExcelValue #{name}() {"
41
- output.puts " static ExcelValue result;"
42
- output.puts " if(variable_set[#{@variable_set_counter}] == 1) { return result;}"
43
- mapper.initializers.each do |i|
44
- output.puts " #{i}"
46
+ # In simple cases, don't bother memoizing the result
47
+ simple = (ast[0] == :constant) || (ast[0] == :cell && ast[1] =~ /common\d+/) || (ast[0] == :blank) || (ast[0] == :error)
48
+
49
+ if simple
50
+ output.puts "#{static_or_not}ExcelValue #{name}() { return #{calculation}; }"
51
+ else
52
+ output.puts "#{static_or_not}ExcelValue #{name}() {"
53
+ output.puts " static ExcelValue result;"
54
+ output.puts " if(variable_set[#{@variable_set_counter}] == 1) { return result;}"
55
+ mapper.initializers.each do |i|
56
+ output.puts " #{i}"
57
+ end
58
+ output.puts " result = #{calculation};"
59
+ output.puts " variable_set[#{@variable_set_counter}] = 1;"
60
+ output.puts " return result;"
61
+ output.puts "}"
62
+ output.puts
45
63
  end
46
- output.puts " result = #{calculation};"
47
- output.puts " variable_set[#{@variable_set_counter}] = 1;"
48
- output.puts " return result;"
49
- output.puts "}"
50
64
  end
51
- output.puts
52
65
  @variable_set_counter += 1
53
66
  mapper.reset
54
67
  rescue Exception => e
55
- puts "Exception at line #{line}"
68
+ puts "Exception at #{ref} #{ast}"
56
69
  raise
57
70
  end
58
71
  end
@@ -1,6 +1,5 @@
1
1
  class CompileToCHeader
2
2
 
3
- attr_accessor :worksheet
4
3
  attr_accessor :gettable
5
4
  attr_accessor :settable
6
5
 
@@ -8,17 +7,18 @@ class CompileToCHeader
8
7
  self.new.rewrite(*args)
9
8
  end
10
9
 
11
- def rewrite(input,sheet_names_file,output,defaults = nil)
12
- c_name = Hash[sheet_names_file.readlines.map { |line| line.strip.split("\t")}][worksheet]
10
+ def rewrite(formulae, c_name_for_worksheet_name, output)
13
11
  self.gettable ||= lambda { |ref| true }
14
12
  self.settable ||= lambda { |ref| false }
15
- input.each_line do |line|
13
+ formulae.each do |ref, ast|
16
14
  begin
17
- ref, formula = line.split("\t")
18
15
  static_or_not = (gettable.call(ref) || settable.call(ref)) ? "" : "static "
19
- output.puts "#{static_or_not}ExcelValue #{c_name}_#{ref.downcase}();"
16
+ worksheet = c_name_for_worksheet_name[ref.first.to_s] || ref.first.to_s
17
+ ref = ref.last.downcase
18
+ name = worksheet.length > 0 ? "#{worksheet}_#{ref}" : ref
19
+ output.puts "#{static_or_not}ExcelValue #{name}();"
20
20
  rescue Exception => e
21
- puts "Exception at line #{line}"
21
+ puts "Exception at #{ref} #{ast}"
22
22
  raise
23
23
  end
24
24
  end
@@ -755,7 +755,7 @@ static ExcelValue excel_match(ExcelValue lookup_value, ExcelValue lookup_array,
755
755
  }
756
756
 
757
757
  static ExcelValue excel_match_2(ExcelValue lookup_value, ExcelValue lookup_array ) {
758
- return excel_match(lookup_value,lookup_array,new_excel_number(0));
758
+ return excel_match(lookup_value, lookup_array, ZERO);
759
759
  }
760
760
 
761
761
  static ExcelValue find(ExcelValue find_text_v, ExcelValue within_text_v, ExcelValue start_number_v) {
@@ -843,12 +843,12 @@ static ExcelValue left(ExcelValue string_v, ExcelValue number_of_characters_v) {
843
843
  printf("Out of memory");
844
844
  exit(-1);
845
845
  }
846
- free_later(left_string);
847
846
  memcpy(left_string,string,number_of_characters);
848
847
  left_string[number_of_characters] = '\0';
849
848
  if(string_must_be_freed == 1) {
850
849
  free(string);
851
850
  }
851
+ free_later(left_string);
852
852
  return new_excel_string(left_string);
853
853
  }
854
854
 
@@ -1331,7 +1331,6 @@ static ExcelValue string_join(int number_of_arguments, ExcelValue *arguments) {
1331
1331
  printf("Out of memory");
1332
1332
  exit(-1);
1333
1333
  }
1334
- free_later(string);
1335
1334
  char *current_string;
1336
1335
  int current_string_length;
1337
1336
  int must_free_current_string;
@@ -1381,6 +1380,7 @@ static ExcelValue string_join(int number_of_arguments, ExcelValue *arguments) {
1381
1380
  }
1382
1381
  string = realloc(string,used_length+1);
1383
1382
  string[used_length] = '\0';
1383
+ free_later(string);
1384
1384
  return new_excel_string(string);
1385
1385
  }
1386
1386
 
@@ -1750,8 +1750,8 @@ static ExcelValue text(ExcelValue number_v, ExcelValue format_v) {
1750
1750
  if(strcmp(format_v.string,"0%") == 0) {
1751
1751
  // FIXME: Too little?
1752
1752
  s = malloc(100);
1753
- free_later(s);
1754
1753
  sprintf(s, "%d%%",(int) round(number_v.number*100));
1754
+ free_later(s);
1755
1755
  result = new_excel_string(s);
1756
1756
  } else {
1757
1757
  return format_v;
@@ -2283,6 +2283,10 @@ int test_functions() {
2283
2283
  assert(string_join(2, string_join_array_4).string[8] == '\0');
2284
2284
  // ... should convert TRUE and FALSE into strings
2285
2285
  assert(string_join(3,string_join_array_5).string[4] == 'T');
2286
+ // Should deal with very long string joins
2287
+ ExcelValue string_join_array_6[] = {new_excel_string("0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"), new_excel_string("012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789")};
2288
+ assert(string_join(2, string_join_array_6).string[0] == '0');
2289
+ free_all_allocated_memory();
2286
2290
 
2287
2291
  // Test SUBTOTAL function
2288
2292
  ExcelValue subtotal_array_1[] = {new_excel_number(10),new_excel_number(100),BLANK};
@@ -17,67 +17,67 @@ class MapFormulaeToC < MapValuesToC
17
17
  end
18
18
 
19
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
- 'CONCATENATE' => 'string_join',
35
- 'COSH' => 'cosh',
36
- 'COUNT' => 'count',
37
- 'COUNTA' => 'counta',
38
- 'FIND2' => 'find_2',
39
- 'FIND3' => 'find',
40
- 'HLOOKUP3' => 'hlookup_3',
41
- 'HLOOKUP4' => 'hlookup',
42
- 'IF2' => 'excel_if_2',
43
- 'IF3' => 'excel_if',
44
- 'IFERROR' => 'iferror',
45
- 'INDEX2' => 'excel_index_2',
46
- 'INDEX3' => 'excel_index',
47
- 'INT' => 'excel_int',
48
- 'ISNUMBER' => 'excel_isnumber',
49
- 'LARGE' => 'large',
50
- 'LEFT1' => 'left_1',
51
- 'LEFT2' => 'left',
52
- 'LOG1' => 'excel_log',
53
- 'LOG2' => 'excel_log_2',
54
- 'MATCH2' => 'excel_match_2',
55
- 'MATCH3' => 'excel_match',
56
- 'MAX' => 'max',
57
- 'MIN' => 'min',
58
- 'MMULT' => 'mmult',
59
- 'MOD' => 'mod',
60
- 'PMT' => 'pmt',
61
- 'PV3' => 'pv_3',
62
- 'PV4' => 'pv_4',
63
- 'PV5' => 'pv_5',
64
- 'RANK2' => 'rank_2',
65
- 'RANK3' => 'rank',
66
- 'ROUND' => 'excel_round',
67
- 'ROUNDDOWN' => 'rounddown',
68
- 'ROUNDUP' => 'roundup',
69
- 'string_join' => 'string_join',
70
- 'SUBTOTAL' => 'subtotal',
71
- 'SUM' => 'sum',
72
- 'SUMIF2' => 'sumif_2',
73
- 'SUMIF3' => 'sumif',
74
- 'SUMIFS' => 'sumifs',
75
- 'TEXT2' => 'text',
76
- 'SUMPRODUCT' => 'sumproduct',
77
- 'VLOOKUP3' => 'vlookup_3',
78
- 'VLOOKUP4' => 'vlookup',
79
- '^' => 'power',
80
- 'POWER' => 'power'
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
+ :'CONCATENATE' => 'string_join',
35
+ :'COSH' => 'cosh',
36
+ :'COUNT' => 'count',
37
+ :'COUNTA' => 'counta',
38
+ :'FIND2' => 'find_2',
39
+ :'FIND3' => 'find',
40
+ :'HLOOKUP3' => 'hlookup_3',
41
+ :'HLOOKUP4' => 'hlookup',
42
+ :'IF2' => 'excel_if_2',
43
+ :'IF3' => 'excel_if',
44
+ :'IFERROR' => 'iferror',
45
+ :'INDEX2' => 'excel_index_2',
46
+ :'INDEX3' => 'excel_index',
47
+ :'INT' => 'excel_int',
48
+ :'ISNUMBER' => 'excel_isnumber',
49
+ :'LARGE' => 'large',
50
+ :'LEFT1' => 'left_1',
51
+ :'LEFT2' => 'left',
52
+ :'LOG1' => 'excel_log',
53
+ :'LOG2' => 'excel_log_2',
54
+ :'MATCH2' => 'excel_match_2',
55
+ :'MATCH3' => 'excel_match',
56
+ :'MAX' => 'max',
57
+ :'MIN' => 'min',
58
+ :'MMULT' => 'mmult',
59
+ :'MOD' => 'mod',
60
+ :'PMT' => 'pmt',
61
+ :'PV3' => 'pv_3',
62
+ :'PV4' => 'pv_4',
63
+ :'PV5' => 'pv_5',
64
+ :'RANK2' => 'rank_2',
65
+ :'RANK3' => 'rank',
66
+ :'ROUND' => 'excel_round',
67
+ :'ROUNDDOWN' => 'rounddown',
68
+ :'ROUNDUP' => 'roundup',
69
+ :'string_join' => 'string_join',
70
+ :'SUBTOTAL' => 'subtotal',
71
+ :'SUM' => 'sum',
72
+ :'SUMIF2' => 'sumif_2',
73
+ :'SUMIF3' => 'sumif',
74
+ :'SUMIFS' => 'sumifs',
75
+ :'TEXT2' => 'text',
76
+ :'SUMPRODUCT' => 'sumproduct',
77
+ :'VLOOKUP3' => 'vlookup_3',
78
+ :'VLOOKUP4' => 'vlookup',
79
+ :'^' => 'power',
80
+ :'POWER' => 'power'
81
81
  }
82
82
 
83
83
  def prefix(symbol,ast)
@@ -103,19 +103,19 @@ class MapFormulaeToC < MapValuesToC
103
103
 
104
104
  def function(function_name,*arguments)
105
105
  # Some functions are special cases
106
- if self.respond_to?("function_#{function_name.downcase}")
107
- send("function_#{function_name.downcase}",*arguments)
106
+ if self.respond_to?("function_#{function_name.to_s.downcase}")
107
+ send("function_#{function_name.to_s.downcase}",*arguments)
108
108
  # Some arguments can take any number of arguments, which we need to treat separately
109
- elsif FUNCTIONS_WITH_ANY_NUMBER_OF_ARGUMENTS.include?(function_name)
109
+ elsif FUNCTIONS_WITH_ANY_NUMBER_OF_ARGUMENTS.include?(function_name.to_s)
110
110
  any_number_of_argument_function(function_name,arguments)
111
111
 
112
112
  # Check for whether this function has variants based on the number of arguments
113
- elsif FUNCTIONS.has_key?("#{function_name}#{arguments.size}")
114
- "#{FUNCTIONS["#{function_name}#{arguments.size}"]}(#{arguments.map { |a| map(a) }.join(",")})"
113
+ elsif FUNCTIONS.has_key?("#{function_name.to_s}#{arguments.size}".to_sym)
114
+ "#{FUNCTIONS["#{function_name.to_s}#{arguments.size}".to_sym]}(#{arguments.map { |a| map(a) }.join(",")})"
115
115
 
116
116
  # Then check for whether it is just a standard type
117
- elsif FUNCTIONS.has_key?(function_name)
118
- "#{FUNCTIONS[function_name]}(#{arguments.map { |a| map(a) }.join(",")})"
117
+ elsif FUNCTIONS.has_key?(function_name.to_sym)
118
+ "#{FUNCTIONS[function_name.to_sym]}(#{arguments.map { |a| map(a) }.join(",")})"
119
119
 
120
120
  else
121
121
  raise NotSupportedException.new("Function #{function_name} with #{arguments.size} arguments not supported")
@@ -129,20 +129,20 @@ class MapFormulaeToC < MapValuesToC
129
129
  end
130
130
 
131
131
  def function_choose(index,*arguments)
132
- "#{FUNCTIONS["CHOOSE"]}(#{map(index)}, #{map_arguments_to_array(arguments)})"
132
+ "#{FUNCTIONS[:CHOOSE]}(#{map(index)}, #{map_arguments_to_array(arguments)})"
133
133
  end
134
134
 
135
135
  def function_subtotal(type,*arguments)
136
- "#{FUNCTIONS["SUBTOTAL"]}(#{map(type)}, #{map_arguments_to_array(arguments)})"
136
+ "#{FUNCTIONS[:SUBTOTAL]}(#{map(type)}, #{map_arguments_to_array(arguments)})"
137
137
  end
138
138
 
139
139
  def function_sumifs(sum_range,*criteria)
140
- "#{FUNCTIONS["SUMIFS"]}(#{map(sum_range)}, #{map_arguments_to_array(criteria)})"
140
+ "#{FUNCTIONS[:SUMIFS]}(#{map(sum_range)}, #{map_arguments_to_array(criteria)})"
141
141
  end
142
142
 
143
143
 
144
144
  def any_number_of_argument_function(function_name,arguments)
145
- "#{FUNCTIONS[function_name]}(#{map_arguments_to_array(arguments)})"
145
+ "#{FUNCTIONS[function_name.to_sym]}(#{map_arguments_to_array(arguments)})"
146
146
  end
147
147
 
148
148
  def map_arguments_to_array(arguments)
@@ -158,35 +158,34 @@ class MapFormulaeToC < MapValuesToC
158
158
  def cell(reference)
159
159
  # FIXME: What a cludge.
160
160
  if reference =~ /common\d+/
161
- "_#{reference}()"
161
+ "#{reference}()"
162
162
  else
163
- reference.downcase.gsub('$','')
163
+ reference.to_s.downcase.gsub('$','')
164
164
  end
165
165
  end
166
166
 
167
167
  def sheet_reference(sheet,reference)
168
- "#{sheet_names[sheet]}_#{map(reference).downcase}()"
168
+ "#{sheet_names[sheet]}_#{map(reference).to_s.downcase}()"
169
169
  end
170
170
 
171
171
  def array(*rows)
172
172
  # Make sure we get the right dimensions
173
173
  number_of_rows = rows.size
174
- number_of_columns = rows.max { |r| r.size }.size - 1
175
-
174
+ number_of_columns = rows[0].size - 1
175
+ size = number_of_rows * number_of_columns
176
+
176
177
  # First we have to create an excel array
177
178
  array_name = "array#{@counter}"
178
179
  @counter +=1
179
180
 
180
- cells = rows.map do |r|
181
- r.shift if r.first == :row
182
- r.map do |c|
183
- map(c)
181
+ initializers << "static ExcelValue #{array_name}[#{size}];"
182
+ i = 0
183
+ rows.each do |row|
184
+ row.each do |cell|
185
+ next if cell.is_a?(Symbol)
186
+ initializers << "#{array_name}[#{i}] = #{map(cell)};"
187
+ i += 1
184
188
  end
185
- end.flatten
186
-
187
- initializers << "static ExcelValue #{array_name}[#{cells.size}];"
188
- cells.each_with_index do |c,i|
189
- initializers << "#{array_name}[#{i}] = #{c};"
190
189
  end
191
190
 
192
191
  # Then we need to assign it to an excel value
@@ -66,7 +66,13 @@ class MapValuesToC
66
66
  "#DIV/0!" => "DIV0",
67
67
  "#REF!" => "REF",
68
68
  "#N/A" => "NA",
69
- "#NUM!" => "NUM"
69
+ "#NUM!" => "NUM",
70
+ :"#NAME?" => "NAME",
71
+ :"#VALUE!" => "VALUE",
72
+ :"#DIV/0!" => "DIV0",
73
+ :"#REF!" => "REF",
74
+ :"#N/A" => "NA",
75
+ :"#NUM!" => "NUM"
70
76
  }
71
77
 
72
78
  REVERSE_ERRORS = ERRORS.invert