sandi_meter 0.0.6 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
![SandiMeter HTML mode](http://
|
68
|
+
![SandiMeter HTML mode pie charts](http://imageshack.us/a/img823/7653/hns3.png)
|
69
|
+
![SandiMeter HTML mode details](http://imageshack.us/a/img820/8711/bygo.png)
|
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
|