develry 0.0.2
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 +7 -0
- data/.gitignore +37 -0
- data/.rspec +5 -0
- data/.ruby-gemset +1 -0
- data/.travis.yml +30 -0
- data/Gemfile +7 -0
- data/Guardfile +32 -0
- data/LICENSE +20 -0
- data/README.md +71 -0
- data/Rakefile +5 -0
- data/TODO +0 -0
- data/bin/develry +18 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/mutant.yml +2 -0
- data/config/reek.yml +106 -0
- data/config/rubocop.yml +66 -0
- data/config/yardstick.yml +2 -0
- data/default/config/develry.yml +4 -0
- data/default/config/flay.yml +3 -0
- data/default/config/flog.yml +2 -0
- data/default/config/mutant.yml +3 -0
- data/default/config/reek.yml +103 -0
- data/default/config/rubocop.yml +58 -0
- data/default/config/yardstick.yml +2 -0
- data/develry.gemspec +53 -0
- data/lib/develry.rb +164 -0
- data/lib/develry/config.rb +167 -0
- data/lib/develry/platform.rb +118 -0
- data/lib/develry/project.rb +144 -0
- data/lib/develry/project/initializer.rb +21 -0
- data/lib/develry/project/initializer/rake.rb +19 -0
- data/lib/develry/project/initializer/rspec.rb +104 -0
- data/lib/develry/site.rb +64 -0
- data/lib/develry/site/initializer.rb +73 -0
- data/lib/develry/spec_helper.rb +5 -0
- data/shared/Gemfile +55 -0
- data/shared/spec/shared/abstract_type_behavior.rb +18 -0
- data/shared/spec/shared/command_method_behavior.rb +7 -0
- data/shared/spec/shared/each_method_behaviour.rb +15 -0
- data/shared/spec/shared/hash_method_behavior.rb +17 -0
- data/shared/spec/shared/idempotent_method_behavior.rb +9 -0
- data/shared/spec/support/ice_nine_config.rb +14 -0
- data/spec/spec_helper.rb +33 -0
- data/tasks/metrics/ci.rake +18 -0
- data/tasks/metrics/coverage.rake +13 -0
- data/tasks/metrics/flay.rake +66 -0
- data/tasks/metrics/flog.rake +59 -0
- data/tasks/metrics/mutant.rake +44 -0
- data/tasks/metrics/reek.rake +27 -0
- data/tasks/metrics/rubocop.rake +18 -0
- data/tasks/metrics/yardstick.rake +42 -0
- data/tasks/spec.rake +28 -0
- data/tasks/yard.rake +11 -0
- metadata +452 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Develry
|
4
|
+
class Site
|
5
|
+
|
6
|
+
# Supports initializing new projects with a Gemfile and Rakefile
|
7
|
+
class Initializer
|
8
|
+
|
9
|
+
def self.call(root)
|
10
|
+
new(root).call
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :site
|
14
|
+
|
15
|
+
attr_reader :root
|
16
|
+
|
17
|
+
attr_reader :config_dir
|
18
|
+
|
19
|
+
def initialize(site)
|
20
|
+
@site = site
|
21
|
+
@root = site.root
|
22
|
+
config_dir = @root.join(DEFAULT_CONFIG_DIR_NAME).tap(&:mkpath)
|
23
|
+
@config_dir = config_dir.parent
|
24
|
+
end
|
25
|
+
|
26
|
+
# Init develry using default config
|
27
|
+
#
|
28
|
+
# @return [undefined]
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
def call
|
32
|
+
FileUtils.cp_r(DEFAULT_CONFIG_PATH, config_dir)
|
33
|
+
|
34
|
+
site.sync
|
35
|
+
init_gemfile
|
36
|
+
init_rakefile
|
37
|
+
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Initialize the Gemfile
|
44
|
+
#
|
45
|
+
# @return [undefined]
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
def init_gemfile
|
49
|
+
gemfile = root.join(DEFAULT_GEMFILE_NAME)
|
50
|
+
unless gemfile.file? && gemfile.read.include?(EVAL_GEMFILE)
|
51
|
+
gemfile.open('a') do |file|
|
52
|
+
file << ANNOTATION_WRAPPER % EVAL_GEMFILE
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Initialize the Rakefile
|
58
|
+
#
|
59
|
+
# @return [undefined]
|
60
|
+
#
|
61
|
+
# @api private
|
62
|
+
def init_rakefile
|
63
|
+
rakefile = root.join(RAKE_FILE_NAME)
|
64
|
+
unless rakefile.file? && rakefile.read.include?(INIT_RAKE_TASKS)
|
65
|
+
rakefile.open('a') do |file|
|
66
|
+
file << ANNOTATION_WRAPPER % [REQUIRE, INIT_RAKE_TASKS].join("\n")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end # class Initializer
|
72
|
+
end # class Site
|
73
|
+
end # module Develry
|
data/shared/Gemfile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
group :development do
|
4
|
+
gem 'rake', '~> 10.1.0'
|
5
|
+
gem 'rspec', '~> 2.14.1'
|
6
|
+
gem 'yard', '~> 0.8.7'
|
7
|
+
end
|
8
|
+
|
9
|
+
group :yard do
|
10
|
+
gem 'kramdown', '~> 1.2.0'
|
11
|
+
end
|
12
|
+
|
13
|
+
group :guard do
|
14
|
+
gem 'guard', '~> 1.8.1'
|
15
|
+
gem 'guard-bundler', '~> 1.0.0'
|
16
|
+
gem 'guard-rspec', '~> 3.0.2'
|
17
|
+
gem 'guard-rubocop', '~> 0.2.0'
|
18
|
+
gem 'guard-mutant', '~> 0.0.1'
|
19
|
+
|
20
|
+
# file system change event handling
|
21
|
+
gem 'listen', '~> 1.3.0'
|
22
|
+
gem 'rb-fchange', '~> 0.0.6', require: false
|
23
|
+
gem 'rb-fsevent', '~> 0.9.3', require: false
|
24
|
+
gem 'rb-inotify', '~> 0.9.0', require: false
|
25
|
+
|
26
|
+
# notification handling
|
27
|
+
gem 'libnotify', '~> 0.8.0', require: false
|
28
|
+
gem 'rb-notifu', '~> 0.0.4', require: false
|
29
|
+
gem 'terminal-notifier-guard', '~> 1.5.3', require: false
|
30
|
+
end
|
31
|
+
|
32
|
+
group :metrics do
|
33
|
+
gem 'coveralls', '~> 0.6.7'
|
34
|
+
gem 'flay', '~> 2.4.0'
|
35
|
+
gem 'flog', '~> 4.1.1'
|
36
|
+
gem 'reek', '~> 1.3.2'
|
37
|
+
gem 'rubocop', '~> 0.13.0'
|
38
|
+
gem 'simplecov', '~> 0.7.1'
|
39
|
+
gem 'yardstick', '~> 0.9.7', git: 'https://github.com/dkubb/yardstick.git'
|
40
|
+
|
41
|
+
platforms :ruby_19, :ruby_20 do
|
42
|
+
gem 'mutant', git: 'https://github.com/mbj/mutant.git'
|
43
|
+
gem 'yard-spellcheck', '~> 0.1.5'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
group :benchmarks do
|
48
|
+
gem 'rbench', '~> 0.2.3'
|
49
|
+
end
|
50
|
+
|
51
|
+
platform :jruby do
|
52
|
+
group :jruby do
|
53
|
+
gem 'jruby-openssl', '~> 0.8.5'
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
shared_examples_for 'an abstract type' do
|
4
|
+
context 'called on a subclass' do
|
5
|
+
let(:object) { Class.new(described_class) }
|
6
|
+
|
7
|
+
it { should be_instance_of(object) }
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'called on the class' do
|
11
|
+
let(:object) { described_class }
|
12
|
+
|
13
|
+
specify do
|
14
|
+
expect { subject }
|
15
|
+
.to raise_error(NotImplementedError, "#{object} is an abstract type")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
shared_examples_for 'an #each method' do
|
4
|
+
it_should_behave_like 'a command method'
|
5
|
+
|
6
|
+
context 'with no block' do
|
7
|
+
subject { object.each }
|
8
|
+
|
9
|
+
it { should be_instance_of(to_enum.class) }
|
10
|
+
|
11
|
+
it 'yields the expected values' do
|
12
|
+
expect(subject.to_a).to eql(object.to_a)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
shared_examples_for 'a hash method' do
|
4
|
+
it_should_behave_like 'an idempotent method'
|
5
|
+
|
6
|
+
specification = proc do
|
7
|
+
should be_instance_of(Fixnum)
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'is a fixnum' do
|
11
|
+
instance_eval(&specification)
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'memoizes the hash code' do
|
15
|
+
expect(subject).to eql(object.memoized(:hash))
|
16
|
+
end
|
17
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'develry/spec_helper'
|
4
|
+
|
5
|
+
if ENV['COVERAGE'] == 'true'
|
6
|
+
require 'simplecov'
|
7
|
+
require 'coveralls'
|
8
|
+
|
9
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
10
|
+
SimpleCov::Formatter::HTMLFormatter,
|
11
|
+
Coveralls::SimpleCov::Formatter
|
12
|
+
]
|
13
|
+
|
14
|
+
SimpleCov.start do
|
15
|
+
command_name 'spec:unit'
|
16
|
+
add_filter 'config'
|
17
|
+
add_filter 'spec'
|
18
|
+
minimum_coverage 100
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'develry'
|
23
|
+
|
24
|
+
# Require spec support files and shared behavior
|
25
|
+
Dir[File.expand_path('../{support,shared}/**/*.rb', __FILE__)].each do |file|
|
26
|
+
require file.chomp('.rb')
|
27
|
+
end
|
28
|
+
|
29
|
+
RSpec.configure do |config|
|
30
|
+
config.expect_with :rspec do |expect_with|
|
31
|
+
expect_with.syntax = :expect
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
desc 'Run all metrics and integration specs'
|
4
|
+
task ci: %w[ ci:metrics metrics:mutant spec:integration ]
|
5
|
+
|
6
|
+
namespace :ci do
|
7
|
+
tasks = %w[
|
8
|
+
metrics:coverage
|
9
|
+
metrics:yardstick:verify
|
10
|
+
metrics:rubocop
|
11
|
+
metrics:flog
|
12
|
+
metrics:flay
|
13
|
+
metrics:reek
|
14
|
+
]
|
15
|
+
|
16
|
+
desc 'Run metrics (except mutant)'
|
17
|
+
task metrics: tasks
|
18
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
namespace :metrics do
|
4
|
+
begin
|
5
|
+
require 'flay'
|
6
|
+
|
7
|
+
project = Develry.project
|
8
|
+
config = project.flay
|
9
|
+
|
10
|
+
compatible_scores = %w(mri-1.9.3 mri-2.0.0)
|
11
|
+
|
12
|
+
if ! compatible_scores.include?(Develry.rvm)
|
13
|
+
task :flay do
|
14
|
+
$stderr.puts "Flay is disabled under #{Develry.rvm}"
|
15
|
+
end
|
16
|
+
elsif config.enabled?
|
17
|
+
# Original code by Marty Andrews:
|
18
|
+
# http://blog.martyandrews.net/2009/05/enforcing-ruby-code-quality.html
|
19
|
+
desc 'Measure code duplication'
|
20
|
+
task :flay do
|
21
|
+
threshold = config.threshold
|
22
|
+
total_score = config.total_score
|
23
|
+
files = Flay.expand_dirs_to_files(project.lib_dir).sort
|
24
|
+
|
25
|
+
# Run flay first to ensure the max mass matches the threshold
|
26
|
+
flay = Flay.new(fuzzy: false, verbose: false, mass: 0)
|
27
|
+
flay.process(*files)
|
28
|
+
flay.analyze
|
29
|
+
|
30
|
+
masses = flay.masses.map do |hash, mass|
|
31
|
+
Rational(mass, flay.hashes[hash].size)
|
32
|
+
end
|
33
|
+
|
34
|
+
max = (masses.max || 0).to_i
|
35
|
+
unless max >= threshold
|
36
|
+
Develry.notify "Adjust flay threshold down to #{max}"
|
37
|
+
end
|
38
|
+
|
39
|
+
total = masses.sum.to_i
|
40
|
+
unless total == total_score
|
41
|
+
Develry.notify "Flay total is now #{total}, but expected #{total_score}"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Run flay a second time with the threshold set
|
45
|
+
flay = Flay.new(fuzzy: false, verbose: false, mass: threshold.succ)
|
46
|
+
flay.process(*files)
|
47
|
+
flay.analyze
|
48
|
+
|
49
|
+
mass_size = flay.masses.size
|
50
|
+
|
51
|
+
if mass_size.nonzero?
|
52
|
+
flay.report
|
53
|
+
Develry.notify "#{mass_size} chunks have a duplicate mass > #{threshold}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
else
|
57
|
+
task :flay do
|
58
|
+
$stderr.puts 'Flay is disabled'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
rescue LoadError
|
62
|
+
task :flay do
|
63
|
+
$stderr.puts 'In order to run flay, you must: gem install flay'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
namespace :metrics do
|
4
|
+
begin
|
5
|
+
require 'backports'
|
6
|
+
require 'flog'
|
7
|
+
require 'flog_cli'
|
8
|
+
|
9
|
+
project = Develry.project
|
10
|
+
config = project.flog
|
11
|
+
|
12
|
+
compatible_scores = %w(mri-1.9.3)
|
13
|
+
|
14
|
+
if ! compatible_scores.include?(Develry.rvm)
|
15
|
+
task :flog do
|
16
|
+
$stderr.puts "Flog is disabled under #{Develry.rvm}"
|
17
|
+
end
|
18
|
+
elsif config.enabled?
|
19
|
+
# Original code by Marty Andrews:
|
20
|
+
# http://blog.martyandrews.net/2009/05/enforcing-ruby-code-quality.html
|
21
|
+
desc 'Measure code complexity'
|
22
|
+
task :flog do
|
23
|
+
threshold = config.threshold.to_f.round(1)
|
24
|
+
flog = Flog.new
|
25
|
+
flog.flog(*FlogCLI.expand_dirs_to_files(project.lib_dir))
|
26
|
+
|
27
|
+
totals = flog.totals.select { |name, score| name[-5, 5] != '#none' }
|
28
|
+
.map { |name, score| [name, score.round(1)] }
|
29
|
+
.sort_by { |name, score| score }
|
30
|
+
|
31
|
+
if totals.any?
|
32
|
+
max = totals.last[1]
|
33
|
+
unless max >= threshold
|
34
|
+
Develry.notify "Adjust flog score down to #{max}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
bad_methods = totals.select { |name, score| score > threshold }
|
39
|
+
if bad_methods.any?
|
40
|
+
bad_methods.reverse_each do |name, score|
|
41
|
+
printf "%8.1f: %s\n", score, name
|
42
|
+
end
|
43
|
+
|
44
|
+
Develry.notify(
|
45
|
+
"#{bad_methods.size} methods have a flog complexity > #{threshold}"
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
else
|
50
|
+
task :flog do
|
51
|
+
$stderr.puts 'Flog is disabled'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
rescue LoadError
|
55
|
+
task :flog do
|
56
|
+
$stderr.puts 'In order to run flog, you must: gem install flog'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
namespace :metrics do
|
4
|
+
allowed_versions = %w(mri-1.9.3 mri-2.0.0 rbx-1.9.3)
|
5
|
+
|
6
|
+
enabled = begin
|
7
|
+
require 'mutant'
|
8
|
+
rescue LoadError
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
config = Develry.project.mutant
|
13
|
+
enabled &&= config.enabled? && allowed_versions.include?(Develry.rvm)
|
14
|
+
|
15
|
+
zombify = %w(
|
16
|
+
adamantium equalizer ice_nine infecto anima concord abstract_type
|
17
|
+
descendants_tracker parser rspec unparser mutant
|
18
|
+
).include?(config.name)
|
19
|
+
|
20
|
+
if enabled && !ENV['DEVTOOLS_SELF']
|
21
|
+
desc 'Measure mutation coverage'
|
22
|
+
task mutant: :coverage do
|
23
|
+
namespace =
|
24
|
+
if zombify
|
25
|
+
Mutant::Zombifier.zombify
|
26
|
+
Zombie::Mutant
|
27
|
+
else
|
28
|
+
Mutant
|
29
|
+
end
|
30
|
+
|
31
|
+
namespaces = Array(config.namespace).map { |n| "::#{n}*" }
|
32
|
+
status = namespace::CLI.run(['--include', 'lib', '--require', config.name, *namespaces, config.strategy])
|
33
|
+
|
34
|
+
if status.nonzero?
|
35
|
+
Develry.notify 'Mutant task is not successful'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
else
|
39
|
+
desc 'Measure mutation coverage'
|
40
|
+
task mutant: :coverage do
|
41
|
+
$stderr.puts 'Mutant is disabled'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|