route_counter 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +82 -0
- data/Rakefile +2 -0
- data/lib/route_counter.rb +24 -0
- data/lib/route_counter/config.rb +27 -0
- data/lib/route_counter/console_formatter.rb +84 -0
- data/lib/route_counter/file_recorder.rb +127 -0
- data/lib/route_counter/middleware.rb +31 -0
- data/lib/route_counter/redis_recorder.rb +53 -0
- data/lib/route_counter/snapshot.rb +13 -0
- data/lib/route_counter/tasks.rb +34 -0
- data/lib/route_counter/version.rb +3 -0
- data/route_counter.gemspec +28 -0
- data/spec/config_spec.rb +38 -0
- data/spec/file_recorder_spec.rb +43 -0
- data/spec/redis_recorder_spec.rb +41 -0
- data/spec/spec_helper.rb +22 -0
- metadata +153 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1fc94b92228e7bbabc32aac5993cc9c40d419b05
|
4
|
+
data.tar.gz: aeb549b53956c26c7c6b34d6ec83491c184deddc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 370d759b06abd2057c2e855b55c83dd2913bda8aff7813c4fcbb8972c498cab8befa68f83a9f01a3acce5abc017821307c1e280d2d9cbfa15890155d37495892
|
7
|
+
data.tar.gz: 404f635724b19c567538865396b2e85edb3b96033894c15d491f77848c2d15e78ee7cb98c829b9db6b1814ed6cc843d541d13634d6910b865882d6937798efa3
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 TODO: Write your name
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# RouteCounter
|
2
|
+
|
3
|
+
When you want to know how much your routes are being used.
|
4
|
+
|
5
|
+
This is particularly useful if you are wondering if they are used at all.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'route_counter'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install route_counter
|
20
|
+
|
21
|
+
Enable the recording in an initializer and insert the middleware:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
RouteCounter.config.enabled = true
|
25
|
+
Rails.application.config.middleware.use RouteCounter::Middleware
|
26
|
+
```
|
27
|
+
|
28
|
+
Add to Rakefile:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
require "route_counter/tasks"
|
32
|
+
```
|
33
|
+
|
34
|
+
## Usage
|
35
|
+
|
36
|
+
|
37
|
+
Check what's been used.
|
38
|
+
|
39
|
+
```bash
|
40
|
+
$ bundle exec rake routes:count:local
|
41
|
+
```
|
42
|
+
|
43
|
+
All of this gets stored on your disk. If you want to clear it out.
|
44
|
+
|
45
|
+
```bash
|
46
|
+
$ bundle exec rake route_counter:local:clear
|
47
|
+
```
|
48
|
+
|
49
|
+
## Global Usage
|
50
|
+
|
51
|
+
You might want to see the counts across your servers.
|
52
|
+
This will use Redis to aggregate info from across all of them.
|
53
|
+
First, you'll need to tell it where Redis is:
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
RouteCounter.config.redis = Redis.new(connection_hash)
|
57
|
+
```
|
58
|
+
|
59
|
+
Then, you can clear out the remote store.
|
60
|
+
Or not to be cumulative to last time you took a snapshot
|
61
|
+
|
62
|
+
```bash
|
63
|
+
$ bundle exec rake route_counter:global:clear
|
64
|
+
```
|
65
|
+
|
66
|
+
Then take a snapshot. You can do this in parallel on all of your servers (with Capistrano for example).
|
67
|
+
|
68
|
+
```bash
|
69
|
+
$ bundle exec rake route_counter:snapshot
|
70
|
+
```
|
71
|
+
|
72
|
+
Then on one of the servers you can run to use the global numbers
|
73
|
+
|
74
|
+
```bash
|
75
|
+
$ bundle exec rake routes:count:global
|
76
|
+
```
|
77
|
+
|
78
|
+
## TODO
|
79
|
+
|
80
|
+
* could make a middleware (or config option) that wrote directly to Redis
|
81
|
+
* should it record more info about the request?
|
82
|
+
* configurable error handler
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require "route_counter/version"
|
2
|
+
|
3
|
+
module RouteCounter
|
4
|
+
autoload :Config, 'route_counter/config'
|
5
|
+
autoload :ConsoleFormatter, 'route_counter/console_formatter'
|
6
|
+
autoload :FileRecorder, 'route_counter/file_recorder'
|
7
|
+
autoload :Middleware, 'route_counter/middleware'
|
8
|
+
autoload :RedisRecorder, 'route_counter/redis_recorder'
|
9
|
+
autoload :Snapshot, 'route_counter/snapshot'
|
10
|
+
autoload :Util, 'route_counter/util'
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def config
|
14
|
+
@config ||= RouteCounter::Config.new
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def reset
|
20
|
+
# mostly for tests, resets eveything
|
21
|
+
@config = nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module RouteCounter
|
2
|
+
class Config
|
3
|
+
attr_writer :directory, :enabled, :redis
|
4
|
+
|
5
|
+
def directory
|
6
|
+
@directory ||= File.join(Dir.home, "route_counter")
|
7
|
+
end
|
8
|
+
|
9
|
+
def enabled
|
10
|
+
!!@enabled
|
11
|
+
end
|
12
|
+
alias :enabled? :enabled
|
13
|
+
|
14
|
+
def redis
|
15
|
+
return @redis if @redis
|
16
|
+
require 'redis'
|
17
|
+
@redis = Redis.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def error!(e)
|
21
|
+
# TODO: not worth it to crash but should log. allow settable
|
22
|
+
if defined?(Rails)
|
23
|
+
Rails.logger.error(e)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'action_dispatch/routing/inspector'
|
2
|
+
|
3
|
+
module RouteCounter
|
4
|
+
class ConsoleFormatter # like ActionDispatch::Routing::ConsoleFormatter
|
5
|
+
class << self
|
6
|
+
def puts!(recorder_klass)
|
7
|
+
# from railties/routes.rake
|
8
|
+
all_routes = Rails.application.routes.routes
|
9
|
+
inspector = ActionDispatch::Routing::RoutesInspector.new(all_routes)
|
10
|
+
path_hash = recorder_klass.actions_visited
|
11
|
+
formatter = RouteCounter::ConsoleFormatter.new(path_hash)
|
12
|
+
puts inspector.format(formatter, ENV['CONTROLLER'])
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(path_hash)
|
17
|
+
@buffer = []
|
18
|
+
@path_hash = path_hash || {}
|
19
|
+
end
|
20
|
+
|
21
|
+
def result
|
22
|
+
@buffer.join("\n")
|
23
|
+
end
|
24
|
+
|
25
|
+
def section_title(title)
|
26
|
+
@buffer << "\n#{title}:"
|
27
|
+
end
|
28
|
+
|
29
|
+
def section(routes)
|
30
|
+
@buffer << draw_section(routes)
|
31
|
+
end
|
32
|
+
|
33
|
+
def header(routes)
|
34
|
+
@buffer << draw_header(routes)
|
35
|
+
end
|
36
|
+
|
37
|
+
def no_routes
|
38
|
+
@buffer << <<-MESSAGE.strip_heredoc
|
39
|
+
You don't have any routes defined!
|
40
|
+
|
41
|
+
Please add some routes in config/routes.rb.
|
42
|
+
|
43
|
+
For more information about routes, see the Rails guide: http://guides.rubyonrails.org/routing.html.
|
44
|
+
MESSAGE
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def draw_section(routes)
|
49
|
+
count_width, name_width, verb_width, path_width = widths(routes)
|
50
|
+
|
51
|
+
routes.map do |r|
|
52
|
+
"#{count_for_route(r).ljust(count_width)} #{r[:name].ljust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def draw_header(routes)
|
57
|
+
count_width, name_width, verb_width, path_width = widths(routes)
|
58
|
+
|
59
|
+
"#{"Count".rjust(count_width)} #{"Prefix".ljust(name_width)} #{"Verb".ljust(verb_width)} #{"URI Pattern".ljust(path_width)} Controller#Action"
|
60
|
+
end
|
61
|
+
|
62
|
+
def widths(routes)
|
63
|
+
[ max_count_width,
|
64
|
+
routes.map { |r| r[:name].length }.max,
|
65
|
+
routes.map { |r| r[:verb].length }.max,
|
66
|
+
routes.map { |r| r[:path].length }.max]
|
67
|
+
end
|
68
|
+
|
69
|
+
def max_count_width
|
70
|
+
@max_count_width ||= [@path_hash.values.max.to_s.length, "Count".length].max
|
71
|
+
end
|
72
|
+
|
73
|
+
def count_for_route(r)
|
74
|
+
has_action = r[:reqs].to_s
|
75
|
+
return "~" unless has_action.include?("#")
|
76
|
+
count = 0
|
77
|
+
@path_hash.each do |action, num|
|
78
|
+
next unless has_action.start_with?(action)
|
79
|
+
count += num
|
80
|
+
end
|
81
|
+
count.to_s
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'monitor'
|
3
|
+
|
4
|
+
# A recorder implements these class methods
|
5
|
+
# * action_visited(controller_name, action_name) : record that it was visited
|
6
|
+
# * actions_visited : returns hash of url => count
|
7
|
+
# * rotate! : backup what was recorded and start counting again. returns hash.
|
8
|
+
# * clear! : clear everything out
|
9
|
+
|
10
|
+
module RouteCounter
|
11
|
+
class FileRecorder
|
12
|
+
class << self
|
13
|
+
|
14
|
+
def parent_directory
|
15
|
+
RouteCounter.config.directory
|
16
|
+
end
|
17
|
+
|
18
|
+
def current_directory
|
19
|
+
File.join(parent_directory, 'current')
|
20
|
+
end
|
21
|
+
|
22
|
+
def read_directory(root)
|
23
|
+
out = {}
|
24
|
+
Dir[ File.join(root, '**', '*') ].each do |file|
|
25
|
+
next if File.directory?(file)
|
26
|
+
hits = File.size(file) # each should be 1 byte
|
27
|
+
action_name = File.basename(file)
|
28
|
+
controller_name = File.dirname(file)
|
29
|
+
controller_name.gsub!("#{root}/", '')
|
30
|
+
key = "#{controller_name}##{action_name}"
|
31
|
+
out[key] ||= 0
|
32
|
+
out[key] += hits
|
33
|
+
end
|
34
|
+
out
|
35
|
+
end
|
36
|
+
|
37
|
+
def action_visited(controller_name, action_name)
|
38
|
+
# write down it was visited
|
39
|
+
file_path = File.join(File.join(current_directory, controller_name, action_name))
|
40
|
+
logdev = LogDevice.new(file_path)
|
41
|
+
logdev.write('X')
|
42
|
+
logdev.close
|
43
|
+
end
|
44
|
+
|
45
|
+
def actions_visited
|
46
|
+
# returns what was visited and counts
|
47
|
+
read_directory(current_directory)
|
48
|
+
end
|
49
|
+
|
50
|
+
def rotate!
|
51
|
+
# lock the current one and return the visited
|
52
|
+
alt_directory = File.join(parent_directory, "#{Time.now.to_i}-#{rand(99999999)}")
|
53
|
+
FileUtils.mkdir_p(current_directory) # make sure it's there
|
54
|
+
FileUtils.mv(current_directory, alt_directory)
|
55
|
+
read_directory(alt_directory)
|
56
|
+
end
|
57
|
+
|
58
|
+
def clear!
|
59
|
+
FileUtils.rm_rf(parent_directory)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class LogDevice # from Logger
|
64
|
+
|
65
|
+
attr_reader :dev
|
66
|
+
attr_reader :filename
|
67
|
+
|
68
|
+
class LogDeviceMutex
|
69
|
+
include MonitorMixin
|
70
|
+
end
|
71
|
+
|
72
|
+
def initialize(log = nil, opt = {})
|
73
|
+
@dev = @filename = nil
|
74
|
+
@mutex = LogDeviceMutex.new
|
75
|
+
if log.respond_to?(:write) and log.respond_to?(:close)
|
76
|
+
@dev = log
|
77
|
+
else
|
78
|
+
@dev = open_logfile(log)
|
79
|
+
@dev.sync = true
|
80
|
+
@filename = log
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def write(message)
|
85
|
+
@mutex.synchronize do
|
86
|
+
@dev.write(message)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def close
|
91
|
+
begin
|
92
|
+
@mutex.synchronize do
|
93
|
+
@dev.close rescue nil
|
94
|
+
end
|
95
|
+
rescue Exception
|
96
|
+
@dev.close rescue nil
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def open_logfile(filename)
|
103
|
+
begin
|
104
|
+
open(filename, (File::WRONLY | File::APPEND))
|
105
|
+
rescue Errno::ENOENT
|
106
|
+
create_logfile(filename)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def create_logfile(filename)
|
111
|
+
begin
|
112
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
113
|
+
|
114
|
+
logdev = open(filename, (File::WRONLY | File::APPEND | File::CREAT | File::EXCL))
|
115
|
+
logdev.flock(File::LOCK_EX)
|
116
|
+
logdev.sync = true
|
117
|
+
logdev.flock(File::LOCK_UN)
|
118
|
+
rescue Errno::EEXIST
|
119
|
+
# file is created by another process
|
120
|
+
logdev = open_logfile(filename)
|
121
|
+
logdev.sync = true
|
122
|
+
end
|
123
|
+
logdev
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module RouteCounter
|
2
|
+
class Middleware
|
3
|
+
attr_reader :env
|
4
|
+
def initialize(app)
|
5
|
+
@app = app
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
@env = env
|
10
|
+
status, headers, body = @app.call(env)
|
11
|
+
write_result! if RouteCounter.config.enabled?
|
12
|
+
[status, headers, body]
|
13
|
+
end
|
14
|
+
|
15
|
+
def write_result!
|
16
|
+
result = env['action_dispatch.request.path_parameters']
|
17
|
+
return unless result
|
18
|
+
|
19
|
+
controller_name = result[:controller]
|
20
|
+
action_name = result[:action]
|
21
|
+
|
22
|
+
return unless controller_name && action_name
|
23
|
+
|
24
|
+
# TODO: case on config for types: file, redis, other
|
25
|
+
# TODO: use env['REQUEST_METHOD'] ?
|
26
|
+
RouteCounter::FileRecorder.action_visited(controller_name, action_name)
|
27
|
+
rescue Exception => e
|
28
|
+
RouteCounter.config.error!("[RouteCleaner] #{e.message}\n#{e.backtrace.join("\n")}")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'monitor'
|
3
|
+
|
4
|
+
# A recorder implements these class methods
|
5
|
+
# * action_visited(controller_name, action_name) : record that it was visited
|
6
|
+
# * actions_visited : returns hash of url => count
|
7
|
+
# * rotate! : backup what was recorded and start counting again. returns hash.
|
8
|
+
# * clear! : clear everything out
|
9
|
+
|
10
|
+
module RouteCounter
|
11
|
+
class RedisRecorder
|
12
|
+
class << self
|
13
|
+
|
14
|
+
def client
|
15
|
+
RouteCounter.config.redis
|
16
|
+
end
|
17
|
+
|
18
|
+
def current_key
|
19
|
+
"route_counter:current"
|
20
|
+
end
|
21
|
+
|
22
|
+
def read_key(key)
|
23
|
+
out = {}
|
24
|
+
client.hgetall(key).each do |action, num|
|
25
|
+
out[action] = num.to_i
|
26
|
+
end
|
27
|
+
out
|
28
|
+
end
|
29
|
+
|
30
|
+
def increment!(action_key, amount)
|
31
|
+
client.hincrby(current_key, action_key, amount)
|
32
|
+
end
|
33
|
+
|
34
|
+
def action_visited(controller_name, action_name)
|
35
|
+
key = "#{controller_name}##{action_name}"
|
36
|
+
increment!(key, 1)
|
37
|
+
end
|
38
|
+
|
39
|
+
def actions_visited
|
40
|
+
# returns what was visited and counts
|
41
|
+
read_key(current_key)
|
42
|
+
end
|
43
|
+
|
44
|
+
def rotate!
|
45
|
+
raise "not supported"
|
46
|
+
end
|
47
|
+
|
48
|
+
def clear!
|
49
|
+
client.del(current_key)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
namespace :routes do
|
2
|
+
namespace :count do
|
3
|
+
desc "Shows the routes and if they've been used locally"
|
4
|
+
task local: :environment do
|
5
|
+
RouteCounter::ConsoleFormatter.puts!(RouteCounter::FileRecorder)
|
6
|
+
end
|
7
|
+
|
8
|
+
desc "Shows the routes and if they've been used globally"
|
9
|
+
task global: :environment do
|
10
|
+
RouteCounter::ConsoleFormatter.puts!(RouteCounter::RedisRecorder)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
namespace :route_counter do
|
16
|
+
desc "send local information to global"
|
17
|
+
task snapshot: :environment do
|
18
|
+
RouteCounter::Snapshot.transfer!(RouteCounter::FileRecorder)
|
19
|
+
end
|
20
|
+
|
21
|
+
namespace :local do
|
22
|
+
desc "clears out the local store"
|
23
|
+
task clear: :environment do
|
24
|
+
RouteCounter::FileRecorder.clear!
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
namespace :global do
|
29
|
+
desc "clears out the global store"
|
30
|
+
task clear: :environment do
|
31
|
+
RouteCounter::RedisRecorder.clear!
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'route_counter/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "route_counter"
|
8
|
+
spec.version = RouteCounter::VERSION
|
9
|
+
spec.authors = ["Brian Leonard"]
|
10
|
+
spec.email = ["brian@bleonard.com"]
|
11
|
+
spec.summary = %q{Monitors the usage of your routes}
|
12
|
+
spec.description = %q{Helps you to find unused Rails routes}
|
13
|
+
spec.homepage = "https://github.com/taskrabbit/route_counter"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "rack"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "redis"
|
26
|
+
spec.add_development_dependency "rspec"
|
27
|
+
spec.add_development_dependency "byebug"
|
28
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RouteCounter::Config do
|
4
|
+
it "should be returned from the module" do
|
5
|
+
RouteCounter.config.class.name.should == "RouteCounter::Config"
|
6
|
+
end
|
7
|
+
|
8
|
+
describe ".directory" do
|
9
|
+
it "should default to ~/" do
|
10
|
+
RouteCounter.send(:reset)
|
11
|
+
RouteCounter.config.directory.to_s.should == File.join(Dir.home, "route_counter")
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should be defaulting to tmp directory in test" do
|
15
|
+
RouteCounter.config.directory.should =~ /\/tmp\/recorder/
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should be able to be set" do
|
19
|
+
RouteCounter.config.directory = "something"
|
20
|
+
RouteCounter.config.directory.should == "something"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe ".enabled" do
|
25
|
+
it "should defualt to false" do
|
26
|
+
RouteCounter.config.enabled.should == false
|
27
|
+
RouteCounter.config.enabled?.should == false
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should be able to be set" do
|
31
|
+
RouteCounter.config.enabled = true
|
32
|
+
|
33
|
+
RouteCounter.config.enabled.should == true
|
34
|
+
RouteCounter.config.enabled?.should == true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
describe RouteCounter::FileRecorder do
|
5
|
+
before(:each) do
|
6
|
+
RouteCounter::FileRecorder.clear!
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#action_visited" do
|
10
|
+
it "should write to file" do
|
11
|
+
controller = "comments"
|
12
|
+
action_name = "create"
|
13
|
+
|
14
|
+
current_path = File.join(RouteCounter::FileRecorder.parent_directory, "current")
|
15
|
+
check_path = File.join(current_path, "comments", "create")
|
16
|
+
|
17
|
+
File.exists?(check_path).should == false
|
18
|
+
|
19
|
+
RouteCounter::FileRecorder.action_visited(controller, action_name)
|
20
|
+
|
21
|
+
File.exists?(check_path).should == true
|
22
|
+
File.read(check_path).should == 'X'
|
23
|
+
|
24
|
+
RouteCounter::FileRecorder.action_visited(controller, action_name)
|
25
|
+
|
26
|
+
File.read(check_path).should == 'XX'
|
27
|
+
|
28
|
+
paths = RouteCounter::FileRecorder.actions_visited
|
29
|
+
paths.should == { "comments#create" => 2 }
|
30
|
+
|
31
|
+
RouteCounter::FileRecorder.action_visited("engine/comments", "create")
|
32
|
+
paths = RouteCounter::FileRecorder.actions_visited
|
33
|
+
paths.should == { "comments#create" => 2, "engine/comments#create" => 1 }
|
34
|
+
|
35
|
+
File.exist?(current_path).should == true
|
36
|
+
|
37
|
+
paths = RouteCounter::FileRecorder.rotate!
|
38
|
+
paths.should == { "comments#create" => 2, "engine/comments#create" => 1 }
|
39
|
+
|
40
|
+
File.exist?(current_path).should == false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RouteCounter::RedisRecorder do
|
4
|
+
before(:each) do
|
5
|
+
@redis = RouteCounter.config.redis
|
6
|
+
RouteCounter::RedisRecorder.clear!
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#action_visited" do
|
10
|
+
it "should write to file" do
|
11
|
+
controller = "comments"
|
12
|
+
action_name = "create"
|
13
|
+
|
14
|
+
key = "route_counter:current"
|
15
|
+
action_key = "#{controller}##{action_name}"
|
16
|
+
@redis.exists(key).should == false
|
17
|
+
|
18
|
+
RouteCounter::RedisRecorder.action_visited(controller, action_name)
|
19
|
+
|
20
|
+
@redis.exists(key).should == true
|
21
|
+
@redis.hget(key, action_key).to_i.should == 1
|
22
|
+
|
23
|
+
RouteCounter::RedisRecorder.action_visited(controller, action_name)
|
24
|
+
|
25
|
+
@redis.hget(key, action_key).to_i.should == 2
|
26
|
+
|
27
|
+
paths = RouteCounter::RedisRecorder.actions_visited
|
28
|
+
paths.should == { "comments#create" => 2 }
|
29
|
+
|
30
|
+
RouteCounter::RedisRecorder.action_visited("engine/comments", "create")
|
31
|
+
paths = RouteCounter::RedisRecorder.actions_visited
|
32
|
+
paths.should == { "comments#create" => 2, "engine/comments#create" => 1 }
|
33
|
+
|
34
|
+
@redis.exists(key).should == true
|
35
|
+
|
36
|
+
RouteCounter::RedisRecorder.clear!
|
37
|
+
|
38
|
+
@redis.exists(key).should == false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'route_counter'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'byebug'
|
5
|
+
|
6
|
+
module Kernel
|
7
|
+
alias :debugger :byebug
|
8
|
+
end
|
9
|
+
|
10
|
+
rescue LoadError => e
|
11
|
+
# byebug isn't installed - no debugging here!
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
RSpec.configure do |config|
|
16
|
+
config.mock_framework = :rspec
|
17
|
+
|
18
|
+
config.before(:each) do
|
19
|
+
RouteCounter.send(:reset)
|
20
|
+
RouteCounter.config.directory = File.expand_path("tmp/recorder")
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: route_counter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Brian Leonard
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-12-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rack
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
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: redis
|
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: rspec
|
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: byebug
|
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: Helps you to find unused Rails routes
|
98
|
+
email:
|
99
|
+
- brian@bleonard.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- .gitignore
|
105
|
+
- .rspec
|
106
|
+
- Gemfile
|
107
|
+
- LICENSE.txt
|
108
|
+
- README.md
|
109
|
+
- Rakefile
|
110
|
+
- lib/route_counter.rb
|
111
|
+
- lib/route_counter/config.rb
|
112
|
+
- lib/route_counter/console_formatter.rb
|
113
|
+
- lib/route_counter/file_recorder.rb
|
114
|
+
- lib/route_counter/middleware.rb
|
115
|
+
- lib/route_counter/redis_recorder.rb
|
116
|
+
- lib/route_counter/snapshot.rb
|
117
|
+
- lib/route_counter/tasks.rb
|
118
|
+
- lib/route_counter/version.rb
|
119
|
+
- route_counter.gemspec
|
120
|
+
- spec/config_spec.rb
|
121
|
+
- spec/file_recorder_spec.rb
|
122
|
+
- spec/redis_recorder_spec.rb
|
123
|
+
- spec/spec_helper.rb
|
124
|
+
homepage: https://github.com/taskrabbit/route_counter
|
125
|
+
licenses:
|
126
|
+
- MIT
|
127
|
+
metadata: {}
|
128
|
+
post_install_message:
|
129
|
+
rdoc_options: []
|
130
|
+
require_paths:
|
131
|
+
- lib
|
132
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
133
|
+
requirements:
|
134
|
+
- - '>='
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
137
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
|
+
requirements:
|
139
|
+
- - '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
requirements: []
|
143
|
+
rubyforge_project:
|
144
|
+
rubygems_version: 2.0.3
|
145
|
+
signing_key:
|
146
|
+
specification_version: 4
|
147
|
+
summary: Monitors the usage of your routes
|
148
|
+
test_files:
|
149
|
+
- spec/config_spec.rb
|
150
|
+
- spec/file_recorder_spec.rb
|
151
|
+
- spec/redis_recorder_spec.rb
|
152
|
+
- spec/spec_helper.rb
|
153
|
+
has_rdoc:
|