route_counter 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in route_counter.gemspec
4
+ gemspec
@@ -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.
@@ -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
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -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,13 @@
1
+ module RouteCounter
2
+ class Snapshot
3
+ class << self
4
+ # send to redis
5
+ def transfer!(recorder_klass)
6
+ hash = recorder_klass.rotate!
7
+ hash.each do |action, num|
8
+ RedisRecorder.increment!(action, num)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ 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,3 @@
1
+ module RouteCounter
2
+ VERSION = "0.1.0"
3
+ 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
@@ -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
@@ -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: