hit_counter 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +13 -0
  4. data/LICENSE.txt +14 -0
  5. data/README.rdoc +53 -0
  6. data/Rakefile +48 -0
  7. data/VERSION +1 -0
  8. data/lib/hit_counter.rb +105 -0
  9. data/lib/tasks/install.rake +7 -0
  10. data/public/images/digits/celtic/0.gif +0 -0
  11. data/public/images/digits/celtic/1.gif +0 -0
  12. data/public/images/digits/celtic/2.gif +0 -0
  13. data/public/images/digits/celtic/3.gif +0 -0
  14. data/public/images/digits/celtic/4.gif +0 -0
  15. data/public/images/digits/celtic/5.gif +0 -0
  16. data/public/images/digits/celtic/6.gif +0 -0
  17. data/public/images/digits/celtic/7.gif +0 -0
  18. data/public/images/digits/celtic/8.gif +0 -0
  19. data/public/images/digits/celtic/9.gif +0 -0
  20. data/public/images/digits/odometer/0.gif +0 -0
  21. data/public/images/digits/odometer/1.gif +0 -0
  22. data/public/images/digits/odometer/2.gif +0 -0
  23. data/public/images/digits/odometer/3.gif +0 -0
  24. data/public/images/digits/odometer/4.gif +0 -0
  25. data/public/images/digits/odometer/5.gif +0 -0
  26. data/public/images/digits/odometer/6.gif +0 -0
  27. data/public/images/digits/odometer/7.gif +0 -0
  28. data/public/images/digits/odometer/8.gif +0 -0
  29. data/public/images/digits/odometer/9.gif +0 -0
  30. data/public/images/digits/scout/0.gif +0 -0
  31. data/public/images/digits/scout/1.gif +0 -0
  32. data/public/images/digits/scout/2.gif +0 -0
  33. data/public/images/digits/scout/3.gif +0 -0
  34. data/public/images/digits/scout/4.gif +0 -0
  35. data/public/images/digits/scout/5.gif +0 -0
  36. data/public/images/digits/scout/6.gif +0 -0
  37. data/public/images/digits/scout/7.gif +0 -0
  38. data/public/images/digits/scout/8.gif +0 -0
  39. data/public/images/digits/scout/9.gif +0 -0
  40. data/spec/lib/hit_counter_spec.rb +53 -0
  41. data/spec/spec_helper.rb +18 -0
  42. metadata +163 -0
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'addressable'
4
+ gem 'mongoid'
5
+ gem 'rmagick', '2.12.2' # version compatible with heroku
6
+
7
+ group :development do
8
+ gem 'jeweler'
9
+ end
10
+
11
+ group :test do
12
+ gem 'rspec'
13
+ end
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
@@ -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
@@ -0,0 +1,7 @@
1
+ namespace :hit_counter do
2
+ desc 'Install HitCounter into your app.'
3
+ task :install do
4
+ dir = Gem.searcher.find('hit_counter').full_gem_path
5
+ system "rsync -ruv #{dir}/public/images public/images"
6
+ end
7
+ 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
@@ -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
+