Class: PeriodicCounter

Inherits:
Object
  • Object
show all
Defined in:
lib/periodic_counter.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(environment, root) ⇒ PeriodicCounter

Returns a new instance of PeriodicCounter.



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/periodic_counter.rb', line 6

def initialize(environment, root)
  @db, @log, @mail = ActiveWrapper.setup(
    :base => root,
    :env => environment
  )
  @db.establish_connection
  
  @tables = ActiveRecord::Base.connection.tables.inject({}) do |hash, table|
    hash[table] = ActiveRecord::Base.connection.columns(table).collect(&:name)
    hash
  end
  
  if File.exists?(counters_yml = "#{root}/config/counters.yml")
    @counters = YAML::load(File.open(counters_yml))
  else
    raise "#{counters_yml} not found"
  end
  
  @counters.each do |table, counters|
    columns = @tables[table]
    if columns
      columns.each do |column|
        if counters.include?(column)
          # Find period columns
          period = columns.select do |col|
            col =~ /^#{column}/ &&
            col != column &&
            !col.include?('_data')
          end
          # Grab all records
          select_columns = [ 'id', column, "#{column}_data" ]
          select_columns += period
          records = ActiveRecord::Base.connection.select_all <<-SQL
            SELECT #{select_columns.join(', ')}
            FROM #{table}
          SQL
          records.each do |record|
            id = record.delete('id')
            data = YAML::load(record["#{column}_data"] || '') || {}
            count = record.delete(column).to_i
            # Set period counters
            period.each do |col|
              computed_at = data["#{col}_at"] || Time.now.utc
              duration = column_to_period_integer(col)
              time_since_compute = Time.now.utc - computed_at
              last_day =
                if col.include?('day')
                  self.class.today
                elsif col.include?('week')
                  self.class.last_monday
                elsif col.include?('month')
                  self.class.first_of_the_month
                end
              if (time_since_compute - duration) >= 0
                data[col] = count
                data["#{col}_at"] = last_day
              else
                data[col] ||= count
                data["#{col}_at"] ||= last_day
              end
              record[col] = count - data[col].to_i
            end
            # Update record
            record["#{column}_data"] = "'#{YAML::dump(data)}'"
            set = record.collect { |col, value| "#{col} = #{value || 0}" }
            ActiveRecord::Base.connection.update <<-SQL
              UPDATE #{table}
              SET #{set.join(', ')}
              WHERE id = #{id}
            SQL
          end
        end
      end
    end
  end
end

Class Method Details

.first_of_the_month(now = Time.now.utc.to_date) ⇒ Object



94
95
96
# File 'lib/periodic_counter.rb', line 94

def first_of_the_month(now=Time.now.utc.to_date)
  Date.new(now.year, now.month, 1).to_time(:utc)
end

.last_monday(now = Time.now.utc.to_date) ⇒ Object



98
99
100
101
102
103
104
105
106
# File 'lib/periodic_counter.rb', line 98

def last_monday(now=Time.now.utc.to_date)
  wday = now.wday
  if wday == 0
    -6
  else
    diff = 1 - wday
  end
  Date.new(now.year, now.month, now.day + diff).to_time(:utc)
end

.today(now = Time.now.utc.to_date) ⇒ Object



108
109
110
# File 'lib/periodic_counter.rb', line 108

def today(now=Time.now.utc.to_date)
  Date.new(now.year, now.month, now.day).to_time(:utc)
end

Instance Method Details

#column_to_period_integer(column) ⇒ Object



83
84
85
86
87
88
89
90
# File 'lib/periodic_counter.rb', line 83

def column_to_period_integer(column)
  column = column.split('_')[-2..-1]
  column[0] = column[0].to_i
  if column[0] == 0
    column[0] = 1
  end
  eval(column.join('.'))
end