excel_to_code 0.3.15 → 0.3.16

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: 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