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.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +37 -0
  3. data/.rspec +5 -0
  4. data/.ruby-gemset +1 -0
  5. data/.travis.yml +30 -0
  6. data/Gemfile +7 -0
  7. data/Guardfile +32 -0
  8. data/LICENSE +20 -0
  9. data/README.md +71 -0
  10. data/Rakefile +5 -0
  11. data/TODO +0 -0
  12. data/bin/develry +18 -0
  13. data/config/flay.yml +3 -0
  14. data/config/flog.yml +2 -0
  15. data/config/mutant.yml +2 -0
  16. data/config/reek.yml +106 -0
  17. data/config/rubocop.yml +66 -0
  18. data/config/yardstick.yml +2 -0
  19. data/default/config/develry.yml +4 -0
  20. data/default/config/flay.yml +3 -0
  21. data/default/config/flog.yml +2 -0
  22. data/default/config/mutant.yml +3 -0
  23. data/default/config/reek.yml +103 -0
  24. data/default/config/rubocop.yml +58 -0
  25. data/default/config/yardstick.yml +2 -0
  26. data/develry.gemspec +53 -0
  27. data/lib/develry.rb +164 -0
  28. data/lib/develry/config.rb +167 -0
  29. data/lib/develry/platform.rb +118 -0
  30. data/lib/develry/project.rb +144 -0
  31. data/lib/develry/project/initializer.rb +21 -0
  32. data/lib/develry/project/initializer/rake.rb +19 -0
  33. data/lib/develry/project/initializer/rspec.rb +104 -0
  34. data/lib/develry/site.rb +64 -0
  35. data/lib/develry/site/initializer.rb +73 -0
  36. data/lib/develry/spec_helper.rb +5 -0
  37. data/shared/Gemfile +55 -0
  38. data/shared/spec/shared/abstract_type_behavior.rb +18 -0
  39. data/shared/spec/shared/command_method_behavior.rb +7 -0
  40. data/shared/spec/shared/each_method_behaviour.rb +15 -0
  41. data/shared/spec/shared/hash_method_behavior.rb +17 -0
  42. data/shared/spec/shared/idempotent_method_behavior.rb +9 -0
  43. data/shared/spec/support/ice_nine_config.rb +14 -0
  44. data/spec/spec_helper.rb +33 -0
  45. data/tasks/metrics/ci.rake +18 -0
  46. data/tasks/metrics/coverage.rake +13 -0
  47. data/tasks/metrics/flay.rake +66 -0
  48. data/tasks/metrics/flog.rake +59 -0
  49. data/tasks/metrics/mutant.rake +44 -0
  50. data/tasks/metrics/reek.rake +27 -0
  51. data/tasks/metrics/rubocop.rake +18 -0
  52. data/tasks/metrics/yardstick.rake +42 -0
  53. data/tasks/spec.rake +28 -0
  54. data/tasks/yard.rake +11 -0
  55. 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
@@ -0,0 +1,5 @@
1
+ # encoding: utf-8
2
+
3
+ require 'develry'
4
+
5
+ Develry.init_spec_helper
@@ -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,7 @@
1
+ # encoding: utf-8
2
+
3
+ shared_examples_for 'a command method' do
4
+ it 'returns self' do
5
+ should equal(object)
6
+ end
7
+ 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
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ shared_examples_for 'an idempotent method' do
4
+ it 'is idempotent' do
5
+ first = subject
6
+ __memoized.delete(:subject)
7
+ should equal(first)
8
+ end
9
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ if defined?(IceNine)
4
+ module IceNine
5
+
6
+ # Freezer namespace
7
+ class Freezer
8
+
9
+ # Rspec freezer
10
+ class RSpec < NoFreeze; end
11
+
12
+ end # Freezer
13
+ end # IceNine
14
+ end
@@ -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,13 @@
1
+ # encoding: utf-8
2
+
3
+ namespace :metrics do
4
+ desc 'Measure code coverage'
5
+ task :coverage do
6
+ begin
7
+ original, ENV['COVERAGE'] = ENV['COVERAGE'], 'true'
8
+ Rake::Task['spec:unit'].invoke
9
+ ensure
10
+ ENV['COVERAGE'] = original
11
+ end
12
+ end
13
+ 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