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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5d2c59c883974dffad372f4ddc7aefd00f1e9847
4
- data.tar.gz: 268cb5f552b2e58ac9039321599593cd88811fcb
3
+ metadata.gz: 17eac22412740a67afd06333f437ce950c03c32d
4
+ data.tar.gz: 1117fdcb2343478712dc0a72649c429d1b9dc8dd
5
5
  SHA512:
6
- metadata.gz: 018a1d2825910da4518ebd04328f08638780e6ebbe965b67940bd2f09213cb0783011ce2f34e7039f79a168754fe2a775240f09b703847ddfe6be744ebd0521d
7
- data.tar.gz: 72264447d6bc4f05f4f4d8597d41aa6ae10be87b9108ea40747f0690ddac88bcb29358e5ad710b4a478cb79186af6abf277b3599ef649324b68d31ec2acf898c
6
+ metadata.gz: 5023ee51c9f7a3909c7768ca58da98c368e3bec955a50e67c33df96387e2052e8c3c734f062c894b9102629509582232c7c08d62fd21b9fe718d1f678d6558fa
7
+ data.tar.gz: e34fd8293696f90562080eeb0f07db35a131d4132883baf62a5edf57f2fa37e36a699a16d355899e27c65c0a13dc262e143e30917593aed1a358868cc6108783
@@ -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
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
@@ -69,7 +69,9 @@ class MapFormulaeToC < MapValuesToC
69
69
  :'MMULT' => 'mmult',
70
70
  :'MOD' => 'mod',
71
71
  :'NPV' => 'npv',
72
- :'PMT' => 'pmt',
72
+ :'PMT3' => 'pmt',
73
+ :'PMT4' => 'pmt_4',
74
+ :'PMT5' => 'pmt_5',
73
75
  :'PV3' => 'pv_3',
74
76
  :'PV4' => 'pv_4',
75
77
  :'PV5' => 'pv_5',
@@ -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
@@ -17,6 +17,7 @@ class MapFormulaeToRuby < MapValuesToRuby
17
17
  :'>' => 'more_than?',
18
18
  :'>=' => 'more_than_or_equal?',
19
19
  :'ABS' => 'abs',
20
+ :'ADDRESS' => 'address',
20
21
  :'AND' => 'excel_and',
21
22
  :'AVERAGE' => 'average',
22
23
  :'AVERAGEIFS' => 'averageifs',
@@ -119,3 +119,5 @@ require_relative 'excel_functions/npv'
119
119
  require_relative 'excel_functions/iserror'
120
120
 
121
121
  require_relative 'excel_functions/char'
122
+
123
+ require_relative 'excel_functions/address'
@@ -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)
@@ -230,7 +230,7 @@ class Formula < RubyPeg
230
230
  end
231
231
 
232
232
  def space
233
- ignore { terminal(/[ \n]*/) }
233
+ ignore { terminal(/[ \n\r]*/) }
234
234
  end
235
235
 
236
236
  def null
@@ -41,7 +41,7 @@ boolean = boolean_true | boolean_false
41
41
  boolean_true := `'TRUE'
42
42
  boolean_false := `'FALSE'
43
43
  prefix := /[-+]/ thing
44
- space = `/[ \n]*/
44
+ space = `/[ \n\r]*/
45
45
  null := &','
46
46
  error := '#REF!' | '#NAME?' | '#VALUE!' | '#DIV/0!' | '#N/A' | '#NUM!'
47
47
 
@@ -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
@@ -1,5 +1,5 @@
1
1
  class ExcelToCode
2
- def self.version() "0.3.15" end
2
+ def self.version() "0.3.16" end
3
3
  end
4
4
 
5
5
  require_relative 'commands'
@@ -81,10 +81,10 @@ class ExtractDataFromWorksheet < ::Ox::Sax
81
81
 
82
82
  unless @formula.empty?
83
83
  begin
84
- formula_text = @formula.join.gsub(/[\r\n]+/,'')
84
+ formula_text = @formula.join
85
85
  ast = @fp.parse(formula_text)
86
- rescue ExternalReferenceException => e
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
@@ -26,7 +26,7 @@ class ExtractSharedStrings < ::Ox::Sax
26
26
  def text(string)
27
27
  return unless @current
28
28
  # FIXME: SHOULDN'T ELINMATE NEWLINES
29
- @current << string.gsub("\n","")
29
+ @current << string#.gsub("\n","")
30
30
  end
31
31
 
32
32
  end
@@ -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.15
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-03-10 00:00:00.000000000 Z
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