occurro 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 820dbd667977ad499b6e91e7b0d200d36dce82eb
4
+ data.tar.gz: eaf179afff4b590d3e5990e6e2038ac2a3488228
5
+ SHA512:
6
+ metadata.gz: 764c8834ae8b34481ce0820e3018e8799d75a9a3482e75500902884c180c32f2bac1fb35d17ef21648306c7e6653a8b956bb9e6660155dafa2b9083c723dfef5
7
+ data.tar.gz: e3df221a6302186694ae48a4eb7da9aa7e4f4f291be220c0f4072625f6e834dbfbeae6c3795d0e5f5815a17c6a701ab9a80d15a4db546f3cd192ea985adcc6a2
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 YOURNAME
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,4 @@
1
+ = Occurro
2
+
3
+ = License
4
+ This project is released under MIT-LICENSE.
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Occurro'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+
24
+
25
+
26
+ Bundler::GemHelper.install_tasks
27
+
@@ -0,0 +1,15 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // the compiled file.
9
+ //
10
+ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
+ // GO AFTER THE REQUIRES BELOW.
12
+ //
13
+ //= require jquery
14
+ //= require jquery_ujs
15
+ //= require_tree .
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,4 @@
1
+ module Occurro
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,21 @@
1
+ module Occurro
2
+ class CountersController < ApplicationController
3
+ respond_to :js
4
+ before_filter :get_countable
5
+
6
+ def increment
7
+ if Occurro::CachedSession.unique_visitor?(@countable, session)
8
+ @countable.increment_counter
9
+ Occurro::CachedSession.add_cache(@countable, session)
10
+ end
11
+ render text: ""
12
+ end
13
+
14
+ private
15
+
16
+ def get_countable
17
+ @countable = params[:countable_type].constantize.find params[:countable_id]
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ module Occurro
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,47 @@
1
+ module Occurro
2
+ class Counter < ActiveRecord::Base
3
+ validates :countable, presence: true
4
+ validates :countable_id, uniqueness: { scope: :countable_type }
5
+
6
+ belongs_to :countable, polymorphic: true
7
+
8
+ # Public: Rotate the counter value for the period_type
9
+ #
10
+ # * period_type:
11
+ # :daily #=> daily rotation
12
+ # :weekly #=> weekly rotation
13
+ # :monthly #=> monthly rotation
14
+ #
15
+ def update_counter(period_type)
16
+ column_from, column_to =
17
+ case period_type.to_s
18
+ when 'daily'
19
+ ['today', 'yesterday']
20
+ when 'weekly'
21
+ ['this_week', 'last_week']
22
+ when 'monthly'
23
+ ['this_month', 'last_month']
24
+ else
25
+ return false
26
+ end
27
+
28
+ self.send("#{column_to}=", self.send(column_from))
29
+ self.send("#{column_from}=", 0)
30
+ self.save
31
+ end
32
+
33
+ # Public: increments 'model' counters by a 'count' factor
34
+ #
35
+ def self.increment_counters(model, count = 1)
36
+ counter = Occurro::Counter.find_or_create_by_countable_type_and_countable_id(model.class.base_class.name, model.id)
37
+ counter.update_attributes({
38
+ :today => counter.today + count,
39
+ :this_week => counter.this_week + count,
40
+ :this_month => counter.this_month + count,
41
+ :total => counter.total + count
42
+ })
43
+ Occurro::DailyCounter.increment_counters(model, count) if model.class.use_daily_counters?
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,13 @@
1
+ module Occurro
2
+ class DailyCounter < ActiveRecord::Base
3
+ validates :countable, :created_on, presence: true
4
+ validates :created_on, uniqueness: { scope: [:countable_type, :countable_id] }
5
+
6
+ belongs_to :countable, polymorphic: true
7
+
8
+ def self.increment_counters(model, count = 1)
9
+ counter = Occurro::DailyCounter.find_or_create_by_countable_type_and_countable_id_and_created_on(model.class.base_class.name, model.id, Date.today)
10
+ counter.increment!(:total, count)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Occurro</title>
5
+ <%= stylesheet_link_tag "occurro/application", :media => "all" %>
6
+ <%= javascript_include_tag "occurro/application" %>
7
+ <%= csrf_meta_tags %>
8
+ </head>
9
+ <body>
10
+
11
+ <%= yield %>
12
+
13
+ </body>
14
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ Occurro::Engine.routes.draw do
2
+ get :increment, path: ':countable_type/:countable_id(.:format)', to: 'counters#increment'
3
+ end
@@ -0,0 +1,19 @@
1
+ class CreateOccurroCounters < ActiveRecord::Migration
2
+ def change
3
+ create_table :occurro_counters do |t|
4
+ t.references :countable , polymorphic: true
5
+ t.integer :today , default: 0 , null: false
6
+ t.integer :yesterday , default: 0 , null: false
7
+ t.integer :this_week , default: 0 , null: false
8
+ t.integer :last_week , default: 0 , null: false
9
+ t.integer :this_month , default: 0 , null: false
10
+ t.integer :last_month , default: 0 , null: false
11
+ t.integer :total , default: 0 , null: false
12
+ t.timestamps
13
+ end
14
+ add_index :occurro_counters , [:countable_type , :countable_id] , unique: true , name: 'countable_unq'
15
+ add_index :occurro_counters , [:countable_type , :today , :yesterday] , name: 'countable_type_daily'
16
+ add_index :occurro_counters , [:countable_type , :this_month , :last_month] , name: 'countable_type_monthly'
17
+ add_index :occurro_counters , [:countable_type , :this_week , :last_week] , name: 'countable_type_weekly'
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ class CreateOccurroDailyCounters < ActiveRecord::Migration
2
+ def change
3
+ create_table :occurro_daily_counters do |t|
4
+ t.references :countable , polymorphic: true
5
+ t.integer :total , default: 0 , null: false
6
+ t.date :created_on
7
+ t.datetime :updated_at
8
+ end
9
+ add_index :occurro_daily_counters, [:countable_type, :countable_id, :created_on], unique: true, name: 'daily_counter_unq'
10
+ add_index :occurro_daily_counters, [:countable_type, :total], name: 'daily_counter_total'
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Explain the generator
3
+
4
+ Example:
5
+ rails generate migrations Thing
6
+
7
+ This will create:
8
+ what/will/it/create
@@ -0,0 +1,19 @@
1
+ module Occurro
2
+ class MigrationsGenerator < Rails::Generators::Base
3
+ include Rails::Generators::Migration
4
+ source_root File.expand_path('../../../../../db/migrate', __FILE__)
5
+
6
+ def copy_migration
7
+ migration_template 'create_occurro_counters.rb', "db/migrate/create_occurro_counters.rb"
8
+ sleep 1
9
+ migration_template 'create_occurro_daily_counters.rb', "db/migrate/create_occurro_daily_counters.rb"
10
+ end
11
+
12
+ private
13
+
14
+ def self.next_migration_number(path)
15
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ module Occurro
2
+ module CachedCounter
3
+
4
+ # Increments the counter based on the model counter_cache option.
5
+ # If the counter_cache limit is not reached, it will store the value
6
+ # on Rails.cache, and will submit it to persistence only when
7
+ # there are as many entries as the counter_cache value
8
+ #
9
+ def self.increment_counter(model)
10
+ cached_counts = Rails.cache.read(key_name(model)).to_i + 1
11
+ return update_cached_counter(model, cached_counts) if cached_counts < model.class.counter_cache
12
+ update_cached_counter(model, 0)
13
+ Occurro::Jobs::Sender.increment_counters_job(model, cached_counts)
14
+ end
15
+
16
+ private
17
+
18
+ # Returns the key name to the cache
19
+ #
20
+ def self.key_name(model)
21
+ "counters_cache_#{model.class.base_class.name}_#{model.id}"
22
+ end
23
+
24
+ # Updates the cached counter with a new value
25
+ #
26
+ def self.update_cached_counter(model, count)
27
+ Rails.cache.write(key_name(model), count)
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,21 @@
1
+ module Occurro
2
+ module CachedSession
3
+
4
+ # Public: Checks if the given session already has a visit for
5
+ # the given model. Retuns true or false.
6
+ #
7
+ def self.unique_visitor?(model, session)
8
+ !(session[:occurro] && session[:occurro]["#{model.class.base_class.name}"] && session[:occurro]["#{model.class.base_class.name}"]["#{model.id}"])
9
+ end
10
+
11
+ # Public: Adds the given model to the given session.
12
+ # Should be used once per unique_visitor.
13
+ #
14
+ def self.add_cache(model, session)
15
+ session[:occurro] ||= {}
16
+ session[:occurro]["#{model.class.base_class.name}"] ||= {}
17
+ session[:occurro]["#{model.class.base_class.name}"]["#{model.id}"] = true
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ module Occurro
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Occurro
4
+ end
5
+ end
@@ -0,0 +1,70 @@
1
+ module Occurro
2
+ module HasCounters
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ has_one :counter , class_name: 'Occurro::Counter' , dependent: :destroy , as: :countable
7
+ has_many :daily_counters , class_name: 'Occurro::DailyCounter' , dependent: :destroy , as: :countable
8
+
9
+ cattr_accessor :occurro_options
10
+ self.occurro_options = {
11
+ counter_cache: 0,
12
+ use_daily_counters: true
13
+ }
14
+
15
+ scope :order_by_today_views , ->() { joins(:counter).order('today DESC') }
16
+ scope :order_by_yesterday_views , ->() { joins(:counter).order('yesterday DESC') }
17
+ scope :order_by_this_week_views , ->() { joins(:counter).order('this_week DESC') }
18
+ scope :order_by_last_week_views , ->() { joins(:counter).order('last_week DESC') }
19
+ scope :order_by_this_month_views , ->() { joins(:counter).order('this_month DESC') }
20
+ scope :order_by_last_month_views , ->() { joins(:counter).order('last_month DESC') }
21
+ scope :order_by_total_views , ->() { joins(:counter).order('total DESC') }
22
+ end
23
+
24
+ # Public: Increments the counter in 1 for this model
25
+ #
26
+ def increment_counter
27
+ return Occurro::CachedCounter.increment_counter(self) if self.class.base_class.counter_cache > 0
28
+ Occurro::Jobs::Sender.increment_counters_job(self, 1)
29
+ end
30
+
31
+ module ClassMethods
32
+
33
+ def use_daily_counters?
34
+ !!self.occurro_options[:use_daily_counters]
35
+ end
36
+
37
+ def counter_cache
38
+ self.occurro_options[:counter_cache]
39
+ end
40
+
41
+ private
42
+
43
+ # Model Configuration
44
+ #
45
+ # Options:
46
+ #
47
+ # * counter_cache (int) -> How many recipes will be cached in memory before
48
+ # submiting them to persistence. Default: 0
49
+ #
50
+ # * use_daily_counters (bool) -> Will keep track of daily counters?
51
+ # this will use an extra table to record
52
+ # counter by model and date. Default: false
53
+ #
54
+ # Example:
55
+ #
56
+ # class Article < ActiveRecord::Base
57
+ # include Occurro::HasCounters
58
+ #
59
+ # occurro_configure do |config|
60
+ # config[:counter_cache] = 10
61
+ # config[:use_daily_counters] = false
62
+ # end
63
+ # end
64
+ #
65
+ def occurro_configure
66
+ yield(self.occurro_options)
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,11 @@
1
+ module Occurro
2
+ module Jobs
3
+ class DelayedJob < Struct.new(:model, :count)
4
+
5
+ def perform
6
+ Occurro::Counter.increment_counters(model, count)
7
+ end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module Occurro
2
+ module Jobs
3
+ class Resque
4
+
5
+ # Performs an async increment of the counter
6
+ #
7
+ def self.perform(countable_type, countable_id, count = 1)
8
+ model = countable_type.constantize.find countable_id
9
+ Occurro::Counter.increment_counters(model, count)
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,35 @@
1
+ module Occurro
2
+ module Jobs
3
+ module Sender
4
+ def self.increment_counters_job(model, count =1)
5
+ find_sender_for(model, count)
6
+ end
7
+
8
+ private
9
+
10
+ # Private: Based on Occurro.custom_sender it finds a sender
11
+ # and send the increment_counter to it.
12
+ #
13
+ # Accepts 4 types of values:
14
+ #
15
+ # * false => Will forward to model, and increment the counter in real time
16
+ # * :resque => Will send it as a default ResqueJob
17
+ # * :delayed_job => the model increment_counter through delayed job
18
+ # * proc(model, count) => Any proc (or class that have call) and
19
+ # accepts model and count as paramenters.
20
+ #
21
+ def self.find_sender_for(model, count)
22
+ case Occurro.custom_job
23
+ when false, nil
24
+ Occurro::Counter.increment_counters(model, count)
25
+ when :resque, 'resque'
26
+ Resque.enqueue Occurro::Jobs::Resque, model.class.base_class.name, model.id, count
27
+ when :delayed_job, 'delayed_job'
28
+ Delayed::Job.enqueue Occurro::Jobs::DelayedJob.new(model, count)
29
+ else
30
+ Occurro.custom_job.call(model, count)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,35 @@
1
+ module Occurro
2
+ module Tasks
3
+
4
+ # Public: Update daily counters from counters table
5
+ #
6
+ def self.daily_update(countable_type = nil)
7
+ update_counters(:daily, countable_type)
8
+ end
9
+
10
+ # Public: Update weekly counters from counters table
11
+ #
12
+ def self.weekly_update(countable_type = nil)
13
+ update_counters(:weekly, countable_type)
14
+ end
15
+
16
+ # Public: Update monthly counters from counters table
17
+ #
18
+ def self.monthly_update(countable_type = nil)
19
+ update_counters(:monthly, countable_type)
20
+ end
21
+
22
+ private
23
+
24
+ # Private: Update counters for the period type and countable_type
25
+ #
26
+ def self.update_counters(period_type, countable_type = nil)
27
+ counters = Occurro::Counter
28
+ counters.where(updatable_type: countable_type) if countable_type
29
+ counters.all.each do |counter|
30
+ counter.update_counter(period_type)
31
+ end
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,3 @@
1
+ module Occurro
2
+ VERSION = "0.2.5"
3
+ end
data/lib/occurro.rb ADDED
@@ -0,0 +1,41 @@
1
+ require "occurro/engine"
2
+ require "occurro/tasks"
3
+ require "occurro/has_counters"
4
+ require "occurro/cached_counter"
5
+ require "occurro/cached_session"
6
+ require "occurro/jobs/sender"
7
+ require "occurro/jobs/resque"
8
+ require 'occurro/jobs/delayed_job'
9
+
10
+ module Occurro
11
+ mattr_accessor :custom_job
12
+ @@custom_job = false
13
+
14
+ # Global configuration
15
+ # Options:
16
+ #
17
+ # * custom_job= #=> Defaults to false
18
+ # Accepts :resque, :delayed_job or a custom proc(model, count)
19
+ #
20
+ # false will make a synchronous call to the model and increment the counter
21
+ # :resque will enqueue a simple job to increment the counter in Resque
22
+ # :delayed_job will do the same, but for DelayedJob
23
+ # a custom proc (or a class that accepts call) will call this instead,
24
+ # you can use it to create a custom job for resque, delayed_job, or any other
25
+ #
26
+ # Example:
27
+ #
28
+ # Occurro.configure do |config|
29
+ # config.custom_job = :resque
30
+ # end
31
+ #
32
+ def self.configure
33
+ yield(self)
34
+ end
35
+
36
+ private
37
+
38
+ def self.custom_job=(job)
39
+ @@custom_job = job
40
+ end
41
+ end
@@ -0,0 +1,24 @@
1
+ # desc "Explaining what the task does"
2
+ # task :occurro do
3
+ # # Task goes here
4
+ # end
5
+
6
+ namespace :occurro do
7
+ desc "Runs the daily rotation in the counters table"
8
+ task :daily_rotation => :environment do
9
+ require 'occurro/tasks'
10
+ Occurro::Tasks.daily_update
11
+ end
12
+
13
+ desc "Runs the weekly rotation in the counters table"
14
+ task :weekly_rotation => :environment do
15
+ require 'occurro/tasks'
16
+ Occurro::Tasks.weekly_update
17
+ end
18
+
19
+ desc "Runs the monthly rotation in the counters table"
20
+ task :monthly_rotation => :environment do
21
+ require 'occurro/tasks'
22
+ Occurro::Tasks.montly_update
23
+ end
24
+ end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: occurro
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.5
5
+ platform: ruby
6
+ authors:
7
+ - Tiago Scolari
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-05-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 3.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 3.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec-rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: database_cleaner
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: factory_girl_rails
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: resque
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: delayed_job_active_record
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Tasks and models for counting model visualizations.
98
+ email:
99
+ - tscolari@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - app/assets/javascripts/occurro/application.js
105
+ - app/assets/stylesheets/occurro/application.css
106
+ - app/controllers/occurro/application_controller.rb
107
+ - app/controllers/occurro/counters_controller.rb
108
+ - app/helpers/occurro/application_helper.rb
109
+ - app/models/occurro/counter.rb
110
+ - app/models/occurro/daily_counter.rb
111
+ - app/views/layouts/occurro/application.html.erb
112
+ - config/routes.rb
113
+ - db/migrate/create_occurro_counters.rb
114
+ - db/migrate/create_occurro_daily_counters.rb
115
+ - lib/generators/occurro/migrations/migrations_generator.rb
116
+ - lib/generators/occurro/migrations/USAGE
117
+ - lib/occurro/cached_counter.rb
118
+ - lib/occurro/cached_session.rb
119
+ - lib/occurro/engine.rb
120
+ - lib/occurro/has_counters.rb
121
+ - lib/occurro/jobs/delayed_job.rb
122
+ - lib/occurro/jobs/resque.rb
123
+ - lib/occurro/jobs/sender.rb
124
+ - lib/occurro/tasks.rb
125
+ - lib/occurro/version.rb
126
+ - lib/occurro.rb
127
+ - lib/tasks/occurro_tasks.rake
128
+ - MIT-LICENSE
129
+ - Rakefile
130
+ - README.rdoc
131
+ homepage: https://github.com/tscolari/occurro
132
+ licenses: []
133
+ metadata: {}
134
+ post_install_message:
135
+ rdoc_options: []
136
+ require_paths:
137
+ - lib
138
+ required_ruby_version: !ruby/object:Gem::Requirement
139
+ requirements:
140
+ - - '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
143
+ required_rubygems_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - '>='
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ requirements: []
149
+ rubyforge_project:
150
+ rubygems_version: 2.0.0
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: Simple counters for ActiveRecord visualizations.
154
+ test_files: []