sandi_meter 0.0.6 → 1.0.0
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 +8 -8
- data/README.md +48 -15
- data/html/_detail_block.html +8 -0
- data/html/forkme.png +0 -0
- data/html/index.html +11 -5
- data/html/script.js +11 -0
- data/html/style.css +75 -0
- data/lib/sandi_meter/analyzer.rb +44 -12
- data/lib/sandi_meter/calculator.rb +89 -9
- data/lib/sandi_meter/cli.rb +22 -8
- data/lib/sandi_meter/file_scanner.rb +4 -2
- data/lib/sandi_meter/formatter.rb +61 -5
- data/lib/sandi_meter/html_generator.rb +94 -1
- data/lib/sandi_meter/version.rb +1 -1
- data/spec/analyzer_spec.rb +70 -32
- data/spec/test_classes/10_controller.rb +6 -0
- data/spec/test_classes/14_controller.rb +8 -0
- data/spec/test_classes/15_controller.rb +21 -0
- metadata +7 -2
checksums.yaml
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
!binary "U0hBMQ==":
|
|
3
3
|
metadata.gz: !binary |-
|
|
4
|
-
|
|
4
|
+
MjRmZDFmOTBlY2IxMzJlMjBhNTQwMDIwMjMzMmNlNWQyZDM2ODEyYQ==
|
|
5
5
|
data.tar.gz: !binary |-
|
|
6
|
-
|
|
6
|
+
ZjQyYWJiNDNlY2RlNjk0YTIzYTQ2MGU2YTUwNDAwMWU2OWQ3M2ZjZQ==
|
|
7
7
|
!binary "U0hBNTEy":
|
|
8
8
|
metadata.gz: !binary |-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
MzgxY2NjZGZjNTJhYmVhNmZhMDUxYmQ5MWQ2ZWEzNGMwZjA1ZTEyYTdjMjUy
|
|
10
|
+
MmQ1ZTZiOGE5OTAyMzBmOTA3MGFmNmRlZjkzNjA1ZWI2MzJlMWUzMDdmNDNi
|
|
11
|
+
MGJjZGFiMzNiNTI2OWIyOTI1YzBkMDNkZGQ0ZDg3ZTc1N2U2Zjc=
|
|
12
12
|
data.tar.gz: !binary |-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
ZDMwMTA4NTA1ZTI3ZjU4OGVmYjI3MDMzMzQ2MGQ5Zjc3OGY0ZGZhYzA2Yjlm
|
|
14
|
+
NzQ1ODg5NmYzMzc0NjZhMmU5ZjFiYmY1YmEyM2FjMWRmNjg5MTRjY2FmNjU4
|
|
15
|
+
MDg1NmJmYjE1Mjc0NzU0YmQ1Y2M5ZDY0ZGRkMjM2YjlkMzMxZGY=
|
data/README.md
CHANGED
|
@@ -15,25 +15,58 @@ Static analysis tool for checking your Ruby code for [Sandi Metz' four rules](ht
|
|
|
15
15
|
gem install sandi_meter
|
|
16
16
|
|
|
17
17
|
sandi_meter --help
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
18
|
+
-d, --details CLI mode. Show details (path, line number)
|
|
19
|
+
-g, --graph HTML mode. Create folder, log data and output stats to HTML file.
|
|
20
|
+
-l, --log Show syntax error and indentation log output
|
|
21
|
+
-p, --path PATH Path to folder or file to analyze (default is ".")
|
|
22
|
+
-r, --rules Show rules
|
|
23
|
+
-h, --help Help
|
|
24
|
+
|
|
25
|
+
cd ~/your/ruby/or/rails/project
|
|
26
|
+
sandi_meter -d
|
|
27
|
+
|
|
28
|
+
1. 85% of classes are under 100 lines.
|
|
29
|
+
2. 45% of methods are under 5 lines.
|
|
30
|
+
3. 99% of method calls accepted are less than 4 parameters.
|
|
31
|
+
4. 66% of controllers have one instance variable per action.
|
|
32
|
+
|
|
33
|
+
Classes with 100+ lines
|
|
34
|
+
Class name | Size | Path
|
|
35
|
+
SandiMeter::Analyzer | 219 | ./lib/sandi_meter/analyzer.rb:7
|
|
36
|
+
SandiMeter::Calculator | 172 | ./lib/sandi_meter/calculator.rb:2
|
|
37
|
+
SandiMeter::HtmlGenerator | 135 | ./lib/sandi_meter/html_generator.rb:5
|
|
38
|
+
Valera | 109 | ./spec/test_classes/12.rb:1
|
|
39
|
+
|
|
40
|
+
Missindented classes
|
|
41
|
+
Class name | Path
|
|
42
|
+
MyApp::TestClass | ./spec/test_classes/1.rb:2
|
|
43
|
+
OneLinerClass | ./spec/test_classes/5.rb:1
|
|
44
|
+
|
|
45
|
+
Methods with 5+ lines
|
|
46
|
+
Class name | Method name | Size | Path
|
|
47
|
+
SandiMeter::Analyzer | initialize | 10 | ./lib/sandi_meter/analyzer.rb:10
|
|
48
|
+
SandiMeter::Analyzer | analyze | 13 | ./lib/sandi_meter/analyzer.rb:22
|
|
49
|
+
|
|
50
|
+
Missindented methods
|
|
51
|
+
Class name | Method name | Path
|
|
52
|
+
MyApp::TestClass | blah | ./spec/test_classes/1.rb:3
|
|
53
|
+
|
|
54
|
+
Method calls with 4+ arguments
|
|
55
|
+
# of arguments | Path
|
|
56
|
+
5 | ./lib/sandi_meter/html_generator.rb:55
|
|
57
|
+
5 | ./lib/sandi_meter/html_generator.rb:71
|
|
58
|
+
|
|
59
|
+
Controllers with 1+ instance variables
|
|
60
|
+
Controller name | Action name | Instance variables
|
|
61
|
+
AnotherUsersController | index | @users, @excess_variable
|
|
30
62
|
~~~
|
|
31
63
|
|
|
32
64
|
## HTML mode
|
|
33
65
|
|
|
34
66
|
Try using gem with `-g (--graph)` option, so it will create a folder with beautiful html output and log file with results of any scan.
|
|
35
67
|
|
|
36
|
-

|
|
69
|
+

|
|
37
70
|
|
|
38
71
|
## Ruby script mode
|
|
39
72
|
|
|
@@ -47,11 +80,11 @@ pp data
|
|
|
47
80
|
# {:first_rule=>
|
|
48
81
|
# {:small_classes_amount=>916,
|
|
49
82
|
# :total_classes_amount=>937,
|
|
50
|
-
# :
|
|
83
|
+
# :misindented_classes_amount=>1},
|
|
51
84
|
# :second_rule=>
|
|
52
85
|
# {:small_methods_amount=>1144,
|
|
53
86
|
# :total_methods_amount=>1833,
|
|
54
|
-
# :
|
|
87
|
+
# :misindented_methods_amount=>0},
|
|
55
88
|
# :third_rule=>{:proper_method_calls=>5857, :total_method_calls=>5894},
|
|
56
89
|
# :fourth_rule=>{:proper_controllers_amount=>17, :total_controllers_amount=>94}}
|
|
57
90
|
~~~
|
data/html/forkme.png
ADDED
|
Binary file
|
data/html/index.html
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
</script>
|
|
14
14
|
</head>
|
|
15
15
|
<body>
|
|
16
|
-
<a href="https://github.com/makaroni4/sandi_meter"><img style="position: absolute; top: 0; left: 0; border: 0;" src="
|
|
16
|
+
<a href="https://github.com/makaroni4/sandi_meter"><img style="position: absolute; top: 0; left: 0; border: 0;" src="assets/forkme.png" alt="Fork me on GitHub"></a>
|
|
17
17
|
<div class="container">
|
|
18
18
|
<header>
|
|
19
19
|
<h1 class="main-title">Sandi Metz rules</h1>
|
|
@@ -26,7 +26,10 @@
|
|
|
26
26
|
<div id="pie4" class="pie-charts-item"></div>
|
|
27
27
|
<div class="clearfix"></div>
|
|
28
28
|
</section>
|
|
29
|
-
<
|
|
29
|
+
<nav class="main-menu">
|
|
30
|
+
<a href="#" class="main-menu-active js-menu-item" data-rel=".js-charts">Charts</a><a href="#" class="js-menu-item" data-rel=".js-details">Details</a>
|
|
31
|
+
</nav>
|
|
32
|
+
<section class="plot-charts js-charts js-tab-item">
|
|
30
33
|
<div class="plot-charts-item">
|
|
31
34
|
<div class="plot-charts-item-caption">Number of 100 line classes vs time</div>
|
|
32
35
|
<div class="plot-charts-item-graph" id="plot1"></div>
|
|
@@ -46,10 +49,13 @@
|
|
|
46
49
|
</div>
|
|
47
50
|
<div class="clearfix"></div>
|
|
48
51
|
</section>
|
|
52
|
+
<section class="details js-details js-tab-item">
|
|
53
|
+
<% details %>
|
|
54
|
+
</section>
|
|
49
55
|
<footer class="main-footer">
|
|
50
|
-
Scanned with love by <a href="https://github.com/makaroni4/sandi_meter">sandi_meter</a> gem.
|
|
51
|
-
Please, <a href="https://github.com/makaroni4/sandi_meter/issues/new">leave an issue</a> or
|
|
52
|
-
<a href="
|
|
56
|
+
Scanned with love by <a href="https://github.com/makaroni4/sandi_meter">sandi_meter</a> gem.
|
|
57
|
+
Please, <a href="https://github.com/makaroni4/sandi_meter/issues/new">leave an issue</a> or
|
|
58
|
+
<a href="mailto:makaroni4@gmail.com">email</a> some feedback!
|
|
53
59
|
</footer>
|
|
54
60
|
</div>
|
|
55
61
|
</body>
|
data/html/script.js
CHANGED
|
@@ -61,4 +61,15 @@ $(document).ready(function(){
|
|
|
61
61
|
plotLine('plot2', data, ['r20', 'r21'], ['under 5 lines', 'more than 5 lines']);
|
|
62
62
|
plotLine('plot3', data, ['r30', 'r31'], ['less than 4 params', 'more than 4 params']);
|
|
63
63
|
plotLine('plot4', data, ['r40', 'r41'], ['one instance variable', 'many instance variables']);
|
|
64
|
+
|
|
65
|
+
var $tabs = $(".js-tab-item");
|
|
66
|
+
var $menuItems = $(".js-menu-item")
|
|
67
|
+
$menuItems.on("click", function(e){
|
|
68
|
+
var rel = $(this).data("rel");
|
|
69
|
+
$tabs.hide();
|
|
70
|
+
$menuItems.removeClass("main-menu-active");
|
|
71
|
+
$(rel).show();
|
|
72
|
+
$(this).addClass("main-menu-active");
|
|
73
|
+
e.preventDefault();
|
|
74
|
+
});
|
|
64
75
|
})
|
data/html/style.css
CHANGED
|
@@ -51,3 +51,78 @@ body {
|
|
|
51
51
|
.plot-charts-item-graph {
|
|
52
52
|
height: 280px;
|
|
53
53
|
}
|
|
54
|
+
|
|
55
|
+
.toggle_report.current_tab {
|
|
56
|
+
text-decoration: none;
|
|
57
|
+
cursor: default;
|
|
58
|
+
pointer-events: none;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.details {
|
|
62
|
+
display: none;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.details h2 {
|
|
66
|
+
margin: 0 0 14px;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.details-stats {
|
|
70
|
+
font-family: monospace;
|
|
71
|
+
margin-bottom: 40px;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.details-stats td {
|
|
75
|
+
padding-right: 20px;
|
|
76
|
+
line-height: 18px;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.details-stats td.warning {
|
|
80
|
+
color: red;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.main-menu {
|
|
84
|
+
margin-bottom: 30px;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.main-menu {
|
|
88
|
+
text-align: center;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.main-menu a {
|
|
92
|
+
display: inline-block;
|
|
93
|
+
padding: 4px 16px;
|
|
94
|
+
font-size: 18px;
|
|
95
|
+
text-decoration: none;
|
|
96
|
+
color: black;
|
|
97
|
+
border: 1px solid rgb(158, 158, 158);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.main-menu a:hover {
|
|
101
|
+
color: rgb(65, 131, 196);;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.main-menu a:first-child {
|
|
105
|
+
border-right: none;
|
|
106
|
+
border-top-left-radius: 4px;
|
|
107
|
+
border-bottom-left-radius: 4px;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.main-menu a:last-child {
|
|
111
|
+
border-top-right-radius: 4px;
|
|
112
|
+
border-bottom-right-radius: 4px;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.main-menu-active {
|
|
116
|
+
background: rgb(240, 240, 240);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.main-menu .main-menu-active:hover {
|
|
120
|
+
color: black;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.hint {
|
|
124
|
+
margin: -40px 0 40px 0;
|
|
125
|
+
font-family: monospace;
|
|
126
|
+
font-style: italic;
|
|
127
|
+
font-weight: normal;
|
|
128
|
+
}
|
data/lib/sandi_meter/analyzer.rb
CHANGED
|
@@ -5,15 +5,18 @@ require_relative 'method_arguments_counter'
|
|
|
5
5
|
|
|
6
6
|
module SandiMeter
|
|
7
7
|
class Analyzer
|
|
8
|
-
attr_reader :classes, :
|
|
8
|
+
attr_reader :classes, :misindented_classes, :methods, :misindented_methods, :method_calls, :instance_variables
|
|
9
9
|
|
|
10
10
|
def initialize
|
|
11
11
|
@classes = []
|
|
12
|
-
@
|
|
13
|
-
@
|
|
12
|
+
@misindented_classes = []
|
|
13
|
+
@misindented_methods = {}
|
|
14
14
|
@methods = {}
|
|
15
15
|
@method_calls = []
|
|
16
16
|
@instance_variables = {}
|
|
17
|
+
|
|
18
|
+
@parent_token = nil
|
|
19
|
+
@private_or_protected = false
|
|
17
20
|
end
|
|
18
21
|
|
|
19
22
|
def analyze(file_path)
|
|
@@ -37,19 +40,31 @@ module SandiMeter
|
|
|
37
40
|
|
|
38
41
|
@classes.map! do |klass_params|
|
|
39
42
|
klass_params << loc_checker.check(klass_params, 'class')
|
|
43
|
+
klass_params << "#{@file_path}:#{klass_params[1]}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
@misindented_classes.map! do |klass_params|
|
|
47
|
+
klass_params << "#{@file_path}:#{klass_params[1]}"
|
|
40
48
|
end
|
|
41
49
|
|
|
42
50
|
@methods.each_pair do |klass, methods|
|
|
43
51
|
methods.each do |method_params|
|
|
44
52
|
method_params << loc_checker.check(method_params, 'def')
|
|
53
|
+
method_params << "#{@file_path}:#{method_params[1]}"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
@misindented_methods.each_pair do |klass, methods|
|
|
58
|
+
methods.each do |method_params|
|
|
59
|
+
method_params << "#{@file_path}:#{method_params[1]}"
|
|
45
60
|
end
|
|
46
61
|
end
|
|
47
62
|
|
|
48
63
|
{
|
|
49
64
|
classes: @classes,
|
|
50
|
-
|
|
65
|
+
misindented_classes: @misindented_classes,
|
|
51
66
|
methods: @methods,
|
|
52
|
-
|
|
67
|
+
misindented_methods: @misindented_methods,
|
|
53
68
|
method_calls: @method_calls,
|
|
54
69
|
instance_variables: @instance_variables
|
|
55
70
|
}
|
|
@@ -104,12 +119,12 @@ module SandiMeter
|
|
|
104
119
|
|
|
105
120
|
if @indentation_warnings['class'] && @indentation_warnings['class'].any? { |first_line, last_line| first_line == class_params.last }
|
|
106
121
|
class_params << nil
|
|
107
|
-
@
|
|
122
|
+
@misindented_classes << class_params
|
|
108
123
|
else
|
|
109
124
|
class_params += [find_last_line(class_params)]
|
|
110
125
|
|
|
111
126
|
# in case of one liner class last line will be nil
|
|
112
|
-
(class_params.last == nil ? @
|
|
127
|
+
(class_params.last == nil ? @misindented_classes : @classes) << class_params
|
|
113
128
|
end
|
|
114
129
|
|
|
115
130
|
current_namespace = class_params.first
|
|
@@ -127,7 +142,7 @@ module SandiMeter
|
|
|
127
142
|
counter = SandiMeter::MethodArgumentsCounter.new
|
|
128
143
|
arguments_count, line = counter.count(sexp)
|
|
129
144
|
|
|
130
|
-
@method_calls << [arguments_count, line]
|
|
145
|
+
@method_calls << [arguments_count, "#{@file_path}:#{line}"]
|
|
131
146
|
|
|
132
147
|
find_args_add_block(sexp)
|
|
133
148
|
else
|
|
@@ -145,7 +160,7 @@ module SandiMeter
|
|
|
145
160
|
if sexp.first == :assign
|
|
146
161
|
@instance_variables[current_namespace] ||= {}
|
|
147
162
|
@instance_variables[current_namespace][method_name] ||= []
|
|
148
|
-
@instance_variables[current_namespace][method_name] << sexp[1][1][1]
|
|
163
|
+
@instance_variables[current_namespace][method_name] << sexp[1][1][1] if sexp[1][1][0] == :@ivar
|
|
149
164
|
else
|
|
150
165
|
scan_def_for_ivars(current_namespace, method_name, sexp)
|
|
151
166
|
end
|
|
@@ -156,24 +171,41 @@ module SandiMeter
|
|
|
156
171
|
sexp.each do |element|
|
|
157
172
|
next unless element.kind_of?(Array)
|
|
158
173
|
|
|
174
|
+
@parent_token = element.first
|
|
159
175
|
case element.first
|
|
160
176
|
when :def
|
|
161
177
|
method_params = find_method_params(element)
|
|
162
178
|
if @indentation_warnings['def'] && @indentation_warnings['def'].any? { |first_line, last_line| first_line == method_params.last }
|
|
163
179
|
method_params << nil
|
|
164
180
|
method_params << number_of_arguments(element)
|
|
165
|
-
@
|
|
166
|
-
@
|
|
181
|
+
@misindented_methods[current_namespace] ||= []
|
|
182
|
+
@misindented_methods[current_namespace] << method_params
|
|
167
183
|
else
|
|
168
184
|
method_params += [find_last_line(method_params, 'def')]
|
|
169
185
|
method_params << number_of_arguments(element)
|
|
170
186
|
@methods[current_namespace] ||= []
|
|
171
187
|
@methods[current_namespace] << method_params
|
|
172
188
|
end
|
|
173
|
-
|
|
189
|
+
if @scan_instance_variables && !@private_or_protected
|
|
190
|
+
scan_def_for_ivars(current_namespace, method_params.first, element)
|
|
191
|
+
end
|
|
192
|
+
|
|
174
193
|
find_args_add_block(element)
|
|
175
194
|
when :module, :class
|
|
176
195
|
scan_class_sexp(element, current_namespace)
|
|
196
|
+
when :vcall
|
|
197
|
+
if element[1].first == :@ident
|
|
198
|
+
case element[1][1]
|
|
199
|
+
when "private"
|
|
200
|
+
@private_or_protected = true
|
|
201
|
+
when "public"
|
|
202
|
+
@private_or_protected = false
|
|
203
|
+
else
|
|
204
|
+
scan_sexp(element, current_namespace)
|
|
205
|
+
end
|
|
206
|
+
else
|
|
207
|
+
scan_sexp(element, current_namespace)
|
|
208
|
+
end
|
|
177
209
|
else
|
|
178
210
|
scan_sexp(element, current_namespace)
|
|
179
211
|
end
|
|
@@ -17,7 +17,9 @@ module SandiMeter
|
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
def calculate!
|
|
20
|
+
def calculate!(store_details = false)
|
|
21
|
+
@store_details = store_details
|
|
22
|
+
|
|
21
23
|
check_first_rule
|
|
22
24
|
check_second_rule
|
|
23
25
|
check_third_rule
|
|
@@ -27,18 +29,90 @@ module SandiMeter
|
|
|
27
29
|
end
|
|
28
30
|
|
|
29
31
|
private
|
|
32
|
+
def log_first_rule
|
|
33
|
+
@output[:first_rule][:log] ||= {}
|
|
34
|
+
@output[:first_rule][:log][:classes] = @data[:classes].inject([]) do |log, class_params|
|
|
35
|
+
# TODO
|
|
36
|
+
# wrap each class params into class and get params with
|
|
37
|
+
# verbose name instead of array keys (class_params[2] should be klass.line_count)
|
|
38
|
+
log << [class_params.first, class_params[2], class_params.last] if class_params[-2] == false
|
|
39
|
+
log
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
@output[:first_rule][:log][:misindented_classes] = @data[:misindented_classes].inject([]) do |log, class_params|
|
|
43
|
+
log << [class_params.first, nil, class_params.last]
|
|
44
|
+
log
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def log_second_rule
|
|
49
|
+
@output[:second_rule][:log] ||= {}
|
|
50
|
+
@output[:second_rule][:log][:methods] ||= []
|
|
51
|
+
@output[:second_rule][:log][:misindented_methods] ||= []
|
|
52
|
+
|
|
53
|
+
@data[:methods].each_pair do |klass, methods|
|
|
54
|
+
methods.select { |m| m[-2] == false }.each do |method_params|
|
|
55
|
+
params = [klass, method_params.first]
|
|
56
|
+
# TODO
|
|
57
|
+
# wrap method param to method class so method_params[1] becomes method.first_line
|
|
58
|
+
# and method_params[2] method.last_line
|
|
59
|
+
params << method_params[2] - method_params[1]
|
|
60
|
+
params << method_params.last
|
|
61
|
+
|
|
62
|
+
@output[:second_rule][:log][:methods] << params
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
@data[:misindented_methods].each_pair do |klass, methods|
|
|
67
|
+
methods.each do |method_params|
|
|
68
|
+
params = [klass, method_params.first]
|
|
69
|
+
params << nil
|
|
70
|
+
params << method_params.last
|
|
71
|
+
|
|
72
|
+
@output[:second_rule][:log][:misindented_methods] << params
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def log_third_rule
|
|
78
|
+
@output[:third_rule][:log] ||={}
|
|
79
|
+
@output[:third_rule][:log][:method_calls] ||= []
|
|
80
|
+
|
|
81
|
+
# TODO
|
|
82
|
+
# add name of method being called
|
|
83
|
+
proper_method_calls = @data[:method_calls].inject(0) do |sum, params|
|
|
84
|
+
@output[:third_rule][:log][:method_calls] << params if params.first > 4
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def log_fourth_rule
|
|
89
|
+
@output[:fourth_rule][:log] ||={}
|
|
90
|
+
@output[:fourth_rule][:log][:controllers] ||= []
|
|
91
|
+
|
|
92
|
+
@data[:instance_variables].each_pair do |controller, methods|
|
|
93
|
+
methods.each_pair do |method, instance_variables|
|
|
94
|
+
if instance_variables.size > 1
|
|
95
|
+
@output[:fourth_rule][:log][:controllers] << [controller, method, instance_variables]
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
30
101
|
def check_first_rule
|
|
31
102
|
total_classes_amount = @data[:classes].size
|
|
32
103
|
small_classes_amount = @data[:classes].inject(0) do |sum, class_params|
|
|
33
|
-
sum += 1 if class_params
|
|
104
|
+
sum += 1 if class_params[-2] == true
|
|
34
105
|
sum
|
|
35
106
|
end
|
|
36
|
-
|
|
107
|
+
|
|
108
|
+
misindented_classes_amount = @data[:misindented_classes].size
|
|
37
109
|
|
|
38
110
|
@output[:first_rule] ||= {}
|
|
39
111
|
@output[:first_rule][:small_classes_amount] = small_classes_amount
|
|
40
112
|
@output[:first_rule][:total_classes_amount] = total_classes_amount
|
|
41
|
-
@output[:first_rule][:
|
|
113
|
+
@output[:first_rule][:misindented_classes_amount] = misindented_classes_amount
|
|
114
|
+
|
|
115
|
+
log_first_rule if @store_details
|
|
42
116
|
end
|
|
43
117
|
|
|
44
118
|
def check_second_rule
|
|
@@ -46,19 +120,21 @@ module SandiMeter
|
|
|
46
120
|
small_methods_amount = 0
|
|
47
121
|
|
|
48
122
|
@data[:methods].each_pair do |klass, methods|
|
|
49
|
-
small_methods_amount += methods.select { |m| m
|
|
123
|
+
small_methods_amount += methods.select { |m| m[-2] == true }.size
|
|
50
124
|
total_methods_amount += methods.size
|
|
51
125
|
end
|
|
52
126
|
|
|
53
|
-
|
|
54
|
-
@data[:
|
|
55
|
-
|
|
127
|
+
misindented_methods_amount = 0
|
|
128
|
+
@data[:misindented_methods].each_pair do |klass, methods|
|
|
129
|
+
misindented_methods_amount += methods.size
|
|
56
130
|
end
|
|
57
131
|
|
|
58
132
|
@output[:second_rule] ||= {}
|
|
59
133
|
@output[:second_rule][:small_methods_amount] = small_methods_amount
|
|
60
134
|
@output[:second_rule][:total_methods_amount] = total_methods_amount
|
|
61
|
-
@output[:second_rule][:
|
|
135
|
+
@output[:second_rule][:misindented_methods_amount] = misindented_methods_amount
|
|
136
|
+
|
|
137
|
+
log_second_rule if @store_details
|
|
62
138
|
end
|
|
63
139
|
|
|
64
140
|
# TODO
|
|
@@ -74,6 +150,8 @@ module SandiMeter
|
|
|
74
150
|
@output[:third_rule] ||= {}
|
|
75
151
|
@output[:third_rule][:proper_method_calls] = proper_method_calls
|
|
76
152
|
@output[:third_rule][:total_method_calls] = total_method_calls
|
|
153
|
+
|
|
154
|
+
log_third_rule if @store_details
|
|
77
155
|
end
|
|
78
156
|
|
|
79
157
|
def check_fourth_rule
|
|
@@ -88,6 +166,8 @@ module SandiMeter
|
|
|
88
166
|
@output[:fourth_rule] ||= {}
|
|
89
167
|
@output[:fourth_rule][:proper_controllers_amount] = proper_controllers_amount
|
|
90
168
|
@output[:fourth_rule][:total_controllers_amount] = total_controllers_amount
|
|
169
|
+
|
|
170
|
+
log_fourth_rule if @store_details
|
|
91
171
|
end
|
|
92
172
|
end
|
|
93
173
|
end
|
data/lib/sandi_meter/cli.rb
CHANGED
|
@@ -20,10 +20,16 @@ module SandiMeter
|
|
|
20
20
|
description: "Show syntax error and indentation log output",
|
|
21
21
|
boolean: true
|
|
22
22
|
|
|
23
|
+
option :details,
|
|
24
|
+
short: "-d",
|
|
25
|
+
long: "--details",
|
|
26
|
+
description: "CLI mode. Show details (path, line number)",
|
|
27
|
+
boolean: true
|
|
28
|
+
|
|
23
29
|
option :graph,
|
|
24
30
|
short: "-g",
|
|
25
31
|
long: "--graph",
|
|
26
|
-
description: "Create folder
|
|
32
|
+
description: "HTML mode. Create folder, log data and output stats to HTML file.",
|
|
27
33
|
boolean: true
|
|
28
34
|
|
|
29
35
|
option :help,
|
|
@@ -53,18 +59,26 @@ module SandiMeter
|
|
|
53
59
|
end
|
|
54
60
|
|
|
55
61
|
scanner = SandiMeter::FileScanner.new(cli.config[:log])
|
|
56
|
-
data = scanner.scan(cli.config[:path])
|
|
62
|
+
data = scanner.scan(cli.config[:path], cli.config[:details] || cli.config[:graph])
|
|
63
|
+
|
|
57
64
|
formatter = SandiMeter::Formatter.new
|
|
58
65
|
|
|
59
66
|
formatter.print_data(data)
|
|
60
67
|
|
|
61
68
|
if cli.config[:graph]
|
|
62
|
-
|
|
63
|
-
|
|
69
|
+
if File.directory?(cli.config[:path])
|
|
70
|
+
logger = SandiMeter::Logger.new
|
|
71
|
+
logger.log!(cli.config[:path], data)
|
|
72
|
+
|
|
73
|
+
html_generator = SandiMeter::HtmlGenerator.new
|
|
74
|
+
html_generator.copy_assets!(cli.config[:path])
|
|
75
|
+
html_generator.generate_data!(cli.config[:path])
|
|
76
|
+
html_generator.generate_details!(cli.config[:path], data)
|
|
64
77
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
78
|
+
system "open sandi_meter/index.html"
|
|
79
|
+
else
|
|
80
|
+
puts "WARNING!!! HTML mode works only if you scan folder."
|
|
81
|
+
end
|
|
68
82
|
end
|
|
69
83
|
end
|
|
70
84
|
|
|
@@ -77,4 +91,4 @@ module SandiMeter
|
|
|
77
91
|
)
|
|
78
92
|
end
|
|
79
93
|
end
|
|
80
|
-
end
|
|
94
|
+
end
|
|
@@ -8,14 +8,14 @@ module SandiMeter
|
|
|
8
8
|
@calculator = SandiMeter::Calculator.new
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
def scan(path)
|
|
11
|
+
def scan(path, store_details = false)
|
|
12
12
|
if File.directory?(path)
|
|
13
13
|
scan_dir(path)
|
|
14
14
|
else
|
|
15
15
|
scan_file(path)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
@calculator.calculate!
|
|
18
|
+
@calculator.calculate!(store_details)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
private
|
|
@@ -32,6 +32,8 @@ module SandiMeter
|
|
|
32
32
|
@calculator.push(data)
|
|
33
33
|
rescue Exception => e
|
|
34
34
|
if @log_errors
|
|
35
|
+
# TODO
|
|
36
|
+
# add backtrace
|
|
35
37
|
puts "Checkout #{path} for:"
|
|
36
38
|
puts "\t#{e.message}"
|
|
37
39
|
end
|
|
@@ -4,25 +4,81 @@ module SandiMeter
|
|
|
4
4
|
if data[:first_rule][:total_classes_amount] > 0
|
|
5
5
|
puts "1. #{data[:first_rule][:small_classes_amount] * 100 / data[:first_rule][:total_classes_amount]}% of classes are under 100 lines."
|
|
6
6
|
else
|
|
7
|
-
puts "1. No classes to
|
|
7
|
+
puts "1. No classes to analyze."
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
if data[:second_rule][:total_methods_amount] > 0
|
|
11
11
|
puts "2. #{data[:second_rule][:small_methods_amount] * 100 / data[:second_rule][:total_methods_amount]}% of methods are under 5 lines."
|
|
12
12
|
else
|
|
13
|
-
puts "2. No methods to
|
|
13
|
+
puts "2. No methods to analyze."
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
if data[:third_rule][:total_method_calls] > 0
|
|
17
|
-
puts "3. #{data[:third_rule][:proper_method_calls] * 100 / data[:third_rule][:total_method_calls]}% of
|
|
17
|
+
puts "3. #{data[:third_rule][:proper_method_calls] * 100 / data[:third_rule][:total_method_calls]}% of method calls accepted are less than 4 parameters."
|
|
18
18
|
else
|
|
19
|
-
puts "3. No method calls to
|
|
19
|
+
puts "3. No method calls to analyze."
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
if data[:fourth_rule][:total_controllers_amount] > 0
|
|
23
23
|
puts "4. #{data[:fourth_rule][:proper_controllers_amount] * 100 / data[:fourth_rule][:total_controllers_amount]}% of controllers have one instance variable per action."
|
|
24
24
|
else
|
|
25
|
-
puts "4. No controllers to
|
|
25
|
+
puts "4. No controllers to analyze."
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
print_log(data)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def print_log(data)
|
|
32
|
+
return unless data[:first_rule][:log] || data[:second_rule][:log] || data[:fourth_rule][:log]
|
|
33
|
+
|
|
34
|
+
if data[:first_rule][:log][:classes].any?
|
|
35
|
+
puts "\nClasses with 100+ lines"
|
|
36
|
+
print_array_of_arrays [["Class name", "Size", "Path"]] + data[:first_rule][:log][:classes]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if data[:first_rule][:log][:misindented_classes].any?
|
|
40
|
+
puts "\nMissindented classes"
|
|
41
|
+
print_array_of_arrays [["Class name", "Path"]] + data[:first_rule][:log][:misindented_classes].map { |row| row.delete_at(1); row } # 1 – size, which nil for misindented_classes
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
if data[:second_rule][:log][:methods].any?
|
|
45
|
+
puts "\nMethods with 5+ lines"
|
|
46
|
+
print_array_of_arrays [["Class name", "Method name", "Size", "Path"]] + data[:second_rule][:log][:methods]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
if data[:second_rule][:log][:misindented_methods].any?
|
|
50
|
+
puts "\nMissindented methods"
|
|
51
|
+
print_array_of_arrays [["Class name", "Method name", "Path"]] + data[:second_rule][:log][:misindented_methods].map { |row| row.delete_at(2); row } # 2 – size, which nil for misindented_methods
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if data[:third_rule][:log][:method_calls].any?
|
|
55
|
+
puts "\nMethod calls with 4+ arguments"
|
|
56
|
+
print_array_of_arrays [["# of arguments", "Path"]] + data[:third_rule][:log][:method_calls]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
if data[:fourth_rule][:log][:controllers].any?
|
|
60
|
+
puts "\nControllers with 1+ instance variables"
|
|
61
|
+
print_array_of_arrays [["Controller name", "Action name", "Instance variables"]] + data[:fourth_rule][:log][:controllers]
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
# TODO
|
|
67
|
+
# sort output by number of lines or any param
|
|
68
|
+
def print_array_of_arrays(nested_array)
|
|
69
|
+
nested_sizes = nested_array.map do |row|
|
|
70
|
+
row.map { |element| element.to_s.size }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
sizes = nested_sizes.transpose.map { |row| row.max }
|
|
74
|
+
|
|
75
|
+
nested_array.each do |row|
|
|
76
|
+
line_elements = row.each_with_index.map do |element, index|
|
|
77
|
+
element_string = element.kind_of?(Array) ? element.join(', ') : element.to_s
|
|
78
|
+
element_string.ljust(sizes[index] + 1, ' ')
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
puts line_elements.join(' | ').prepend(" ")
|
|
26
82
|
end
|
|
27
83
|
end
|
|
28
84
|
end
|
|
@@ -8,7 +8,7 @@ module SandiMeter
|
|
|
8
8
|
FileUtils.mkdir(asset_dir_path) unless Dir.exists?(asset_dir_path)
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
Dir[File.join(File.dirname(__FILE__), "../../html/*.{js,css}")].each do |file|
|
|
11
|
+
Dir[File.join(File.dirname(__FILE__), "../../html/*.{js,css,png}")].each do |file|
|
|
12
12
|
FileUtils.cp file, File.join(asset_dir_path, File.basename(file))
|
|
13
13
|
end
|
|
14
14
|
|
|
@@ -39,5 +39,98 @@ module SandiMeter
|
|
|
39
39
|
file.write(index)
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
|
+
|
|
43
|
+
def generate_details!(path, data)
|
|
44
|
+
details = ""
|
|
45
|
+
|
|
46
|
+
if data[:first_rule][:log][:classes].any?
|
|
47
|
+
data[:first_rule][:log][:misindented_classes] ||= []
|
|
48
|
+
data[:first_rule][:log][:misindented_classes].each do |class_params|
|
|
49
|
+
class_params.insert(1, nil)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
details << string_to_h2("Classes with 100+ lines")
|
|
53
|
+
details << generate_details_block(
|
|
54
|
+
["Class name", "Size", "Path"],
|
|
55
|
+
proper_data: data[:first_rule][:log][:classes],
|
|
56
|
+
warning_data: data[:first_rule][:log][:misindented_classes],
|
|
57
|
+
hint: "NOTE: Red classes are misindented. Start improving your project by fixing them.",
|
|
58
|
+
warning_message: 'Misindented classes'
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
if data[:second_rule][:log][:methods].any?
|
|
63
|
+
data[:second_rule][:log][:misindented_methods] ||= []
|
|
64
|
+
data[:second_rule][:log][:misindented_methods].each do |method_params|
|
|
65
|
+
method_params.insert(2, nil)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
details << string_to_h2("Methods with 5+ lines")
|
|
69
|
+
details << generate_details_block(
|
|
70
|
+
["Class name", "Method name", "Size", "Path"],
|
|
71
|
+
proper_data: data[:second_rule][:log][:methods].sort_by { |a| -a[2].to_i },
|
|
72
|
+
warning_data: data[:second_rule][:log][:misindented_methods].sort_by { |a| -a[1].to_i },
|
|
73
|
+
hint: "NOTE: Red methods are misindented. Continue your way to perfect code by fixing them.",
|
|
74
|
+
warning_message: 'Misindented methods'
|
|
75
|
+
)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
if data[:third_rule][:log][:method_calls].any?
|
|
79
|
+
details << string_to_h2("Method calls with 4+ arguments")
|
|
80
|
+
details << generate_details_block(
|
|
81
|
+
["# of arguments", "Path"],
|
|
82
|
+
proper_data: data[:third_rule][:log][:method_calls]
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
if data[:fourth_rule][:log][:controllers].any?
|
|
87
|
+
details << string_to_h2("Controllers with 1+ instance variables")
|
|
88
|
+
details << generate_details_block(
|
|
89
|
+
["Controller name", "Action name", "Instance variables"],
|
|
90
|
+
proper_data: data[:fourth_rule][:log][:controllers]
|
|
91
|
+
)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
index_file = File.join(path, 'sandi_meter', 'index.html')
|
|
95
|
+
index = File.read(index_file)
|
|
96
|
+
index.gsub!('<% details %>', details)
|
|
97
|
+
|
|
98
|
+
File.open(index_file, 'w') do |file|
|
|
99
|
+
file.write(index)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
private
|
|
104
|
+
def generate_details_block(head_row, data)
|
|
105
|
+
block_partial = File.read File.join(File.dirname(__FILE__), "../../html", "_detail_block.html")
|
|
106
|
+
block_partial.gsub!('<% head %>', array_to_tr(head_row, cell: "th"))
|
|
107
|
+
|
|
108
|
+
table_rows = data[:proper_data].map { |row| array_to_tr(row) }.join('')
|
|
109
|
+
|
|
110
|
+
if data[:warning_data]
|
|
111
|
+
table_rows << data[:warning_data].map { |row| array_to_tr(row, css_class: 'warning', tip: data[:warning_message]) }.join('')
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
block_partial.gsub!('<% rows %>', table_rows)
|
|
115
|
+
block_partial << hint(data[:hint]) if data[:hint]
|
|
116
|
+
block_partial
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def hint(string)
|
|
120
|
+
%(<div class="hint">#{string}</div>)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def string_to_h2(string)
|
|
124
|
+
"<h2>#{string}</h2>\n"
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def cell_to_s(element)
|
|
128
|
+
element.kind_of?(Array) ? element.join(', ') : element.to_s
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def array_to_tr(array, params = {})
|
|
132
|
+
cell = params[:cell] || "td"
|
|
133
|
+
array.map { |element| "<#{cell} class=\"#{params[:css_class]}\" title=\"#{params[:tip]}\">#{cell_to_s(element)}</#{cell}>\n" }.join('').prepend("<tr>\n").concat("</tr>\n")
|
|
134
|
+
end
|
|
42
135
|
end
|
|
43
136
|
end
|
data/lib/sandi_meter/version.rb
CHANGED
data/spec/analyzer_spec.rb
CHANGED
|
@@ -12,21 +12,21 @@ describe SandiMeter::Analyzer do
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
it 'finds indentation warnings for method' do
|
|
15
|
-
analyzer.classes.should eq([["TestClass", 1, 5, true]])
|
|
16
|
-
analyzer.
|
|
15
|
+
analyzer.classes.should eq([["TestClass", 1, 5, true, "#{test_file_path(3)}:1"]])
|
|
16
|
+
analyzer.misindented_classes.should be_empty
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
it 'finds methods' do
|
|
20
|
-
analyzer.methods.should eq({"TestClass"=>[["blah", 2, 4, 0, true]]})
|
|
21
|
-
analyzer.
|
|
20
|
+
analyzer.methods.should eq({"TestClass"=>[["blah", 2, 4, 0, true, "#{test_file_path(3)}:2"]]})
|
|
21
|
+
analyzer.misindented_methods.should be_empty
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
it 'finds method calls that brakes third rule' do
|
|
25
|
-
analyzer.method_calls.should eq([[5,3]])
|
|
25
|
+
analyzer.method_calls.should eq([[5, "#{test_file_path(3)}:3"]])
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
describe 'finds
|
|
29
|
+
describe 'finds misindented classes without last line' do
|
|
30
30
|
let(:test_class) { test_file_path(1) }
|
|
31
31
|
|
|
32
32
|
before do
|
|
@@ -35,12 +35,12 @@ describe SandiMeter::Analyzer do
|
|
|
35
35
|
|
|
36
36
|
it 'finds indentation warnings for method' do
|
|
37
37
|
analyzer.classes.should be_empty
|
|
38
|
-
analyzer.
|
|
38
|
+
analyzer.misindented_classes.should eq([["MyApp::TestClass", 2, nil, "#{test_file_path(1)}:2"]])
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
it 'finds methods' do
|
|
42
42
|
analyzer.methods.should be_empty
|
|
43
|
-
analyzer.
|
|
43
|
+
analyzer.misindented_methods.should eq({"MyApp::TestClass"=>[["blah", 3, nil, 0, "#{test_file_path(1)}:3"]]})
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
@@ -52,15 +52,15 @@ describe SandiMeter::Analyzer do
|
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
it 'finds classes' do
|
|
55
|
-
analyzer.classes.should include(["FirstTestClass", 1, 4, true])
|
|
56
|
-
analyzer.classes.should include(["SecondTestClass", 6, 9, true])
|
|
57
|
-
analyzer.
|
|
55
|
+
analyzer.classes.should include(["FirstTestClass", 1, 4, true, "#{test_file_path(4)}:1"])
|
|
56
|
+
analyzer.classes.should include(["SecondTestClass", 6, 9, true, "#{test_file_path(4)}:6"])
|
|
57
|
+
analyzer.misindented_classes.should be_empty
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
it 'finds methods' do
|
|
61
|
-
analyzer.methods["FirstTestClass"].should eq([["first_meth", 2, 3, 1, true]])
|
|
62
|
-
analyzer.methods["SecondTestClass"].should eq([["second_meth", 7, 8, 1, true]])
|
|
63
|
-
analyzer.
|
|
61
|
+
analyzer.methods["FirstTestClass"].should eq([["first_meth", 2, 3, 1, true, "#{test_file_path(4)}:2"]])
|
|
62
|
+
analyzer.methods["SecondTestClass"].should eq([["second_meth", 7, 8, 1, true, "#{test_file_path(4)}:7"]])
|
|
63
|
+
analyzer.misindented_methods.should be_empty
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
|
|
@@ -72,13 +72,13 @@ describe SandiMeter::Analyzer do
|
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
it 'finds classes' do
|
|
75
|
-
analyzer.
|
|
75
|
+
analyzer.misindented_classes.should eq([["OneLinerClass", 1, nil, "#{test_file_path(5)}:1"]])
|
|
76
76
|
analyzer.classes.should be_empty
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
it 'finds methods' do
|
|
80
80
|
analyzer.methods.should be_empty
|
|
81
|
-
analyzer.
|
|
81
|
+
analyzer.misindented_methods.should be_empty
|
|
82
82
|
end
|
|
83
83
|
end
|
|
84
84
|
|
|
@@ -90,16 +90,16 @@ describe SandiMeter::Analyzer do
|
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
it 'finds class and subclass' do
|
|
93
|
-
analyzer.classes.should include(["MyApp::Blah::User", 5, 13, true])
|
|
94
|
-
analyzer.classes.should include(["MyApp::Blah::User::SubUser", 9, 12, true])
|
|
95
|
-
analyzer.
|
|
93
|
+
analyzer.classes.should include(["MyApp::Blah::User", 5, 13, true, "#{test_file_path(7)}:5"])
|
|
94
|
+
analyzer.classes.should include(["MyApp::Blah::User::SubUser", 9, 12, true, "#{test_file_path(7)}:9"])
|
|
95
|
+
analyzer.misindented_classes.should be_empty
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
it 'finds methods' do
|
|
99
|
-
analyzer.methods["MyApp::Blah"].should eq([["module_meth", 2, 3, 0, true]])
|
|
100
|
-
analyzer.methods["MyApp::Blah::User"].should eq([["class_meth", 6, 7, 0, true]])
|
|
101
|
-
analyzer.methods["MyApp::Blah::User::SubUser"].should eq([["sub_meth", 10, 11, 0, true]])
|
|
102
|
-
analyzer.
|
|
99
|
+
analyzer.methods["MyApp::Blah"].should eq([["module_meth", 2, 3, 0, true, "#{test_file_path(7)}:2"]])
|
|
100
|
+
analyzer.methods["MyApp::Blah::User"].should eq([["class_meth", 6, 7, 0, true, "#{test_file_path(7)}:6"]])
|
|
101
|
+
analyzer.methods["MyApp::Blah::User::SubUser"].should eq([["sub_meth", 10, 11, 0, true, "#{test_file_path(7)}:10"]])
|
|
102
|
+
analyzer.misindented_methods.should be_empty
|
|
103
103
|
end
|
|
104
104
|
end
|
|
105
105
|
|
|
@@ -111,15 +111,15 @@ describe SandiMeter::Analyzer do
|
|
|
111
111
|
end
|
|
112
112
|
|
|
113
113
|
it 'finds class and subclass' do
|
|
114
|
-
analyzer.classes.should include(["RailsController", 1, 12, true])
|
|
115
|
-
analyzer.
|
|
114
|
+
analyzer.classes.should include(["RailsController", 1, 12, true, "#{test_file_path(8)}:1"])
|
|
115
|
+
analyzer.misindented_classes.should be_empty
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
it 'finds methods' do
|
|
119
|
-
analyzer.methods["RailsController"].should include(["index", 2, 3, 0, true])
|
|
120
|
-
analyzer.methods["RailsController"].should include(["destroy", 5, 6, 0, true])
|
|
121
|
-
analyzer.methods["RailsController"].should include(["private_meth", 9, 10, 0, true])
|
|
122
|
-
analyzer.
|
|
119
|
+
analyzer.methods["RailsController"].should include(["index", 2, 3, 0, true, "#{test_file_path(8)}:2"])
|
|
120
|
+
analyzer.methods["RailsController"].should include(["destroy", 5, 6, 0, true, "#{test_file_path(8)}:5"])
|
|
121
|
+
analyzer.methods["RailsController"].should include(["private_meth", 9, 10, 0, true, "#{test_file_path(8)}:9"])
|
|
122
|
+
analyzer.misindented_methods.should be_empty
|
|
123
123
|
end
|
|
124
124
|
end
|
|
125
125
|
|
|
@@ -136,6 +136,18 @@ describe SandiMeter::Analyzer do
|
|
|
136
136
|
end
|
|
137
137
|
end
|
|
138
138
|
|
|
139
|
+
context 'in controller class with non instance variables' do
|
|
140
|
+
let(:test_class) { test_file_path('14_controller') }
|
|
141
|
+
|
|
142
|
+
before do
|
|
143
|
+
analyzer.analyze(test_class)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it 'does not find instance variables' do
|
|
147
|
+
analyzer.instance_variables.should eq({"GuestController"=>{"create_guest_user"=>[]}})
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
139
151
|
context 'not in controller class' do
|
|
140
152
|
let(:test_class) { test_file_path(10) }
|
|
141
153
|
|
|
@@ -147,6 +159,32 @@ describe SandiMeter::Analyzer do
|
|
|
147
159
|
analyzer.instance_variables.should be_empty
|
|
148
160
|
end
|
|
149
161
|
end
|
|
162
|
+
|
|
163
|
+
context 'in controller class with private method' do
|
|
164
|
+
let(:test_class) { test_file_path("15_controller") }
|
|
165
|
+
|
|
166
|
+
before do
|
|
167
|
+
analyzer.analyze(test_class)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
it 'finds method defined after public keyword' do
|
|
171
|
+
analyzer.instance_variables["UsersController"].should have_key("create")
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it 'omits actions without instance variables' do
|
|
175
|
+
analyzer.instance_variables["UsersController"].should_not have_key("show")
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
it 'omits private methods' do
|
|
179
|
+
analyzer.instance_variables["UsersController"].should_not have_key("find_user")
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
it 'omits protected methods' do
|
|
183
|
+
analyzer.instance_variables["UsersController"].should_not have_key("protected_find_user")
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
end
|
|
150
188
|
end
|
|
151
189
|
|
|
152
190
|
describe 'hash method arguments' do
|
|
@@ -157,7 +195,7 @@ describe SandiMeter::Analyzer do
|
|
|
157
195
|
end
|
|
158
196
|
|
|
159
197
|
it 'counts arguments' do
|
|
160
|
-
analyzer.method_calls.should eq([[5, 3]])
|
|
198
|
+
analyzer.method_calls.should eq([[5, "#{test_file_path(11)}:3"]])
|
|
161
199
|
end
|
|
162
200
|
end
|
|
163
201
|
|
|
@@ -169,11 +207,11 @@ describe SandiMeter::Analyzer do
|
|
|
169
207
|
end
|
|
170
208
|
|
|
171
209
|
it 'are count for class definition' do
|
|
172
|
-
analyzer.classes.should eq([["Valera", 1, 109, false]])
|
|
210
|
+
analyzer.classes.should eq([["Valera", 1, 109, false, "#{test_file_path(12)}:1"]])
|
|
173
211
|
end
|
|
174
212
|
|
|
175
213
|
it 'are count for method definition' do
|
|
176
|
-
analyzer.methods.should eq({"Valera"=>[["doodle", 2, 9, 0, false]]})
|
|
214
|
+
analyzer.methods.should eq({"Valera"=>[["doodle", 2, 9, 0, false, "#{test_file_path(12)}:2"]]})
|
|
177
215
|
end
|
|
178
216
|
end
|
|
179
217
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class UsersController
|
|
2
|
+
before_filter :find_user
|
|
3
|
+
|
|
4
|
+
def show
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
private
|
|
8
|
+
def find_user
|
|
9
|
+
@user = User.find(params[:id])
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
protected
|
|
13
|
+
def protected_find_user
|
|
14
|
+
@user = User.find(params[:id])
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
public
|
|
18
|
+
def create
|
|
19
|
+
@user = User.new(params[:user])
|
|
20
|
+
end
|
|
21
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sandi_meter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Anatoli Makarevich
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2013-
|
|
11
|
+
date: 2013-10-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -64,7 +64,9 @@ files:
|
|
|
64
64
|
- README.md
|
|
65
65
|
- Rakefile
|
|
66
66
|
- sandi_meter.gemspec
|
|
67
|
+
- html/_detail_block.html
|
|
67
68
|
- html/chart.js
|
|
69
|
+
- html/forkme.png
|
|
68
70
|
- html/index.html
|
|
69
71
|
- html/jquery.js
|
|
70
72
|
- html/morris.css
|
|
@@ -88,9 +90,12 @@ files:
|
|
|
88
90
|
- spec/method_arguments_counter_spec.rb
|
|
89
91
|
- spec/test_classes/1.rb
|
|
90
92
|
- spec/test_classes/10.rb
|
|
93
|
+
- spec/test_classes/10_controller.rb
|
|
91
94
|
- spec/test_classes/11.rb
|
|
92
95
|
- spec/test_classes/12.rb
|
|
93
96
|
- spec/test_classes/13.rb
|
|
97
|
+
- spec/test_classes/14_controller.rb
|
|
98
|
+
- spec/test_classes/15_controller.rb
|
|
94
99
|
- spec/test_classes/2.rb
|
|
95
100
|
- spec/test_classes/3.rb
|
|
96
101
|
- spec/test_classes/4.rb
|