quality 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3b529fe70947f211e50846ac7eeca8401e7af353
4
- data.tar.gz: ae51331dff7e90e9c860631bde9a3001bbcb4be6
3
+ metadata.gz: b5685a2d62cde5dfe205d5a86d1291a6c194bfd5
4
+ data.tar.gz: ee00ee02ea7878fa1c292b1143b39c1ae4328cd1
5
5
  SHA512:
6
- metadata.gz: 96c466f3f82770eb6b591d0f0ab348f616f2656a74ea1abe06ab844c1d44f90be5fc58d4542792dc24d03d255f64a6d0a9177b6061e72eced6b04ff04c300a41
7
- data.tar.gz: c27d3c90ec6234412cfaa4583b057d11c19db6d0e7d25bdc9ed585241d445ebb827d6e732ead3fdfdea38c30c445c9aaa58a616f8bd125f63183847559602289
6
+ metadata.gz: 155a536e9accec95840cd873704efeb53aac9ef31f4f92e2da2a60c31af7532944e57c9ea140c04225811befc6f008755dca411cbae7fce355df9ce29303b1b7
7
+ data.tar.gz: 2fb571730ecfad52008c969ba5b64e0d99f4583f4b49035ed8e01dd8a4afff7eb4b05e884d187ee75a1c619f271c21f52809d99e33c5a933e941963c6f977d9f
data/README.md CHANGED
@@ -61,13 +61,6 @@ Quality::Rake::Task.new { |t|
61
61
  }
62
62
  ```
63
63
 
64
-
65
- ## Optional tools
66
-
67
- The 'reek' gem is supported, but not by default. To support it, add the 'reek' gem to your Gemspec. Once reek supports Ruby 2.0, it will presumably support newer versions of the 'ruby_parser' gem. Currently it will disable Ruby 2.0 supports in other quality-check gems by forcing them to a lower version.
68
-
69
- https://github.com/troessner/reek/issues/165
70
-
71
64
  ## Contributing
72
65
 
73
66
  * Fork the repo
@@ -82,6 +75,7 @@ Quality makes use of the following other gems, which do the actual checking:
82
75
  * cane
83
76
  * flog
84
77
  * flay
78
+ * rubocop
85
79
 
86
80
  ### Learn More
87
81
 
@@ -0,0 +1,53 @@
1
+ module Quality
2
+ # Class processes output from a code quality command, tweaking it
3
+ # for editor output and counting the number of violations found
4
+ class CommandOutputProcessor
5
+ attr_accessor :emacs_format
6
+ attr_accessor :file
7
+ attr_reader :found_output
8
+ attr_reader :violations
9
+
10
+ def initialize
11
+ @emacs_format = false
12
+ @found_output = false
13
+ @violations = 0
14
+ end
15
+
16
+ def process!(&count_violations_on_line)
17
+ process_file(file, &count_violations_on_line)
18
+ end
19
+
20
+ private
21
+
22
+ def process_file(file, &count_violations_on_line)
23
+ out = ''
24
+ while (@current_line = file.gets)
25
+ out <<
26
+ process_line(&count_violations_on_line)
27
+ end
28
+ out
29
+ end
30
+
31
+ def process_line(&count_violations_on_line)
32
+ output =
33
+ if emacs_format
34
+ preprocess_line_for_emacs
35
+ else
36
+ @current_line
37
+ end
38
+ @found_output = true
39
+ @violations += yield @current_line
40
+ output
41
+ end
42
+
43
+ def preprocess_line_for_emacs
44
+ if @current_line =~ /^ *(\S*.rb:[0-9]*) *(.*)/
45
+ $1 + ': ' + $2 + "\n"
46
+ elsif @current_line =~ /^ *(.*) +(\S*.rb:[0-9]*) *(.*)/
47
+ $2 + ': ' + $1 + "\n"
48
+ else
49
+ @current_line
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,108 @@
1
+ require_relative 'command_output_processor'
2
+
3
+ module Quality
4
+ # Runs a quality-checking, command, checks it agaist the existing
5
+ # number of violations for that command, and decreases that number
6
+ # if possible, or outputs data if the number of violations increased.
7
+ class QualityChecker
8
+ def initialize(cmd, command_options, output_dir, dependencies = {})
9
+ @popener = dependencies[:popener] || IO
10
+ @count_file = dependencies[:count_file] || File
11
+ @count_io = dependencies[:count_io] || IO
12
+ @command_output_processor_class =
13
+ dependencies[:command_output_processor_class] ||
14
+ Quality::CommandOutputProcessor
15
+ @cmd = cmd
16
+ @command_options = command_options
17
+ @filename = File.join(output_dir, "#{cmd}_high_water_mark")
18
+ end
19
+
20
+ def execute(&count_violations_on_line)
21
+ processor, exit_status = process_command(&count_violations_on_line)
22
+ @violations = processor.violations
23
+ check_exit_status(exit_status)
24
+ ratchet_violations
25
+ end
26
+
27
+ private
28
+
29
+ def process_command(&count_violations_on_line)
30
+ processor = @command_output_processor_class.new
31
+ processor.emacs_format = @command_options[:emacs_format]
32
+ exit_status = run_command(processor, &count_violations_on_line)
33
+ [processor, $?.exitstatus]
34
+ end
35
+
36
+ def run_command(processor, &count_violations_on_line)
37
+ @popener.popen(full_cmd) do |file|
38
+ processor.file = file
39
+ @command_output = processor.process!(&count_violations_on_line)
40
+ end
41
+ end
42
+
43
+ def check_exit_status(exit_status)
44
+ unless @command_options[:gives_error_code_on_violations]
45
+ if exit_status != 0
46
+ fail("Error detected running #{full_cmd}. " +
47
+ "Exit status is #{exit_status}, output is [#{out}]")
48
+ end
49
+ end
50
+ end
51
+
52
+ def existing_violations
53
+ if @count_file.exist?(@filename)
54
+ @count_io.read(@filename).to_i
55
+ else
56
+ 9_999_999_999
57
+ end
58
+ end
59
+
60
+ def ratchet_violations
61
+ existing = existing_violations
62
+ report_violations(existing)
63
+ if @violations > existing
64
+ fail("Output from #{@cmd}\n\n#{@command_output}\n\n" +
65
+ "Reduce total number of #{@cmd} violations " +
66
+ "to #{existing} or below!")
67
+ elsif @violations < existing
68
+ puts 'Ratcheting quality up...'
69
+ write_violations(@violations)
70
+ end
71
+ end
72
+
73
+ def report_violations(existing)
74
+ puts "Existing violations: #{existing}"
75
+ puts "Found #{@violations} #{@cmd} violations"
76
+ end
77
+
78
+ private
79
+
80
+ def full_cmd
81
+ args = @command_options[:args]
82
+ args ||= ''
83
+
84
+ @found_output = false
85
+ if args.size > 0
86
+ "#{get_cmd_with_ruby_hack_prefix} #{args}"
87
+ else
88
+ "#{get_cmd_with_ruby_hack_prefix}"
89
+ end
90
+ end
91
+
92
+ def get_cmd_with_ruby_hack_prefix
93
+ if defined?(RUBY_ENGINE) && (RUBY_ENGINE == 'jruby')
94
+ "jruby -S #{@cmd}"
95
+ elsif RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
96
+ "#{@cmd}.bat"
97
+ else
98
+ @cmd
99
+ end
100
+ end
101
+
102
+ def write_violations(new_violations)
103
+ @count_file.open(@filename, 'w') do |file|
104
+ file.write(new_violations.to_s)
105
+ end
106
+ end
107
+ end
108
+ end
@@ -3,13 +3,12 @@
3
3
  require 'rake'
4
4
  require 'rake/tasklib'
5
5
  require 'rbconfig'
6
+ require_relative '../quality_checker'
6
7
 
7
8
  module Quality
8
9
 
9
10
  #
10
11
  # Defines a task library for running quality's various tools
11
- # (Classes here will be configured via the Rakefile, and therefore will
12
- # possess a :reek:attribute or two.)
13
12
  #
14
13
  module Rake
15
14
 
@@ -26,7 +25,6 @@ module Quality
26
25
  # This will create a task that can be run with:
27
26
  #
28
27
  # rake quality
29
- #
30
28
  class Task < ::Rake::TaskLib
31
29
 
32
30
  # Name of quality task.
@@ -62,14 +60,11 @@ module Quality
62
60
 
63
61
  # allow unit tests to override the class that Rake DSL
64
62
  # messages are sent to.
65
- @dsl = args[:dsl]
63
+ @dsl = args[:dsl] || ::Rake::Task
66
64
 
67
65
  # likewise, but for system()
68
66
  @cmd_runner = args[:cmd_runner] || Kernel
69
67
 
70
- # likewise, but for IO.popen()
71
- @popener = args[:popener] || IO
72
-
73
68
  # likewise, but for File.open() on the count files
74
69
  @count_file = args[:count_file] || File
75
70
 
@@ -79,149 +74,110 @@ module Quality
79
74
  # likewise, but for Dir.glob() on target Ruby files
80
75
  @globber = args[:globber] || Dir
81
76
 
77
+ # likewise, but for checking whether a gem is installed
78
+ @gem_spec = args[:gem_spec] || Gem::Specification
79
+
82
80
  # uses exist?() and open() to write out configuration files
83
81
  # for tools if needed (e.g., .cane file)
84
82
  @configuration_writer = args[:configuration_writer] || File
85
83
 
86
- @skip_tools = [] if @skip_tools.nil?
87
- @config_files = nil
88
- @source_files = nil
89
- @ruby_opts = []
90
- @reek_opts = ''
91
- @fail_on_error = true
92
- @sort = nil
84
+ # Class which actually runs the quality check commands
85
+ @quality_checker_class =
86
+ args[:quality_checker_class] || Quality::QualityChecker
87
+
88
+ @skip_tools = []
89
+
90
+ @output_dir = '.'
93
91
 
94
92
  yield self if block_given?
95
- @config_files ||= 'config/**/*.reek'
96
- @source_files ||= 'lib/**/*.rb'
97
- @output_dir ||= "."
93
+
98
94
  define
99
95
  end
100
96
 
101
- private
97
+ private
102
98
 
103
99
  def define # :nodoc:
104
100
  desc 'Verify quality has increased or stayed ' +
105
101
  'the same' unless ::Rake.application.last_comment
106
- if @dsl.nil?
107
- task(quality_name) { run_quality }
108
- task(ratchet_name) { run_ratchet }
109
- else
110
- @dsl.task(quality_name) { run_quality }
111
- @dsl.task(ratchet_name) { run_ratchet }
112
- end
102
+ @dsl.define_task(quality_name) { run_quality }
103
+ @dsl.define_task(ratchet_name) { run_ratchet }
113
104
  end
114
105
 
115
106
  def run_quality
116
107
  tools = ['cane', 'flog', 'flay', 'reek', 'rubocop']
117
108
  tools.each do |tool|
118
- installed = Gem::Specification.find_all_by_name(tool).any?
119
- suppressed = @skip_tools.include? tool
109
+ run_quality_with_tool(tool)
110
+ end
111
+ end
120
112
 
121
- if !installed
122
- puts "#{tool} not installed"
123
- elsif suppressed
124
- puts "Suppressing use of #{tool}"
125
- else
126
- method("quality_#{tool}".to_sym).call
127
- end
113
+ def run_quality_with_tool(tool)
114
+ installed = @gem_spec.find_all_by_name(tool).any?
115
+ suppressed = @skip_tools.include? tool
116
+
117
+ if !installed
118
+ puts "#{tool} not installed"
119
+ elsif suppressed
120
+ puts "Suppressing use of #{tool}"
121
+ else
122
+ method("quality_#{tool}".to_sym).call
128
123
  end
129
124
  end
130
125
 
131
126
  def run_ratchet
132
- @globber.glob("*_high_water_mark").each { |filename|
133
- puts "Processing #{filename}"
134
- existing_violations = @count_io.read(filename).to_i
135
- if existing_violations < 0
136
- raise "Problem with file #{filename}"
137
- end
138
- new_violations = [0, existing_violations - 1].max
139
- @count_file.open(filename, 'w') {|f| f.write(new_violations.to_s) }
140
- if new_violations != existing_violations
141
- @cmd_runner.system("git commit -m 'tighten quality standard' #{filename}")
142
- end
143
- }
127
+ @globber.glob('*_high_water_mark').each do |filename|
128
+ run_ratchet_on_file(filename)
129
+ end
144
130
  end
145
131
 
146
- def ratchet_quality_cmd(cmd,
147
- options,
148
- &process_output_line)
149
-
150
- gives_error_code_on_violations ||= options[:gives_error_code_on_violations]
151
-
152
- args ||= options[:args]
153
- emacs_format ||= options[:emacs_format]
132
+ def run_ratchet_on_file(filename)
133
+ puts "Processing #{filename}"
134
+ existing_violations = count_existing_violations(filename)
135
+ new_violations = [0, existing_violations - 1].max
136
+ write_violations(filename, new_violations)
137
+ tighten_standard(filename) if new_violations != existing_violations
138
+ end
154
139
 
155
- violations = 0
156
- out = ""
157
- found_output = false
158
- if defined?(RUBY_ENGINE) && (RUBY_ENGINE == 'jruby')
159
- full_cmd = "jruby -S #{cmd}"
160
- elsif RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
161
- full_cmd = "#{cmd}.bat"
162
- else
163
- full_cmd = cmd
140
+ def write_violations(filename, new_violations)
141
+ @count_file.open(filename, 'w') do |file|
142
+ file.write(new_violations.to_s)
164
143
  end
144
+ end
165
145
 
166
- if !args.nil?
167
- full_cmd = "#{full_cmd} #{args}"
168
- end
146
+ def count_existing_violations(filename)
147
+ existing_violations = @count_io.read(filename).to_i
148
+ fail("Problem with file #{filename}") if existing_violations < 0
149
+ existing_violations
150
+ end
169
151
 
170
- @popener.popen(full_cmd) do |f|
171
- while line = f.gets
172
- if emacs_format
173
- if line =~ /^ *(\S*.rb:[0-9]*) *(.*)/
174
- out << $1 << ": " << $2 << "\n"
175
- elsif line =~ /^ *(.*) +(\S*.rb:[0-9]*) *(.*)/
176
- out << $2 << ": " << $1 << "\n"
177
- else
178
- out << line
179
- end
180
- else
181
- out << line
182
- end
183
- found_output = true
184
- violations += yield line
185
- end
186
- end
187
- exit_status = $?.exitstatus
188
- if !gives_error_code_on_violations
189
- if exit_status != 0
190
- fail "Error detected running #{full_cmd}. Exit status is #{exit_status}, output is [#{out}]"
191
- end
192
- end
193
- filename = File.join(@output_dir, "#{cmd}_high_water_mark")
194
- if @count_file.exist?(filename)
195
- existing_violations = @count_io.read(filename).to_i
196
- else
197
- existing_violations = 9999999999
198
- end
199
- puts "Existing violations: #{existing_violations}"
200
- puts "Found #{violations} #{cmd} violations"
201
- if violations > existing_violations
202
- fail "Output from #{cmd}\n\n#{out}\n\n" +
203
- "Reduce total number of #{cmd} violations to #{existing_violations} or below!"
204
- elsif violations < existing_violations
205
- puts "Ratcheting quality up..."
206
- @count_file.open(filename, 'w') do |f|
207
- f.write(violations.to_s)
208
- end
209
- end
152
+ def tighten_standard(filename)
153
+ @cmd_runner
154
+ .system("git commit -m 'tighten quality standard' #{filename}")
155
+ end
156
+
157
+ def ratchet_quality_cmd(cmd,
158
+ command_options,
159
+ &count_violations_on_line)
160
+ quality_checker = @quality_checker_class.new(cmd,
161
+ command_options,
162
+ @output_dir)
163
+ quality_checker.execute(&count_violations_on_line)
210
164
  end
211
165
 
212
166
  def quality_cane
213
- if ! @configuration_writer.exist?(".cane")
214
- @configuration_writer.open(".cane", "w") {|f| f.write("-f **/*.rb")}
167
+ unless @configuration_writer.exist?('.cane')
168
+ @configuration_writer.open('.cane', 'w') do |file|
169
+ file.write('-f **/*.rb')
170
+ end
215
171
  end
216
- ratchet_quality_cmd("cane",
172
+ ratchet_quality_cmd('cane',
217
173
  gives_error_code_on_violations: true,
218
- emacs_format: true) { |line|
174
+ emacs_format: true) do |line|
219
175
  if line =~ /\(([0-9]*)\):$/
220
176
  $1.to_i
221
177
  else
222
178
  0
223
179
  end
224
- }
180
+ end
225
181
  end
226
182
 
227
183
  def ruby_dirs
@@ -229,68 +185,79 @@ module Quality
229
185
  end
230
186
 
231
187
  def ruby_files
232
- @globber.glob('*.rb').concat(@globber.glob(File.join("{#{ruby_dirs.join(',')}}", '**', '*.rb'))).join(' ')
188
+ @globber.glob('*.rb')
189
+ .concat(@globber.glob(File.join("{#{ruby_dirs.join(',')}}",
190
+ '**', '*.rb'))).join(' ')
233
191
  end
234
192
 
235
193
  def quality_reek
236
- args = "--line-number #{ruby_files}"
237
- ratchet_quality_cmd("reek",
194
+ args = "--single-line #{ruby_files}"
195
+ ratchet_quality_cmd('reek',
238
196
  args: args,
239
197
  emacs_format: true,
240
- gives_error_code_on_violations: true) { |line|
241
- if line =~ /^ .* (.*)$/
242
- 1
243
- else
244
- 0
245
- end
246
- }
198
+ gives_error_code_on_violations: true) do |line|
199
+ self.class.count_reek_violations(line)
200
+ end
201
+ end
202
+
203
+ def self.count_reek_violations(line)
204
+ if line =~ /^ .* (.*)$/
205
+ 1
206
+ else
207
+ 0
208
+ end
247
209
  end
248
210
 
249
211
  def quality_flog
250
- threshold = 50
251
- ratchet_quality_cmd("flog",
252
- args: "--all --continue --methods-only #{ruby_files}",
253
- emacs_format: true) { |line|
254
- if line =~ /^ *([0-9.]*): flog total$/
255
- 0
256
- #$1.to_i
257
- elsif line =~ /^ *([0-9.]*): (.*) .*.rb:[0-9]*$/
258
- score = $1.to_i
259
- if score > threshold
260
- 1
261
- else
262
- 0
263
- end
212
+ ratchet_quality_cmd('flog',
213
+ args: "--all --continue --methods-only #{ruby_files}",
214
+ emacs_format: true) do |line|
215
+ self.class.count_violations_in_flog_output(line)
216
+ end
217
+ end
218
+
219
+ def self.count_violations_in_flog_output(line, threshold = 50)
220
+ if line =~ /^ *([0-9.]*): flog total$/
221
+ 0
222
+ elsif line =~ /^ *([0-9.]*): (.*) .*.rb:[0-9]*$/
223
+ score = $1.to_i
224
+ if score > threshold
225
+ 1
264
226
  else
265
227
  0
266
228
  end
267
- }
229
+ else
230
+ 0
231
+ end
268
232
  end
269
233
 
270
234
  def quality_flay
271
- ratchet_quality_cmd("flay",
235
+ ratchet_quality_cmd('flay',
272
236
  args: "-m 75 -t 99999 #{ruby_files}",
273
- emacs_format: true) { |line|
237
+ emacs_format: true) do |line|
274
238
  if line =~ /^[0-9]*\).* \(mass = ([0-9]*)\)$/
275
239
  $1.to_i
276
240
  else
277
241
  0
278
242
  end
279
- }
243
+ end
280
244
  end
281
245
 
282
246
  def quality_rubocop
283
- ratchet_quality_cmd("rubocop",
247
+ ratchet_quality_cmd('rubocop',
284
248
  gives_error_code_on_violations: true,
285
- args: "--format emacs #{ruby_files}") { |line|
286
- if line =~ /^.* file[s|] inspected, (.*) offence[s|] detected$/
287
- 0
288
- else
289
- 1
290
- end
291
- }
249
+ args: "--format emacs #{ruby_files}") do |line|
250
+ self.class.count_rubocop_violations(line)
251
+ end
292
252
  end
293
253
 
254
+ def self.count_rubocop_violations(line)
255
+ if line =~ /^.* file[s|] inspected, (.*) offence[s|] detected$/
256
+ 0
257
+ else
258
+ 1
259
+ end
260
+ end
294
261
  end
295
262
  end
296
263
  end
@@ -1,3 +1,3 @@
1
1
  module Quality
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0'
3
3
  end
data/quality.gemspec CHANGED
@@ -29,7 +29,7 @@ your numbers don't get any worse over time.
29
29
  s.summary = %q{Code quality tools for Ruby}
30
30
 
31
31
  s.add_runtime_dependency(%q<cane>, [">= 2.6"])
32
- s.add_runtime_dependency(%q<reek>, [">= 1.3.2"])
32
+ s.add_runtime_dependency(%q<reek>, [">= 1.3.4"])
33
33
  s.add_runtime_dependency(%q<flog>, [">= 4.1.1"])
34
34
  s.add_runtime_dependency(%q<flay>, [">= 2.4"])
35
35
  s.add_runtime_dependency(%q<rubocop>)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quality
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vince Broz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-13 00:00:00.000000000 Z
11
+ date: 2013-10-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: cane
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - '>='
32
32
  - !ruby/object:Gem::Version
33
- version: 1.3.2
33
+ version: 1.3.4
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - '>='
39
39
  - !ruby/object:Gem::Version
40
- version: 1.3.2
40
+ version: 1.3.4
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: flog
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -190,6 +190,8 @@ files:
190
190
  - License.txt
191
191
  - README.md
192
192
  - Rakefile
193
+ - lib/quality/command_output_processor.rb
194
+ - lib/quality/quality_checker.rb
193
195
  - lib/quality/rake/task.rb
194
196
  - lib/quality/version.rb
195
197
  - quality.gemspec