devtools 0.1.0 → 0.1.26

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.
Files changed (65) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +41 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +1 -2
  5. data/Gemfile +9 -2
  6. data/README.md +3 -3
  7. data/config/devtools.yml +2 -0
  8. data/config/flay.yml +2 -2
  9. data/config/flog.yml +1 -1
  10. data/config/mutant.yml +6 -2
  11. data/config/reek.yml +105 -106
  12. data/config/rubocop.yml +37 -3
  13. data/devtools.gemspec +27 -25
  14. data/lib/devtools/config.rb +74 -66
  15. data/lib/devtools/flay.rb +98 -0
  16. data/lib/devtools/project/initializer/rake.rb +11 -7
  17. data/lib/devtools/project/initializer/rspec.rb +30 -55
  18. data/lib/devtools/project/initializer.rb +2 -12
  19. data/lib/devtools/project.rb +27 -105
  20. data/lib/devtools/rake/flay.rb +155 -0
  21. data/lib/devtools/spec_helper.rb +1 -3
  22. data/lib/devtools.rb +42 -89
  23. data/shared/spec/shared/abstract_type_behavior.rb +0 -2
  24. data/shared/spec/shared/command_method_behavior.rb +0 -2
  25. data/shared/spec/shared/each_method_behaviour.rb +0 -2
  26. data/shared/spec/shared/idempotent_method_behavior.rb +2 -3
  27. data/shared/spec/support/ice_nine_config.rb +0 -2
  28. data/spec/integration/devtools/rake/flay/verify_spec.rb +196 -0
  29. data/spec/spec_helper.rb +4 -11
  30. data/spec/unit/devtools/config/yardstick_spec.rb +17 -0
  31. data/spec/unit/devtools/config_spec.rb +78 -0
  32. data/spec/unit/devtools/flay/file_list/call_spec.rb +19 -0
  33. data/spec/unit/devtools/flay/scale/flay_report_spec.rb +17 -0
  34. data/spec/unit/devtools/flay/scale/measure_spec.rb +43 -0
  35. data/spec/unit/devtools/project/initializer/rake_spec.rb +21 -0
  36. data/spec/unit/devtools/project/initializer/rspec_spec.rb +52 -0
  37. data/spec/unit/devtools/project_spec.rb +34 -0
  38. data/spec/unit/devtools_spec.rb +14 -0
  39. data/tasks/metrics/ci.rake +3 -7
  40. data/tasks/metrics/coverage.rake +2 -2
  41. data/tasks/metrics/flay.rake +6 -33
  42. data/tasks/metrics/flog.rake +10 -7
  43. data/tasks/metrics/reek.rake +5 -4
  44. data/tasks/metrics/rubocop.rake +1 -3
  45. data/tasks/metrics/yardstick.rake +0 -14
  46. data/tasks/spec.rake +1 -3
  47. data/tasks/yard.rake +1 -3
  48. metadata +124 -65
  49. data/.ruby-gemset +0 -1
  50. data/.travis.yml +0 -15
  51. data/TODO +0 -0
  52. data/bin/devtools +0 -18
  53. data/circle.yml +0 -7
  54. data/default/config/devtools.yml +0 -2
  55. data/default/config/flay.yml +0 -3
  56. data/default/config/flog.yml +0 -2
  57. data/default/config/mutant.yml +0 -3
  58. data/default/config/reek.yml +0 -103
  59. data/default/config/rubocop.yml +0 -91
  60. data/default/config/yardstick.yml +0 -2
  61. data/lib/devtools/platform.rb +0 -118
  62. data/lib/devtools/site/initializer.rb +0 -57
  63. data/lib/devtools/site.rb +0 -41
  64. data/shared/spec/shared/hash_method_behavior.rb +0 -9
  65. data/tasks/metrics/mutant.rake +0 -50
@@ -0,0 +1,19 @@
1
+ describe Devtools::Flay::FileList, '.call' do
2
+ subject(:output) { described_class.call([tmpdir.to_s].freeze, [exclude]) }
3
+
4
+ let(:tmpdir) { Dir.mktmpdir }
5
+ let(:one) { Pathname(tmpdir).join('1.rb') }
6
+ let(:two) { Pathname(tmpdir).join('2.erb') }
7
+ let(:three) { Pathname(tmpdir).join('3.rb') }
8
+ let(:exclude) { Pathname(tmpdir).join('3*').to_s }
9
+
10
+ around(:each) do |example|
11
+ [one, two, three].map(&FileUtils.method(:touch))
12
+
13
+ example.run
14
+
15
+ FileUtils.rm_rf(tmpdir)
16
+ end
17
+
18
+ it { should eql(Set.new([one, two])) }
19
+ end
@@ -0,0 +1,17 @@
1
+ describe Devtools::Flay::Scale, '#flay_report' do
2
+ subject(:instance) { described_class.new(minimum_mass: 0, files: []) }
3
+
4
+ let(:flay) do
5
+ instance_double(::Flay, process: nil, analyze: nil, masses: {})
6
+ end
7
+
8
+ before do
9
+ allow(::Flay).to receive(:new).with(mass: 0).and_return(flay)
10
+ end
11
+
12
+ specify do
13
+ allow(flay).to receive(:report)
14
+ instance.flay_report
15
+ expect(flay).to have_received(:report)
16
+ end
17
+ end
@@ -0,0 +1,43 @@
1
+ describe Devtools::Flay::Scale, '#measure' do
2
+ subject(:measure) { instance.measure }
3
+
4
+ let(:minimum_mass) { 0 }
5
+ let(:files) { [instance_double(File)] }
6
+ let(:flay_masses) { { 0 => 5, 1 => 10 } }
7
+
8
+ let(:instance) do
9
+ described_class.new(minimum_mass: minimum_mass, files: files)
10
+ end
11
+
12
+ let(:flay_hashes) do
13
+ {
14
+ 0 => instance_double(Array, size: 3),
15
+ 1 => instance_double(Array, size: 11)
16
+ }
17
+ end
18
+
19
+ let(:flay) do
20
+ instance_double(
21
+ ::Flay,
22
+ analyze: nil,
23
+ masses: flay_masses,
24
+ hashes: flay_hashes
25
+ )
26
+ end
27
+
28
+ before do
29
+ allow(::Flay).to receive(:new).with(mass: minimum_mass).and_return(flay)
30
+ allow(flay).to receive(:process).with(*files)
31
+ end
32
+
33
+ it { should eql([Rational(5, 3), Rational(10, 11)]) }
34
+
35
+ context 'when minimum mass is not 0' do
36
+ let(:minimum_mass) { 1 }
37
+
38
+ specify do
39
+ measure
40
+ expect(::Flay).to have_received(:new).with(mass: 1)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ describe Devtools::Project::Initializer::Rake do
2
+ describe '.call' do
3
+ subject do
4
+ described_class.call
5
+ end
6
+
7
+ it 'performs expected rake initialization' do
8
+ path_a = instance_double(Pathname)
9
+ path_b = instance_double(Pathname)
10
+
11
+ expect(FileList).to receive(:glob)
12
+ .with(Devtools.root.join('tasks/**/*.rake').to_s)
13
+ .and_return([path_a, path_b])
14
+
15
+ expect(Rake.application).to receive(:add_import).with(path_a)
16
+ expect(Rake.application).to receive(:add_import).with(path_b)
17
+
18
+ expect(subject).to be(described_class)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,52 @@
1
+ describe Devtools::Project::Initializer::Rspec do
2
+ let(:spec_root) { Devtools.root.join('spec') }
3
+ let(:unit_test_timeout) { instance_double(Float) }
4
+
5
+ let(:project) do
6
+ instance_double(
7
+ Devtools::Project,
8
+ spec_root: spec_root,
9
+ devtools: instance_double(
10
+ Devtools::Config::Devtools,
11
+ unit_test_timeout: unit_test_timeout
12
+ )
13
+ )
14
+ end
15
+
16
+ describe '.call' do
17
+ subject do
18
+ described_class.call(project)
19
+ end
20
+
21
+ it 'performs expected rspec initialization' do
22
+ called = false
23
+ example = -> { called = true }
24
+
25
+ expect(Dir).to receive(:glob)
26
+ .with(Devtools.root.join('shared/spec/{shared,support}/**/*.rb'))
27
+ .and_return(%w[shared-a shared-b])
28
+
29
+ expect(Kernel).to receive(:require).with('shared-a')
30
+ expect(Kernel).to receive(:require).with('shared-b')
31
+
32
+ expect(Dir).to receive(:glob)
33
+ .with(Devtools.root.join('spec/{shared,support}/**/*.rb'))
34
+ .and_return(%w[support-a support-b])
35
+
36
+ expect(Kernel).to receive(:require).with('support-a')
37
+ expect(Kernel).to receive(:require).with('support-b')
38
+
39
+ expect(Timeout).to receive(:timeout).with(unit_test_timeout) do |&block|
40
+ block.call
41
+ end
42
+
43
+ expect(RSpec.configuration).to receive(:around)
44
+ .with(file_path: %r{\bspec/unit/})
45
+ .and_yield(example)
46
+
47
+ expect(subject).to be(described_class)
48
+
49
+ expect(called).to be(true)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,34 @@
1
+ RSpec.describe Devtools::Project do
2
+ let(:object) { described_class.new(Devtools.root) }
3
+
4
+ describe '#init_rspec' do
5
+ subject { object.init_rspec }
6
+
7
+ it 'calls the rspec initializer' do
8
+ expect(Devtools::Project::Initializer::Rspec)
9
+ .to receive(:call).with(Devtools.project)
10
+ expect(subject).to be(object)
11
+ end
12
+ end
13
+
14
+ {
15
+ devtools: Devtools::Config::Devtools,
16
+ flay: Devtools::Config::Flay,
17
+ flog: Devtools::Config::Flog,
18
+ reek: Devtools::Config::Reek,
19
+ rubocop: Devtools::Config::Rubocop,
20
+ yardstick: Devtools::Config::Yardstick
21
+ }.each do |name, klass|
22
+ describe "##{name}" do
23
+ subject { object.send(name) }
24
+
25
+ specify { should eql(klass.new(Devtools.root.join('config'))) }
26
+ end
27
+ end
28
+
29
+ describe '#spec_root' do
30
+ subject { object.spec_root }
31
+
32
+ specify { should eql(Devtools.root.join('spec')) }
33
+ end
34
+ end
@@ -0,0 +1,14 @@
1
+ describe Devtools do
2
+ describe '.project' do
3
+ specify do
4
+ expect(Devtools.project).to equal(Devtools::PROJECT)
5
+ end
6
+ end
7
+
8
+ describe '.init_rake_tasks' do
9
+ specify do
10
+ expect(Devtools::Project::Initializer::Rake).to receive(:call)
11
+ expect(Devtools.init_rake_tasks).to be(Devtools)
12
+ end
13
+ end
14
+ end
@@ -1,7 +1,5 @@
1
- # encoding: utf-8
2
-
3
- desc 'Run all specs, metrics and mutant'
4
- task ci: %w[spec ci:metrics metrics:mutant]
1
+ desc 'Run all specs and metrics'
2
+ task ci: %w[ci:metrics]
5
3
 
6
4
  namespace :ci do
7
5
  tasks = %w[
@@ -11,8 +9,6 @@ namespace :ci do
11
9
  metrics:flog
12
10
  metrics:flay
13
11
  metrics:reek
12
+ spec:integration
14
13
  ]
15
-
16
- desc 'Run metrics (except mutant)'
17
- task metrics: tasks
18
14
  end
@@ -1,10 +1,10 @@
1
- # encoding: utf-8
2
-
3
1
  namespace :metrics do
4
2
  desc 'Measure code coverage'
5
3
  task :coverage do
6
4
  begin
5
+ # rubocop:disable Style/ParallelAssignment
7
6
  original, ENV['COVERAGE'] = ENV['COVERAGE'], 'true'
7
+ # rubocop:enable Style/ParallelAssignment
8
8
  Rake::Task['spec:unit'].execute
9
9
  ensure
10
10
  ENV['COVERAGE'] = original
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  namespace :metrics do
4
2
  require 'flay'
5
3
 
@@ -12,37 +10,12 @@ namespace :metrics do
12
10
  task :flay do
13
11
  threshold = config.threshold
14
12
  total_score = config.total_score
15
- files = Flay.expand_dirs_to_files(config.lib_dirs).sort
16
-
17
- # Run flay first to ensure the max mass matches the threshold
18
- flay = Flay.new(fuzzy: false, verbose: false, mass: 0)
19
- flay.process(*files)
20
- flay.analyze
21
-
22
- masses = flay.masses.map do |hash, mass|
23
- Rational(mass, flay.hashes[hash].size)
24
- end
25
-
26
- max = (masses.max || 0).to_i
27
- unless max >= threshold
28
- Devtools.notify_metric_violation "Adjust flay threshold down to #{max}"
29
- end
30
-
31
- total = masses.inject(:+).to_i
32
- unless total == total_score
33
- Devtools.notify_metric_violation "Flay total is now #{total}, but expected #{total_score}"
34
- end
35
-
36
- # Run flay a second time with the threshold set
37
- flay = Flay.new(fuzzy: false, verbose: false, mass: threshold.succ)
38
- flay.process(*files)
39
- flay.analyze
40
-
41
- mass_size = flay.masses.size
42
13
 
43
- if mass_size.nonzero?
44
- flay.report
45
- Devtools.notify_metric_violation "#{mass_size} chunks have a duplicate mass > #{threshold}"
46
- end
14
+ Devtools::Rake::Flay.call(
15
+ threshold: threshold,
16
+ total_score: total_score,
17
+ lib_dirs: config.lib_dirs,
18
+ excludes: config.excludes
19
+ )
47
20
  end
48
21
  end
@@ -1,5 +1,4 @@
1
- # encoding: utf-8
2
-
1
+ # rubocop:disable Metrics/BlockLength
3
2
  namespace :metrics do
4
3
  require 'flog'
5
4
  require 'flog_cli'
@@ -13,11 +12,13 @@ namespace :metrics do
13
12
  task :flog do
14
13
  threshold = config.threshold.to_f.round(1)
15
14
  flog = Flog.new
16
- flog.flog(*FlogCLI.expand_dirs_to_files(config.lib_dirs))
15
+ flog.flog(*PathExpander.new(config.lib_dirs.dup, '**/*.rb').process)
17
16
 
18
- totals = flog.totals.select { |name, score| name[-5, 5] != '#none' }
19
- .map { |name, score| [name, score.round(1)] }
20
- .sort_by { |name, score| score }
17
+ totals = flog
18
+ .totals
19
+ .reject { |name, _score| name.end_with?('#none') }
20
+ .map { |name, score| [name, score.round(1)] }
21
+ .sort_by { |_name, score| score }
21
22
 
22
23
  if totals.any?
23
24
  max = totals.last[1]
@@ -26,7 +27,8 @@ namespace :metrics do
26
27
  end
27
28
  end
28
29
 
29
- bad_methods = totals.select { |name, score| score > threshold }
30
+ bad_methods = totals.select { |_name, score| score > threshold }
31
+
30
32
  if bad_methods.any?
31
33
  bad_methods.reverse_each do |name, score|
32
34
  printf "%8.1f: %s\n", score, name
@@ -38,3 +40,4 @@ namespace :metrics do
38
40
  end
39
41
  end
40
42
  end
43
+ # rubocop:enable Metrics/BlockLength
@@ -1,7 +1,8 @@
1
- # encoding: utf-8
2
-
3
1
  namespace :metrics do
4
- task :reek do
5
- $stderr.puts 'Reek is disabled due defunct AST processing'
2
+ require 'reek/rake/task'
3
+
4
+ Reek::Rake::Task.new do |reek|
5
+ reek.source_files = '{app,lib}/**/*.rb'
6
+ reek.config_file = 'config/reek.yml'
6
7
  end
7
8
  end
@@ -1,12 +1,10 @@
1
- # encoding: utf-8
2
-
3
1
  namespace :metrics do
4
2
  desc 'Check with code style guide'
5
3
  task :rubocop do
6
4
  require 'rubocop'
7
5
  config = Devtools.project.rubocop
8
6
  begin
9
- exit_status = RuboCop::CLI.new.run(%W[--config #{config.config_file.to_s}])
7
+ exit_status = RuboCop::CLI.new.run(%W[--config #{config.config_file}])
10
8
  fail 'Rubocop not successful' unless exit_status.zero?
11
9
  rescue Encoding::CompatibilityError => exception
12
10
  Devtools.notify_metric_violation exception.message
@@ -1,22 +1,8 @@
1
- # encoding: utf-8
2
-
3
1
  namespace :metrics do
4
2
  namespace :yardstick do
5
3
  require 'yardstick/rake/measurement'
6
4
  require 'yardstick/rake/verify'
7
5
 
8
- # Enable the legacy parser for JRuby until ripper is fully supported
9
- if Devtools.jruby?
10
- # Remove when https://github.com/lsegal/yard/issues/681 is resolved
11
- # This code first requires ripper, then removes the constant so
12
- # that it does not trigger a bug in YARD where if it checks if Ripper
13
- # is available and assumes other constants are defined, when JRuby's
14
- # implementation does not yet.
15
- require 'ripper'
16
- Object.send(:remove_const, :Ripper)
17
- YARD::Parser::SourceParser.parser_type = :ruby18
18
- end
19
-
20
6
  options = Devtools.project.yardstick.options
21
7
 
22
8
  Yardstick::Rake::Measurement.new(:measure, options)
data/tasks/spec.rake CHANGED
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  begin
4
2
  require 'rspec/core/rake_task'
5
3
 
@@ -28,7 +26,7 @@ begin
28
26
  rescue LoadError
29
27
  %w[spec spec:unit spec:integration].each do |name|
30
28
  task name do
31
- $stderr.puts "In order to run #{name}, do: gem install rspec"
29
+ warn "In order to run #{name}, do: gem install rspec"
32
30
  end
33
31
  end
34
32
  end
data/tasks/yard.rake CHANGED
@@ -1,11 +1,9 @@
1
- # encoding: utf-8
2
-
3
1
  begin
4
2
  require 'yard'
5
3
 
6
4
  YARD::Rake::YardocTask.new
7
5
  rescue LoadError
8
6
  task :yard do
9
- $stderr.puts 'In order to run yard, you must: gem install yard'
7
+ warn 'In order to run yard, you must: gem install yard'
10
8
  end
11
9
  end