excel_to_code 0.3.15 → 0.3.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/src/commands/excel_to_x.rb +4 -1
- data/src/compile/c/a.out +0 -0
- data/src/compile/c/a.out.dSYM/Contents/Resources/DWARF/a.out +0 -0
- data/src/compile/c/excel_to_c_runtime.c +25 -0
- data/src/compile/c/excel_to_c_runtime_test.c +2 -0
- data/src/compile/c/map_formulae_to_c.rb +3 -1
- data/src/compile/ruby/compile_to_ruby_unit_test.rb +2 -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/address.rb +57 -0
- data/src/excel/excel_functions/pmt.rb +11 -2
- data/src/excel/formula_peg.rb +1 -1
- data/src/excel/formula_peg.txt +1 -1
- data/src/excel/reference.rb +4 -0
- data/src/excel_to_code.rb +1 -1
- data/src/extract/extract_data_from_worksheet.rb +3 -3
- data/src/extract/extract_shared_strings.rb +1 -1
- data/src/rewrite/caching_formula_parser.rb +29 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 17eac22412740a67afd06333f437ce950c03c32d
|
4
|
+
data.tar.gz: 1117fdcb2343478712dc0a72649c429d1b9dc8dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5023ee51c9f7a3909c7768ca58da98c368e3bec955a50e67c33df96387e2052e8c3c734f062c894b9102629509582232c7c08d62fd21b9fe718d1f678d6558fa
|
7
|
+
data.tar.gz: e34fd8293696f90562080eeb0f07db35a131d4132883baf62a5edf57f2fa37e36a699a16d355899e27c65c0a13dc262e143e30917593aed1a358868cc6108783
|
data/src/commands/excel_to_x.rb
CHANGED
@@ -917,6 +917,8 @@ class ExcelToX
|
|
917
917
|
@sheetless_cell_reference_replacer ||= RewriteCellReferencesToIncludeSheetAst.new
|
918
918
|
@replace_references_to_blanks_with_zeros ||= ReplaceReferencesToBlanksWithZeros.new(@formulae, nil, inline_ast_decision)
|
919
919
|
@fix_subtotal_of_subtotals ||= FixSubtotalOfSubtotals.new(@formulae)
|
920
|
+
# FIXME: Bodge to put it here as well, but seems to be required
|
921
|
+
column_and_row_function_replacement = ReplaceColumnAndRowFunctionsAST.new
|
920
922
|
|
921
923
|
#require 'pry'; binding.pry
|
922
924
|
|
@@ -939,6 +941,8 @@ class ExcelToX
|
|
939
941
|
@replace_arithmetic_on_ranges_replacer.map(ast)
|
940
942
|
@replace_string_joins_on_ranges_replacer.map(ast)
|
941
943
|
@wrap_formulae_that_return_arrays_replacer.map(ast)
|
944
|
+
column_and_row_function_replacement.current_reference = ref.last
|
945
|
+
column_and_row_function_replacement.replace(ast)
|
942
946
|
@replace_references_to_blanks_with_zeros.current_sheet_name = ref.first
|
943
947
|
@replace_references_to_blanks_with_zeros.map(ast)
|
944
948
|
@fix_subtotal_of_subtotals.map(ast)
|
@@ -947,7 +951,6 @@ class ExcelToX
|
|
947
951
|
raise
|
948
952
|
end
|
949
953
|
end
|
950
|
-
#require 'pry'; binding.pry
|
951
954
|
end
|
952
955
|
|
953
956
|
# These types of cells don't conatain formulae and can therefore be skipped
|
data/src/compile/c/a.out
CHANGED
Binary file
|
Binary file
|
@@ -87,6 +87,8 @@ static ExcelValue mod(ExcelValue a_v, ExcelValue b_v);
|
|
87
87
|
static ExcelValue negative(ExcelValue a_v);
|
88
88
|
static ExcelValue npv(ExcelValue rate, int number_of_arguments, ExcelValue *arguments);
|
89
89
|
static ExcelValue pmt(ExcelValue rate_v, ExcelValue number_of_periods_v, ExcelValue present_value_v);
|
90
|
+
static ExcelValue pmt_4(ExcelValue rate_v, ExcelValue number_of_periods_v, ExcelValue present_value_v, ExcelValue final_value_v);
|
91
|
+
static ExcelValue pmt_5(ExcelValue rate_v, ExcelValue number_of_periods_v, ExcelValue present_value_v, ExcelValue final_value_v, ExcelValue type_v);
|
90
92
|
static ExcelValue power(ExcelValue a_v, ExcelValue b_v);
|
91
93
|
static ExcelValue pv_3(ExcelValue a_v, ExcelValue b_v, ExcelValue c_v);
|
92
94
|
static ExcelValue pv_4(ExcelValue a_v, ExcelValue b_v, ExcelValue c_v, ExcelValue d_v);
|
@@ -1527,6 +1529,29 @@ static ExcelValue pmt(ExcelValue rate_v, ExcelValue number_of_periods_v, ExcelVa
|
|
1527
1529
|
return EXCEL_NUMBER(-present_value*(rate*(pow((1+rate),number_of_periods)))/((pow((1+rate),number_of_periods))-1));
|
1528
1530
|
}
|
1529
1531
|
|
1532
|
+
static ExcelValue pmt_4(ExcelValue rate_v, ExcelValue number_of_periods_v, ExcelValue present_value_v, ExcelValue final_value_v) {
|
1533
|
+
CHECK_FOR_PASSED_ERROR(final_value_v)
|
1534
|
+
|
1535
|
+
NUMBER(final_value_v, final_value)
|
1536
|
+
CHECK_FOR_CONVERSION_ERROR
|
1537
|
+
|
1538
|
+
if(final_value == 0) return pmt(rate_v, number_of_periods_v, present_value_v);
|
1539
|
+
printf("PMT with non-zero final_value not implemented. halting.");
|
1540
|
+
exit(-1);
|
1541
|
+
}
|
1542
|
+
|
1543
|
+
static ExcelValue pmt_5(ExcelValue rate_v, ExcelValue number_of_periods_v, ExcelValue present_value_v, ExcelValue final_value_v, ExcelValue type_v) {
|
1544
|
+
CHECK_FOR_PASSED_ERROR(type_v)
|
1545
|
+
|
1546
|
+
NUMBER(type_v, type)
|
1547
|
+
CHECK_FOR_CONVERSION_ERROR
|
1548
|
+
|
1549
|
+
if(type == 0) return pmt(rate_v, number_of_periods_v, present_value_v);
|
1550
|
+
printf("PMT with non-zero type not implemented. halting.");
|
1551
|
+
exit(-1);
|
1552
|
+
}
|
1553
|
+
|
1554
|
+
|
1530
1555
|
static ExcelValue pv_3(ExcelValue rate_v, ExcelValue nper_v, ExcelValue pmt_v) {
|
1531
1556
|
return pv_4(rate_v, nper_v, pmt_v, ZERO);
|
1532
1557
|
}
|
@@ -425,6 +425,8 @@ int test_functions() {
|
|
425
425
|
assert((pmt(EXCEL_NUMBER(0.1),EXCEL_NUMBER(10),EXCEL_NUMBER(100)).number - -16.27) < 0.01);
|
426
426
|
assert((pmt(EXCEL_NUMBER(0.0123),EXCEL_NUMBER(99.1),EXCEL_NUMBER(123.32)).number - -2.159) < 0.01);
|
427
427
|
assert((pmt(EXCEL_NUMBER(0),EXCEL_NUMBER(2),EXCEL_NUMBER(10)).number - -5) < 0.01);
|
428
|
+
assert((pmt_4(EXCEL_NUMBER(0),EXCEL_NUMBER(2),EXCEL_NUMBER(10), EXCEL_NUMBER(0)).number - -5) < 0.01);
|
429
|
+
assert((pmt_5(EXCEL_NUMBER(0),EXCEL_NUMBER(2),EXCEL_NUMBER(10), EXCEL_NUMBER(0), EXCEL_NUMBER(0)).number - -5) < 0.01);
|
428
430
|
|
429
431
|
// Test power
|
430
432
|
// ... should return power of its arguments
|
@@ -37,6 +37,8 @@ class CompileToRubyUnitTest
|
|
37
37
|
else
|
38
38
|
o.puts " def #{test_name}; assert_equal(#{value}, #{full_reference}); end"
|
39
39
|
end
|
40
|
+
when :string
|
41
|
+
o.puts " def #{test_name}; assert_equal(#{value.gsub(/(\\n|\\r|\r|\n)+/,'')}, #{full_reference}.to_s.gsub(/[\\n\\r]+/,'')); end"
|
40
42
|
when :number
|
41
43
|
if sloppy
|
42
44
|
if value.to_f.abs <= 1
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module ExcelFunctions
|
2
|
+
|
3
|
+
# ADDRESS(row_num,column_num,abs_num,a1,sheet_text)
|
4
|
+
# row_num
|
5
|
+
# The row number to use in the cell reference.
|
6
|
+
# column_num
|
7
|
+
# The column number to use in the cell reference.
|
8
|
+
# abs_num
|
9
|
+
# Specifies the type of reference to return.
|
10
|
+
# 1 or omitted returns the following type of reference: absolute.
|
11
|
+
# 2 returns the following type of reference: absolute row; relative column.
|
12
|
+
# 3 returns the following type of reference: relative row; absolute column.
|
13
|
+
# 4 returns the following type of reference: relative.
|
14
|
+
# a1
|
15
|
+
# A logical value that specifies the A1 or R1C1 reference style.
|
16
|
+
# If a1 is TRUE or omitted, ADDRESS returns an A1-style reference.
|
17
|
+
# If a1 is FALSE, ADDRESS returns an R1C1-style reference.
|
18
|
+
# sheet_text
|
19
|
+
# Text specifying the name of the sheet to be used as the external reference.
|
20
|
+
# If sheet_text is omitted, no sheet name is used.
|
21
|
+
def address(row_num, column_num, abs_num = 1, a1 = true, sheet_text = nil)
|
22
|
+
raise NotSupportedException.new("address() function R1C1 references not implemented") if a1 == false
|
23
|
+
|
24
|
+
return row_num if row_num.is_a?(Symbol)
|
25
|
+
return column_num if column_num.is_a?(Symbol)
|
26
|
+
return abs_num if abs_num.is_a?(Symbol)
|
27
|
+
return a1 if a1.is_a?(Symbol)
|
28
|
+
return sheet_text if sheet_text.is_a?(Symbol)
|
29
|
+
|
30
|
+
row_num = number_argument(row_num)
|
31
|
+
column_num = number_argument(column_num)
|
32
|
+
abs_num = number_argument(abs_num)
|
33
|
+
|
34
|
+
return :value if row_num < 1
|
35
|
+
return :value if column_num < 1
|
36
|
+
return :value if abs_num < 1
|
37
|
+
return :value if abs_num > 4
|
38
|
+
|
39
|
+
row = row_num.to_i.to_s
|
40
|
+
column = Reference.column_letters_for_column_number[column_num.to_i].to_s
|
41
|
+
|
42
|
+
ref = case abs_num
|
43
|
+
when 1; "$"+column+"$"+row
|
44
|
+
when 2; "" +column+"$" +row
|
45
|
+
when 3; "$"+column+"" +row
|
46
|
+
when 4; ""+column+"" +row
|
47
|
+
end
|
48
|
+
|
49
|
+
if sheet_text
|
50
|
+
ref = "'#{sheet_text}'!"+ref
|
51
|
+
end
|
52
|
+
|
53
|
+
ref
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -1,14 +1,23 @@
|
|
1
1
|
module ExcelFunctions
|
2
2
|
|
3
|
-
def pmt(rate,number_of_periods,present_value)
|
3
|
+
def pmt(rate,number_of_periods,present_value, final_value = 0, type = 0)
|
4
|
+
|
4
5
|
rate = number_argument(rate)
|
5
6
|
number_of_periods = number_argument(number_of_periods)
|
6
7
|
present_value = number_argument(present_value)
|
7
|
-
|
8
|
+
final_value = number_argument(final_value)
|
9
|
+
type = number_argument(type)
|
10
|
+
|
8
11
|
return rate if rate.is_a?(Symbol)
|
9
12
|
return number_of_periods if number_of_periods.is_a?(Symbol)
|
10
13
|
return present_value if present_value.is_a?(Symbol)
|
14
|
+
return final_value if final_value.is_a?(Symbol)
|
15
|
+
return type if type.is_a?(Symbol)
|
16
|
+
|
11
17
|
return :num if number_of_periods == 0
|
18
|
+
|
19
|
+
raise NotSupportedException.new("pmt() function non zero final value not implemented") unless final_value == 0
|
20
|
+
raise NotSupportedException.new("pmt() function non zero type not implemented") unless type == 0
|
12
21
|
|
13
22
|
return -(present_value / number_of_periods) if rate == 0
|
14
23
|
-present_value*(rate*((1+rate)**number_of_periods))/(((1+rate)**number_of_periods)-1)
|
data/src/excel/formula_peg.rb
CHANGED
data/src/excel/formula_peg.txt
CHANGED
data/src/excel/reference.rb
CHANGED
@@ -32,6 +32,10 @@ class Reference < String
|
|
32
32
|
letters
|
33
33
|
end
|
34
34
|
|
35
|
+
def self.column_letters_for_column_number
|
36
|
+
@@column_letters_for_column_number
|
37
|
+
end
|
38
|
+
|
35
39
|
attr_reader :excel_row_number, :excel_column_number, :excel_column, :excel_row
|
36
40
|
|
37
41
|
def calculate_excel_variables
|
data/src/excel_to_code.rb
CHANGED
@@ -81,10 +81,10 @@ class ExtractDataFromWorksheet < ::Ox::Sax
|
|
81
81
|
|
82
82
|
unless @formula.empty?
|
83
83
|
begin
|
84
|
-
formula_text = @formula.join
|
84
|
+
formula_text = @formula.join
|
85
85
|
ast = @fp.parse(formula_text)
|
86
|
-
rescue
|
87
|
-
e.ref = key # Attach the sheet and reference to the exception
|
86
|
+
rescue ExcelToCodeException => e
|
87
|
+
e.ref = key if e.respond_to?(:ref) # Attach the sheet and reference to the exception
|
88
88
|
raise
|
89
89
|
end
|
90
90
|
unless ast
|
@@ -17,7 +17,7 @@ class ExternalReferenceException < ExcelToCodeException
|
|
17
17
|
|
18
18
|
Sorry, ExcelToCode can't handle external references
|
19
19
|
|
20
|
-
It found one in #{ref.join("!")}
|
20
|
+
It found one in #{ref && ref.join("!")}
|
21
21
|
The formula was #{formula_text}
|
22
22
|
Which was parsed to #{full_ast}
|
23
23
|
Which seemed to have an external reference at #{reference_ast}
|
@@ -29,6 +29,32 @@ class ExternalReferenceException < ExcelToCodeException
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
+
class ParseFailedException < ExcelToCodeException
|
33
|
+
|
34
|
+
attr_accessor :formula_text
|
35
|
+
attr_accessor :ref
|
36
|
+
|
37
|
+
def initialize(formula_text)
|
38
|
+
@formula_text = formula_text
|
39
|
+
end
|
40
|
+
|
41
|
+
def message
|
42
|
+
<<-END
|
43
|
+
|
44
|
+
|
45
|
+
Sorry, ExcelToCode couldn't parse one of the formulae
|
46
|
+
|
47
|
+
It was in #{ref && ref.join("!")}
|
48
|
+
The formula was #{formula_text}
|
49
|
+
|
50
|
+
Please report the problem at http://github.com/tamc/excel_to_code/issues
|
51
|
+
|
52
|
+
END
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
|
32
58
|
class CachingFormulaParser
|
33
59
|
include Singleton
|
34
60
|
|
@@ -56,10 +82,11 @@ class CachingFormulaParser
|
|
56
82
|
def parse(text)
|
57
83
|
ast = Formula.parse(text)
|
58
84
|
@text = text # Kept in case of Exception below
|
59
|
-
@full_ast = ast.to_ast[1] # Kept in case of Exception below
|
60
85
|
if ast
|
86
|
+
@full_ast = ast.to_ast[1] # Kept in case of Exception below
|
61
87
|
map(ast.to_ast[1])
|
62
88
|
else
|
89
|
+
raise ParseFailedException.new(text)
|
63
90
|
nil
|
64
91
|
end
|
65
92
|
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.3.
|
4
|
+
version: 0.3.16
|
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: 2015-
|
11
|
+
date: 2015-05-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubypeg
|
@@ -150,6 +150,7 @@ files:
|
|
150
150
|
- src/excel/excel_functions.rb
|
151
151
|
- src/excel/excel_functions/abs.rb
|
152
152
|
- src/excel/excel_functions/add.rb
|
153
|
+
- src/excel/excel_functions/address.rb
|
153
154
|
- src/excel/excel_functions/and.rb
|
154
155
|
- src/excel/excel_functions/apply_to_range.rb
|
155
156
|
- src/excel/excel_functions/average.rb
|