notches 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ .sass-cache
4
+ Gemfile.lock
5
+ pkg/*
6
+ *.sqlite
7
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
data/HISTORY ADDED
@@ -0,0 +1,2 @@
1
+ 0.1.0 - ?
2
+ * Initial Release
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Hyper Tiny
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.
@@ -0,0 +1,54 @@
1
+ Notches
2
+ -------
3
+
4
+ A Rails Engine for tracking your web traffic.
5
+
6
+ Installation
7
+ ------------
8
+
9
+ Add this to your Gemfile and run the `bundle` command.
10
+
11
+ gem 'notches', '~> 0.1.0'
12
+
13
+ And then install and run the necessary migrations.
14
+
15
+ rake notches:install:migrations
16
+ rake db:migrate
17
+
18
+ Mount your engine at your desired location in `config/routes.rb`.
19
+
20
+ mount Notches::Engine => '/notches'
21
+
22
+ Finally to start recording hits include the notch pixel image at the bottom of your views.
23
+
24
+ <%= image_tag "/notches/hits/new.gif?url=#{request.url}" %>
25
+
26
+ Counting hits
27
+ -------------
28
+
29
+ For a URL:
30
+
31
+ Notches::Hit.joins(:url).where('url like ?', '/posts').count
32
+
33
+ For an IP:
34
+
35
+ Notches::Hit.joins(:ip).where('ip = ?', '127.0.0.1').count
36
+
37
+ For a session id:
38
+
39
+ Notches::Hit.joins(:session).where('session_id = ?', 'abcd').count
40
+
41
+ For a date:
42
+
43
+ Notches::Hit.joins(:date).where('date = ?', Date.today).count
44
+
45
+ For a particular time of day:
46
+
47
+ Notches::Hit.joins(:time).where('time between ?', '09:00:00', '17:00:00').count
48
+
49
+ Or a user agent:
50
+
51
+ Notches::Hit.joins(:user_agent).where('user_agent like ?', '%Mobile%').count
52
+
53
+ To get a better idea of how Notches is setup check out the
54
+ [Notches::Hit](http://github.com/hypertiny/notches/blob/master/app/models/notches/hit.rb) model.
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.require :default, :development
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ require 'rspec/core/rake_task'
8
+ RSpec::Core::RakeTask.new
9
+
10
+ task :default => :test
11
+ task :test => :spec
@@ -0,0 +1,18 @@
1
+ class Notches::HitsController < ActionController::Base
2
+ def new
3
+ session[:notches]
4
+ Notches::Hit.log(
5
+ :url => params[:url],
6
+ :user_agent => request.env["HTTP_USER_AGENT"],
7
+ :session_id => request.session_options[:id],
8
+ :ip => request.remote_ip
9
+ )
10
+
11
+ # Don't cache the image.
12
+ response.header["Last-Modified"] = Time.now.httpdate
13
+
14
+ send_file Notches::Engine.root.join("app/assets/images/notches/hit.gif"),
15
+ :type => "image/gif",
16
+ :disposition => "inline"
17
+ end
18
+ end
@@ -0,0 +1,6 @@
1
+ class Notches::Date < ActiveRecord::Base
2
+ self.table_name = "notches_dates"
3
+
4
+ has_many :hits, :class_name => "Notches::Hit",
5
+ :foreign_key => 'notches_date_id'
6
+ end
@@ -0,0 +1,37 @@
1
+ class Notches::Hit < ActiveRecord::Base
2
+ self.table_name = "notches_hits"
3
+
4
+ validates :url, :presence => true
5
+ validates :session, :presence => true
6
+ validates :ip, :presence => true
7
+
8
+ validates_associated :url, :session, :ip
9
+
10
+ belongs_to :url, :foreign_key => :notches_url_id, :class_name => "URL"
11
+ belongs_to :user_agent, :foreign_key => :notches_user_agent_id
12
+ belongs_to :session, :foreign_key => :notches_session_id
13
+ belongs_to :ip, :foreign_key => :notches_ip_id, :class_name => "IP"
14
+ belongs_to :date, :foreign_key => :notches_date_id
15
+ belongs_to :time, :foreign_key => :notches_time_id
16
+
17
+ scope :unique, group("notches_url_id, notches_session_id, notches_ip_id")
18
+
19
+ def self.log(attributes)
20
+ hit = self.new
21
+ hit.transaction do
22
+ Rails.logger.info("[Notches] Tracking #{attributes.inspect} at #{Date.today} #{Time.now}")
23
+ hit.url = Notches::URL.find_or_create_by_url(attributes[:url])
24
+ hit.user_agent = Notches::UserAgent.find_or_create_by_user_agent(attributes[:user_agent])
25
+ hit.session = Notches::Session.find_or_create_by_session_id(attributes[:session_id])
26
+ hit.ip = Notches::IP.find_or_create_by_ip(attributes[:ip])
27
+ hit.date = Notches::Date.find_or_create_by_date(Date.today)
28
+ hit.time = Notches::Time.find_or_create_by_time(Time.now)
29
+ begin
30
+ hit.save!
31
+ rescue #ActiveRecord::RecordNotUnique
32
+ Rails.logger.info "Skipping non-unique hit"
33
+ end
34
+ end
35
+ hit
36
+ end
37
+ end
@@ -0,0 +1,8 @@
1
+ class Notches::IP < ActiveRecord::Base
2
+ self.table_name = "notches_ips"
3
+
4
+ has_many :hits, :class_name => "Notches::Hit",
5
+ :foreign_key => 'notches_ip_id'
6
+
7
+ validates :ip, :presence => true, :allow_blank => false
8
+ end
@@ -0,0 +1,8 @@
1
+ class Notches::Session < ActiveRecord::Base
2
+ self.table_name = "notches_sessions"
3
+
4
+ has_many :hits, :class_name => "Notches::Hit",
5
+ :foreign_key => 'notches_session_id'
6
+
7
+ validates :session_id, :presence => true
8
+ end
@@ -0,0 +1,6 @@
1
+ class Notches::Time < ActiveRecord::Base
2
+ self.table_name = "notches_times"
3
+
4
+ has_many :hits, :class_name => "Notches::Hit",
5
+ :foreign_key => 'notches_time_id'
6
+ end
@@ -0,0 +1,8 @@
1
+ class Notches::URL < ActiveRecord::Base
2
+ self.table_name = "notches_urls"
3
+
4
+ has_many :hits, :class_name => "Notches::Hit",
5
+ :foreign_key => 'notches_url_id'
6
+
7
+ validates :url, :presence => true
8
+ end
@@ -0,0 +1,5 @@
1
+ class Notches::UserAgent < ActiveRecord::Base
2
+ self.table_name = "notches_user_agents"
3
+
4
+ has_many :hits, :class_name => "Notches::Hit"
5
+ end
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.require :default, :development
5
+
6
+ Combustion.initialize!
7
+ run Combustion::Application
@@ -0,0 +1,3 @@
1
+ Notches::Engine.routes.draw do
2
+ get '/hits/new' => 'hits#new', :as => :new_hit
3
+ end
@@ -0,0 +1,55 @@
1
+ class CreateNotches < ActiveRecord::Migration
2
+ def up
3
+ create_table :notches_urls do |t|
4
+ t.string :url
5
+ end
6
+ create_table :notches_sessions do |t|
7
+ t.string :session_id
8
+ end
9
+ create_table :notches_ips do |t|
10
+ t.string :ip
11
+ end
12
+ create_table :notches_dates do |t|
13
+ t.date :date
14
+ end
15
+ create_table :notches_times do |t|
16
+ t.time :time
17
+ end
18
+ create_table :notches_hits do |t|
19
+ t.integer :notches_url_id, :null => false
20
+ t.integer :notches_session_id, :null => false
21
+ t.integer :notches_ip_id, :null => false
22
+ t.integer :notches_date_id, :null => false
23
+ t.integer :notches_time_id, :null => false
24
+ end
25
+ add_index :notches_urls, :url
26
+ add_index :notches_sessions, :session_id
27
+ add_index :notches_ips, :ip
28
+ add_index :notches_dates, :date
29
+ add_index :notches_times, :time
30
+ add_index :notches_hits, [
31
+ :notches_time_id,
32
+ :notches_date_id,
33
+ :notches_ip_id,
34
+ :notches_session_id,
35
+ :notches_url_id
36
+ ], :name => :notches_index, :unique => true
37
+ end
38
+
39
+ def down
40
+ remove_index :notches_urls, :url
41
+ remove_index :notches_sessions, :session_id
42
+ remove_index :notches_ips, :ip
43
+ remove_index :notches_dates, :date
44
+ remove_index :notches_times, :time
45
+ change_table :notches_hits do |t|
46
+ t.remove_index :name => :notches_index
47
+ end
48
+ drop_table :notches_urls
49
+ drop_table :notches_sessions
50
+ drop_table :notches_ips
51
+ drop_table :notches_dates
52
+ drop_table :notches_times
53
+ drop_table :notches_hits
54
+ end
55
+ end
@@ -0,0 +1,34 @@
1
+ class CreateNotchesUserAgents < ActiveRecord::Migration
2
+ def up
3
+ create_table :notches_user_agents do |t|
4
+ t.text :user_agent
5
+ end
6
+ add_column :notches_hits, :notches_user_agent_id, :integer
7
+ change_table :notches_hits do |t|
8
+ t.remove_index :name => :notches_index
9
+ end
10
+ add_index :notches_hits, [
11
+ :notches_time_id,
12
+ :notches_date_id,
13
+ :notches_ip_id,
14
+ :notches_session_id,
15
+ :notches_url_id,
16
+ :notches_user_agent_id
17
+ ], :name => :notches_index, :unique => true
18
+ end
19
+
20
+ def down
21
+ change_table :notches_hits do |t|
22
+ t.remove_index :name => :notches_index
23
+ end
24
+ add_index :notches_hits, [
25
+ :notches_time_id,
26
+ :notches_date_id,
27
+ :notches_ip_id,
28
+ :notches_session_id,
29
+ :notches_url_id
30
+ ], :name => :notches_index, :unique => true
31
+ remove_column :notches_hits, :notches_user_agent_id
32
+ drop_table :notches_user_agents
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ require 'rails'
2
+ require 'notches/engine'
3
+ require 'notches/version'
@@ -0,0 +1,5 @@
1
+ module Notches
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace Notches
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module Notches
2
+ VERSION = '0.3.0'
3
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "notches/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'notches'
7
+ s.version = Notches::VERSION
8
+ s.authors = ["Cillian O'Ruanaidh", "Paul Campbell"]
9
+ s.email = ['contact@cilliano.com']
10
+ s.homepage = 'http://github.com/hypertiny/notches'
11
+ s.summary = %q{Simple Rails web traffic counter}
12
+ s.description = %q{A Rails Engine for tracking your web traffic.}
13
+
14
+ s.rubyforge_project = 'notches'
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f|
19
+ File.basename(f)
20
+ }
21
+ s.require_paths = ['lib']
22
+
23
+ s.add_runtime_dependency 'rails', '~> 3.1'
24
+
25
+ s.add_development_dependency 'combustion', '~> 0.3.2'
26
+ s.add_development_dependency 'rspec-rails', '~> 2.11'
27
+ s.add_development_dependency 'sqlite3', '~> 1.3.4'
28
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Notches::HitsController do
4
+ describe "#new" do
5
+ it "returns an image" do
6
+ get :new, :url => '/posts', :format => 'gif'
7
+
8
+ response.headers["Content-Type"].should == 'image/gif'
9
+ end
10
+
11
+ it "logs the hit" do
12
+ @request.env['HTTP_USER_AGENT'] = 'FeedBurner/1.0'
13
+ @request.stub(:remote_ip => '234.101.82.14')
14
+ @request.stub(:session_options => { :id => 'abcd' })
15
+
16
+ get :new, :url => '/posts', :format => 'gif'
17
+
18
+ Notches::Hit.count.should == 1
19
+ hit = Notches::Hit.first
20
+ hit.url.url.should == '/posts'
21
+ hit.user_agent.user_agent.should == 'FeedBurner/1.0'
22
+ hit.ip.ip.should == '234.101.82.14'
23
+ hit.session.session_id.should == 'abcd'
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,3 @@
1
+ test:
2
+ adapter: sqlite3
3
+ database: db/notches_test.sqlite
@@ -0,0 +1,5 @@
1
+ Rails.application.routes.draw do
2
+ namespace 'notches' do
3
+ resources :hits, :only => [:new]
4
+ end
5
+ end
@@ -0,0 +1,2 @@
1
+ ActiveRecord::Schema.define do
2
+ end
@@ -0,0 +1 @@
1
+ *.log
File without changes
@@ -0,0 +1,156 @@
1
+ require 'spec_helper'
2
+
3
+ describe Notches::Hit do
4
+ describe "validations" do
5
+ let(:hit) do
6
+ Notches::Hit.new(
7
+ :url => Notches::URL.new(:url => "/posts"),
8
+ :session => Notches::Session.new(:session_id => '1234'),
9
+ :ip => Notches::IP.new(:ip => '209.85.143.94')
10
+ )
11
+ end
12
+
13
+ its "valid with valid attributes" do
14
+ hit.should be_valid
15
+ end
16
+
17
+ it "requires an ip" do
18
+ hit.ip = nil
19
+ hit.should have(1).error_on(:ip)
20
+ end
21
+
22
+ it "requires a session" do
23
+ hit.session = nil
24
+ hit.should have(1).error_on(:session)
25
+ end
26
+
27
+ it "requires a " do
28
+ hit.url = nil
29
+ hit.should have(1).error_on(:url)
30
+ end
31
+
32
+ it "does not validate if its IP's ip blank" do
33
+ hit.ip = Notches::IP.new(:ip => '')
34
+ hit.should have(1).error_on(:ip)
35
+ end
36
+
37
+ it "does not validate if its Session's session_id is blank" do
38
+ hit.session = Notches::Session.new(:session_id => '')
39
+ hit.should have(1).error_on(:session)
40
+ end
41
+
42
+ it "does not validate if its URL's url is blank" do
43
+ hit.url = Notches::URL.new(:url => '')
44
+ hit.should have(1).error_on(:url)
45
+ end
46
+ end
47
+
48
+ describe ".log" do
49
+
50
+ context "with valid attributes" do
51
+ let(:today) { Date.today }
52
+ let(:now) { Time.now }
53
+ before do
54
+ Date.stub(:today => today)
55
+ Time.stub(:now => now)
56
+ end
57
+
58
+ it "creates a hit for today and current time with those attributes" do
59
+ Notches::Hit.log({
60
+ :url => '/posts',
61
+ :user_agent => 'FeedBurner/1.0',
62
+ :session_id => '1',
63
+ :ip => '0.0.0.1'
64
+ })
65
+ hit = Notches::Hit.first
66
+ hit.should be_present
67
+ hit.url.url.should == '/posts'
68
+ hit.session.session_id.should == '1'
69
+ hit.ip.ip.should == '0.0.0.1'
70
+ hit.date.date.should == today
71
+ hit.time.time.strftime('%H:%M:%S').should == now.strftime('%H:%M:%S')
72
+ hit.user_agent.user_agent.should == 'FeedBurner/1.0'
73
+ end
74
+ end
75
+
76
+ let(:existing_hit) {
77
+ Notches::Hit.log(
78
+ :url => "/posts/1",
79
+ :user_agent => 'FeedBurner/1.0',
80
+ :session_id => '1',
81
+ :ip => '0.0.0.1'
82
+ )
83
+ }
84
+
85
+ it "does not create a new IP record if there's a record for that IP already" do
86
+ hit = Notches::Hit.log(
87
+ :url => "/posts/2",
88
+ :session_id => '2',
89
+ :ip => existing_hit.ip.ip
90
+ )
91
+ hit.ip.id.should == existing_hit.ip.id
92
+ end
93
+
94
+ it "does not create a new URL record if there's a record for that URL already" do
95
+ hit = Notches::Hit.log(
96
+ :url => existing_hit.url.url,
97
+ :session_id => '2',
98
+ :ip => '0.0.0.2'
99
+ )
100
+ hit.url.id.should == existing_hit.url.id
101
+ end
102
+
103
+ it "does not create a new Session record there's a record for that session id already" do
104
+ hit = Notches::Hit.log(
105
+ :url => "/posts/2",
106
+ :session_id => existing_hit.session.session_id,
107
+ :ip => '0.0.0.2'
108
+ )
109
+ hit.session.id.should == existing_hit.session.id
110
+ end
111
+
112
+ it "does not create a new Date record there's a record for that Date already" do
113
+ hit = Notches::Hit.log(
114
+ :url => '/posts/2',
115
+ :session_id => '2',
116
+ :ip => '0.0.0.2'
117
+ )
118
+ hit.date.id.should == existing_hit.date.id
119
+ end
120
+
121
+ it "does not create a new Time record there's a record for that Time already" do
122
+ Time.stub(:now => existing_hit.time.time)
123
+ hit = Notches::Hit.log(
124
+ :url => '/posts/2',
125
+ :session_id => '2',
126
+ :ip => '0.0.0.2'
127
+ )
128
+ hit.time.id.should == existing_hit.time.id
129
+ end
130
+
131
+ it "does not create a new UserAgent record if there's a record for that UserAgent already" do
132
+ hit = Notches::Hit.log(
133
+ :url => '/post/2',
134
+ :user_agent => 'FeedBurner/1.0',
135
+ :session_id => '2',
136
+ :ip => '0.0.0.2'
137
+ )
138
+ hit.user_agent.id.should == existing_hit.user_agent.id
139
+ end
140
+
141
+ context "a hit with the same url, session, ip, date and time exists already" do
142
+ it "does not log the hit" do
143
+ Date.stub(:today => existing_hit.date.date)
144
+ Time.stub(:now => existing_hit.time.time)
145
+ expect {
146
+ hit = Notches::Hit.log(
147
+ :url => existing_hit.url.url,
148
+ :user_agent => 'FeedBurner/1.0',
149
+ :session_id => existing_hit.session.session_id,
150
+ :ip => existing_hit.ip.ip
151
+ )
152
+ }.to_not change { Notches::Hit.count }
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+
4
+ Bundler.require :default, :development
5
+
6
+ Combustion.initialize!
7
+
8
+ require 'rspec/rails'
9
+
10
+ RSpec.configure do |config|
11
+ config.use_transactional_fixtures = true
12
+ end
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: notches
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Cillian O'Ruanaidh
9
+ - Paul Campbell
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2012-07-22 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rails
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: '3.1'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: '3.1'
31
+ - !ruby/object:Gem::Dependency
32
+ name: combustion
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ~>
37
+ - !ruby/object:Gem::Version
38
+ version: 0.3.2
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: 0.3.2
47
+ - !ruby/object:Gem::Dependency
48
+ name: rspec-rails
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '2.11'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: '2.11'
63
+ - !ruby/object:Gem::Dependency
64
+ name: sqlite3
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ version: 1.3.4
71
+ type: :development
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ~>
77
+ - !ruby/object:Gem::Version
78
+ version: 1.3.4
79
+ description: A Rails Engine for tracking your web traffic.
80
+ email:
81
+ - contact@cilliano.com
82
+ executables: []
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - .gitignore
87
+ - Gemfile
88
+ - HISTORY
89
+ - LICENSE
90
+ - README.md
91
+ - Rakefile
92
+ - app/assets/images/notches/hit.gif
93
+ - app/controllers/notches/hits_controller.rb
94
+ - app/models/notches/date.rb
95
+ - app/models/notches/hit.rb
96
+ - app/models/notches/ip.rb
97
+ - app/models/notches/session.rb
98
+ - app/models/notches/time.rb
99
+ - app/models/notches/url.rb
100
+ - app/models/notches/user_agent.rb
101
+ - config.ru
102
+ - config/routes.rb
103
+ - db/migrate/20120323111734_create_notches.rb
104
+ - db/migrate/20120713142636_create_notches_user_agents.rb
105
+ - lib/notches.rb
106
+ - lib/notches/engine.rb
107
+ - lib/notches/version.rb
108
+ - notches.gemspec
109
+ - spec/controllers/notches/hits_controller_spec.rb
110
+ - spec/internal/config/database.yml
111
+ - spec/internal/config/routes.rb
112
+ - spec/internal/db/schema.rb
113
+ - spec/internal/log/.gitignore
114
+ - spec/internal/public/favicon.ico
115
+ - spec/models/notches/hit_spec.rb
116
+ - spec/spec_helper.rb
117
+ homepage: http://github.com/hypertiny/notches
118
+ licenses: []
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ! '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ segments:
130
+ - 0
131
+ hash: 1181156043935805657
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ none: false
134
+ requirements:
135
+ - - ! '>='
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ segments:
139
+ - 0
140
+ hash: 1181156043935805657
141
+ requirements: []
142
+ rubyforge_project: notches
143
+ rubygems_version: 1.8.24
144
+ signing_key:
145
+ specification_version: 3
146
+ summary: Simple Rails web traffic counter
147
+ test_files:
148
+ - spec/controllers/notches/hits_controller_spec.rb
149
+ - spec/internal/config/database.yml
150
+ - spec/internal/config/routes.rb
151
+ - spec/internal/db/schema.rb
152
+ - spec/internal/log/.gitignore
153
+ - spec/internal/public/favicon.ico
154
+ - spec/models/notches/hit_spec.rb
155
+ - spec/spec_helper.rb