Class: Sycsvpro::Calculator

Inherits:
Object
  • Object
show all
Includes:
Dsl
Defined in:
lib/sycsvpro/calculator.rb

Overview

Processes arithmetic operations on columns of a csv file. A column value has to be a number. Possible operations are +, -, * and /. It is also possible to use values of columns as an operator like c1*2 will multiply the value of column 1 with 2.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Dsl

#clean_up, #params, #rows, #str2utf8, #unstring, #write_to

Constructor Details

#initialize(options = {}) ⇒ Calculator

Creates a new Calculator. Options expects :infile, :outfile, :rows and :columns. Optionally a header can be provided. The header can be supplemented with additional column names that are generated due to a arithmetic operation that creates new columns :call-seq:

Sycsvpro::Calculator.new(infile:  "in.csv",
                         outfile: "out.csv",
                         df:      "%d.%m.%Y",
                         rows:    "1,2,BEGINn3>20END",
                         header:  "*,Count",
                         cols:    "4:Count=c1+c2*2",
                         sum:     true).execute


45
46
47
48
49
50
51
52
53
54
55
# File 'lib/sycsvpro/calculator.rb', line 45

def initialize(options={})
  @infile      = options[:infile]
  @outfile     = options[:outfile]
  @date_format = options[:df] || "%Y-%m-%d"
  @row_filter  = RowFilter.new(options[:rows], df: options[:df])
  @header      = Header.new(options[:header])
  @sum_row     = []
  @add_sum_row = options[:sum] || false
  @formulae    = {}
  create_calculator(options[:cols])
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(id, *args, &block) ⇒ Object

Retrieves the values from a row as the result of a arithmetic operation with #eval



59
60
61
62
63
# File 'lib/sycsvpro/calculator.rb', line 59

def method_missing(id, *args, &block)
  return to_number(columns[$1.to_i]) if id =~ /c(\d+)/
  return to_date(columns[$1.to_i])   if id =~ /d(\d+)/
  super
end

Instance Attribute Details

#add_sum_rowObject (readonly)

if true add a sum row at the bottom of the out file



31
32
33
# File 'lib/sycsvpro/calculator.rb', line 31

def add_sum_row
  @add_sum_row
end

#columnsObject (readonly)

filter that is used for columns



29
30
31
# File 'lib/sycsvpro/calculator.rb', line 29

def columns
  @columns
end

#date_formatObject (readonly)

date format for date operations



23
24
25
# File 'lib/sycsvpro/calculator.rb', line 23

def date_format
  @date_format
end

#formulaeObject (readonly)

the operations on columns



25
26
27
# File 'lib/sycsvpro/calculator.rb', line 25

def formulae
  @formulae
end

#headerObject (readonly)

header of the outfile



27
28
29
# File 'lib/sycsvpro/calculator.rb', line 27

def header
  @header
end

#infileObject (readonly)

infile contains the data that is operated on



17
18
19
# File 'lib/sycsvpro/calculator.rb', line 17

def infile
  @infile
end

#outfileObject (readonly)

outfile is the file where the result is written to



19
20
21
# File 'lib/sycsvpro/calculator.rb', line 19

def outfile
  @outfile
end

#row_filterObject (readonly)

filter that is used for rows



21
22
23
# File 'lib/sycsvpro/calculator.rb', line 21

def row_filter
  @row_filter
end

Instance Method Details

#executeObject

Executes the calculator and writes the result to the outfile



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/sycsvpro/calculator.rb', line 66

def execute
  processed_header = false

  File.open(outfile, 'w') do |out|
    File.open(infile).each_with_index do |line, index|
      next if line.chomp.empty?

      unless processed_header
        header_row = header.process(line.chomp)
        out.puts header_row unless header_row.empty?
        processed_header = true
        next
      end

      next if row_filter.process(line, row: index).nil?

      @columns = unstring(line).chomp.split(';')
      formulae.each do |col, formula|
        @columns[col.to_i] = eval(formula)
      end
      out.puts @columns.join(';')

      @columns.each_with_index do |column, index|
        column = 0 unless column.to_s =~ /^[\d\.,]*$/

        if @sum_row[index]
          @sum_row[index] += to_number column
        else
          @sum_row[index] =  to_number column
        end
      end if add_sum_row

    end

    out.puts @sum_row.join(';') if add_sum_row

  end
end