lib/formulae/compile/formula_builder.rb in rubyfromexcel-0.0.10 vs lib/formulae/compile/formula_builder.rb in rubyfromexcel-0.0.13

- old
+ new

@@ -104,11 +104,12 @@ sheet_name.gsub!(/^\[\d+\]/,'') end if reference.type == :named_reference return ":name" unless formula_cell worksheet = formula_cell.worksheet.workbook.worksheets[SheetNames.instance[sheet_name]] - raise Exception.new("#{sheet_name.inspect} not found in #{SheetNames.instance} and therefore in #{formula_cell.worksheet.workbook.worksheets.keys}") unless worksheet + # raise Exception.new("#{sheet_name.inspect} not found in #{SheetNames.instance} and therefore in #{formula_cell.worksheet.workbook.worksheets.keys}") unless worksheet + return ":ref" unless worksheet named_reference(reference.first,worksheet) else "#{SheetNames.instance[sheet_name]}.#{reference.visit(self)}" end end @@ -128,15 +129,15 @@ def operator(excel_operator) OPERATOR_CONVERSIONS[excel_operator] || excel_operator end def string_join(*strings) - strings.map { |s| s.type == :string ? s.visit(self) : "#{s.visit(self)}.to_s"}.join('+') + strings.map { |s| s.type == :string ? s.visit(self) : "(#{s.visit(self)}).to_s"}.join('+') end def string(string_text) - string_text.inspect + string_text.gsub('""','"').inspect end def function(name,*args) raise ExcelFunctionNotImplementedError.new("#{name}(#{args})") unless self.respond_to?("#{name.downcase}_function") self.send("#{name.downcase}_function",*args) @@ -172,26 +173,28 @@ excel_function :round excel_function :roundup excel_function :rounddown excel_function :mod excel_function :pmt + excel_function :npv + excel_function :countif def standard_function(name_to_use_in_ruby,args) "#{name_to_use_in_ruby}(#{args.map {|a| a.visit(self) }.join(',')})" end def index_function(*args) - attempt_to_caclulate_index(*args) || + attempt_to_calculate_index(*args) || standard_function("index",args) end def match_function(*args) - attempt_to_caclulate_match(*args) || + attempt_to_calculate_match(*args) || standard_function("match",args) end - def attempt_to_caclulate_index(lookup_array,row_number,column_number = :ignore) + def attempt_to_calculate_index(lookup_array,row_number,column_number = :ignore) lookup_array = range_for(lookup_array) row_number = single_value_for(row_number) column_number = single_value_for(column_number) unless column_number == :ignore return nil unless lookup_array return nil unless row_number @@ -206,17 +209,17 @@ return ref.to_ruby(true) rescue DependsOnCalculatedFormulaError return nil end - def attempt_to_caclulate_match(lookup_value,lookup_array,match_type = :ignore) + def attempt_to_calculate_match(lookup_value,lookup_array,match_type = :ignore) lookup_value = single_value_for(lookup_value) lookup_array = range_for(lookup_array) match_type = single_value_for(match_type) unless match_type == :ignore return nil unless lookup_value return nil unless lookup_array - return nil unless match_type + return nil if match_type == nil result = nil if match_type == :ignore result = FunctionCompiler.new(formula_cell.worksheet).match(lookup_value,lookup_array).to_f else result = FunctionCompiler.new(formula_cell.worksheet).match(lookup_value,lookup_array,match_type) @@ -227,12 +230,12 @@ end def single_value_for(ast) return nil unless ast.respond_to?(:visit) ast = ast.visit(self) - return ast if ast == "true" - return ast if ast == "false" + return true if ast == "true" + return false if ast == "false" return ast if ast.is_a?(Numeric) return ast if ast =~ /^[0-9.]+$/ return $1 if ast =~ /^"([^"]*)"$/ return nil unless formula_cell return nil unless formula_cell.worksheet @@ -256,10 +259,11 @@ def indirect_function(text_formula) attempt_to_parse_indirect(text_formula) || (formula_cell.worksheet.workbook.indirects_used = true; "indirect(#{text_formula.visit(self)},'#{formula_cell && formula_cell.reference}')") end def attempt_to_parse_indirect(text_formula) + #puts "Attempting to parse indirect #{text_formula.inspect}" return parse_and_visit(text_formula.first) if text_formula.type == :string return nil unless text_formula.type == :string_join reformated_indirect = text_formula.map do |non_terminal| if non_terminal.respond_to?(:type) case non_terminal.type @@ -273,10 +277,11 @@ else "" end when :sheet_reference, :named_reference, :table_reference, :local_table_reference reference = non_terminal.visit(self) + # puts reference return nil unless reference =~ /^(sheet\d+)\.([a-z]+\d+)$/ cell = formula_cell.worksheet.workbook.worksheets[$1].cell($2) if cell return nil unless cell.can_be_replaced_with_value? cell.value_for_including @@ -288,20 +293,22 @@ end else non_terminal end end + # puts "Reformatted indirect: #{reformated_indirect.join}" parse_and_visit(reformated_indirect.join) end def parse_and_visit(text) ast = Formula.parse(text) + # p [text,ast] return ":name" unless ast ast.visit(self.class.new(formula_cell)) end - def comparison(*strings) - strings.map { |s| s.visit(self) }.join + def comparison(left,comparator,right) + "excel_comparison(#{left.visit(self)},\"#{comparator.visit(self)}\",#{right.visit(self)})" end def arithmetic(*strings) strings.map { |s| s.visit(self) }.join end \ No newline at end of file