lib/formulae/run/excel_functions.rb in rubyfromexcel-0.0.10 vs lib/formulae/run/excel_functions.rb in rubyfromexcel-0.0.13

- old
+ new

@@ -1,7 +1,8 @@ class Numeric def number_like?; true; end + def array_formula_offset(i,j); self; end end class String def +@; number_like? ? self.to_f : self; end def -@; number_like? ? -self.to_f : self; end @@ -136,10 +137,18 @@ end def pmt(rate,periods,principal) -principal*(rate*((1+rate)**periods))/(((1+rate)**periods)-1) end + + def npv(rate,*cashflows) + discount_factor = 1 + flatten_and_inject(cashflows) do |pv,cashlfow| + discount_factor = discount_factor * (1 + rate) + cashlfow.is_a?(Numeric) ? pv + (cashlfow / discount_factor) : pv + end + end def sum(*args) flatten_and_inject(args) do |counter,arg| arg.is_a?(Numeric) ? counter + arg.to_f : counter end @@ -170,11 +179,19 @@ check_value = check_value.to_s.downcase [check_range,check_value] end accumulator = 0 sum_range.each_with_index do |potential_sum,i| - next unless checks.all? { |c| c.first[i] == c.last } + next unless checks.all? do |c| + if c.last =~ /^>([0-9.]+)$/ + c.first[i].to_f > $1.to_f + elsif c.last =~ /^<([0-9.]+)$/ + c.first[i].to_f < $1.to_f + else + c.first[i] == c.last + end + end next unless potential_sum.is_a?(Numeric) accumulator = accumulator + potential_sum end accumulator end @@ -188,10 +205,12 @@ total * cell end end.inject(0) do |product,total| total + product end + rescue IndexError + return :value end def choose(choice,*choices) return choice if iserr(choice) choices[choice - 1] @@ -200,10 +219,52 @@ def count(*args) flatten_and_inject(args) do |counter,arg| arg.is_a?(Numeric) && !arg.is_a?(Empty) ? counter + 1 : counter end end + + def countif(check_range,criteria,count_range = check_range) + countifs(count_range,check_range,criteria) + end + + def countifs(count_range,*args) + return :na if iserr(count_range) + return :na if args.any? { |c| iserr(c) } + if count_range.is_a?(ExcelRange) + return :na unless count_range.single_row_or_column? + count_range = count_range.to_a + else + count_range = [count_range] + end + checks = Hash[*args].to_a.map do |check| + check_range, check_value = check.first, check.last + if check_range.is_a?(ExcelRange) + return :na unless check_range.single_row_or_column? + check_range = check_range.to_a + else + check_range = [check_range] + end + check_range = check_range.map { |c| c.to_s.downcase } + check_value = check_value.to_s.downcase + [check_range,check_value] + end + accumulator = 0 + count_range.each_with_index do |potential_count,i| + next unless checks.all? do |c| + if c.last =~ /^>([0-9.]+)$/ + c.first[i].to_f > $1.to_f + elsif c.last =~ /^<([0-9.]+)$/ + c.first[i].to_f < $1.to_f + else + c.first[i] == c.last + end + end + next unless potential_count.is_a?(Numeric) && !potential_count.is_a?(Empty) + accumulator = accumulator + 1 + end + accumulator + end def counta(*args) flatten_and_inject(args) do |counter,arg| arg.is_a?(Empty) ? counter : counter + 1 end @@ -356,10 +417,16 @@ end def excel_if(condition,true_value,false_value = false) condition ? true_value : false_value end - + + def excel_comparison(left,comparison,right) + left = left.downcase if left.is_a?(String) + right = right.downcase if right.is_a?(String) + left.send(comparison,right) + end + def iferror(value,value_if_error) iserr(value) ? value_if_error : value rescue ZeroDivisionError => e puts e return :div0 \ No newline at end of file