excel_to_code 0.2.17 → 0.2.18

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: dcc23d2c3bc1b795812df13662b81933f5c7f063
4
- data.tar.gz: d62a97bca9808a673114f2169aeaa9e129a681fd
3
+ metadata.gz: 337fc100f3818bf193414bcd8fb3aaec557e1a6b
4
+ data.tar.gz: 34218ff7c787a63a1e0081b688ff328d1235316e
5
5
  SHA512:
6
- metadata.gz: f3d4e6502be8a144b705bdc4848b174fca86136f8e59d96b1cbc1e70605ec96e6034542f336fff212df4fd818e63ad841567285d95e0569443d68dd5f1e5fbed
7
- data.tar.gz: ef7aac9705e55a267e129a160a29614f1d24926fec23b4686e8eecca0d5c82a51ab8c91d8f3fdb68aee42de2686c86a075ca14403f43b6021f3fcb09bab5a751
6
+ metadata.gz: 10b5b04a5fe6ae0b5df092a010b5cbf0cad48025db71b99350da7a040e2992c5301c08f23652040b4eb340fcb2f064aa7bae7c02b765c53c8849e11480a66a71
7
+ data.tar.gz: 3ec3fbfbad7b341990559ae40d121dfdbd46839aa3f92f5a1b41b58ce597e43606d91de146bc940d5976b682320b593925bea0619463f9e183b98800f0b15a5c
@@ -838,6 +838,7 @@ class ExcelToX
838
838
  @replace_arrays_with_single_cells_replacer ||= ReplaceArraysWithSingleCellsAst.new
839
839
  @replace_string_joins_on_ranges_replacer ||= ReplaceStringJoinOnRangesAST.new
840
840
  @sheetless_cell_reference_replacer ||= RewriteCellReferencesToIncludeSheetAst.new
841
+ @replace_references_to_blanks_with_zeros ||= ReplaceReferencesToBlanksWithZeros.new(@formulae, nil, inline_ast_decision)
841
842
 
842
843
  cells.each do |ref, ast|
843
844
  begin
@@ -858,6 +859,8 @@ class ExcelToX
858
859
  @replace_arithmetic_on_ranges_replacer.map(ast)
859
860
  @replace_string_joins_on_ranges_replacer.map(ast)
860
861
  @wrap_formulae_that_return_arrays_replacer.map(ast)
862
+ @replace_references_to_blanks_with_zeros.current_sheet_name = ref.first
863
+ @replace_references_to_blanks_with_zeros.map(ast)
861
864
  rescue Exception => e
862
865
  log.fatal "Exception when simplifying #{ref}: #{ast}"
863
866
  raise
data/src/compile/c/a.out CHANGED
Binary file
@@ -100,6 +100,7 @@ static ExcelValue sumif(ExcelValue check_range_v, ExcelValue criteria_v, ExcelVa
100
100
  static ExcelValue sumif_2(ExcelValue check_range_v, ExcelValue criteria_v);
101
101
  static ExcelValue sumproduct(int number_of_arguments, ExcelValue *arguments);
102
102
  static ExcelValue text(ExcelValue number_v, ExcelValue format_v);
103
+ static ExcelValue value(ExcelValue string_v);
103
104
  static ExcelValue vlookup_3(ExcelValue lookup_value_v,ExcelValue lookup_table_v, ExcelValue column_number_v);
104
105
  static ExcelValue vlookup(ExcelValue lookup_value_v,ExcelValue lookup_table_v, ExcelValue column_number_v, ExcelValue match_type_v);
105
106
 
@@ -1716,6 +1717,11 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
1716
1717
  value_to_be_checked = ((ExcelValue *) ((ExcelValue) criteria_range[i]).array)[j];
1717
1718
  comparison = criteria[i];
1718
1719
  comparator = comparison.comparator;
1720
+
1721
+ // For the purposes of comparison, treates a blank criteria as matching zeros.
1722
+ if(comparator.type == ExcelEmpty) {
1723
+ comparator = ZERO;
1724
+ }
1719
1725
 
1720
1726
  switch(value_to_be_checked.type) {
1721
1727
  case ExcelError: // Errors match only errors
@@ -1737,7 +1743,6 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
1737
1743
  if(strlen(comparator.string) != 0) passed = 0; // Empty strings match blanks.
1738
1744
  break;
1739
1745
  }
1740
- break;
1741
1746
  case ExcelNumber:
1742
1747
  if(comparator.type == ExcelNumber) {
1743
1748
  number = comparator.number;
@@ -1781,6 +1786,13 @@ static ExcelValue filter_range(ExcelValue original_range_v, int number_of_argume
1781
1786
  passed = 0;
1782
1787
  break;
1783
1788
  }
1789
+
1790
+ // Special case, empty strings don't match zeros here
1791
+ if(strlen(value_to_be_checked.string) == 0) {
1792
+ passed = 0;
1793
+ break;
1794
+ }
1795
+
1784
1796
  number = number_from(value_to_be_checked);
1785
1797
  if(conversion_error == 1) {
1786
1798
  conversion_error = 0;
@@ -2080,3 +2092,11 @@ static ExcelValue hlookup(ExcelValue lookup_value_v,ExcelValue lookup_table_v, E
2080
2092
  }
2081
2093
  return NA;
2082
2094
  }
2095
+
2096
+
2097
+ static ExcelValue value(ExcelValue string_v) {
2098
+ CHECK_FOR_PASSED_ERROR(string_v)
2099
+ NUMBER(string_v, a)
2100
+ CHECK_FOR_CONVERSION_ERROR
2101
+ return new_excel_number(a);
2102
+ }
@@ -492,16 +492,25 @@ int test_functions() {
492
492
  ExcelValue sumifs_array_10f[] = { sumifs_array_3_v, new_excel_string(">=3")};
493
493
  assert(sumifs(sumifs_array_3_v,2, sumifs_array_10f).number == 17);
494
494
 
495
- // ... should treat BLANK as an empty string when in the check_range, but not in the criteria
496
- ExcelValue sumifs_array_11[] = { BLANK, new_excel_number(20)};
495
+ // ... BLANK in check range should match empty strings, BLANK in criteria should match zero
496
+ ExcelValue sumifs_array_11[] = { BLANK, new_excel_number(0)};
497
497
  assert(sumifs(new_excel_number(100),2,sumifs_array_11).number == 0);
498
498
 
499
- ExcelValue sumifs_array_12[] = {BLANK, new_excel_string("")};
499
+ ExcelValue sumifs_array_11b[] = { BLANK, new_excel_string("")};
500
+ assert(sumifs(new_excel_number(100),2,sumifs_array_11b).number == 100);
501
+
502
+ ExcelValue sumifs_array_11c[] = { new_excel_string(""), BLANK};
503
+ assert(sumifs(new_excel_number(100),2,sumifs_array_11c).number == 0);
504
+
505
+ ExcelValue sumifs_array_12[] = {new_excel_number(0), BLANK};
500
506
  assert(sumifs(new_excel_number(100),2,sumifs_array_12).number == 100);
501
507
 
502
508
  ExcelValue sumifs_array_13[] = {BLANK, BLANK};
503
509
  assert(sumifs(new_excel_number(100),2,sumifs_array_13).number == 0);
504
510
 
511
+ ExcelValue sumifs_array_14[] = {new_excel_number(10), BLANK};
512
+ assert(sumifs(new_excel_number(100),2,sumifs_array_14).number == 0);
513
+
505
514
  // ... should return an error if range argument is an error
506
515
  assert(sumifs(REF,2,sumifs_array_13).type == ExcelError);
507
516
 
@@ -817,7 +826,7 @@ int test_functions() {
817
826
  ExcelValue averageifs_array_11[] = { BLANK, new_excel_number(20)};
818
827
  assert(averageifs(new_excel_number(100),2,averageifs_array_11).type == ExcelError);
819
828
 
820
- ExcelValue averageifs_array_12[] = {BLANK, new_excel_string("")};
829
+ ExcelValue averageifs_array_12[] = {new_excel_number(0), BLANK};
821
830
  assert(averageifs(new_excel_number(100),2,averageifs_array_12).number == 100);
822
831
 
823
832
  ExcelValue averageifs_array_13[] = {BLANK, BLANK};
@@ -881,6 +890,16 @@ int test_functions() {
881
890
  assert(len(TRUE).number == 4);
882
891
  assert(len(FALSE).number == 5);
883
892
 
893
+
894
+ // VALUE(something)
895
+ assert(value(BLANK).type == ExcelNumber);
896
+ assert(value(BLANK).number == 0);
897
+ assert(value(ONE).type == ExcelNumber);
898
+ assert(value(ONE).number == 1);
899
+ assert(value(new_excel_string("1")).type == ExcelNumber);
900
+ assert(value(new_excel_string("1")).number == 1);
901
+ assert(value(new_excel_string("A1A")).type == ExcelError);
902
+
884
903
  // Release memory
885
904
  free_all_allocated_memory();
886
905
 
@@ -82,6 +82,7 @@ class MapFormulaeToC < MapValuesToC
82
82
  :'SUMIFS' => 'sumifs',
83
83
  :'TEXT2' => 'text',
84
84
  :'SUMPRODUCT' => 'sumproduct',
85
+ :'VALUE' => 'value',
85
86
  :'VLOOKUP3' => 'vlookup_3',
86
87
  :'VLOOKUP4' => 'vlookup',
87
88
  :'^' => 'power',
@@ -65,6 +65,7 @@ class MapFormulaeToRuby < MapValuesToRuby
65
65
  :'SUMPRODUCT' => 'sumproduct',
66
66
  :'TEXT' => 'text',
67
67
  :'TRIM' => 'trim',
68
+ :'VALUE' => 'value',
68
69
  :'VLOOKUP' => 'vlookup',
69
70
  :'^' => 'power'
70
71
  }
@@ -106,3 +106,5 @@ require_relative 'excel_functions/averageifs'
106
106
  require_relative 'excel_functions/forecast'
107
107
 
108
108
  require_relative 'excel_functions/ensure_is_number'
109
+
110
+ require_relative 'excel_functions/value'
@@ -31,10 +31,10 @@ module ExcelFunctions
31
31
 
32
32
  0.step(criteria.length-1,2).each do |i|
33
33
  check_range = criteria[i]
34
- required_value = criteria[i+1]
34
+ required_value = criteria[i+1] || 0
35
35
  return :value if index >= check_range.length
36
36
  check_value = check_range[index]
37
-
37
+
38
38
  pass = case check_value
39
39
  when String
40
40
  check_value.downcase == required_value.to_s.downcase
@@ -0,0 +1,7 @@
1
+ module ExcelFunctions
2
+
3
+ def value(a)
4
+ number_argument(a)
5
+ end
6
+
7
+ end
@@ -159,7 +159,7 @@ class Formula < RubyPeg
159
159
 
160
160
  def sheet_reference
161
161
  node :sheet_reference do
162
- (single_quoted_string || terminal(/[\p{word}][\p{word}_.]+/)) && ignore { terminal("!") } && (sheetless_reference || named_reference)
162
+ (single_quoted_string || terminal(/[\p{word}][\p{word}_.]+/)) && ignore { terminal("!") } && (sheetless_reference || error || named_reference)
163
163
  end
164
164
  end
165
165
 
@@ -27,7 +27,7 @@ complex_structured_reference = /\[[^\u005d]*\],\[[^\u005d]*\]/
27
27
  overly_structured_reference = `'[' simple_structured_reference `']'
28
28
  simple_structured_reference = /[^\u005d]*/
29
29
  named_reference := /[#\p{word}][\p{word}_.!]+/
30
- sheet_reference := (single_quoted_string | /[\p{word}][\p{word}_.]+/) `'!' (sheetless_reference | named_reference)
30
+ sheet_reference := (single_quoted_string | /[\p{word}][\p{word}_.]+/) `'!' (sheetless_reference | error | named_reference)
31
31
  single_quoted_string = `"'" /[^']*/ `"'"
32
32
  sheetless_reference = column_range | row_range | area | cell
33
33
  column_range := column `':' column
data/src/excel_to_code.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  class ExcelToCode
2
- def self.version() "0.2.17" end
2
+ def self.version() "0.2.18" end
3
3
  end
4
4
 
5
5
  require_relative 'commands'
@@ -64,7 +64,13 @@ class CachingFormulaParser
64
64
  def sheet_reference(ast)
65
65
  ast[1] = ast[1].to_sym
66
66
  ast[2] = map(ast[2])
67
- @sheet_reference_cache[ast] ||= ast
67
+ # We do this to deal with Control!#REF! style rerferences
68
+ # that occasionally pop up in named references
69
+ if ast[2].first == :error
70
+ return ast[2]
71
+ else
72
+ @sheet_reference_cache[ast] ||= ast
73
+ end
68
74
  end
69
75
 
70
76
  def cell(ast)
data/src/simplify.rb CHANGED
@@ -21,3 +21,4 @@ require_relative "simplify/wrap_formulae_that_return_arrays_and_are_not_in_array
21
21
  require_relative "simplify/replace_string_join_on_ranges"
22
22
  require_relative "simplify/emergency_array_formula_replace_indirect_bodge.rb"
23
23
  require_relative "simplify/replace_transpose_function"
24
+ require_relative "simplify/replace_references_to_blanks_with_zeros"
@@ -2,8 +2,6 @@ module BlankCell; end
2
2
 
3
3
  class InlineFormulaeAst
4
4
 
5
- BLANK = [:inlined_blank]
6
-
7
5
  attr_accessor :references, :current_sheet_name, :inline_ast
8
6
  attr_accessor :count_replaced
9
7
 
@@ -48,10 +46,9 @@ class InlineFormulaeAst
48
46
  ref = ast[2][1].to_s.upcase.gsub('$','').to_sym
49
47
  # FIXME: Need to check if valid worksheet and return [:error, "#REF!"] if not
50
48
  # Now check user preference on this
49
+ ast_to_inline = ast_to_inline(sheet, ref)
51
50
  return unless inline_ast.call(sheet,ref, references)
52
51
  @count_replaced += 1
53
- ast_to_inline = references[[sheet, ref]]
54
- return ast.replace(BLANK) unless ast_to_inline
55
52
  current_sheet_name.push(sheet)
56
53
  map(ast_to_inline)
57
54
  current_sheet_name.pop
@@ -62,10 +59,9 @@ class InlineFormulaeAst
62
59
  def cell(ast)
63
60
  sheet = current_sheet_name.last
64
61
  ref = ast[1].to_s.upcase.gsub('$', '').to_sym
62
+ ast_to_inline = ast_to_inline(sheet, ref)
65
63
  if inline_ast.call(sheet, ref, references)
66
64
  @count_replaced += 1
67
- ast_to_inline = references[[sheet, ref]]
68
- return ast.replace(BLANK) unless ast_to_inline
69
65
  map(ast_to_inline)
70
66
  ast.replace(ast_to_inline)
71
67
  # FIXME: Check - is this right? does it work recursively enough?
@@ -73,6 +69,14 @@ class InlineFormulaeAst
73
69
  ast.replace([:sheet_reference, sheet, ast.dup])
74
70
  end
75
71
  end
72
+
73
+ def ast_to_inline(sheet, ref)
74
+ ast_to_inline = references[[sheet, ref]]
75
+ return ast_to_inline if ast_to_inline
76
+ # Need to add a new blank cell and return ast for an inlined blank
77
+ references[[sheet, ref]] = [:blank]
78
+ [:inlined_blank]
79
+ end
76
80
 
77
81
  end
78
82
 
@@ -0,0 +1,43 @@
1
+ class ReplaceReferencesToBlanksWithZeros
2
+
3
+ attr_accessor :references, :current_sheet_name, :inline_ast
4
+ attr_accessor :count_replaced
5
+
6
+ def initialize(references = nil, current_sheet_name = nil, inline_ast = nil)
7
+ @references, @current_sheet_name, @inline_ast = references, [current_sheet_name], inline_ast
8
+ @count_replaced = 0
9
+ @inline_ast ||= lambda { |sheet, ref, references| true } # Default is to always inline
10
+ end
11
+
12
+ def map(ast)
13
+ return ast unless ast.is_a?(Array)
14
+
15
+ sheet = nil
16
+ ref = nil
17
+
18
+ case ast.first
19
+ when :sheet_reference
20
+ return ast unless ast[2][0] == :cell
21
+ sheet = ast[1].to_sym
22
+ ref = ast[2][1].to_s.upcase.gsub('$','').to_sym
23
+ when :cell
24
+ sheet = current_sheet_name.last
25
+ ref = ast[1].to_s.upcase.gsub('$', '').to_sym
26
+ else
27
+ # We aren't interested
28
+ return ast
29
+ end
30
+
31
+ ast_to_inline = references[[sheet, ref]] || [:blank]
32
+
33
+ return ast unless ast_to_inline == [:blank]
34
+
35
+ if inline_ast.call(sheet, ref, references)
36
+ ast.replace([:number, 0])
37
+ else
38
+ reference = [:sheet_reference, sheet, [:cell, ref]]
39
+ ast.replace([:function, :IF, [:function, :ISBLANK, reference], [:number, 0], reference])
40
+ end
41
+ ast
42
+ end
43
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: excel_to_code
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.17
4
+ version: 0.2.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Counsell, Green on Black Ltd
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-11 00:00:00.000000000 Z
11
+ date: 2014-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubypeg
@@ -199,6 +199,7 @@ files:
199
199
  - src/excel/excel_functions/sumproduct.rb
200
200
  - src/excel/excel_functions/text.rb
201
201
  - src/excel/excel_functions/trim.rb
202
+ - src/excel/excel_functions/value.rb
202
203
  - src/excel/excel_functions/vlookup.rb
203
204
  - src/excel/formula_peg.rb
204
205
  - src/excel/formula_peg.txt
@@ -244,6 +245,7 @@ files:
244
245
  - src/simplify/replace_named_references.rb
245
246
  - src/simplify/replace_offsets_with_references.rb
246
247
  - src/simplify/replace_ranges_with_array_literals.rb
248
+ - src/simplify/replace_references_to_blanks_with_zeros.rb
247
249
  - src/simplify/replace_shared_strings.rb
248
250
  - src/simplify/replace_string_join_on_ranges.rb
249
251
  - src/simplify/replace_table_references.rb