ruby-watchr 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 +4 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +12 -0
- data/Rakefile +1 -0
- data/lib/watchr.rb +9 -0
- data/lib/watchr/analyse.rb +42 -0
- data/lib/watchr/file_analyse.rb +69 -0
- data/lib/watchr/flay_metric/diff.rb +27 -0
- data/lib/watchr/flay_metric/report.rb +54 -0
- data/lib/watchr/flog_metric/class.rb +24 -0
- data/lib/watchr/flog_metric/method.rb +17 -0
- data/lib/watchr/flog_metric/report.rb +84 -0
- data/lib/watchr/location.rb +18 -0
- data/lib/watchr/paths.rb +15 -0
- data/lib/watchr/smell.rb +63 -0
- data/lib/watchr/smells_collector.rb +19 -0
- data/lib/watchr/version.rb +3 -0
- data/spec/fixtures/class.rb +21 -0
- data/spec/fixtures/module.rb +9 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/watchr/analyse_spec.rb +13 -0
- data/spec/watchr/file_analyse_spec.rb +30 -0
- data/spec/watchr/flay/report_spec.rb +30 -0
- data/spec/watchr/flog_metric/flog_matric/flog_report_spec.rb +90 -0
- data/spec/watchr/location_spec.rb +29 -0
- data/spec/watchr/paths_spec.rb +11 -0
- data/spec/watchr/smell_spec.rb +45 -0
- data/spec/watchr/smells_collector_spec.rb +42 -0
- data/watchr.gemspec +27 -0
- metadata +142 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use ruby-1.9.2-p180@watchr
|
data/Gemfile
ADDED
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/watchr.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'watchr/paths'
|
2
|
+
require 'watchr/flay_metric/report'
|
3
|
+
require 'watchr/file_analyse'
|
4
|
+
|
5
|
+
module Watchr
|
6
|
+
|
7
|
+
#
|
8
|
+
# Code analyse information for a given path. Returns list of files,
|
9
|
+
# each containing its own detailed data for used metrics.
|
10
|
+
#
|
11
|
+
class Analyse
|
12
|
+
|
13
|
+
#
|
14
|
+
# Analysed file data.
|
15
|
+
#
|
16
|
+
attr_reader :files
|
17
|
+
|
18
|
+
#
|
19
|
+
# Run the analyse.
|
20
|
+
#
|
21
|
+
# @param {String} Path to code folders.
|
22
|
+
#
|
23
|
+
def initialize(path)
|
24
|
+
files = Paths.files_by_dirs(path)
|
25
|
+
|
26
|
+
# Flay essentially cant be done on file level because its first class
|
27
|
+
# citizen is duplication of code between files. Its done once for all
|
28
|
+
# the files in the analyse and results are injected to the proper file
|
29
|
+
# later.
|
30
|
+
flay = Watchr::FlayMetric::Report.new(files)
|
31
|
+
|
32
|
+
# Create report for each file.
|
33
|
+
@files = files.map do |file|
|
34
|
+
file_report = Watchr::FileAnalyse.new(file)
|
35
|
+
file_report.flay(flay.duplications_by_file(file))
|
36
|
+
|
37
|
+
file_report
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'watchr/flog_metric/report'
|
2
|
+
require 'watchr/smell'
|
3
|
+
require 'watchr/smells_collector'
|
4
|
+
|
5
|
+
module Watchr
|
6
|
+
#
|
7
|
+
# Analyse for one given file. All the different metric analyse data are
|
8
|
+
# collected in order to output reasonable recommendations for a code
|
9
|
+
# improvements.
|
10
|
+
#
|
11
|
+
class FileAnalyse
|
12
|
+
|
13
|
+
attr_reader :path
|
14
|
+
|
15
|
+
#
|
16
|
+
# Craete new file analyse.
|
17
|
+
#
|
18
|
+
# @param {String} Path to file.
|
19
|
+
#
|
20
|
+
def initialize(path)
|
21
|
+
@path = path
|
22
|
+
@smells = SmellsCollector.new
|
23
|
+
|
24
|
+
flog_metric = FlogMetric::Report.new([path])
|
25
|
+
flog_metric.classes.each do |klass|
|
26
|
+
if klass.total_score > 150
|
27
|
+
@smells.add(
|
28
|
+
Smell.new(
|
29
|
+
Smell::VERY_COMPLEX_OBJECT,
|
30
|
+
klass.name,
|
31
|
+
[klass.location],
|
32
|
+
klass.total_score
|
33
|
+
)
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
if klass.total_score > 50
|
38
|
+
@smells.add(
|
39
|
+
Smell.new(
|
40
|
+
Smell::COMPLEX_OBJECT,
|
41
|
+
klass.name,
|
42
|
+
[klass.location],
|
43
|
+
klass.total_score
|
44
|
+
)
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def smelly?
|
51
|
+
smells.any?
|
52
|
+
end
|
53
|
+
|
54
|
+
#
|
55
|
+
# Store the flay report, which was evaluated on global basis
|
56
|
+
# to check for duplications across multiple files.
|
57
|
+
#
|
58
|
+
# @param {Array.<Watchr::FlayMetric::Diff>} Duplication details.
|
59
|
+
# @return nil
|
60
|
+
#
|
61
|
+
def flay(report)
|
62
|
+
@flay_report = report
|
63
|
+
end
|
64
|
+
|
65
|
+
def smells
|
66
|
+
@smells.all
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Watchr
|
2
|
+
module FlayMetric
|
3
|
+
class Diff
|
4
|
+
IDENTICAL = :identical
|
5
|
+
|
6
|
+
SIMILAR = :similar
|
7
|
+
|
8
|
+
attr_reader :locations, :match, :nodes, :bonus, :mass, :code
|
9
|
+
|
10
|
+
def initialize(same, nodes, bonus, mass)
|
11
|
+
@locations = []
|
12
|
+
@match = same ? IDENTICAL : SIMILAR
|
13
|
+
@nodes = nodes
|
14
|
+
@bonus = bonus
|
15
|
+
@mass = mass
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_location(location)
|
19
|
+
@locations << location
|
20
|
+
end
|
21
|
+
|
22
|
+
def code=(code)
|
23
|
+
@code = code
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'flay'
|
2
|
+
require 'watchr/flay_metric/diff'
|
3
|
+
require 'watchr/location'
|
4
|
+
|
5
|
+
module Watchr
|
6
|
+
module FlayMetric
|
7
|
+
class Report < Flay
|
8
|
+
attr_reader :duplications
|
9
|
+
|
10
|
+
def initialize(path)
|
11
|
+
super(:mass => 12, :diff => true)
|
12
|
+
|
13
|
+
files = Flay.expand_dirs_to_files(path)
|
14
|
+
|
15
|
+
process(*files)
|
16
|
+
process_result
|
17
|
+
end
|
18
|
+
|
19
|
+
def total_score
|
20
|
+
total
|
21
|
+
end
|
22
|
+
|
23
|
+
def duplications_by_file(path)
|
24
|
+
duplications.find_all do |duplication|
|
25
|
+
false
|
26
|
+
# duplication.locations.any? {|location| location.file == path}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def process_result
|
31
|
+
@duplications = []
|
32
|
+
|
33
|
+
masses.sort_by { |h,m| [-m, hashes[h].first.file] }.each do |hash, mass|
|
34
|
+
nodes = hashes[hash]
|
35
|
+
|
36
|
+
same = identical[hash]
|
37
|
+
node = nodes.first
|
38
|
+
bonus = same ? nodes.size : 0
|
39
|
+
|
40
|
+
diff = Diff.new(same, nodes, bonus, mass)
|
41
|
+
|
42
|
+
nodes.each do |x|
|
43
|
+
diff.add_location(Location.new(x.file, x.line))
|
44
|
+
end
|
45
|
+
|
46
|
+
r2r = Ruby2Ruby.new
|
47
|
+
diff.code = n_way_diff(*nodes.map { |s| r2r.process(s.deep_clone) })
|
48
|
+
|
49
|
+
@duplications << diff
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Watchr
|
2
|
+
class FlogReportClass
|
3
|
+
attr_reader :name, :methods, :total_score, :location
|
4
|
+
|
5
|
+
def initialize(name, score)
|
6
|
+
@name = name
|
7
|
+
@total_score = (10 * score).round / 10.0
|
8
|
+
@methods = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def location
|
12
|
+
@location
|
13
|
+
end
|
14
|
+
|
15
|
+
def total_methods_score
|
16
|
+
@methods.reduce(0) {|sum, i| sum += i.total_score}
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_method(method_report)
|
20
|
+
@methods << method_report
|
21
|
+
@location = Location.new(method_report.location.file)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Watchr
|
2
|
+
class FlogReportMethod
|
3
|
+
attr_reader :clazz, :name, :total_score, :location
|
4
|
+
|
5
|
+
def initialize(clazz, name, score, location)
|
6
|
+
@clazz = clazz
|
7
|
+
@full_name = name
|
8
|
+
@name = name.split(/#|::/).last
|
9
|
+
@total_score = (10 * score).round / 10.0
|
10
|
+
@location = location
|
11
|
+
end
|
12
|
+
|
13
|
+
def full_name
|
14
|
+
@full_name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'flog'
|
2
|
+
require 'watchr/flog_metric/class'
|
3
|
+
require 'watchr/flog_metric/method'
|
4
|
+
require 'watchr/location'
|
5
|
+
|
6
|
+
module Watchr
|
7
|
+
module FlogMetric
|
8
|
+
|
9
|
+
#
|
10
|
+
# Seattle.rb Flog report.
|
11
|
+
#
|
12
|
+
class Report < Flog
|
13
|
+
|
14
|
+
#
|
15
|
+
# Generate flog report for a given files.
|
16
|
+
#
|
17
|
+
# @param {Array} Array of file paths.
|
18
|
+
#
|
19
|
+
def initialize(files)
|
20
|
+
super({})
|
21
|
+
|
22
|
+
flog(files)
|
23
|
+
process_result
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Get total complexity score.
|
28
|
+
#
|
29
|
+
# @return {Number} Score.
|
30
|
+
#
|
31
|
+
def total_score
|
32
|
+
(10 * total).round / 10.0
|
33
|
+
end
|
34
|
+
|
35
|
+
#
|
36
|
+
# Get list of class reports.
|
37
|
+
#
|
38
|
+
# @return {Array.<FlogReportClass>} List of class reports.
|
39
|
+
#
|
40
|
+
def classes
|
41
|
+
@classes
|
42
|
+
end
|
43
|
+
|
44
|
+
def classes_by_file(file)
|
45
|
+
classes.find_all {|klass| klass.file == file}
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def process_result
|
51
|
+
@classes = []
|
52
|
+
|
53
|
+
scores = Hash.new 0
|
54
|
+
methods = Hash.new { |h,k| h[k] = [] }
|
55
|
+
|
56
|
+
each_by_score(nil) do |class_method, score, call_list|
|
57
|
+
klass = class_method.split(/#|::/)[0..-2].join('::')
|
58
|
+
|
59
|
+
methods[klass] << [class_method, score]
|
60
|
+
scores[klass] += score
|
61
|
+
end
|
62
|
+
|
63
|
+
scores.each do |klass, total|
|
64
|
+
clazz = FlogReportClass.new(klass, total)
|
65
|
+
|
66
|
+
methods[klass].each do |name, score|
|
67
|
+
next if name =~ /#none/
|
68
|
+
|
69
|
+
clazz.add_method(
|
70
|
+
FlogReportMethod.new(
|
71
|
+
clazz,
|
72
|
+
name,
|
73
|
+
score,
|
74
|
+
Location.from_path(method_locations[name])
|
75
|
+
)
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
@classes << clazz
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Watchr
|
2
|
+
class Location
|
3
|
+
attr_reader :file, :line
|
4
|
+
|
5
|
+
def initialize(file, line = nil)
|
6
|
+
@file = file
|
7
|
+
@line = line
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.from_path(path)
|
11
|
+
file, line = path.split(':')
|
12
|
+
line = line && line.to_i
|
13
|
+
|
14
|
+
Location.new(file, line)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
data/lib/watchr/paths.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Watchr
|
2
|
+
module Paths
|
3
|
+
def self.files_by_dirs *dirs
|
4
|
+
extensions = ['rb']
|
5
|
+
|
6
|
+
dirs.flatten.map { |p|
|
7
|
+
if File.directory? p then
|
8
|
+
Dir[File.join(p, '**', "*.{#{extensions.join(',')}}")]
|
9
|
+
else
|
10
|
+
p
|
11
|
+
end
|
12
|
+
}.flatten.sort
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/watchr/smell.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
module Watchr
|
2
|
+
class Smell
|
3
|
+
|
4
|
+
#
|
5
|
+
# Method complexity is high.
|
6
|
+
#
|
7
|
+
COMPLEX_METHOD = :complex_method
|
8
|
+
|
9
|
+
#
|
10
|
+
# Method complexity is very high.
|
11
|
+
#
|
12
|
+
VERY_COMPLEX_METHOD = :very_complex_method
|
13
|
+
|
14
|
+
#
|
15
|
+
# Object (class / module) total complexity is high.
|
16
|
+
#
|
17
|
+
COMPLEX_OBJECT = :complex_object
|
18
|
+
|
19
|
+
#
|
20
|
+
# Object (class / module) total complexity is very high.
|
21
|
+
#
|
22
|
+
VERY_COMPLEX_OBJECT = :very_complex_object
|
23
|
+
|
24
|
+
#
|
25
|
+
# Code in multiple places is identical.
|
26
|
+
#
|
27
|
+
IDENTICAL_CODE = :identical_code
|
28
|
+
|
29
|
+
#
|
30
|
+
# Code in multiple places is similar (not identical).
|
31
|
+
#
|
32
|
+
SIMILAR_CODE = :similar_code
|
33
|
+
|
34
|
+
def initialize(type, context, description, locations)
|
35
|
+
@type = type
|
36
|
+
@context = context
|
37
|
+
@description = description
|
38
|
+
@locations = []
|
39
|
+
|
40
|
+
Array(locations).each {|l| add_location(l)}
|
41
|
+
end
|
42
|
+
|
43
|
+
def type
|
44
|
+
@type
|
45
|
+
end
|
46
|
+
|
47
|
+
def locations
|
48
|
+
@locations
|
49
|
+
end
|
50
|
+
|
51
|
+
def description
|
52
|
+
@description
|
53
|
+
end
|
54
|
+
|
55
|
+
def context
|
56
|
+
@context
|
57
|
+
end
|
58
|
+
|
59
|
+
def add_location(location)
|
60
|
+
@locations << location
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'shoulda/matchers/active_model'
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
5
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
6
|
+
|
7
|
+
# Requires supporting files with custom matchers and macros, etc,
|
8
|
+
# in ./support/ and its subdirectories.
|
9
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
10
|
+
|
11
|
+
# Include ActiveModel matchers from Shoulda into RSpec Matchers
|
12
|
+
module RSpec::Matchers
|
13
|
+
include Shoulda::Matchers::ActiveModel
|
14
|
+
end
|
15
|
+
|
16
|
+
RSpec.configure do |config|
|
17
|
+
config.mock_with :mocha
|
18
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'watchr/analyse'
|
3
|
+
|
4
|
+
describe Watchr::Analyse do
|
5
|
+
let(:analyse) { Watchr::Analyse.new('spec/fixtures/') }
|
6
|
+
|
7
|
+
describe '#files' do
|
8
|
+
subject { analyse.files }
|
9
|
+
|
10
|
+
its(:count) { should == 2 }
|
11
|
+
its(:first) { subject.class.should == Watchr::FileAnalyse }
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'watchr/file_analyse'
|
3
|
+
|
4
|
+
describe Watchr::FileAnalyse do
|
5
|
+
let(:path) { 'spec/fixtures/class.rb' }
|
6
|
+
|
7
|
+
let(:file_analyse) { Watchr::FileAnalyse.new(path) }
|
8
|
+
|
9
|
+
describe '#path' do
|
10
|
+
subject { file_analyse.path }
|
11
|
+
|
12
|
+
it { should == path }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#smelly?' do
|
16
|
+
subject { file_analyse.smelly? }
|
17
|
+
|
18
|
+
context 'with no smells' do
|
19
|
+
it { should be_false }
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with smells' do
|
23
|
+
let(:smell) { stub('smell') }
|
24
|
+
|
25
|
+
before { file_analyse.stubs(:smells).returns([smell]) }
|
26
|
+
|
27
|
+
it { should be_true }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'watchr/flay_metric/report'
|
3
|
+
|
4
|
+
describe Watchr::FlayMetric::Report do
|
5
|
+
let(:report) {
|
6
|
+
Watchr::FlayMetric::Report.new('spec/fixtures/')
|
7
|
+
}
|
8
|
+
|
9
|
+
describe '#total_score' do
|
10
|
+
subject { report.total_score }
|
11
|
+
|
12
|
+
it { should == 52 }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#duplications' do
|
16
|
+
describe '.first' do
|
17
|
+
subject { report.duplications.first }
|
18
|
+
|
19
|
+
describe 'locations' do
|
20
|
+
subject { report.duplications.first.locations }
|
21
|
+
|
22
|
+
its(:first) { subject.file.should == 'spec/fixtures/class.rb' }
|
23
|
+
its(:first) { subject.line.should == 5 }
|
24
|
+
|
25
|
+
its(:last) { subject.file.should == 'spec/fixtures/module.rb' }
|
26
|
+
its(:last) { subject.line.should == 2 }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'watchr/flog_metric/report'
|
3
|
+
|
4
|
+
describe Watchr::FlogMetric::Report do
|
5
|
+
let(:flog_report) {
|
6
|
+
Watchr::FlogMetric::Report.new([
|
7
|
+
'spec/fixtures/class.rb',
|
8
|
+
'spec/fixtures/module.rb'
|
9
|
+
])
|
10
|
+
}
|
11
|
+
|
12
|
+
describe '#total_score' do
|
13
|
+
subject { flog_report.total_score }
|
14
|
+
|
15
|
+
it { should == 6 }
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#classes' do
|
19
|
+
describe 'Foo' do
|
20
|
+
subject { flog_report.classes.first }
|
21
|
+
|
22
|
+
its(:name) { should == 'Baz::Foo' }
|
23
|
+
its(:total_score) { should == 4.5 }
|
24
|
+
its(:total_methods_score) { should == 3.4 }
|
25
|
+
|
26
|
+
describe '#location' do
|
27
|
+
subject { flog_report.classes.first.location }
|
28
|
+
|
29
|
+
its(:file) { should == 'spec/fixtures/class.rb' }
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
describe '.methods' do
|
34
|
+
describe '.last' do
|
35
|
+
subject { flog_report.classes.first.methods.last }
|
36
|
+
|
37
|
+
its(:name) { should == 'bar' }
|
38
|
+
its(:full_name) { should == 'Baz::Foo#bar' }
|
39
|
+
its(:total_score) { should == 1.7 }
|
40
|
+
its(:clazz) { should == flog_report.classes.first }
|
41
|
+
|
42
|
+
describe '#location' do
|
43
|
+
subject { flog_report.classes.first.methods.last.location }
|
44
|
+
|
45
|
+
its(:file) { should == 'spec/fixtures/class.rb' }
|
46
|
+
its(:line) { should == 5 }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '.first' do
|
51
|
+
subject { flog_report.classes.first.methods.first }
|
52
|
+
|
53
|
+
its(:name) { should == 'bar' }
|
54
|
+
its(:full_name) { should == 'Baz::Foo::bar' }
|
55
|
+
its(:total_score) { should == 1.7 }
|
56
|
+
its(:clazz) { should == flog_report.classes.first }
|
57
|
+
|
58
|
+
describe '#location' do
|
59
|
+
subject { flog_report.classes.first.methods.first.location }
|
60
|
+
|
61
|
+
its(:file) { should == 'spec/fixtures/class.rb' }
|
62
|
+
its(:line) { should == 13 }
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '#by_file' do
|
71
|
+
subject { flog_report.classes_by_file('fixture') }
|
72
|
+
|
73
|
+
let(:classes) { [klass] }
|
74
|
+
|
75
|
+
before { flog_report.stubs(:classes).returns(classes) }
|
76
|
+
|
77
|
+
context 'with matching file' do
|
78
|
+
let(:klass) { stub('klass', :file => 'fixture') }
|
79
|
+
|
80
|
+
it { should include(klass) }
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'without matching file' do
|
84
|
+
let(:klass) { stub('klass', :file => 'blah') }
|
85
|
+
|
86
|
+
it { should_not include(klass) }
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'watchr/location'
|
3
|
+
|
4
|
+
describe Watchr::Location do
|
5
|
+
let(:location) { Watchr::Location.new('foo.rb', 42) }
|
6
|
+
|
7
|
+
subject { location }
|
8
|
+
|
9
|
+
its(:file) { should == 'foo.rb' }
|
10
|
+
its(:line) { should == 42 }
|
11
|
+
|
12
|
+
describe '.from_path' do
|
13
|
+
subject { Watchr::Location.from_path(path) }
|
14
|
+
|
15
|
+
context 'with line' do
|
16
|
+
let(:path) { 'foo.rb:21' }
|
17
|
+
|
18
|
+
its(:file) { should == 'foo.rb' }
|
19
|
+
its(:line) { should == 21 }
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'without line' do
|
23
|
+
let(:path) { 'foo.rb' }
|
24
|
+
|
25
|
+
its(:file) { should == 'foo.rb' }
|
26
|
+
its(:line) { should be_nil }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'watchr/smell'
|
3
|
+
|
4
|
+
describe Watchr::Smell do
|
5
|
+
|
6
|
+
let(:type) { 'foo' }
|
7
|
+
|
8
|
+
let(:location) { 'location' }
|
9
|
+
|
10
|
+
let(:locations) { location }
|
11
|
+
|
12
|
+
let(:description) { 'description' }
|
13
|
+
|
14
|
+
let(:context) { 'context' }
|
15
|
+
|
16
|
+
let(:smell) { Watchr::Smell.new(type, context, description, locations) }
|
17
|
+
|
18
|
+
subject { smell }
|
19
|
+
|
20
|
+
describe '#type' do
|
21
|
+
its(:type) { should == type }
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#locations' do
|
25
|
+
subject { smell.locations }
|
26
|
+
|
27
|
+
context 'one location' do
|
28
|
+
it { should == [location] }
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'multiple locations' do
|
32
|
+
let(:locations) { [location, location] }
|
33
|
+
|
34
|
+
it { should == [location, location] }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#description' do
|
39
|
+
its(:description) { should == description }
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#context' do
|
43
|
+
its(:context) { should == context }
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'watchr/smells_collector'
|
3
|
+
|
4
|
+
describe Watchr::SmellsCollector do
|
5
|
+
let(:collector) { Watchr::SmellsCollector.new }
|
6
|
+
|
7
|
+
describe '#all' do
|
8
|
+
|
9
|
+
subject { collector.all }
|
10
|
+
|
11
|
+
context 'with no smells' do
|
12
|
+
it { should be_empty }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with smells' do
|
16
|
+
let(:smell) { stub('smell') }
|
17
|
+
|
18
|
+
before { collector.add(smell) }
|
19
|
+
|
20
|
+
it { should_not be_empty }
|
21
|
+
its(:first) { should == smell }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe '#empty?' do
|
26
|
+
subject { collector.empty? }
|
27
|
+
|
28
|
+
context 'with no smells' do
|
29
|
+
it { should be_true }
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'with smells' do
|
33
|
+
let(:smell) { stub('smell') }
|
34
|
+
|
35
|
+
before { collector.add(smell) }
|
36
|
+
|
37
|
+
it { should be_false }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
end
|
data/watchr.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "watchr/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "ruby-watchr"
|
7
|
+
s.version = Watchr::VERSION
|
8
|
+
s.authors = ["Petr Janda"]
|
9
|
+
s.email = ["petrjanda@me.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = 'Ruby static code analysis'
|
12
|
+
s.description = 'Utility to gather summary of code smells according to multiple analysers.'
|
13
|
+
|
14
|
+
s.rubyforge_project = "watchr"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# specify any dependencies here; for example:
|
22
|
+
# s.add_development_dependency "rspec"
|
23
|
+
# s.add_runtime_dependency "rest-client"
|
24
|
+
s.add_dependency 'flog'
|
25
|
+
s.add_dependency 'flay'
|
26
|
+
s.add_dependency 'ruby2ruby'
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ruby-watchr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
version: 0.0.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Petr Janda
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2012-07-05 00:00:00 +02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: flog
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: flay
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
version: "0"
|
44
|
+
type: :runtime
|
45
|
+
version_requirements: *id002
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: ruby2ruby
|
48
|
+
prerelease: false
|
49
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
version: "0"
|
57
|
+
type: :runtime
|
58
|
+
version_requirements: *id003
|
59
|
+
description: Utility to gather summary of code smells according to multiple analysers.
|
60
|
+
email:
|
61
|
+
- petrjanda@me.com
|
62
|
+
executables: []
|
63
|
+
|
64
|
+
extensions: []
|
65
|
+
|
66
|
+
extra_rdoc_files: []
|
67
|
+
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- .rspec
|
71
|
+
- .rvmrc
|
72
|
+
- Gemfile
|
73
|
+
- Rakefile
|
74
|
+
- lib/watchr.rb
|
75
|
+
- lib/watchr/analyse.rb
|
76
|
+
- lib/watchr/file_analyse.rb
|
77
|
+
- lib/watchr/flay_metric/diff.rb
|
78
|
+
- lib/watchr/flay_metric/report.rb
|
79
|
+
- lib/watchr/flog_metric/class.rb
|
80
|
+
- lib/watchr/flog_metric/method.rb
|
81
|
+
- lib/watchr/flog_metric/report.rb
|
82
|
+
- lib/watchr/location.rb
|
83
|
+
- lib/watchr/paths.rb
|
84
|
+
- lib/watchr/smell.rb
|
85
|
+
- lib/watchr/smells_collector.rb
|
86
|
+
- lib/watchr/version.rb
|
87
|
+
- spec/fixtures/class.rb
|
88
|
+
- spec/fixtures/module.rb
|
89
|
+
- spec/spec_helper.rb
|
90
|
+
- spec/watchr/analyse_spec.rb
|
91
|
+
- spec/watchr/file_analyse_spec.rb
|
92
|
+
- spec/watchr/flay/report_spec.rb
|
93
|
+
- spec/watchr/flog_metric/flog_matric/flog_report_spec.rb
|
94
|
+
- spec/watchr/location_spec.rb
|
95
|
+
- spec/watchr/paths_spec.rb
|
96
|
+
- spec/watchr/smell_spec.rb
|
97
|
+
- spec/watchr/smells_collector_spec.rb
|
98
|
+
- watchr.gemspec
|
99
|
+
has_rdoc: true
|
100
|
+
homepage: ""
|
101
|
+
licenses: []
|
102
|
+
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
|
106
|
+
require_paths:
|
107
|
+
- lib
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
segments:
|
114
|
+
- 0
|
115
|
+
version: "0"
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
segments:
|
122
|
+
- 0
|
123
|
+
version: "0"
|
124
|
+
requirements: []
|
125
|
+
|
126
|
+
rubyforge_project: watchr
|
127
|
+
rubygems_version: 1.3.7
|
128
|
+
signing_key:
|
129
|
+
specification_version: 3
|
130
|
+
summary: Ruby static code analysis
|
131
|
+
test_files:
|
132
|
+
- spec/fixtures/class.rb
|
133
|
+
- spec/fixtures/module.rb
|
134
|
+
- spec/spec_helper.rb
|
135
|
+
- spec/watchr/analyse_spec.rb
|
136
|
+
- spec/watchr/file_analyse_spec.rb
|
137
|
+
- spec/watchr/flay/report_spec.rb
|
138
|
+
- spec/watchr/flog_metric/flog_matric/flog_report_spec.rb
|
139
|
+
- spec/watchr/location_spec.rb
|
140
|
+
- spec/watchr/paths_spec.rb
|
141
|
+
- spec/watchr/smell_spec.rb
|
142
|
+
- spec/watchr/smells_collector_spec.rb
|