sandi_meter 1.1.8 → 1.2.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 +4 -4
- data/README.md +6 -2
- data/lib/sandi_meter/cli.rb +26 -12
- data/lib/sandi_meter/html_generator.rb +7 -7
- data/lib/sandi_meter/logger.rb +1 -1
- data/lib/sandi_meter/rules_checker.rb +8 -2
- data/lib/sandi_meter/version.rb +1 -1
- data/lib/sandi_meter/warning_scanner.rb +1 -1
- data/spec/analyzer_spec.rb +35 -35
- data/spec/calculator_spec.rb +4 -4
- data/spec/cli_spec.rb +76 -15
- data/spec/loc_checker_spec.rb +4 -4
- data/spec/method_arguments_counter_spec.rb +12 -12
- data/spec/rules_checker_spec.rb +2 -2
- data/spec/support/attr_matcher.rb +1 -1
- data/spec/support/terminate_matcher.rb +39 -0
- data/spec/test_helper.rb +19 -1
- data/spec/warning_scanner_spec.rb +3 -3
- metadata +20 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9a83923b441f198ed909f5cc7e0b3933b4b0b2ad
|
4
|
+
data.tar.gz: 5f0d9b05649988b2c7e2094ee81490212be49444
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7b35f03467396393d3ce937b5850c3cd1e6d1ac83becbc137feac43d7bb1b904e1fc21f3f195150b98dd7daa8c917406e30ad06bd7490bfc02a7fd71e51e69f5
|
7
|
+
data.tar.gz: 047facafdc3447ea5c37ed7e11260504fe6e7fb2e42f980b65e04f3a673d1bcaabc54328a9b33471cca1e4cabbbc14b7c5e095fccdd96da73cfcdbcfd6eced64
|
data/README.md
CHANGED
@@ -7,7 +7,7 @@ Static analysis tool for checking your Ruby code for [Sandi Metz' four rules](ht
|
|
7
7
|
* 100 lines per class
|
8
8
|
* 5 lines per method
|
9
9
|
* 4 params per method call (and don't even try cheating with hash params)
|
10
|
-
* 1 instance
|
10
|
+
* 1 instance variable per controller action
|
11
11
|
|
12
12
|
## CLI mode
|
13
13
|
|
@@ -19,8 +19,12 @@ sandi_meter --help
|
|
19
19
|
-g, --graph HTML mode. Create folder, log data and output stats to HTML file.
|
20
20
|
--json Output as JSON
|
21
21
|
-l, --log Show syntax error and indentation log output
|
22
|
-
-
|
22
|
+
-o, --output-path PATH Path for storing generated output files (default: ./sandi_meter/)
|
23
|
+
-p, --path PATH Path to folder or file to analyze
|
24
|
+
-q, --quiet Do not open HTML report for graph option in browser.
|
25
|
+
-t, --thresholds THRESHOLD Thresholds for each rule (default: "90,90,90,90" or in config.yml)
|
23
26
|
-r, --rules Show rules
|
27
|
+
-v, --version Gem version
|
24
28
|
-h, --help Help
|
25
29
|
|
26
30
|
cd ~/your/ruby/or/rails/project
|
data/lib/sandi_meter/cli.rb
CHANGED
@@ -21,6 +21,11 @@ module SandiMeter
|
|
21
21
|
description: "Path to folder or file to analyze",
|
22
22
|
default: "."
|
23
23
|
|
24
|
+
option :output_path,
|
25
|
+
short: "-o PATH",
|
26
|
+
long: "--output-path PATH",
|
27
|
+
description: "Path for storing generated output files (default: ./sandi_meter/)"
|
28
|
+
|
24
29
|
option :log,
|
25
30
|
short: "-l",
|
26
31
|
long: "--log",
|
@@ -70,6 +75,12 @@ module SandiMeter
|
|
70
75
|
long: "--json",
|
71
76
|
description: "Output as JSON",
|
72
77
|
boolean: false
|
78
|
+
|
79
|
+
option :rule_thresholds,
|
80
|
+
short: "-t THRESHOLD",
|
81
|
+
long: "--thresholds THRESHOLD",
|
82
|
+
description: "Thresholds for each rule (default: 90,90,90,90) or in config.yml",
|
83
|
+
default: "90,90,90,90"
|
73
84
|
end
|
74
85
|
|
75
86
|
class CLI
|
@@ -78,12 +89,15 @@ module SandiMeter
|
|
78
89
|
cli = CommandParser.new
|
79
90
|
cli.parse_options
|
80
91
|
|
92
|
+
cli.config[:output_path] ||= File.expand_path(File.join(cli.config[:path], 'sandi_meter'))
|
93
|
+
|
94
|
+
cli.config[:rule_thresholds] = cli.config[:rule_thresholds].split(",").map(&:to_i)
|
95
|
+
|
81
96
|
if cli.config[:graph]
|
82
|
-
|
83
|
-
FileUtils.mkdir(log_dir_path) unless Dir.exists?(log_dir_path)
|
97
|
+
FileUtils.mkdir_p(cli.config[:output_path]) unless Dir.exists?(cli.config[:output_path])
|
84
98
|
|
85
|
-
create_config_file(cli.config[:
|
86
|
-
create_config_file(cli.config[:
|
99
|
+
create_config_file(cli.config[:output_path], '.sandi_meter', %w(db vendor).join("\n"))
|
100
|
+
create_config_file(cli.config[:output_path], 'config.yml', YAML.dump({ thresholds: [90, 90, 90, 90] }))
|
87
101
|
end
|
88
102
|
|
89
103
|
if cli.config[:version]
|
@@ -108,16 +122,16 @@ module SandiMeter
|
|
108
122
|
formatter.print_data(data)
|
109
123
|
|
110
124
|
if cli.config[:graph]
|
111
|
-
if File.directory?(cli.config[:
|
125
|
+
if File.directory?(cli.config[:output_path])
|
112
126
|
logger = SandiMeter::Logger.new(data)
|
113
|
-
logger.log!(cli.config[:
|
127
|
+
logger.log!(cli.config[:output_path])
|
114
128
|
|
115
129
|
html_generator = SandiMeter::HtmlGenerator.new
|
116
|
-
html_generator.copy_assets!(cli.config[:
|
117
|
-
html_generator.generate_data!(cli.config[:
|
118
|
-
html_generator.generate_details!(cli.config[:
|
130
|
+
html_generator.copy_assets!(cli.config[:output_path])
|
131
|
+
html_generator.generate_data!(cli.config[:output_path])
|
132
|
+
html_generator.generate_details!(cli.config[:output_path], data)
|
119
133
|
|
120
|
-
index_html_path = File.join(cli.config[:
|
134
|
+
index_html_path = File.join(cli.config[:output_path], 'index.html')
|
121
135
|
unless cli.config[:quiet]
|
122
136
|
open_in_browser(index_html_path)
|
123
137
|
end
|
@@ -126,11 +140,11 @@ module SandiMeter
|
|
126
140
|
end
|
127
141
|
end
|
128
142
|
|
129
|
-
config_file_path = File.join(cli.config[:
|
143
|
+
config_file_path = File.join(cli.config[:output_path], 'config.yml')
|
130
144
|
config = if File.exists?(config_file_path)
|
131
145
|
YAML.load(File.read(config_file_path))
|
132
146
|
else
|
133
|
-
{
|
147
|
+
{ thresholds: cli.config[:rule_thresholds] }
|
134
148
|
end
|
135
149
|
|
136
150
|
if RulesChecker.new(data, config).ok?
|
@@ -4,19 +4,19 @@ require 'json'
|
|
4
4
|
module SandiMeter
|
5
5
|
class HtmlGenerator
|
6
6
|
def copy_assets!(path)
|
7
|
-
asset_dir_path = File.join(path, '
|
7
|
+
asset_dir_path = File.join(path, 'assets')
|
8
8
|
FileUtils.mkdir(asset_dir_path) unless Dir.exists?(asset_dir_path)
|
9
|
+
html_dir = File.expand_path('../../html', File.dirname(__FILE__))
|
9
10
|
|
10
|
-
|
11
|
-
Dir[File.join(File.dirname(__FILE__), "../../html/*.{js,css,png}")].each do |file|
|
11
|
+
Dir[File.join(html_dir, "*.{js,css,png}")].each do |file|
|
12
12
|
FileUtils.cp file, File.join(asset_dir_path, File.basename(file))
|
13
13
|
end
|
14
14
|
|
15
|
-
FileUtils.cp File.join(
|
15
|
+
FileUtils.cp File.join(html_dir, 'index.html'), File.join(path, 'index.html')
|
16
16
|
end
|
17
17
|
|
18
18
|
def generate_data!(path)
|
19
|
-
raw_data = File.read(File.join(path, 'sandi_meter
|
19
|
+
raw_data = File.read(File.join(path, 'sandi_meter.log')).split("\n")
|
20
20
|
raw_data.map! { |row| row.split(';').map(&:to_i) }
|
21
21
|
|
22
22
|
data = []
|
@@ -31,7 +31,7 @@ module SandiMeter
|
|
31
31
|
data << hash
|
32
32
|
end
|
33
33
|
|
34
|
-
index_file = File.join(path, '
|
34
|
+
index_file = File.join(path, 'index.html')
|
35
35
|
index = File.read(index_file)
|
36
36
|
index.gsub!('<% plot_data %>', data.to_json)
|
37
37
|
|
@@ -91,7 +91,7 @@ module SandiMeter
|
|
91
91
|
)
|
92
92
|
end
|
93
93
|
|
94
|
-
index_file = File.join(path, '
|
94
|
+
index_file = File.join(path, 'index.html')
|
95
95
|
index = File.read(index_file)
|
96
96
|
index.gsub!('<% details %>', details)
|
97
97
|
|
data/lib/sandi_meter/logger.rb
CHANGED
@@ -10,12 +10,18 @@ module SandiMeter
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def ok?
|
13
|
-
|
13
|
+
if @config[:threshold]
|
14
|
+
puts "DEPRECATION WARNING: sandi_meter threshold will be deprecated. Set thresholds for each rule in sandi_meter config.yml"
|
15
|
+
|
16
|
+
@rules.reduce(:+) / 4 > @config[:threshold]
|
17
|
+
elsif @config[:thresholds]
|
18
|
+
@rules.each_with_index.map { |percentage, index| percentage >= @config[:thresholds][index].to_f }.reduce(:&)
|
19
|
+
end
|
14
20
|
end
|
15
21
|
|
16
22
|
private
|
17
23
|
def percentage(amount, total)
|
18
|
-
total > 0 ? (amount / total.to_f)*100 : 100
|
24
|
+
total > 0 ? (amount / total.to_f) * 100 : 100
|
19
25
|
end
|
20
26
|
end
|
21
27
|
end
|
data/lib/sandi_meter/version.rb
CHANGED
data/spec/analyzer_spec.rb
CHANGED
@@ -14,7 +14,7 @@ describe SandiMeter::Analyzer do
|
|
14
14
|
it 'finds indentation warnings for method' do
|
15
15
|
klass = analyzer.classes.find { |c| c.name == "TestClass" }
|
16
16
|
|
17
|
-
klass.
|
17
|
+
expect(klass).to have_attributes(
|
18
18
|
first_line: 1,
|
19
19
|
last_line: 5,
|
20
20
|
path: test_file_path(3)
|
@@ -24,7 +24,7 @@ describe SandiMeter::Analyzer do
|
|
24
24
|
it 'finds methods' do
|
25
25
|
method = analyzer.methods["TestClass"].find { |m| m.name == "blah" }
|
26
26
|
|
27
|
-
method.
|
27
|
+
expect(method).to have_attributes(
|
28
28
|
first_line: 2,
|
29
29
|
last_line: 4,
|
30
30
|
number_of_arguments: 0,
|
@@ -35,7 +35,7 @@ describe SandiMeter::Analyzer do
|
|
35
35
|
it 'finds method calls that brakes third rule' do
|
36
36
|
method_call = analyzer.method_calls.first
|
37
37
|
|
38
|
-
method_call.
|
38
|
+
expect(method_call).to have_attributes(
|
39
39
|
first_line: 3,
|
40
40
|
number_of_arguments: 5,
|
41
41
|
path: test_file_path(3)
|
@@ -53,7 +53,7 @@ describe SandiMeter::Analyzer do
|
|
53
53
|
it 'finds indentation warnings for method' do
|
54
54
|
klass = analyzer.classes.find { |c| c.name == "MyApp::TestClass" }
|
55
55
|
|
56
|
-
klass.
|
56
|
+
expect(klass).to have_attributes(
|
57
57
|
first_line: 2,
|
58
58
|
last_line: nil,
|
59
59
|
path: test_file_path(1)
|
@@ -63,7 +63,7 @@ describe SandiMeter::Analyzer do
|
|
63
63
|
it 'finds methods' do
|
64
64
|
method = analyzer.methods["MyApp::TestClass"].find { |m| m.name == "blah" }
|
65
65
|
|
66
|
-
method.
|
66
|
+
expect(method).to have_attributes(
|
67
67
|
first_line: 3,
|
68
68
|
last_line: nil,
|
69
69
|
number_of_arguments: 0,
|
@@ -82,7 +82,7 @@ describe SandiMeter::Analyzer do
|
|
82
82
|
it 'finds classes' do
|
83
83
|
klass = analyzer.classes.find { |c| c.name == "FirstTestClass" }
|
84
84
|
|
85
|
-
klass.
|
85
|
+
expect(klass).to have_attributes(
|
86
86
|
first_line: 1,
|
87
87
|
last_line: 4,
|
88
88
|
path: test_file_path(4)
|
@@ -90,7 +90,7 @@ describe SandiMeter::Analyzer do
|
|
90
90
|
|
91
91
|
klass = analyzer.classes.find { |c| c.name == "SecondTestClass" }
|
92
92
|
|
93
|
-
klass.
|
93
|
+
expect(klass).to have_attributes(
|
94
94
|
first_line: 6,
|
95
95
|
last_line: 9,
|
96
96
|
path: test_file_path(4)
|
@@ -100,7 +100,7 @@ describe SandiMeter::Analyzer do
|
|
100
100
|
it 'finds methods' do
|
101
101
|
method = analyzer.methods["FirstTestClass"].find { |m| m.name == "first_meth" }
|
102
102
|
|
103
|
-
method.
|
103
|
+
expect(method).to have_attributes(
|
104
104
|
first_line: 2,
|
105
105
|
last_line: 3,
|
106
106
|
number_of_arguments: 1,
|
@@ -109,7 +109,7 @@ describe SandiMeter::Analyzer do
|
|
109
109
|
|
110
110
|
method = analyzer.methods["SecondTestClass"].find { |m| m.name == "second_meth" }
|
111
111
|
|
112
|
-
method.
|
112
|
+
expect(method).to have_attributes(
|
113
113
|
first_line: 7,
|
114
114
|
last_line: 8,
|
115
115
|
number_of_arguments: 1,
|
@@ -128,7 +128,7 @@ describe SandiMeter::Analyzer do
|
|
128
128
|
it 'finds classes' do
|
129
129
|
klass = analyzer.classes.find { |c| c.name == "OneLinerClass" }
|
130
130
|
|
131
|
-
klass.
|
131
|
+
expect(klass).to have_attributes(
|
132
132
|
first_line: 1,
|
133
133
|
last_line: nil,
|
134
134
|
path: test_file_path(5)
|
@@ -136,7 +136,7 @@ describe SandiMeter::Analyzer do
|
|
136
136
|
end
|
137
137
|
|
138
138
|
it 'finds methods' do
|
139
|
-
analyzer.methods.
|
139
|
+
expect(analyzer.methods).to be_empty
|
140
140
|
end
|
141
141
|
end
|
142
142
|
|
@@ -149,14 +149,14 @@ describe SandiMeter::Analyzer do
|
|
149
149
|
|
150
150
|
it 'finds class and subclass' do
|
151
151
|
klass = analyzer.classes.find { |c| c.name == "MyApp::Blah::User" }
|
152
|
-
klass.
|
152
|
+
expect(klass).to have_attributes(
|
153
153
|
first_line: 5,
|
154
154
|
last_line: 13,
|
155
155
|
path: test_file_path(7)
|
156
156
|
)
|
157
157
|
|
158
158
|
klass = analyzer.classes.find { |c| c.name == "MyApp::Blah::User::SubUser" }
|
159
|
-
klass.
|
159
|
+
expect(klass).to have_attributes(
|
160
160
|
first_line: 9,
|
161
161
|
last_line: 12,
|
162
162
|
path: test_file_path(7)
|
@@ -165,7 +165,7 @@ describe SandiMeter::Analyzer do
|
|
165
165
|
|
166
166
|
it 'finds methods' do
|
167
167
|
method = analyzer.methods["MyApp::Blah"].find { |m| m.name == "module_meth" }
|
168
|
-
method.
|
168
|
+
expect(method).to have_attributes(
|
169
169
|
first_line: 2,
|
170
170
|
last_line: 3,
|
171
171
|
number_of_arguments: 0,
|
@@ -173,7 +173,7 @@ describe SandiMeter::Analyzer do
|
|
173
173
|
)
|
174
174
|
|
175
175
|
method = analyzer.methods["MyApp::Blah::User"].find { |m| m.name == "class_meth" }
|
176
|
-
method.
|
176
|
+
expect(method).to have_attributes(
|
177
177
|
first_line: 6,
|
178
178
|
last_line: 7,
|
179
179
|
number_of_arguments: 0,
|
@@ -181,7 +181,7 @@ describe SandiMeter::Analyzer do
|
|
181
181
|
)
|
182
182
|
|
183
183
|
method = analyzer.methods["MyApp::Blah::User::SubUser"].find { |m| m.name == "sub_meth" }
|
184
|
-
method.
|
184
|
+
expect(method).to have_attributes(
|
185
185
|
first_line: 10,
|
186
186
|
last_line: 11,
|
187
187
|
number_of_arguments: 0,
|
@@ -199,7 +199,7 @@ describe SandiMeter::Analyzer do
|
|
199
199
|
|
200
200
|
it 'finds class and subclass' do
|
201
201
|
klass = analyzer.classes.find { |c| c.name == "RailsController" }
|
202
|
-
klass.
|
202
|
+
expect(klass).to have_attributes(
|
203
203
|
first_line: 1,
|
204
204
|
last_line: 12,
|
205
205
|
path: test_file_path(8)
|
@@ -208,7 +208,7 @@ describe SandiMeter::Analyzer do
|
|
208
208
|
|
209
209
|
it 'finds methods' do
|
210
210
|
method = analyzer.methods["RailsController"].find { |m| m.name == "index" }
|
211
|
-
method.
|
211
|
+
expect(method).to have_attributes(
|
212
212
|
first_line: 2,
|
213
213
|
last_line: 3,
|
214
214
|
number_of_arguments: 0,
|
@@ -216,7 +216,7 @@ describe SandiMeter::Analyzer do
|
|
216
216
|
)
|
217
217
|
|
218
218
|
method = analyzer.methods["RailsController"].find { |m| m.name == "destroy" }
|
219
|
-
method.
|
219
|
+
expect(method).to have_attributes(
|
220
220
|
first_line: 5,
|
221
221
|
last_line: 6,
|
222
222
|
number_of_arguments: 0,
|
@@ -224,7 +224,7 @@ describe SandiMeter::Analyzer do
|
|
224
224
|
)
|
225
225
|
|
226
226
|
method = analyzer.methods["RailsController"].find { |m| m.name == "private_meth" }
|
227
|
-
method.
|
227
|
+
expect(method).to be_nil
|
228
228
|
end
|
229
229
|
end
|
230
230
|
|
@@ -238,7 +238,7 @@ describe SandiMeter::Analyzer do
|
|
238
238
|
|
239
239
|
it 'finds instance variable' do
|
240
240
|
method = analyzer.methods["UsersController"].find { |m| m.name == "index" }
|
241
|
-
method.ivars.
|
241
|
+
expect(method.ivars).to eq(["@users"])
|
242
242
|
end
|
243
243
|
end
|
244
244
|
|
@@ -251,7 +251,7 @@ describe SandiMeter::Analyzer do
|
|
251
251
|
|
252
252
|
it 'does not find instance variables' do
|
253
253
|
method = analyzer.methods["GuestController"].find { |m| m.name == "create_guest_user" }
|
254
|
-
method.ivars.
|
254
|
+
expect(method.ivars).to be_empty
|
255
255
|
end
|
256
256
|
end
|
257
257
|
|
@@ -264,10 +264,10 @@ describe SandiMeter::Analyzer do
|
|
264
264
|
|
265
265
|
it 'does not find instance variable' do
|
266
266
|
method = analyzer.methods["User"].find { |m| m.name == "initialize" }
|
267
|
-
method.ivars.
|
267
|
+
expect(method.ivars).to be_empty
|
268
268
|
|
269
269
|
method = analyzer.methods["User"].find { |m| m.name == "hi" }
|
270
|
-
method.ivars.
|
270
|
+
expect(method.ivars).to be_empty
|
271
271
|
end
|
272
272
|
end
|
273
273
|
|
@@ -280,22 +280,22 @@ describe SandiMeter::Analyzer do
|
|
280
280
|
|
281
281
|
it 'finds method defined after public keyword' do
|
282
282
|
method = analyzer.methods["UsersController"].find { |m| m.name == "create" }
|
283
|
-
method.ivars.
|
283
|
+
expect(method.ivars).to eq(["@user"])
|
284
284
|
end
|
285
285
|
|
286
286
|
it 'omits actions without instance variables' do
|
287
287
|
method = analyzer.methods["UsersController"].find { |m| m.name == "show" }
|
288
|
-
method.ivars.
|
288
|
+
expect(method.ivars).to be_empty
|
289
289
|
end
|
290
290
|
|
291
291
|
it 'omits private methods' do
|
292
292
|
method = analyzer.methods["UsersController"].find { |m| m.name == "find_user" }
|
293
|
-
method.
|
293
|
+
expect(method).to be_nil
|
294
294
|
end
|
295
295
|
|
296
296
|
it 'omits protected methods' do
|
297
297
|
method = analyzer.methods["UsersController"].find { |m| m.name == "protected_find_user" }
|
298
|
-
method.
|
298
|
+
expect(method).to be_nil
|
299
299
|
end
|
300
300
|
end
|
301
301
|
end
|
@@ -310,7 +310,7 @@ describe SandiMeter::Analyzer do
|
|
310
310
|
it 'counts arguments' do
|
311
311
|
method_call = analyzer.method_calls.first
|
312
312
|
|
313
|
-
method_call.
|
313
|
+
expect(method_call).to have_attributes(
|
314
314
|
first_line: 3,
|
315
315
|
number_of_arguments: 5,
|
316
316
|
path: test_file_path(11)
|
@@ -328,7 +328,7 @@ describe SandiMeter::Analyzer do
|
|
328
328
|
it 'are count for class definition' do
|
329
329
|
klass = analyzer.classes.find { |c| c.name == "Valera" }
|
330
330
|
|
331
|
-
klass.
|
331
|
+
expect(klass).to have_attributes(
|
332
332
|
first_line: 1,
|
333
333
|
last_line: 109,
|
334
334
|
path: test_file_path(12)
|
@@ -338,7 +338,7 @@ describe SandiMeter::Analyzer do
|
|
338
338
|
it 'are count for method definition' do
|
339
339
|
method = analyzer.methods["Valera"].find { |m| m.name == "doodle" }
|
340
340
|
|
341
|
-
method.
|
341
|
+
expect(method).to have_attributes(
|
342
342
|
first_line: 2,
|
343
343
|
last_line: 9,
|
344
344
|
number_of_arguments: 0,
|
@@ -355,7 +355,7 @@ describe SandiMeter::Analyzer do
|
|
355
355
|
end
|
356
356
|
|
357
357
|
it 'is not scanned' do
|
358
|
-
analyzer.method_calls.
|
358
|
+
expect(analyzer.method_calls).to be_empty
|
359
359
|
end
|
360
360
|
end
|
361
361
|
|
@@ -370,7 +370,7 @@ describe SandiMeter::Analyzer do
|
|
370
370
|
it 'mark 4line methods good' do
|
371
371
|
method = analyzer.methods["TestClass"].find { |m| m.name == "render4" }
|
372
372
|
|
373
|
-
method.
|
373
|
+
expect(method).to have_attributes(
|
374
374
|
first_line: 2,
|
375
375
|
last_line: 7,
|
376
376
|
number_of_arguments: 0,
|
@@ -381,7 +381,7 @@ describe SandiMeter::Analyzer do
|
|
381
381
|
it 'mark 5line methods good' do
|
382
382
|
method = analyzer.methods["TestClass"].find { |m| m.name == "render5" }
|
383
383
|
|
384
|
-
method.
|
384
|
+
expect(method).to have_attributes(
|
385
385
|
first_line: 9,
|
386
386
|
last_line: 15,
|
387
387
|
number_of_arguments: 0,
|
@@ -392,7 +392,7 @@ describe SandiMeter::Analyzer do
|
|
392
392
|
it 'mark 6line methods bad' do
|
393
393
|
method = analyzer.methods["TestClass"].find { |m| m.name == "render6" }
|
394
394
|
|
395
|
-
method.
|
395
|
+
expect(method).to have_attributes(
|
396
396
|
first_line: 17,
|
397
397
|
last_line: 24,
|
398
398
|
number_of_arguments: 0,
|
data/spec/calculator_spec.rb
CHANGED
@@ -17,13 +17,13 @@ describe SandiMeter::Calculator do
|
|
17
17
|
it 'counts class lines' do
|
18
18
|
output = calculator.calculate!(true)
|
19
19
|
klass = output[:first_rule][:log][:classes].find { |params| params.first == "User" }
|
20
|
-
klass[1].
|
20
|
+
expect(klass[1]).to eq(109)
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'counts method lines' do
|
24
24
|
output = calculator.calculate!(true)
|
25
25
|
method_params = output[:second_rule][:log][:methods].find { |method| method[1] == "create" }
|
26
|
-
method_params[2].
|
26
|
+
expect(method_params[2]).to eq(6)
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
@@ -69,12 +69,12 @@ describe SandiMeter::Calculator do
|
|
69
69
|
describe 'no matching ruby files found' do
|
70
70
|
it 'counts class lines' do
|
71
71
|
output = calculator.calculate!(false)
|
72
|
-
output[:first_rule][:total_classes_amount].
|
72
|
+
expect(output[:first_rule][:total_classes_amount]).to eql(0)
|
73
73
|
end
|
74
74
|
|
75
75
|
it 'counts method lines' do
|
76
76
|
output = calculator.calculate!(true)
|
77
|
-
output[:second_rule][:total_methods_amount].
|
77
|
+
expect(output[:second_rule][:total_methods_amount]).to eq(0)
|
78
78
|
end
|
79
79
|
end
|
80
80
|
end
|
data/spec/cli_spec.rb
CHANGED
@@ -2,25 +2,37 @@ require 'test_helper'
|
|
2
2
|
require_relative '../lib/sandi_meter/cli'
|
3
3
|
|
4
4
|
describe SandiMeter::CLI do
|
5
|
+
include FakeFS::SpecHelpers
|
6
|
+
|
5
7
|
let(:cli) { SandiMeter::CLI }
|
6
|
-
|
7
|
-
|
8
|
-
|
8
|
+
let(:gem_root) { File.expand_path('../', File.dirname(__FILE__)) }
|
9
|
+
|
10
|
+
before do
|
11
|
+
FakeFS.activate!
|
12
|
+
|
13
|
+
FakeFS::FileSystem.clone(gem_root)
|
14
|
+
end
|
15
|
+
|
16
|
+
after do
|
17
|
+
FakeFS.deactivate!
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#execute', silent_cli: true do
|
21
|
+
before do
|
9
22
|
@original_argv = ARGV
|
10
23
|
ARGV.clear
|
11
24
|
end
|
12
|
-
|
13
|
-
after do
|
25
|
+
|
26
|
+
after do
|
14
27
|
ARGV.clear
|
15
28
|
ARGV.concat(@original_argv)
|
16
29
|
end
|
17
|
-
|
30
|
+
|
18
31
|
context 'with the graph flag passed in' do
|
19
32
|
before { ARGV.push('-g') }
|
20
|
-
|
21
|
-
|
33
|
+
|
22
34
|
it 'opens the graph in a web browser' do
|
23
|
-
cli.
|
35
|
+
expect(cli).to receive(:open_in_browser)
|
24
36
|
expect { cli.execute }.to raise_error(SystemExit)
|
25
37
|
end
|
26
38
|
end
|
@@ -30,15 +42,64 @@ describe SandiMeter::CLI do
|
|
30
42
|
ARGV.push('-q')
|
31
43
|
ARGV.push('-g')
|
32
44
|
end
|
33
|
-
|
34
|
-
ARGV.pop
|
35
|
-
ARGV.pop
|
36
|
-
end
|
37
|
-
|
45
|
+
|
38
46
|
it 'does not open the browser' do
|
39
|
-
cli.
|
47
|
+
expect(cli).to_not receive(:open_in_browser)
|
40
48
|
expect { cli.execute }.to raise_error(SystemExit)
|
41
49
|
end
|
42
50
|
end
|
51
|
+
|
52
|
+
context 'output path passed in' do
|
53
|
+
let(:test_path) { '/test_out_dir/test2' }
|
54
|
+
before do
|
55
|
+
ARGV.push('-q')
|
56
|
+
ARGV.push('-g')
|
57
|
+
ARGV.push('-o')
|
58
|
+
ARGV.push(test_path)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'saves output files to specified output path' do
|
62
|
+
expect { cli.execute }.to raise_error(SystemExit)
|
63
|
+
expect(File.directory?(test_path)).to eq(true)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'output path not specified' do
|
68
|
+
before do
|
69
|
+
ARGV.push('-q')
|
70
|
+
ARGV.push('-g')
|
71
|
+
ARGV.push('-p')
|
72
|
+
ARGV.push('/')
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'saves output files in sandi_meter folder relative to scanned path' do
|
76
|
+
expect { cli.execute }.to raise_error(SystemExit)
|
77
|
+
expect(File.directory?(File.expand_path('/sandi_meter'))).to eq(true)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'makes account for rules thresholds' do
|
82
|
+
context 'for low thresholds' do
|
83
|
+
before do
|
84
|
+
ARGV.push('-t')
|
85
|
+
ARGV.push("1,1,1,1")
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'terminates with 0 code' do
|
89
|
+
expect { cli.execute }.to terminate.with_code(0)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'for high thresholds' do
|
94
|
+
before do
|
95
|
+
ARGV.push('-t')
|
96
|
+
ARGV.push("99,99,99,99")
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'terminates with 1 code' do
|
100
|
+
expect { cli.execute }.to terminate.with_code(1)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
43
104
|
end
|
44
105
|
end
|
data/spec/loc_checker_spec.rb
CHANGED
@@ -8,24 +8,24 @@ describe SandiMeter::LOCChecker do
|
|
8
8
|
context 'for short code' do
|
9
9
|
before do
|
10
10
|
stub_const('SandiMeter::LOCChecker::MAX_LOC', { 'blah' => 10 })
|
11
|
-
checker.
|
11
|
+
allow(checker).to receive(:locs_size).and_return(rand(0..10))
|
12
12
|
end
|
13
13
|
|
14
14
|
# REFACTOR
|
15
15
|
# avoid passing dumb arguments to tested methods
|
16
16
|
it 'passes the check' do
|
17
|
-
checker.check([1,2,3], 'blah').
|
17
|
+
expect(checker.check([1,2,3], 'blah')).to eq true
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
context 'for large code' do
|
22
22
|
before do
|
23
23
|
stub_const('SandiMeter::LOCChecker::MAX_LOC', { 'blah' => 10 })
|
24
|
-
checker.
|
24
|
+
allow(checker).to receive(:locs_size).and_return(rand(11..100))
|
25
25
|
end
|
26
26
|
|
27
27
|
it 'does not pass the check' do
|
28
|
-
checker.check([1,2,3], 'blah').
|
28
|
+
expect(checker.check([1,2,3], 'blah')).to eq false
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -10,8 +10,8 @@ describe SandiMeter::MethodArgumentsCounter do
|
|
10
10
|
let(:args_add_block_2) { load_args_block('blah(arg1, arg2)')}
|
11
11
|
|
12
12
|
it 'counts arguments' do
|
13
|
-
analyzer.count(args_add_block_1).
|
14
|
-
analyzer.count(args_add_block_2).
|
13
|
+
expect(analyzer.count(args_add_block_1)).to eq([2, 1])
|
14
|
+
expect(analyzer.count(args_add_block_2)).to eq([2, 1])
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -23,10 +23,10 @@ describe SandiMeter::MethodArgumentsCounter do
|
|
23
23
|
let(:args_add_block_4) { load_args_block('blah(k1: :v1, k2: :v2)') }
|
24
24
|
|
25
25
|
it 'counts arguments' do
|
26
|
-
analyzer.count(args_add_block_1).
|
27
|
-
analyzer.count(args_add_block_2).
|
28
|
-
analyzer.count(args_add_block_3).
|
29
|
-
analyzer.count(args_add_block_4).
|
26
|
+
expect(analyzer.count(args_add_block_1)).to eq([1, 1])
|
27
|
+
expect(analyzer.count(args_add_block_2)).to eq([1, 1])
|
28
|
+
expect(analyzer.count(args_add_block_3)).to eq([2, 1])
|
29
|
+
expect(analyzer.count(args_add_block_4)).to eq([2, 1])
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
@@ -37,13 +37,13 @@ describe SandiMeter::MethodArgumentsCounter do
|
|
37
37
|
let(:code_4) { load_args_block('blah(arg_1, arg_2, k1: :v1, k2: :v2)') }
|
38
38
|
|
39
39
|
it 'counts arguments' do
|
40
|
-
analyzer.count(code_1).
|
41
|
-
analyzer.count(code_2).
|
40
|
+
expect(analyzer.count(code_1)).to eq([3, 1])
|
41
|
+
expect(analyzer.count(code_2)).to eq([3, 1])
|
42
42
|
end
|
43
43
|
|
44
44
|
it 'counts hash keys as argumets' do
|
45
|
-
analyzer.count(code_3).
|
46
|
-
analyzer.count(code_4).
|
45
|
+
expect(analyzer.count(code_3)).to eq([4, 1])
|
46
|
+
expect(analyzer.count(code_4)).to eq([4, 1])
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
@@ -52,8 +52,8 @@ describe SandiMeter::MethodArgumentsCounter do
|
|
52
52
|
let(:code_2) { load_args_block('blah(arg_1 = "blah")') }
|
53
53
|
|
54
54
|
it 'counts arguments' do
|
55
|
-
analyzer.count(code_1).
|
56
|
-
analyzer.count(code_2).
|
55
|
+
expect(analyzer.count(code_1)).to eq([1, 1])
|
56
|
+
expect(analyzer.count(code_2)).to eq([1, 1])
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
data/spec/rules_checker_spec.rb
CHANGED
@@ -13,11 +13,11 @@ describe SandiMeter::RulesChecker do
|
|
13
13
|
|
14
14
|
describe "#ok?" do
|
15
15
|
it "returns false with 100 threshold" do
|
16
|
-
expect(SandiMeter::RulesChecker.new(conditions, {
|
16
|
+
expect(SandiMeter::RulesChecker.new(conditions, {thresholds: [100, 100, 100, 100]})).to_not be_ok
|
17
17
|
end
|
18
18
|
|
19
19
|
it "returns true with threshold less than 100" do
|
20
|
-
expect(SandiMeter::RulesChecker.new(conditions, {
|
20
|
+
expect(SandiMeter::RulesChecker.new(conditions, {thresholds: [50, 100, 100, 100]})).to be_ok
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
#https://gist.github.com/mmasashi/58bd7e2668836a387856
|
2
|
+
|
3
|
+
RSpec::Matchers.define :terminate do |code|
|
4
|
+
actual = nil
|
5
|
+
|
6
|
+
def supports_block_expectations?
|
7
|
+
true
|
8
|
+
end
|
9
|
+
|
10
|
+
match do |block|
|
11
|
+
begin
|
12
|
+
block.call
|
13
|
+
rescue SystemExit => e
|
14
|
+
actual = e.status
|
15
|
+
end
|
16
|
+
actual and actual == status_code
|
17
|
+
end
|
18
|
+
|
19
|
+
chain :with_code do |status_code|
|
20
|
+
@status_code = status_code
|
21
|
+
end
|
22
|
+
|
23
|
+
failure_message do |block|
|
24
|
+
"expected block to call exit(#{status_code}) but exit" +
|
25
|
+
(actual.nil? ? " not called" : "(#{actual}) was called")
|
26
|
+
end
|
27
|
+
|
28
|
+
failure_message_when_negated do |block|
|
29
|
+
"expected block not to call exit(#{status_code})"
|
30
|
+
end
|
31
|
+
|
32
|
+
description do
|
33
|
+
"expect block to call exit(#{status_code})"
|
34
|
+
end
|
35
|
+
|
36
|
+
def status_code
|
37
|
+
@status_code ||= 0
|
38
|
+
end
|
39
|
+
end
|
data/spec/test_helper.rb
CHANGED
@@ -1,4 +1,22 @@
|
|
1
|
-
require '
|
1
|
+
require 'pry'
|
2
2
|
require 'ripper'
|
3
|
+
require 'fakefs/spec_helpers'
|
4
|
+
|
5
|
+
# silence CLI output
|
6
|
+
RSpec.configure do |config|
|
7
|
+
original_stderr = $stderr
|
8
|
+
original_stdout = $stdout
|
9
|
+
|
10
|
+
config.before silent_cli: true do
|
11
|
+
# Redirect stderr and stdout
|
12
|
+
$stderr = File.open(File::NULL, "w")
|
13
|
+
$stdout = File.open(File::NULL, "w")
|
14
|
+
end
|
15
|
+
|
16
|
+
config.after silent_cli: true do
|
17
|
+
$stderr = original_stderr
|
18
|
+
$stdout = original_stdout
|
19
|
+
end
|
20
|
+
end
|
3
21
|
|
4
22
|
Dir["#{Dir.pwd}/spec/support/**/*.rb"].each { |f| require f }
|
@@ -12,15 +12,15 @@ describe SandiMeter::WarningScanner do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'finds indentation warnings for method' do
|
15
|
-
scanner.indentation_warnings['def'].
|
15
|
+
expect(scanner.indentation_warnings['def']).to eq([[3, 4]])
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'finds indentation warnings for class' do
|
19
|
-
scanner.indentation_warnings['class'].
|
19
|
+
expect(scanner.indentation_warnings['class']).to eq([[2, 5]])
|
20
20
|
end
|
21
21
|
|
22
22
|
it 'finds indentation warnings for module' do
|
23
|
-
scanner.indentation_warnings['module'].
|
23
|
+
expect(scanner.indentation_warnings['module']).to eq([[1, 6]])
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
metadata
CHANGED
@@ -1,97 +1,97 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sandi_meter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.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:
|
11
|
+
date: 2015-05-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.3'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '2.13'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '2.13'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: mixlib-cli
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: json
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0'
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: launchy
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- -
|
87
|
+
- - ">="
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '0'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- -
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
description: Sandi Metz rules checker
|
@@ -105,7 +105,7 @@ files:
|
|
105
105
|
- LICENSE
|
106
106
|
- README.md
|
107
107
|
- Rakefile
|
108
|
-
- sandi_meter
|
108
|
+
- bin/sandi_meter
|
109
109
|
- html/_detail_block.html
|
110
110
|
- html/chart.js
|
111
111
|
- html/forkme.png
|
@@ -131,7 +131,7 @@ files:
|
|
131
131
|
- lib/sandi_meter/sandi_meter/method_call.rb
|
132
132
|
- lib/sandi_meter/version.rb
|
133
133
|
- lib/sandi_meter/warning_scanner.rb
|
134
|
-
-
|
134
|
+
- sandi_meter.gemspec
|
135
135
|
- spec/analyzer_spec.rb
|
136
136
|
- spec/calculator_spec.rb
|
137
137
|
- spec/cli_spec.rb
|
@@ -141,6 +141,7 @@ files:
|
|
141
141
|
- spec/support/args_loader.rb
|
142
142
|
- spec/support/attr_matcher.rb
|
143
143
|
- spec/support/helper_methods.rb
|
144
|
+
- spec/support/terminate_matcher.rb
|
144
145
|
- spec/test_classes/1.rb
|
145
146
|
- spec/test_classes/10.rb
|
146
147
|
- spec/test_classes/10_controller.rb
|
@@ -171,17 +172,17 @@ require_paths:
|
|
171
172
|
- lib
|
172
173
|
required_ruby_version: !ruby/object:Gem::Requirement
|
173
174
|
requirements:
|
174
|
-
- -
|
175
|
+
- - ">="
|
175
176
|
- !ruby/object:Gem::Version
|
176
177
|
version: 1.9.0
|
177
178
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
178
179
|
requirements:
|
179
|
-
- -
|
180
|
+
- - ">="
|
180
181
|
- !ruby/object:Gem::Version
|
181
182
|
version: '0'
|
182
183
|
requirements: []
|
183
184
|
rubyforge_project:
|
184
|
-
rubygems_version: 2.
|
185
|
+
rubygems_version: 2.4.5
|
185
186
|
signing_key:
|
186
187
|
specification_version: 4
|
187
188
|
summary: Sandi Metz rules checker
|