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 +4 -4
- data/src/commands/excel_to_x.rb +3 -0
- data/src/compile/c/a.out +0 -0
- data/src/compile/c/excel_to_c_runtime.c +21 -1
- data/src/compile/c/excel_to_c_runtime_test.c +23 -4
- data/src/compile/c/map_formulae_to_c.rb +1 -0
- data/src/compile/ruby/map_formulae_to_ruby.rb +1 -0
- data/src/excel/excel_functions.rb +2 -0
- data/src/excel/excel_functions/sumifs.rb +2 -2
- data/src/excel/excel_functions/value.rb +7 -0
- data/src/excel/formula_peg.rb +1 -1
- data/src/excel/formula_peg.txt +1 -1
- data/src/excel_to_code.rb +1 -1
- data/src/rewrite/caching_formula_parser.rb +7 -1
- data/src/simplify.rb +1 -0
- data/src/simplify/inline_formulae.rb +10 -6
- data/src/simplify/replace_references_to_blanks_with_zeros.rb +43 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 337fc100f3818bf193414bcd8fb3aaec557e1a6b
|
4
|
+
data.tar.gz: 34218ff7c787a63a1e0081b688ff328d1235316e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10b5b04a5fe6ae0b5df092a010b5cbf0cad48025db71b99350da7a040e2992c5301c08f23652040b4eb340fcb2f064aa7bae7c02b765c53c8849e11480a66a71
|
7
|
+
data.tar.gz: 3ec3fbfbad7b341990559ae40d121dfdbd46839aa3f92f5a1b41b58ce597e43606d91de146bc940d5976b682320b593925bea0619463f9e183b98800f0b15a5c
|
data/src/commands/excel_to_x.rb
CHANGED
@@ -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
|
-
// ...
|
496
|
-
ExcelValue sumifs_array_11[] = { BLANK, new_excel_number(
|
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
|
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[] = {
|
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
|
|
@@ -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
|
data/src/excel/formula_peg.rb
CHANGED
@@ -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
|
|
data/src/excel/formula_peg.txt
CHANGED
@@ -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
@@ -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
|
-
|
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.
|
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
|
+
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
|