code_hunter 0.0.1
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.
- 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
|