codescout-analyzer 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 62251be9162445198519b9683c482b680f905c47
4
+ data.tar.gz: 4c3d259900e1fa5bb7e2eb42f4422555e0c08d53
5
+ SHA512:
6
+ metadata.gz: 1ecb2fe301d2cbb23644a595e05718287f40718398fe4aeaf6663e374677b4d21f388d0f0f120dc7b971f4f60769f99e5741fe5193bd7a850471205f5ed481a1
7
+ data.tar.gz: 9ef8e29a834c4b5df1040de509a855c3d70a71ebeba8272c0a7dfbc2902f0e4061cc302e49fc36626b587fe71af006ac28e1d7d27968fa11d90736f3bd17690c
data/.gitignore ADDED
@@ -0,0 +1,24 @@
1
+ #*
2
+ *.gem
3
+ *.rbc
4
+ *.swp
5
+ *.tmproj
6
+ *~
7
+ .#*
8
+ .DS_Store
9
+ .bundle
10
+ .config
11
+ .yardoc
12
+ Gemfile.lock
13
+ InstalledFiles
14
+ _yardoc
15
+ coverage
16
+ doc/
17
+ lib/bundler/man
18
+ pkg
19
+ rdoc
20
+ spec/reports
21
+ test/tmp
22
+ test/version_tmp
23
+ tmp
24
+ tmtags
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/codescout ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + "/../lib")
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require "rubygems"
7
+
8
+ path = ARGV.shift.to_s
9
+ if path.empty?
10
+ STDERR.puts "Please specify path to project"
11
+ exit 1
12
+ end
13
+
14
+ require "codescout/repo_analyzer"
15
+ require "codescout/source_file"
16
+ require "codescout/flog_stats"
17
+ require "codescout/flay_stats"
18
+ require "codescout/file_stats"
19
+ require "codescout/churn_stats"
20
+ require "codescout/brakeman_stats"
21
+ require "codescout/rubocop_stats"
22
+
23
+ analyzer = Codescout::RepoAnalyzer.new(path)
24
+ analyzer.analyze
25
+
26
+ puts JSON.dump(analyzer.result)
@@ -0,0 +1,25 @@
1
+ require File.expand_path("../lib/codescout/version", __FILE__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "codescout-analyzer"
5
+ s.version = Codescout::VERSION
6
+ s.summary = "No description for now"
7
+ s.description = "No description for now, maybe later"
8
+ s.homepage = "https://github.com"
9
+ s.authors = ["Dan Sosedoff"]
10
+ s.email = ["dan.sosedoff@gmail.com"]
11
+ s.license = "MIT"
12
+
13
+ s.add_dependency "flog", "4.3.0"
14
+ s.add_dependency "flay", "2.5.0"
15
+ s.add_dependency "churn", "1.0.1"
16
+ s.add_dependency "parser", "2.2.0.pre.4"
17
+ s.add_dependency "ruby2ruby", "2.1.1"
18
+ s.add_dependency "brakeman", "2.6.2"
19
+ s.add_dependency "rubocop", "0.25.0"
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
+ s.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
24
+ s.require_paths = ["lib"]
25
+ end
@@ -0,0 +1,283 @@
1
+ AllCops:
2
+ Exclude:
3
+ - db/schema.rb
4
+
5
+ AccessorMethodName:
6
+ Enabled: false
7
+
8
+ AccessModifierIndentation:
9
+ Enabled: false
10
+
11
+ ActionFilter:
12
+ Enabled: false
13
+
14
+ Alias:
15
+ Enabled: false
16
+
17
+ ArrayJoin:
18
+ Enabled: false
19
+
20
+ AsciiComments:
21
+ Enabled: false
22
+
23
+ AsciiIdentifiers:
24
+ Enabled: false
25
+
26
+ Attr:
27
+ Enabled: false
28
+
29
+ BlockNesting:
30
+ Enabled: false
31
+
32
+ CaseEquality:
33
+ Enabled: false
34
+
35
+ CharacterLiteral:
36
+ Enabled: false
37
+
38
+ ClassAndModuleChildren:
39
+ Enabled: false
40
+
41
+ ClassLength:
42
+ Enabled: false
43
+
44
+ ClassVars:
45
+ Enabled: false
46
+
47
+ CollectionMethods:
48
+ PreferredMethods:
49
+ find: detect
50
+ reduce: inject
51
+ collect: map
52
+ find_all: select
53
+
54
+ ColonMethodCall:
55
+ Enabled: false
56
+
57
+ CommentAnnotation:
58
+ Enabled: false
59
+
60
+ CyclomaticComplexity:
61
+ Enabled: false
62
+
63
+ Delegate:
64
+ Enabled: false
65
+
66
+ DeprecatedHashMethods:
67
+ Enabled: false
68
+
69
+ Documentation:
70
+ Enabled: false
71
+
72
+ DotPosition:
73
+ EnforcedStyle: trailing
74
+
75
+ DoubleNegation:
76
+ Enabled: false
77
+
78
+ EachWithObject:
79
+ Enabled: false
80
+
81
+ EmptyLiteral:
82
+ Enabled: false
83
+
84
+ EmptyLines:
85
+ Enabled: false
86
+
87
+ Encoding:
88
+ Enabled: false
89
+
90
+ EvenOdd:
91
+ Enabled: false
92
+
93
+ HashSyntax:
94
+ Enabled: false
95
+
96
+ FileName:
97
+ Enabled: false
98
+
99
+ FlipFlop:
100
+ Enabled: false
101
+
102
+ FormatString:
103
+ Enabled: false
104
+
105
+ GlobalVars:
106
+ Enabled: false
107
+
108
+ GuardClause:
109
+ Enabled: false
110
+
111
+ IfUnlessModifier:
112
+ Enabled: false
113
+
114
+ IfWithSemicolon:
115
+ Enabled: false
116
+
117
+ InlineComment:
118
+ Enabled: false
119
+
120
+ Lambda:
121
+ Enabled: false
122
+
123
+ LambdaCall:
124
+ Enabled: false
125
+
126
+ LineEndConcatenation:
127
+ Enabled: false
128
+
129
+ LineLength:
130
+ Max: 80
131
+
132
+ MethodLength:
133
+ Enabled: false
134
+
135
+ ModuleFunction:
136
+ Enabled: false
137
+
138
+ NegatedIf:
139
+ Enabled: false
140
+
141
+ NegatedWhile:
142
+ Enabled: false
143
+
144
+ Next:
145
+ Enabled: false
146
+
147
+ NilComparison:
148
+ Enabled: false
149
+
150
+ Not:
151
+ Enabled: false
152
+
153
+ NumericLiterals:
154
+ Enabled: false
155
+
156
+ OneLineConditional:
157
+ Enabled: false
158
+
159
+ OpMethod:
160
+ Enabled: false
161
+
162
+ ParameterLists:
163
+ Enabled: false
164
+
165
+ PercentLiteralDelimiters:
166
+ Enabled: false
167
+
168
+ PerlBackrefs:
169
+ Enabled: false
170
+
171
+ PredicateName:
172
+ NamePrefixBlacklist:
173
+ - is_
174
+
175
+ Proc:
176
+ Enabled: false
177
+
178
+ RaiseArgs:
179
+ Enabled: false
180
+
181
+ RegexpLiteral:
182
+ Enabled: false
183
+
184
+ SelfAssignment:
185
+ Enabled: false
186
+
187
+ SingleLineBlockParams:
188
+ Enabled: false
189
+
190
+ SingleLineMethods:
191
+ Enabled: false
192
+
193
+ SignalException:
194
+ Enabled: false
195
+
196
+ SingleSpaceBeforeFirstArg:
197
+ Enabled: false
198
+
199
+ SpecialGlobalVars:
200
+ Enabled: false
201
+
202
+ SpaceAfterSemicolon:
203
+ Enabled: false
204
+
205
+ StringLiterals:
206
+ Enabled: false
207
+
208
+ TrailingBlankLines:
209
+ Enabled: false
210
+
211
+ VariableInterpolation:
212
+ Enabled: false
213
+
214
+ TrailingComma:
215
+ Enabled: false
216
+
217
+ TrailingWhitespace:
218
+ Enabled: false
219
+
220
+ TrivialAccessors:
221
+ Enabled: false
222
+
223
+ VariableInterpolation:
224
+ Enabled: false
225
+
226
+ WhenThen:
227
+ Enabled: false
228
+
229
+ WhileUntilModifier:
230
+ Enabled: false
231
+
232
+ WordArray:
233
+ Enabled: false
234
+
235
+ PerceivedComplexity:
236
+ Enabled: false
237
+
238
+ # Lint
239
+
240
+ AmbiguousOperator:
241
+ Enabled: false
242
+
243
+ AmbiguousRegexpLiteral:
244
+ Enabled: false
245
+
246
+ AssignmentInCondition:
247
+ Enabled: false
248
+
249
+ ConditionPosition:
250
+ Enabled: false
251
+
252
+ DeprecatedClassMethods:
253
+ Enabled: false
254
+
255
+ ElseLayout:
256
+ Enabled: false
257
+
258
+ HandleExceptions:
259
+ Enabled: false
260
+
261
+ InvalidCharacterLiteral:
262
+ Enabled: false
263
+
264
+ LiteralInCondition:
265
+ Enabled: false
266
+
267
+ LiteralInInterpolation:
268
+ Enabled: false
269
+
270
+ Loop:
271
+ Enabled: false
272
+
273
+ ParenthesesAsGroupedExpression:
274
+ Enabled: false
275
+
276
+ RequireParentheses:
277
+ Enabled: false
278
+
279
+ UnderscorePrefixedVariableName:
280
+ Enabled: false
281
+
282
+ Void:
283
+ Enabled: false
@@ -0,0 +1,26 @@
1
+ module Codescout
2
+ class BrakemanStats
3
+ attr_reader :results
4
+
5
+ def initialize(analyzer)
6
+ @results = []
7
+
8
+ collect_results if generate_report
9
+ end
10
+
11
+ private
12
+
13
+ def generate_report
14
+ `brakeman -f json -o brakeman.json`
15
+ $?.success?
16
+ end
17
+
18
+ def report
19
+ JSON.load(File.read("brakeman.json"))
20
+ end
21
+
22
+ def collect_results
23
+ @results = report["warnings"]
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,34 @@
1
+ require "churn/calculator"
2
+
3
+ module Codescout
4
+ class ChurnStats
5
+ OPTIONS = {
6
+ minimum_churn_count: 1,
7
+ start_date: nil
8
+ }
9
+
10
+ attr_reader :files
11
+
12
+ def initialize(analyzer)
13
+ @analyzer = analyzer
14
+ @files = {}
15
+
16
+ generate_report
17
+ collect_results
18
+ end
19
+
20
+ private
21
+
22
+ def generate_report
23
+ @churn = Churn::ChurnCalculator.new(OPTIONS)
24
+ @churn.report
25
+ end
26
+
27
+ def collect_results
28
+ @churn.instance_variable_get("@changes").each do |c|
29
+ next unless @analyzer.valid_file?(c[:file_path])
30
+ @files[c[:file_path]] = c[:times_changed]
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,84 @@
1
+ module Codescout
2
+ class FileStats
3
+ PATTERNS = {
4
+ line_comment: /^\s*#/,
5
+ begin_block_comment: /^=begin/,
6
+ end_block_comment: /^=end/,
7
+ class: /^\s*class\s+[_A-Z]/,
8
+ method: /^\s*def\s+[_a-z]/,
9
+ }
10
+
11
+ attr_reader :file_size, # File size in bytes
12
+ :lines, # Total number of lines
13
+ :loc, # Number of code lines
14
+ :method_loc, # Average lines of code per method
15
+ :classes_count, # Number of class definitions
16
+ :methods_count # Number of methods definitions
17
+
18
+ def initialize(base_path, path)
19
+ @path = path
20
+ @full_path = File.join(base_path, path)
21
+
22
+ init_metrics
23
+ calculate_file_metrics
24
+ calculate_code_metrics
25
+ end
26
+
27
+ def to_hash
28
+ {
29
+ file_size: file_size,
30
+ lines: lines,
31
+ loc: loc,
32
+ method_loc: method_loc,
33
+ classes_count: classes_count,
34
+ methods_count: methods_count
35
+ }
36
+ end
37
+
38
+ private
39
+
40
+ def init_metrics
41
+ @file_size = 0
42
+ @lines = 0
43
+ @loc = 0
44
+ @method_loc = 0
45
+ @classes_count = 0
46
+ @methods_count = 0
47
+ end
48
+
49
+ def calculate_file_metrics
50
+ @file_size = File.size(@full_path)
51
+ end
52
+
53
+ def calculate_code_metrics
54
+ io = File.open(@full_path)
55
+ patterns = PATTERNS
56
+ comment_started = false
57
+
58
+ while line = io.gets
59
+ @lines += 1
60
+
61
+ if comment_started
62
+ if patterns[:end_block_comment] && line =~ patterns[:end_block_comment]
63
+ comment_started = false
64
+ end
65
+ next
66
+ else
67
+ if patterns[:begin_block_comment] && line =~ patterns[:begin_block_comment]
68
+ comment_started = true
69
+ next
70
+ end
71
+ end
72
+
73
+ @classes_count += 1 if patterns[:class] && line =~ patterns[:class]
74
+ @methods_count += 1 if patterns[:method] && line =~ patterns[:method]
75
+
76
+ if line !~ /^\s*$/ && (patterns[:line_comment].nil? || line !~ patterns[:line_comment])
77
+ @loc += 1
78
+ end
79
+ end
80
+
81
+ @method_loc = @methods_count > 0 ? @loc / @methods_count : 0
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,85 @@
1
+ require "flay"
2
+
3
+ module Codescout
4
+ class FlayStats
5
+ OPTIONS = {
6
+ :diff => true,
7
+ :mass => 16,
8
+ :summary => false,
9
+ :verbose => false,
10
+ :number => true,
11
+ :timeout => 10,
12
+ :liberal => false,
13
+ :fuzzy => false,
14
+ :only => nil
15
+ }
16
+
17
+ attr_reader :matches
18
+
19
+ def initialize(analyzer)
20
+ @matches = []
21
+ @base_path = analyzer.base_path
22
+
23
+ @flay = Flay.new(OPTIONS)
24
+ @flay.process(*analyzer.files)
25
+
26
+ process_matches(@flay.analyze)
27
+ @flay = nil
28
+ end
29
+
30
+ private
31
+
32
+ def process_matches(items)
33
+ items.each_with_index do |item, count|
34
+ match_item = {
35
+ match: item.identical? ? "identical" : "similar",
36
+ node: item.name.to_s,
37
+ bonus: item.bonus ? item.bonus.sub("*", "").to_i : nil,
38
+ mass: item.mass,
39
+ locations: locations(item)
40
+ }
41
+
42
+ nodes = @flay.hashes[item.structural_hash]
43
+
44
+ sources = nodes.map do |s|
45
+ msg = "sexp_to_#{File.extname(s.file).sub(/./, '')}"
46
+ @flay.respond_to?(msg) ? @flay.send(msg, s) : @flay.sexp_to_rb(s)
47
+ end
48
+
49
+ diff = @flay.n_way_diff(*sources)
50
+
51
+ parse_diff(diff, item.locations.size).each_with_index do |code,i|
52
+ match_item[:locations][i][:code] = code
53
+ end
54
+
55
+ @matches << match_item
56
+ end
57
+ end
58
+
59
+ def locations(item)
60
+ item.locations.map do |l|
61
+ {
62
+ file: l.file.sub("#{@base_path}/", ""),
63
+ line: l.line
64
+ }
65
+ end
66
+ end
67
+
68
+ def parse_diff(diff, size)
69
+ chunks = Array.new(size) { [] }
70
+
71
+ diff.split("\n").each do |line|
72
+ if line =~ /^([^:]):\s?(.+)/
73
+ key = ($1.ord - ?A.ord).to_i
74
+ chunks[key] << $2
75
+ else
76
+ chunks.each_with_index do |_,i|
77
+ chunks[i] << line.gsub(/^\s{3}/, "")
78
+ end
79
+ end
80
+ end
81
+
82
+ chunks.map { |c| c.join("\n") }
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,87 @@
1
+ require "flog"
2
+
3
+ module Codescout
4
+ class FlogStats
5
+ attr_reader :score, :average_score
6
+ attr_reader :scores
7
+
8
+ def initialize(analyzer)
9
+ options = {
10
+ all: true,
11
+ methods: true,
12
+ continue: true,
13
+ parser: Ruby19Parser
14
+ }
15
+
16
+ @flog = Flog.new(options)
17
+ @flog.flog(*analyzer.files)
18
+ @flog.calculate
19
+
20
+ @score = @flog.total_score
21
+ @average_score = @flog.average
22
+ @scores = {}
23
+
24
+ @flog.mass.each_pair do |file, mass|
25
+ @scores[file] = { score: 0, scores: [] }
26
+ end
27
+
28
+ @flog.totals.each_pair do |k,v|
29
+ next if @flog.method_locations[k].nil?
30
+
31
+ score = v.round
32
+ class_name, method_name = parse_method_string(k)
33
+ path, line = @flog.method_locations[k].split(":")
34
+ code = nil
35
+
36
+ if score >= 25 && method_name
37
+ method_source = Codescout::SourceFile.new(File.read(path)).method_source(method_name)
38
+
39
+ if method_source
40
+ code = method_source.code
41
+ end
42
+ end
43
+
44
+ @scores[path][:score] += score
45
+
46
+ @scores[path][:scores] << {
47
+ class_name: class_name,
48
+ method_name: method_name,
49
+ score: score,
50
+ line: line,
51
+ code: code
52
+ }
53
+ end
54
+
55
+ @flog = nil
56
+ end
57
+
58
+ private
59
+
60
+ def parse_method_string(str)
61
+ chunks = str.split("#")
62
+ klass = extract_class(chunks[0])
63
+ method = chunks[1]
64
+
65
+ # Parse class method, they're prefixed with "::"
66
+ if method.nil?
67
+ method = chunks[0].split("::").last
68
+ end
69
+
70
+ # Allow only properly formatter method names in ruby.
71
+ # Anything that looks like DSL or sugar does not have a method name.
72
+ if invalid_def?(method)
73
+ method = nil
74
+ end
75
+
76
+ return klass, method
77
+ end
78
+
79
+ def extract_class(str)
80
+ str.split("::").reject { |c| c =~ /^[^A-Z]/ }.join("::")
81
+ end
82
+
83
+ def invalid_def?(str)
84
+ str =~ /[\/\(\)]/ ? true : false
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,87 @@
1
+ module Codescout
2
+ class RepoAnalyzer
3
+ ALLOWED_FILES = %w(.rb .rake .gemspec)
4
+
5
+ attr_reader :base_path, :files
6
+
7
+ def initialize(path)
8
+ @base_path = File.expand_path(path)
9
+ @files = []
10
+ end
11
+
12
+ def analyze
13
+ within_base do
14
+ scan_files
15
+ run_filestats
16
+ run_flog
17
+ run_flay
18
+ run_churn
19
+ run_brakeman
20
+ run_rubocop
21
+ end
22
+ end
23
+
24
+ def result
25
+ {
26
+ file_stats: @file_stats,
27
+ flog: @flog,
28
+ flay: @flay,
29
+ churn: @churn,
30
+ brakeman: @brakeman,
31
+ rubocop: @rubocop
32
+ }
33
+ end
34
+
35
+ def within_base(&blk)
36
+ Dir.chdir(@base_path) { blk.call }
37
+ end
38
+
39
+ def scan_files
40
+ Dir["**/*"].each { |file| @files << file if valid_file?(file) }
41
+ end
42
+
43
+ def run_flay
44
+ STDERR.puts "Running flay"
45
+ @flay = Codescout::FlayStats.new(self).matches
46
+ end
47
+
48
+ def run_flog
49
+ STDERR.puts "Running flog"
50
+ @flog = Codescout::FlogStats.new(self).scores
51
+ end
52
+
53
+ def run_filestats
54
+ STDERR.puts "Running filestats"
55
+ @file_stats = {}
56
+
57
+ @files.each do |f|
58
+ @file_stats[f] = Codescout::FileStats.new(@base_path, f).to_hash
59
+ end
60
+
61
+ if File.exists?("Gemfile")
62
+ @file_stats["Gemfile"] = Codescout::FileStats.new(@base_path, "Gemfile").to_hash
63
+ end
64
+ end
65
+
66
+ def run_churn
67
+ STDERR.puts "Running churn"
68
+ @churn = Codescout::ChurnStats.new(self).files
69
+ end
70
+
71
+ def run_brakeman
72
+ STDERR.puts "Running brakeman"
73
+ @brakeman = Codescout::BrakemanStats.new(self).results
74
+ end
75
+
76
+ def run_rubocop
77
+ STDERR.puts "Running rubocop"
78
+ @rubocop = Codescout::RubocopStats.new(self).results
79
+ end
80
+
81
+ def valid_file?(file)
82
+ return false unless ALLOWED_FILES.include?(File.extname(file))
83
+ return false if file =~ /^db|spec|features|test|examples|samples\//
84
+ true
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,39 @@
1
+ module Codescout
2
+ class RubocopStats
3
+ attr_reader :results
4
+
5
+ def initialize(analyzer)
6
+ @analyzer = analyzer
7
+ @results = {}
8
+
9
+ install_config
10
+
11
+ `rubocop -c rubocop.yml -f json -o rubocop.json`
12
+
13
+ json = JSON.load(File.read("rubocop.json"))
14
+
15
+ json["files"].each do |file|
16
+ next unless @analyzer.files.include?(file["path"])
17
+ next if file["offenses"].empty?
18
+
19
+ lines = File.read(file["path"]).split("\n")
20
+
21
+ @results[file["path"]] = select_offences(lines, file["offenses"])
22
+ end
23
+ end
24
+
25
+ def select_offences(lines, offenses)
26
+ offenses.map { |o| o["code"] = lines[o["location"]["line"] - 1] ; o }
27
+ end
28
+
29
+ private
30
+
31
+ def config_path
32
+ "#{File.dirname(__FILE__)}/../../config/rubocop.yml"
33
+ end
34
+
35
+ def install_config
36
+ FileUtils.cp(config_path, "rubocop.yml")
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,56 @@
1
+ require "parser/current"
2
+
3
+ module Codescout
4
+ class SourceFile
5
+ class ObjectMethod
6
+ attr_reader :line, :line_end
7
+ attr_reader :code
8
+
9
+ def initialize(exp)
10
+ @line = exp.begin.line
11
+ @line_end = exp.end.line
12
+ @code = exp.source
13
+ end
14
+ end
15
+
16
+ def initialize(code)
17
+ @parser = Parser::CurrentRuby.parse(code)
18
+ end
19
+
20
+ def method_source(method_name)
21
+ @method_source = nil
22
+
23
+ recursive_search_ast(@parser, method_name) do |exp|
24
+ @method_source = ObjectMethod.new(exp)
25
+ end
26
+
27
+ @method_source
28
+ end
29
+
30
+ def method_lines(method_name)
31
+ @method_lines = nil
32
+
33
+ recursive_search_ast(@parser, method_name) do |exp|
34
+ @method_lines = exp.begin.line, exp.end.line
35
+ end
36
+
37
+ @method_lines
38
+ end
39
+
40
+ private
41
+
42
+ def recursive_search_ast(ast, method_name, &blk)
43
+ ast.children.each do |child|
44
+ if child.kind_of?(Parser::AST::Node)
45
+ if (child.type.to_s == "def" || child.type.to_s == "defs")
46
+ if child.children[0].to_s == method_name || child.children[1].to_s == method_name
47
+ blk.call(child.loc.expression)
48
+ end
49
+ else
50
+ recursive_search_ast(child, method_name, &blk)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,3 @@
1
+ module Codescout
2
+ VERSION = "0.0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: codescout-analyzer
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Dan Sosedoff
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: flog
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 4.3.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 4.3.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: flay
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 2.5.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 2.5.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: churn
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 1.0.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: parser
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 2.2.0.pre.4
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 2.2.0.pre.4
69
+ - !ruby/object:Gem::Dependency
70
+ name: ruby2ruby
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 2.1.1
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 2.1.1
83
+ - !ruby/object:Gem::Dependency
84
+ name: brakeman
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 2.6.2
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
96
+ version: 2.6.2
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 0.25.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 0.25.0
111
+ description: No description for now, maybe later
112
+ email:
113
+ - dan.sosedoff@gmail.com
114
+ executables:
115
+ - codescout
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - ".gitignore"
120
+ - Gemfile
121
+ - Rakefile
122
+ - bin/codescout
123
+ - codescout-analyzer.gemspec
124
+ - config/rubocop.yml
125
+ - lib/codescout/brakeman_stats.rb
126
+ - lib/codescout/churn_stats.rb
127
+ - lib/codescout/file_stats.rb
128
+ - lib/codescout/flay_stats.rb
129
+ - lib/codescout/flog_stats.rb
130
+ - lib/codescout/repo_analyzer.rb
131
+ - lib/codescout/rubocop_stats.rb
132
+ - lib/codescout/source_file.rb
133
+ - lib/codescout/version.rb
134
+ homepage: https://github.com
135
+ licenses:
136
+ - MIT
137
+ metadata: {}
138
+ post_install_message:
139
+ rdoc_options: []
140
+ require_paths:
141
+ - lib
142
+ required_ruby_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ requirements: []
153
+ rubyforge_project:
154
+ rubygems_version: 2.2.2
155
+ signing_key:
156
+ specification_version: 4
157
+ summary: No description for now
158
+ test_files: []