hit_counter 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +14 -0
- data/README.rdoc +53 -0
- data/Rakefile +48 -0
- data/VERSION +1 -0
- data/lib/hit_counter.rb +105 -0
- data/lib/tasks/install.rake +7 -0
- data/public/images/digits/celtic/0.gif +0 -0
- data/public/images/digits/celtic/1.gif +0 -0
- data/public/images/digits/celtic/2.gif +0 -0
- data/public/images/digits/celtic/3.gif +0 -0
- data/public/images/digits/celtic/4.gif +0 -0
- data/public/images/digits/celtic/5.gif +0 -0
- data/public/images/digits/celtic/6.gif +0 -0
- data/public/images/digits/celtic/7.gif +0 -0
- data/public/images/digits/celtic/8.gif +0 -0
- data/public/images/digits/celtic/9.gif +0 -0
- data/public/images/digits/odometer/0.gif +0 -0
- data/public/images/digits/odometer/1.gif +0 -0
- data/public/images/digits/odometer/2.gif +0 -0
- data/public/images/digits/odometer/3.gif +0 -0
- data/public/images/digits/odometer/4.gif +0 -0
- data/public/images/digits/odometer/5.gif +0 -0
- data/public/images/digits/odometer/6.gif +0 -0
- data/public/images/digits/odometer/7.gif +0 -0
- data/public/images/digits/odometer/8.gif +0 -0
- data/public/images/digits/odometer/9.gif +0 -0
- data/public/images/digits/scout/0.gif +0 -0
- data/public/images/digits/scout/1.gif +0 -0
- data/public/images/digits/scout/2.gif +0 -0
- data/public/images/digits/scout/3.gif +0 -0
- data/public/images/digits/scout/4.gif +0 -0
- data/public/images/digits/scout/5.gif +0 -0
- data/public/images/digits/scout/6.gif +0 -0
- data/public/images/digits/scout/7.gif +0 -0
- data/public/images/digits/scout/8.gif +0 -0
- data/public/images/digits/scout/9.gif +0 -0
- data/spec/lib/hit_counter_spec.rb +53 -0
- data/spec/spec_helper.rb +18 -0
- metadata +163 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
Copyright (c) 2011 Roderick Monje
|
2
|
+
|
3
|
+
This program is free software: you can redistribute it and/or modify
|
4
|
+
it under the terms of the GNU General Public License as published by
|
5
|
+
the Free Software Foundation, either version 3 of the License, or
|
6
|
+
(at your option) any later version.
|
7
|
+
|
8
|
+
This program is distributed in the hope that it will be useful,
|
9
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
GNU General Public License for more details.
|
12
|
+
|
13
|
+
You should have received a copy of the GNU General Public License
|
14
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
data/README.rdoc
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
= hit_counter
|
2
|
+
|
3
|
+
Ruby version of that old 90s chestnut, the web-site hit counter.
|
4
|
+
|
5
|
+
== How to Install
|
6
|
+
|
7
|
+
1. Install the gem.
|
8
|
+
|
9
|
+
Gemfile:
|
10
|
+
|
11
|
+
gem 'hit_counter'
|
12
|
+
|
13
|
+
2. Add a controller action to your app.
|
14
|
+
|
15
|
+
controller.rb:
|
16
|
+
|
17
|
+
def hit_counter
|
18
|
+
return if params[:url].blank?
|
19
|
+
hc = HitCounter.get params[:url]
|
20
|
+
hc.increment
|
21
|
+
send_data hc.image(params[:style]).to_blob, :disposition => 'inline', :filename => "#{hc.hits}.png", :type => :png
|
22
|
+
end
|
23
|
+
|
24
|
+
routes.rb:
|
25
|
+
|
26
|
+
get 'hit-counter' => 'webmaster_tools#hit_counter' # technically should be PUT, but GET makes integration simpler
|
27
|
+
|
28
|
+
3. Add the hit-counter image tag to your site's HTML:
|
29
|
+
|
30
|
+
<img alt="Hit Counter" border="0" src="/hit-counter?url=http://cnn.com&style=1" />
|
31
|
+
|
32
|
+
== How to Customize the Hit-Counter Image
|
33
|
+
|
34
|
+
1. Create a GIF for each of the digits, 0.gif through 9.gif.
|
35
|
+
|
36
|
+
2. Add the images to a folder named after your new style in public/images/digits.
|
37
|
+
|
38
|
+
3. Add the folder name to HitCounter::STYLES. In your HTML, specify the new style with a params[:style] equal to its index in the array plus one.
|
39
|
+
|
40
|
+
== Contributing to hit_counter
|
41
|
+
|
42
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
43
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
44
|
+
* Fork the project
|
45
|
+
* Start a feature/bugfix branch
|
46
|
+
* Commit and push until you are happy with your contribution
|
47
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
48
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
49
|
+
|
50
|
+
== Copyright
|
51
|
+
|
52
|
+
Copyright (c) 2011 Roderick Monje. See LICENSE.txt for
|
53
|
+
further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development, :test)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "hit_counter"
|
18
|
+
gem.homepage = "http://github.com/ivanoblomov/hit_counter"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Ruby version of that old 90s chestnut, the web-site hit counter.}
|
21
|
+
gem.email = "rod@seologic.com"
|
22
|
+
gem.authors = ["Roderick Monje"]
|
23
|
+
# dependencies defined in Gemfile
|
24
|
+
end
|
25
|
+
Jeweler::RubygemsDotOrgTasks.new
|
26
|
+
|
27
|
+
require 'rspec/core'
|
28
|
+
require 'rspec/core/rake_task'
|
29
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
30
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
31
|
+
end
|
32
|
+
|
33
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
34
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
35
|
+
spec.rcov = true
|
36
|
+
end
|
37
|
+
|
38
|
+
task :default => :spec
|
39
|
+
|
40
|
+
require 'rake/rdoctask'
|
41
|
+
Rake::RDocTask.new do |rdoc|
|
42
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
43
|
+
|
44
|
+
rdoc.rdoc_dir = 'rdoc'
|
45
|
+
rdoc.title = "hit_counter #{version}"
|
46
|
+
rdoc.rdoc_files.include('README*')
|
47
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
48
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
data/lib/hit_counter.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
# Copyright (c) 2011 Roderick Monje
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
class HitCounter
|
16
|
+
include Mongoid::Document
|
17
|
+
include Mongoid::Timestamps
|
18
|
+
|
19
|
+
# Mongo Config ===================================================================================
|
20
|
+
field :url
|
21
|
+
field :hits, :type => Integer, :default => 0
|
22
|
+
|
23
|
+
# Validates the <code>HitCounter</code>'s URL.
|
24
|
+
#
|
25
|
+
# If the URI library can parse the value and the scheme is valid, then we assume the url is valid.
|
26
|
+
class UrlValidator < ActiveModel::EachValidator
|
27
|
+
def validate_each record, attribute, value
|
28
|
+
begin
|
29
|
+
uri = Addressable::URI.parse value
|
30
|
+
|
31
|
+
if !['http', 'https'].include? uri.scheme
|
32
|
+
raise Addressable::URI::InvalidURIError
|
33
|
+
end
|
34
|
+
rescue Addressable::URI::InvalidURIError
|
35
|
+
record.errors[attribute] << 'Invalid URL'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
validates :url, :presence => true, :url => true, :uniqueness => true
|
41
|
+
|
42
|
+
# Class methods ==================================================================================
|
43
|
+
|
44
|
+
# Returns a <code>HitCounter</code> matching the specified URL. The HitCounter is created if no
|
45
|
+
# matching one is found.
|
46
|
+
#
|
47
|
+
# * *Args*
|
48
|
+
# - +url+ -> the URL for the site being counted
|
49
|
+
# * *Returns*
|
50
|
+
# - the site's HitCounter
|
51
|
+
def self.get url
|
52
|
+
self.find_or_create_by :url => HitCounter.normalize_url(url)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Instance methods: Overrides ====================================================================
|
56
|
+
|
57
|
+
# Sets the URL to be tracked. The http prefix is optional.
|
58
|
+
#
|
59
|
+
# * *Args*
|
60
|
+
# - +value+ -> the URL for the site being counted
|
61
|
+
# * *Returns*
|
62
|
+
# - the value
|
63
|
+
def url= value
|
64
|
+
self[:url] = HitCounter.normalize_url value
|
65
|
+
end
|
66
|
+
|
67
|
+
# Instance methods ===============================================================================
|
68
|
+
|
69
|
+
# Returns the hit count as a PNG image, using the specified style:
|
70
|
+
# 1 odometer
|
71
|
+
# 2 scout
|
72
|
+
# 3 Celtic
|
73
|
+
#
|
74
|
+
# * *Args*
|
75
|
+
# - +style_number+ -> the image style
|
76
|
+
# * *Returns*
|
77
|
+
# - the current hit count as a PNG image
|
78
|
+
def image style_number = 0
|
79
|
+
image = HitCounter.cat_image self.hits.to_s, style_number.to_i - 1
|
80
|
+
image.format = 'png'
|
81
|
+
image
|
82
|
+
end
|
83
|
+
|
84
|
+
# Increments the hit count and saves the HitCounter.
|
85
|
+
#
|
86
|
+
# * *Returns*
|
87
|
+
# - true if the save was successful
|
88
|
+
def increment
|
89
|
+
self.hits += 1
|
90
|
+
self.save
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
STYLES = ['odometer', 'scout', 'celtic']
|
96
|
+
|
97
|
+
def self.cat_image number = '0', style_index = 0, images = Magick::ImageList.new
|
98
|
+
return images.append(false) if number.blank?
|
99
|
+
HitCounter.cat_image number[1..-1], style_index, images << Magick::Image.read("#{Rails.root}/public/images/digits/#{STYLES[style_index]}/#{number[0..0]}.gif").first
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.normalize_url value
|
103
|
+
value !~ %r{^http://} ? "http://#{value}" : value
|
104
|
+
end
|
105
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe HitCounter do
|
4
|
+
before :all do
|
5
|
+
HitCounter.delete_all
|
6
|
+
@hit_counter = HitCounter.get 'www.google.com'
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#get' do
|
10
|
+
context 'when existing URL' do
|
11
|
+
describe 'document count' do
|
12
|
+
specify { HitCounter.count.should == 1 }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when new URL' do
|
17
|
+
before { HitCounter.get 'www.cnn.com' }
|
18
|
+
|
19
|
+
describe 'document count' do
|
20
|
+
specify { HitCounter.count.should == 2 }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#hits' do
|
26
|
+
subject { @hit_counter.hits }
|
27
|
+
|
28
|
+
it { should == 0 }
|
29
|
+
|
30
|
+
context 'when incremented' do
|
31
|
+
before { @hit_counter.increment }
|
32
|
+
|
33
|
+
specify { @hit_counter.hits.should == 1 }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#image' do
|
38
|
+
subject { @hit_counter.image }
|
39
|
+
|
40
|
+
it { should be_a Magick::Image }
|
41
|
+
pending 'should reflect hits'
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#normalize_url' do
|
45
|
+
context 'with "cnn.com"' do
|
46
|
+
specify { HitCounter.normalize_url('cnn.com').should == 'http://cnn.com' }
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'with "http://www.nytimes.com"' do
|
50
|
+
specify { HitCounter.normalize_url('http://www.nytimes.com').should == 'http://www.nytimes.com' }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'addressable/uri'
|
4
|
+
require 'mongoid'
|
5
|
+
require 'rmagick'
|
6
|
+
require 'rspec'
|
7
|
+
|
8
|
+
require 'hit_counter'
|
9
|
+
|
10
|
+
Mongoid::Config.from_hash 'database' => 'hit_counter'
|
11
|
+
Mongoid.logger = false
|
12
|
+
|
13
|
+
# Stub Rails root during tests.
|
14
|
+
module Rails
|
15
|
+
def self.root
|
16
|
+
'.'
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hit_counter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 31
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 0.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Roderick Monje
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-09-17 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: addressable
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: mongoid
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: rmagick
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - "="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 59
|
57
|
+
segments:
|
58
|
+
- 2
|
59
|
+
- 12
|
60
|
+
- 2
|
61
|
+
version: 2.12.2
|
62
|
+
type: :runtime
|
63
|
+
version_requirements: *id003
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: jeweler
|
66
|
+
prerelease: false
|
67
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
hash: 3
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
version: "0"
|
76
|
+
type: :development
|
77
|
+
version_requirements: *id004
|
78
|
+
description:
|
79
|
+
email: rod@seologic.com
|
80
|
+
executables: []
|
81
|
+
|
82
|
+
extensions: []
|
83
|
+
|
84
|
+
extra_rdoc_files:
|
85
|
+
- LICENSE.txt
|
86
|
+
- README.rdoc
|
87
|
+
files:
|
88
|
+
- .document
|
89
|
+
- .rspec
|
90
|
+
- Gemfile
|
91
|
+
- LICENSE.txt
|
92
|
+
- README.rdoc
|
93
|
+
- Rakefile
|
94
|
+
- VERSION
|
95
|
+
- lib/hit_counter.rb
|
96
|
+
- lib/tasks/install.rake
|
97
|
+
- public/images/digits/celtic/0.gif
|
98
|
+
- public/images/digits/celtic/1.gif
|
99
|
+
- public/images/digits/celtic/2.gif
|
100
|
+
- public/images/digits/celtic/3.gif
|
101
|
+
- public/images/digits/celtic/4.gif
|
102
|
+
- public/images/digits/celtic/5.gif
|
103
|
+
- public/images/digits/celtic/6.gif
|
104
|
+
- public/images/digits/celtic/7.gif
|
105
|
+
- public/images/digits/celtic/8.gif
|
106
|
+
- public/images/digits/celtic/9.gif
|
107
|
+
- public/images/digits/odometer/0.gif
|
108
|
+
- public/images/digits/odometer/1.gif
|
109
|
+
- public/images/digits/odometer/2.gif
|
110
|
+
- public/images/digits/odometer/3.gif
|
111
|
+
- public/images/digits/odometer/4.gif
|
112
|
+
- public/images/digits/odometer/5.gif
|
113
|
+
- public/images/digits/odometer/6.gif
|
114
|
+
- public/images/digits/odometer/7.gif
|
115
|
+
- public/images/digits/odometer/8.gif
|
116
|
+
- public/images/digits/odometer/9.gif
|
117
|
+
- public/images/digits/scout/0.gif
|
118
|
+
- public/images/digits/scout/1.gif
|
119
|
+
- public/images/digits/scout/2.gif
|
120
|
+
- public/images/digits/scout/3.gif
|
121
|
+
- public/images/digits/scout/4.gif
|
122
|
+
- public/images/digits/scout/5.gif
|
123
|
+
- public/images/digits/scout/6.gif
|
124
|
+
- public/images/digits/scout/7.gif
|
125
|
+
- public/images/digits/scout/8.gif
|
126
|
+
- public/images/digits/scout/9.gif
|
127
|
+
- spec/lib/hit_counter_spec.rb
|
128
|
+
- spec/spec_helper.rb
|
129
|
+
homepage: http://github.com/ivanoblomov/hit_counter
|
130
|
+
licenses:
|
131
|
+
- MIT
|
132
|
+
post_install_message:
|
133
|
+
rdoc_options: []
|
134
|
+
|
135
|
+
require_paths:
|
136
|
+
- lib
|
137
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
hash: 3
|
143
|
+
segments:
|
144
|
+
- 0
|
145
|
+
version: "0"
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
none: false
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
hash: 3
|
152
|
+
segments:
|
153
|
+
- 0
|
154
|
+
version: "0"
|
155
|
+
requirements: []
|
156
|
+
|
157
|
+
rubyforge_project:
|
158
|
+
rubygems_version: 1.8.10
|
159
|
+
signing_key:
|
160
|
+
specification_version: 3
|
161
|
+
summary: Ruby version of that old 90s chestnut, the web-site hit counter.
|
162
|
+
test_files: []
|
163
|
+
|