code_hunter 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +15 -0
- data/Rakefile +1 -0
- data/bin/code_hunter +6 -0
- data/code_hunter.gemspec +27 -0
- data/lib/code_hunter.rb +9 -0
- data/lib/code_hunter/brakeman.rb +40 -0
- data/lib/code_hunter/brakeman/invoker.rb +18 -0
- data/lib/code_hunter/brakeman/summarizer.rb +57 -0
- data/lib/code_hunter/git_blamer.rb +26 -0
- data/lib/code_hunter/option_parser.rb +84 -0
- data/lib/code_hunter/rails_best_practices.rb +40 -0
- data/lib/code_hunter/rails_best_practices/invoker.rb +19 -0
- data/lib/code_hunter/rails_best_practices/summarizer.rb +48 -0
- data/lib/code_hunter/renderer.rb +36 -0
- data/lib/code_hunter/runner.rb +46 -0
- data/lib/code_hunter/version.rb +3 -0
- data/spec/code_hunter/renderer_spec.rb +59 -0
- data/spec/spec_helper.rb +8 -0
- metadata +165 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Ryo Nakamura
|
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,15 @@
|
|
1
|
+
# Code Hunter
|
2
|
+
Hunt out weak spots in your rails application with 2 static metrics tools:
|
3
|
+
|
4
|
+
* [Brakeman](https://github.com/presidentbeef/brakeman) - A static analysis security vulnerability scanner for Rails
|
5
|
+
* [RailsBestPractices](https://github.com/railsbp/rails_best_practices) - A code metric tool for rails projects
|
6
|
+
|
7
|
+
## Usage
|
8
|
+
```
|
9
|
+
$ ./bin/code_hunter --help
|
10
|
+
Usage: code_hunter [options]
|
11
|
+
--application-path= (default: ./) rails application root path
|
12
|
+
```
|
13
|
+
|
14
|
+
## Requirements
|
15
|
+
* Ruby >= 1.9
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/code_hunter
ADDED
data/code_hunter.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "code_hunter/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "code_hunter"
|
8
|
+
gem.version = CodeHunter::VERSION
|
9
|
+
gem.authors = ["Ryo Nakamura"]
|
10
|
+
gem.email = ["r7kamura@gmail.com"]
|
11
|
+
gem.description = "Hunt out weak spots in your rails application"
|
12
|
+
gem.summary = "Code hunter"
|
13
|
+
gem.homepage = "https://github.com/r7kamura/code_hunter"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency "nokogiri"
|
21
|
+
gem.add_dependency "activesupport"
|
22
|
+
gem.add_dependency "brakeman"
|
23
|
+
gem.add_dependency "rails_best_practices"
|
24
|
+
|
25
|
+
gem.add_development_dependency "rspec", ">= 2.12.0"
|
26
|
+
gem.add_development_dependency "simplecov"
|
27
|
+
end
|
data/lib/code_hunter.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
require "active_support/all"
|
2
|
+
|
3
|
+
require "code_hunter/version"
|
4
|
+
require "code_hunter/option_parser"
|
5
|
+
require "code_hunter/runner"
|
6
|
+
require "code_hunter/renderer"
|
7
|
+
require "code_hunter/brakeman"
|
8
|
+
require "code_hunter/rails_best_practices"
|
9
|
+
require "code_hunter/git_blamer"
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "code_hunter/brakeman/invoker"
|
2
|
+
require "code_hunter/brakeman/summarizer"
|
3
|
+
require "pathname"
|
4
|
+
require "tmpdir"
|
5
|
+
|
6
|
+
module CodeHunter
|
7
|
+
class Brakeman
|
8
|
+
TEMPORAL_PATHNAME = Pathname.new("#{Dir.tmpdir}/brakeman.html")
|
9
|
+
|
10
|
+
attr_reader :options
|
11
|
+
|
12
|
+
delegate :invoke, :to => :invoker
|
13
|
+
delegate :summarize, :to => :summarizer
|
14
|
+
|
15
|
+
def initialize(options = {})
|
16
|
+
@options = options
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
invoke
|
21
|
+
summarize
|
22
|
+
ensure
|
23
|
+
clean
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def clean
|
29
|
+
TEMPORAL_PATHNAME.delete if TEMPORAL_PATHNAME.exist?
|
30
|
+
end
|
31
|
+
|
32
|
+
def summarizer
|
33
|
+
Summarizer.new(options)
|
34
|
+
end
|
35
|
+
|
36
|
+
def invoker
|
37
|
+
Invoker.new(options)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module CodeHunter
|
2
|
+
class Brakeman
|
3
|
+
class Invoker
|
4
|
+
attr_reader :options
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def invoke
|
11
|
+
system(
|
12
|
+
"brakeman",
|
13
|
+
"--output", Brakeman::TEMPORAL_PATHNAME.to_s
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
|
3
|
+
module CodeHunter
|
4
|
+
class Brakeman
|
5
|
+
class Summarizer
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def summarize
|
13
|
+
warning_elements.map do |element|
|
14
|
+
{
|
15
|
+
:service => "brakeman",
|
16
|
+
:line => find_line(element),
|
17
|
+
:path => find_path(element),
|
18
|
+
:message => find_message(element),
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_line(element)
|
24
|
+
find_message(element)[/near line (\d+)/, 1].try(:to_i)
|
25
|
+
end
|
26
|
+
|
27
|
+
def find_message(element)
|
28
|
+
element.child.text.strip
|
29
|
+
end
|
30
|
+
|
31
|
+
def find_path(element)
|
32
|
+
element.css("caption").text.strip
|
33
|
+
end
|
34
|
+
|
35
|
+
def warning_elements
|
36
|
+
tree.css(".warning_message")
|
37
|
+
end
|
38
|
+
|
39
|
+
def tree
|
40
|
+
Nokogiri.HTML(content)
|
41
|
+
end
|
42
|
+
|
43
|
+
def content
|
44
|
+
Brakeman::TEMPORAL_PATHNAME.read
|
45
|
+
end
|
46
|
+
|
47
|
+
def summarize_with_file_existence_check
|
48
|
+
if Brakeman::TEMPORAL_PATHNAME.exist?
|
49
|
+
summarize_without_file_existence_check
|
50
|
+
else
|
51
|
+
warn "Brakeman output file is not found"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
alias_method_chain :summarize, :file_existence_check
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module CodeHunter
|
2
|
+
class GitBlamer
|
3
|
+
def initialize(args)
|
4
|
+
@path = args[:path]
|
5
|
+
@line = args[:line]
|
6
|
+
end
|
7
|
+
|
8
|
+
def blame
|
9
|
+
result = invoke
|
10
|
+
parse(result) unless result.empty?
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse(str)
|
14
|
+
{
|
15
|
+
:sha1 => str.lines.to_a[0][/^[0-9a-f]+/],
|
16
|
+
:author => str[/author (.+)/, 1],
|
17
|
+
:email => str[/author-mail <(.+)>/, 1],
|
18
|
+
:modified_at => str[/author-time (\d+)/, 1].to_i,
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def invoke
|
23
|
+
`git blame #{File.realpath(@path)} -L #@line,+1 -l -e -p`
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
module CodeHunter
|
4
|
+
class OptionParser < ::OptionParser
|
5
|
+
OPTIONS = [
|
6
|
+
"--application-path=", "(default: ./) rails application root path",
|
7
|
+
"--format=", "(default: yaml) output format (yaml or json)",
|
8
|
+
]
|
9
|
+
|
10
|
+
def self.parse!(argv)
|
11
|
+
new.parse!(argv)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.help
|
15
|
+
new.help
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(*)
|
19
|
+
super
|
20
|
+
configure_options
|
21
|
+
end
|
22
|
+
|
23
|
+
def parse!(*)
|
24
|
+
super
|
25
|
+
options
|
26
|
+
end
|
27
|
+
|
28
|
+
def options
|
29
|
+
@options ||= {}
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def configure_options
|
35
|
+
arguments.each do |argument|
|
36
|
+
on(argument.key, argument.description) do |value|
|
37
|
+
options[argument.to_sym] = value
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def arguments
|
43
|
+
OPTIONS.each_slice(2).map do |key, description|
|
44
|
+
Argument.new(key, description)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Argument
|
49
|
+
attr_reader :key, :description
|
50
|
+
|
51
|
+
def initialize(key, description)
|
52
|
+
@key = key
|
53
|
+
@description = description
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_sym
|
57
|
+
str = @key
|
58
|
+
str = without_head_hyphen(str)
|
59
|
+
str = without_head_no(str)
|
60
|
+
str = without_last_equal(str)
|
61
|
+
str = underscored(str)
|
62
|
+
str.to_sym
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def underscored(str)
|
68
|
+
str.gsub("-", "_")
|
69
|
+
end
|
70
|
+
|
71
|
+
def without_head_hyphen(str)
|
72
|
+
str.gsub(/^--/, "")
|
73
|
+
end
|
74
|
+
|
75
|
+
def without_head_no(str)
|
76
|
+
str.gsub(/^no-/, "")
|
77
|
+
end
|
78
|
+
|
79
|
+
def without_last_equal(str)
|
80
|
+
str.gsub(/=$/, "")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "code_hunter/rails_best_practices/invoker"
|
2
|
+
require "code_hunter/rails_best_practices/summarizer"
|
3
|
+
require "pathname"
|
4
|
+
require "tmpdir"
|
5
|
+
|
6
|
+
module CodeHunter
|
7
|
+
class RailsBestPractices
|
8
|
+
TEMPORAL_PATHNAME = Pathname.new("#{Dir.tmpdir}/rails_best_practices.html")
|
9
|
+
|
10
|
+
attr_reader :options
|
11
|
+
|
12
|
+
delegate :invoke, :to => :invoker
|
13
|
+
delegate :summarize, :to => :summarizer
|
14
|
+
|
15
|
+
def initialize(options = {})
|
16
|
+
@options = options
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
invoke
|
21
|
+
summarize
|
22
|
+
ensure
|
23
|
+
clean
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def clean
|
29
|
+
TEMPORAL_PATHNAME.delete if TEMPORAL_PATHNAME.exist?
|
30
|
+
end
|
31
|
+
|
32
|
+
def summarizer
|
33
|
+
Summarizer.new(options)
|
34
|
+
end
|
35
|
+
|
36
|
+
def invoker
|
37
|
+
Invoker.new(options)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module CodeHunter
|
2
|
+
class RailsBestPractices
|
3
|
+
class Invoker
|
4
|
+
attr_reader :options
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def invoke
|
11
|
+
system(
|
12
|
+
"rails_best_practices",
|
13
|
+
"--format", "html",
|
14
|
+
"--output-file", RailsBestPractices::TEMPORAL_PATHNAME.to_s
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
|
3
|
+
module CodeHunter
|
4
|
+
class RailsBestPractices
|
5
|
+
class Summarizer
|
6
|
+
attr_reader :options
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
@options = options
|
10
|
+
end
|
11
|
+
|
12
|
+
def summarize
|
13
|
+
warning_elements.map do |element|
|
14
|
+
{
|
15
|
+
:service => "rails_best_practices",
|
16
|
+
:line => find_line(element),
|
17
|
+
:path => find_path(element),
|
18
|
+
:message => find_message(element),
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_line(element)
|
24
|
+
element.css(".line").text.strip.to_i
|
25
|
+
end
|
26
|
+
|
27
|
+
def find_path(element)
|
28
|
+
element.css(".filename").text.strip
|
29
|
+
end
|
30
|
+
|
31
|
+
def find_message(element)
|
32
|
+
element.css(".message").text.strip
|
33
|
+
end
|
34
|
+
|
35
|
+
def warning_elements
|
36
|
+
tree.css(".result tbody tr")
|
37
|
+
end
|
38
|
+
|
39
|
+
def tree
|
40
|
+
Nokogiri.HTML(content)
|
41
|
+
end
|
42
|
+
|
43
|
+
def content
|
44
|
+
RailsBestPractices::TEMPORAL_PATHNAME.read
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "json"
|
2
|
+
require "yaml"
|
3
|
+
|
4
|
+
module CodeHunter
|
5
|
+
# Render warnings to string with the specified format.
|
6
|
+
# As its format, AVAILABLE_FORMATS are available ("yaml" is default).
|
7
|
+
class Renderer
|
8
|
+
AVAILABLE_FORMATS = %w[json yaml]
|
9
|
+
|
10
|
+
def self.render(*args)
|
11
|
+
new(*args).render
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(warnings, options = {})
|
15
|
+
@warnings = warnings
|
16
|
+
@format = options[:format] || "yaml"
|
17
|
+
end
|
18
|
+
|
19
|
+
def render
|
20
|
+
case format
|
21
|
+
when "yaml"
|
22
|
+
@warnings.to_yaml
|
23
|
+
when "json"
|
24
|
+
JSON.unparse(@warnings)
|
25
|
+
else
|
26
|
+
raise ArgumentError, "format #{format} is not available. Use #{AVAILABLE_FORMATS}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def format
|
33
|
+
@format.to_s
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module CodeHunter
|
2
|
+
class Runner
|
3
|
+
attr_reader :options
|
4
|
+
|
5
|
+
def self.run(*args)
|
6
|
+
new(*args).run
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(argv = [])
|
10
|
+
@options = OptionParser.parse!(argv)
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
warnings = collect_warnings
|
15
|
+
warnings = merge_git_metadata(warnings)
|
16
|
+
output = Renderer.render(warnings, :format => options[:format])
|
17
|
+
puts output
|
18
|
+
end
|
19
|
+
|
20
|
+
def collect_warnings
|
21
|
+
services.map(&:run).compact.inject([], :+)
|
22
|
+
end
|
23
|
+
|
24
|
+
def merge_git_metadata(warnings)
|
25
|
+
warnings.map do |warning|
|
26
|
+
metadata = GitBlamer.new(warning).blame or next
|
27
|
+
warning.merge(metadata)
|
28
|
+
end.compact
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def services
|
34
|
+
[Brakeman, RailsBestPractices].map {|klass| klass.new(options) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def run_with_application_path
|
38
|
+
Dir.chdir(application_path) { run_without_application_path }
|
39
|
+
end
|
40
|
+
alias_method_chain :run, :application_path
|
41
|
+
|
42
|
+
def application_path
|
43
|
+
options[:application_path] || "./"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "active_support/core_ext/string/strip"
|
3
|
+
|
4
|
+
module CodeHunter
|
5
|
+
describe Renderer do
|
6
|
+
describe ".render(warnings, options = {})" do
|
7
|
+
subject do
|
8
|
+
described_class.render(warnings, options)
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:warnings) do
|
12
|
+
[{ :a => :b }]
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:options) do
|
16
|
+
{ :format => format }
|
17
|
+
end
|
18
|
+
|
19
|
+
shared_examples_for "render warnings with yaml" do
|
20
|
+
it "renders warnings as yaml" do
|
21
|
+
should == <<-EOS.strip_heredoc
|
22
|
+
---
|
23
|
+
- :a: :b
|
24
|
+
EOS
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "when options[:format] is not specified" do
|
29
|
+
let(:format) do
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
include_examples "render warnings with yaml"
|
33
|
+
end
|
34
|
+
|
35
|
+
context "when options[:format] is :yaml" do
|
36
|
+
let(:format) do
|
37
|
+
:yaml
|
38
|
+
end
|
39
|
+
include_examples "render warnings with yaml"
|
40
|
+
end
|
41
|
+
|
42
|
+
context "when options[:format] is :json" do
|
43
|
+
let(:format) do
|
44
|
+
:json
|
45
|
+
end
|
46
|
+
it "renders warnings as json" do
|
47
|
+
should == '[{"a":"b"}]'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "when options[:format] is invalid" do
|
52
|
+
let(:format) do
|
53
|
+
:invalid
|
54
|
+
end
|
55
|
+
it { expect { subject }.to raise_error(ArgumentError) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: code_hunter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ryo Nakamura
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-21 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: nokogiri
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activesupport
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: brakeman
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rails_best_practices
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :runtime
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rspec
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 2.12.0
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 2.12.0
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: simplecov
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
description: Hunt out weak spots in your rails application
|
111
|
+
email:
|
112
|
+
- r7kamura@gmail.com
|
113
|
+
executables:
|
114
|
+
- code_hunter
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- .gitignore
|
119
|
+
- Gemfile
|
120
|
+
- LICENSE.txt
|
121
|
+
- README.md
|
122
|
+
- Rakefile
|
123
|
+
- bin/code_hunter
|
124
|
+
- code_hunter.gemspec
|
125
|
+
- lib/code_hunter.rb
|
126
|
+
- lib/code_hunter/brakeman.rb
|
127
|
+
- lib/code_hunter/brakeman/invoker.rb
|
128
|
+
- lib/code_hunter/brakeman/summarizer.rb
|
129
|
+
- lib/code_hunter/git_blamer.rb
|
130
|
+
- lib/code_hunter/option_parser.rb
|
131
|
+
- lib/code_hunter/rails_best_practices.rb
|
132
|
+
- lib/code_hunter/rails_best_practices/invoker.rb
|
133
|
+
- lib/code_hunter/rails_best_practices/summarizer.rb
|
134
|
+
- lib/code_hunter/renderer.rb
|
135
|
+
- lib/code_hunter/runner.rb
|
136
|
+
- lib/code_hunter/version.rb
|
137
|
+
- spec/code_hunter/renderer_spec.rb
|
138
|
+
- spec/spec_helper.rb
|
139
|
+
homepage: https://github.com/r7kamura/code_hunter
|
140
|
+
licenses: []
|
141
|
+
post_install_message:
|
142
|
+
rdoc_options: []
|
143
|
+
require_paths:
|
144
|
+
- lib
|
145
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
146
|
+
none: false
|
147
|
+
requirements:
|
148
|
+
- - ! '>='
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
152
|
+
none: false
|
153
|
+
requirements:
|
154
|
+
- - ! '>='
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '0'
|
157
|
+
requirements: []
|
158
|
+
rubyforge_project:
|
159
|
+
rubygems_version: 1.8.24
|
160
|
+
signing_key:
|
161
|
+
specification_version: 3
|
162
|
+
summary: Code hunter
|
163
|
+
test_files:
|
164
|
+
- spec/code_hunter/renderer_spec.rb
|
165
|
+
- spec/spec_helper.rb
|