Add project infrastructure
* This infrastructure, especially the rake tasks should be gemified at some point in the future. I copied exactly the same bytes many times in the last month.
This commit is contained in:
commit
8c1fa8dace
23 changed files with 822 additions and 0 deletions
42
Gemfile
Normal file
42
Gemfile
Normal file
|
@ -0,0 +1,42 @@
|
|||
# encoding: utf-8
|
||||
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gemspec
|
||||
|
||||
group :development do
|
||||
gem 'rake', '~> 0.9.2'
|
||||
gem 'rspec', '~> 1.3.2'
|
||||
gem 'yard', '~> 0.8.1'
|
||||
end
|
||||
|
||||
group :guard do
|
||||
gem 'guard', '~> 1.1.1'
|
||||
gem 'guard-bundler', '~> 0.1.3'
|
||||
gem 'guard-rspec', '~> 0.7.3'
|
||||
end
|
||||
|
||||
group :metrics do
|
||||
gem 'flay', '~> 1.4.2'
|
||||
gem 'flog', '~> 2.5.1'
|
||||
gem 'reek', '~> 1.2.8', :github => 'dkubb/reek'
|
||||
gem 'roodi', '~> 2.1.0'
|
||||
gem 'yardstick', '~> 0.5.0'
|
||||
gem 'yard-spellcheck', '~> 0.1.5'
|
||||
|
||||
platforms :mri_18 do
|
||||
gem 'arrayfields', '~> 4.7.4' # for metric_fu
|
||||
gem 'fattr', '~> 2.2.0' # for metric_fu
|
||||
gem 'heckle', '~> 1.4.3'
|
||||
gem 'json', '~> 1.7.3' # for metric_fu rake task
|
||||
gem 'map', '~> 6.0.1' # for metric_fu
|
||||
gem 'metric_fu', '~> 2.1.1'
|
||||
gem 'mspec', '~> 1.5.17'
|
||||
gem 'rcov', '~> 1.0.0'
|
||||
gem 'ruby2ruby', '= 1.2.2'
|
||||
end
|
||||
|
||||
platforms :rbx do
|
||||
gem 'pelusa', '~> 0.2.1'
|
||||
end
|
||||
end
|
150
Gemfile.lock
Normal file
150
Gemfile.lock
Normal file
|
@ -0,0 +1,150 @@
|
|||
GIT
|
||||
remote: git://github.com/dkubb/reek.git
|
||||
revision: b85adad65e992e194023f6346f3e72c3b46b4c56
|
||||
specs:
|
||||
reek (1.2.8)
|
||||
ruby2ruby (~> 1.2)
|
||||
ruby_parser (~> 2.0)
|
||||
sexp_processor (~> 3.0)
|
||||
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
mutant (0.0.1)
|
||||
backports (~> 2.6.1)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
ParseTree (3.0.8)
|
||||
RubyInline (>= 3.7.0)
|
||||
sexp_processor (>= 3.0.0)
|
||||
RubyInline (3.11.3)
|
||||
ZenTest (~> 4.3)
|
||||
Saikuro (1.1.0)
|
||||
ZenTest (4.8.1)
|
||||
activesupport (3.2.6)
|
||||
i18n (~> 0.6)
|
||||
multi_json (~> 1.0)
|
||||
arrayfields (4.7.4)
|
||||
awesome_print (1.0.2)
|
||||
backports (2.6.2)
|
||||
chronic (0.3.0)
|
||||
churn (0.0.13)
|
||||
chronic (>= 0.2.3)
|
||||
hirb
|
||||
json_pure
|
||||
main
|
||||
ruby_parser (~> 2.0.4)
|
||||
sexp_processor (~> 3.0.3)
|
||||
colored (1.2)
|
||||
env (0.3.0)
|
||||
erubis (2.7.0)
|
||||
fattr (2.2.1)
|
||||
ffi (1.1.0)
|
||||
ffi-hunspell (0.2.5)
|
||||
env (~> 0.2)
|
||||
ffi (~> 1.0)
|
||||
flay (1.4.3)
|
||||
ruby_parser (~> 2.0)
|
||||
sexp_processor (~> 3.0)
|
||||
flog (2.5.3)
|
||||
ruby_parser (~> 2.0)
|
||||
sexp_processor (~> 3.0)
|
||||
guard (1.1.1)
|
||||
listen (>= 0.4.2)
|
||||
thor (>= 0.14.6)
|
||||
guard-bundler (0.1.3)
|
||||
bundler (>= 1.0.0)
|
||||
guard (>= 0.2.2)
|
||||
guard-rspec (0.7.3)
|
||||
guard (>= 0.10.0)
|
||||
heckle (1.4.3)
|
||||
ParseTree (>= 2.0.0)
|
||||
ZenTest (>= 3.5.2)
|
||||
ruby2ruby (>= 1.1.6)
|
||||
hirb (0.7.0)
|
||||
i18n (0.6.0)
|
||||
json (1.7.3)
|
||||
json_pure (1.7.3)
|
||||
listen (0.4.7)
|
||||
rb-fchange (~> 0.0.5)
|
||||
rb-fsevent (~> 0.9.1)
|
||||
rb-inotify (~> 0.8.8)
|
||||
main (4.7.1)
|
||||
map (6.0.1)
|
||||
metric_fu (2.1.1)
|
||||
Saikuro (>= 1.1.0)
|
||||
activesupport (>= 2.0.0)
|
||||
chronic (~> 0.3.0)
|
||||
churn (>= 0.0.7)
|
||||
flay (>= 1.2.1)
|
||||
flog (>= 2.3.0)
|
||||
rails_best_practices (>= 0.6.4)
|
||||
rcov (>= 0.8.3.3)
|
||||
reek (>= 1.2.6)
|
||||
roodi (>= 2.1.0)
|
||||
syntax
|
||||
mspec (1.5.17)
|
||||
multi_json (1.3.6)
|
||||
pelusa (0.2.1)
|
||||
progressbar (0.11.0)
|
||||
rails_best_practices (1.10.1)
|
||||
activesupport
|
||||
awesome_print
|
||||
colored
|
||||
erubis
|
||||
i18n
|
||||
progressbar
|
||||
sexp_processor
|
||||
rake (0.9.2.2)
|
||||
rb-fchange (0.0.5)
|
||||
ffi
|
||||
rb-fsevent (0.9.1)
|
||||
rb-inotify (0.8.8)
|
||||
ffi (>= 0.5.0)
|
||||
rcov (1.0.0)
|
||||
roodi (2.1.0)
|
||||
ruby_parser
|
||||
rspec (1.3.2)
|
||||
ruby2ruby (1.2.2)
|
||||
ParseTree (~> 3.0)
|
||||
ruby_parser (2.0.6)
|
||||
sexp_processor (~> 3.0)
|
||||
sexp_processor (3.0.10)
|
||||
syntax (1.0.0)
|
||||
thor (0.15.4)
|
||||
yard (0.8.2.1)
|
||||
yard-spellcheck (0.1.5)
|
||||
ffi-hunspell (~> 0.2)
|
||||
yard (~> 0.6)
|
||||
yardstick (0.5.0)
|
||||
yard (~> 0.8.1)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
arrayfields (~> 4.7.4)
|
||||
fattr (~> 2.2.0)
|
||||
flay (~> 1.4.2)
|
||||
flog (~> 2.5.1)
|
||||
guard (~> 1.1.1)
|
||||
guard-bundler (~> 0.1.3)
|
||||
guard-rspec (~> 0.7.3)
|
||||
heckle (~> 1.4.3)
|
||||
json (~> 1.7.3)
|
||||
map (~> 6.0.1)
|
||||
metric_fu (~> 2.1.1)
|
||||
mspec (~> 1.5.17)
|
||||
mutant!
|
||||
pelusa (~> 0.2.1)
|
||||
rake (~> 0.9.2)
|
||||
rcov (~> 1.0.0)
|
||||
reek (~> 1.2.8)!
|
||||
roodi (~> 2.1.0)
|
||||
rspec (~> 1.3.2)
|
||||
ruby2ruby (= 1.2.2)
|
||||
yard (~> 0.8.1)
|
||||
yard-spellcheck (~> 0.1.5)
|
||||
yardstick (~> 0.5.0)
|
18
Guardfile
Normal file
18
Guardfile
Normal file
|
@ -0,0 +1,18 @@
|
|||
# encoding: utf-8
|
||||
|
||||
guard :bundler do
|
||||
watch('Gemfile')
|
||||
end
|
||||
|
||||
guard :rspec do
|
||||
# run all specs if the spec_helper or supporting files files are modified
|
||||
watch('spec/spec_helper.rb') { 'spec' }
|
||||
watch(%r{\Aspec/(?:lib|support|shared)/.+\.rb\z}) { 'spec' }
|
||||
|
||||
# run unit specs if associated lib code is modified
|
||||
watch(%r{\Alib/(.+)\.rb\z}) { |m| Dir["spec/unit/#{m[1]}"] }
|
||||
watch("lib/#{File.basename(File.expand_path('../', __FILE__))}.rb") { 'spec' }
|
||||
|
||||
# run a spec if it is modified
|
||||
watch(%r{\Aspec/(?:unit|integration)/.+_spec\.rb\z})
|
||||
end
|
9
TODO
Normal file
9
TODO
Normal file
|
@ -0,0 +1,9 @@
|
|||
* Get a rid of heckle and test mutant with mutant.
|
||||
This is interesting IMHO mutant should have another entry point
|
||||
that does not create the ::Mutant namespace.
|
||||
This will be easy when there is a gem release.
|
||||
This ::Zombie namespace can be created with dynamically creating a
|
||||
new library under a differend load path. Also a gem release
|
||||
could provide this feature.
|
||||
* Get a rid of rspec-1 (can be done once we do not use heckle anymore)
|
||||
* Add an infrastructure to whitelist components to heckle.
|
3
config/flay.yml
Normal file
3
config/flay.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
threshold: 9
|
||||
total_score: 41
|
2
config/flog.yml
Normal file
2
config/flog.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
threshold: 12.4
|
26
config/roodi.yml
Normal file
26
config/roodi.yml
Normal file
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
AbcMetricMethodCheck:
|
||||
score: 12.1
|
||||
AssignmentInConditionalCheck: {}
|
||||
CaseMissingElseCheck: {}
|
||||
ClassLineCountCheck:
|
||||
line_count: 200
|
||||
ClassNameCheck:
|
||||
pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/
|
||||
ClassVariableCheck: {}
|
||||
CyclomaticComplexityBlockCheck:
|
||||
complexity: 2
|
||||
CyclomaticComplexityMethodCheck:
|
||||
complexity: 2
|
||||
EmptyRescueBodyCheck: {}
|
||||
ForLoopCheck: {}
|
||||
MethodLineCountCheck:
|
||||
line_count: 9
|
||||
MethodNameCheck:
|
||||
pattern: !ruby/regexp /\A(?:[a-z\d](?:_?[a-z\d])+[?!=]?|\[\]=?|==|<=>|<<|[+*&|-])\z/
|
||||
ModuleLineCountCheck:
|
||||
line_count: 202
|
||||
ModuleNameCheck:
|
||||
pattern: !ruby/regexp /\A(?:[A-Z]+|[A-Z][a-z](?:[A-Z]?[a-z])+)\z/
|
||||
ParameterNumberCheck:
|
||||
parameter_count: 2
|
91
config/site.reek
Normal file
91
config/site.reek
Normal file
|
@ -0,0 +1,91 @@
|
|||
---
|
||||
UncommunicativeParameterName:
|
||||
accept: []
|
||||
exclude: []
|
||||
enabled: true
|
||||
reject:
|
||||
- !ruby/regexp /^.$/
|
||||
- !ruby/regexp /[0-9]$/
|
||||
- !ruby/regexp /[A-Z]/
|
||||
LargeClass:
|
||||
max_methods: 10
|
||||
exclude: []
|
||||
enabled: true
|
||||
max_instance_variables: 3
|
||||
UncommunicativeMethodName:
|
||||
accept: []
|
||||
exclude: []
|
||||
enabled: true
|
||||
reject:
|
||||
- !ruby/regexp /^[a-z]$/
|
||||
- !ruby/regexp /[0-9]$/
|
||||
- !ruby/regexp /[A-Z]/
|
||||
LongParameterList:
|
||||
max_params: 2
|
||||
exclude: []
|
||||
enabled: true
|
||||
overrides: {}
|
||||
FeatureEnvy:
|
||||
exclude: []
|
||||
enabled: true
|
||||
ClassVariable:
|
||||
exclude: []
|
||||
enabled: true
|
||||
BooleanParameter:
|
||||
exclude: []
|
||||
enabled: true
|
||||
IrresponsibleModule:
|
||||
exclude: []
|
||||
enabled: true
|
||||
UncommunicativeModuleName:
|
||||
accept: []
|
||||
exclude: []
|
||||
enabled: true
|
||||
reject:
|
||||
- !ruby/regexp /^.$/
|
||||
- !ruby/regexp /[0-9]$/
|
||||
NestedIterators:
|
||||
ignore_iterators: []
|
||||
exclude: []
|
||||
enabled: true
|
||||
max_allowed_nesting: 1
|
||||
LongMethod:
|
||||
max_statements: 6
|
||||
exclude: []
|
||||
enabled: true
|
||||
Duplication:
|
||||
allow_calls: []
|
||||
exclude: []
|
||||
enabled: true
|
||||
max_calls: 1
|
||||
UtilityFunction:
|
||||
max_helper_calls: 0
|
||||
exclude: []
|
||||
enabled: true
|
||||
Attribute:
|
||||
exclude: []
|
||||
enabled: false
|
||||
UncommunicativeVariableName:
|
||||
accept: []
|
||||
exclude: []
|
||||
enabled: true
|
||||
reject:
|
||||
- !ruby/regexp /^.$/
|
||||
- !ruby/regexp /[0-9]$/
|
||||
- !ruby/regexp /[A-Z]/
|
||||
SimulatedPolymorphism:
|
||||
exclude: []
|
||||
enabled: true
|
||||
max_ifs: 1
|
||||
DataClump:
|
||||
exclude: []
|
||||
enabled: true
|
||||
max_copies: 2
|
||||
min_clump_size: 2
|
||||
ControlCouple:
|
||||
exclude: []
|
||||
enabled: true
|
||||
LongYieldList:
|
||||
max_params: 1
|
||||
exclude: []
|
||||
enabled: true
|
2
config/yardstick.yml
Normal file
2
config/yardstick.yml
Normal file
|
@ -0,0 +1,2 @@
|
|||
---
|
||||
threshold: 100
|
3
lib/mutant/version.rb
Normal file
3
lib/mutant/version.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
module Mutant
|
||||
VERSION = '0.0.1'.freeze
|
||||
end
|
20
mutant.gemspec
Normal file
20
mutant.gemspec
Normal file
|
@ -0,0 +1,20 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
|
||||
require File.expand_path('../lib/mutant/version.rb', __FILE__)
|
||||
|
||||
Gem::Specification.new do |gem|
|
||||
gem.name = 'mutant'
|
||||
gem.version = Mutant::VERSION.dup
|
||||
gem.authors = [ 'Markus Schirp' ]
|
||||
gem.email = [ 'mbj@seonic.net' ]
|
||||
gem.description = 'Mutation testing for ruby under rubinius'
|
||||
gem.summary = gem.description
|
||||
gem.homepage = 'https://github.com/mbj/mutant'
|
||||
|
||||
gem.require_paths = [ 'lib' ]
|
||||
gem.files = `git ls-files`.split("\n")
|
||||
gem.test_files = `git ls-files -- spec`.split("\n")
|
||||
gem.extra_rdoc_files = %w[TODO]
|
||||
|
||||
gem.add_runtime_dependency('backports', '~> 2.6.1')
|
||||
end
|
3
spec/spec.opts
Normal file
3
spec/spec.opts
Normal file
|
@ -0,0 +1,3 @@
|
|||
--color
|
||||
--loadby random
|
||||
--format profile
|
12
spec/spec_helper.rb
Normal file
12
spec/spec_helper.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
# encoding: utf-8
|
||||
|
||||
require 'mutant'
|
||||
require 'spec'
|
||||
require 'spec/autorun'
|
||||
|
||||
# require spec support files and shared behavior
|
||||
Dir[File.expand_path('../{support,shared}/**/*.rb', __FILE__)].each { |f| require f }
|
||||
|
||||
Spec::Runner.configure do |config|
|
||||
config.extend Spec::ExampleGroupMethods
|
||||
end
|
7
tasks/metrics/ci.rake
Normal file
7
tasks/metrics/ci.rake
Normal file
|
@ -0,0 +1,7 @@
|
|||
desc 'Run metrics with Heckle'
|
||||
task :ci => %w[ ci:metrics heckle ]
|
||||
|
||||
namespace :ci do
|
||||
desc 'Run metrics'
|
||||
task :metrics => %w[ verify_measurements flog flay reek roodi metrics:all ]
|
||||
end
|
47
tasks/metrics/flay.rake
Normal file
47
tasks/metrics/flay.rake
Normal file
|
@ -0,0 +1,47 @@
|
|||
begin
|
||||
if RUBY_VERSION == '1.8.7' and !defined?(RUBY_ENGINE)
|
||||
require 'flay'
|
||||
require 'yaml'
|
||||
|
||||
config = YAML.load_file(File.expand_path('../../../config/flay.yml', __FILE__)).freeze
|
||||
threshold = config.fetch('threshold').to_i
|
||||
total_score = config.fetch('total_score').to_f
|
||||
files = Flay.expand_dirs_to_files(config.fetch('path', 'lib'))
|
||||
|
||||
# original code by Marty Andrews:
|
||||
# http://blog.martyandrews.net/2009/05/enforcing-ruby-code-quality.html
|
||||
desc 'Analyze for code duplication'
|
||||
task :flay do
|
||||
# run flay once without a threshold to ensure the max mass matches the threshold
|
||||
flay = Flay.new(:fuzzy => false, :verbose => false, :mass => 0)
|
||||
flay.process(*files)
|
||||
|
||||
max = flay.masses.map { |hash, mass| mass.to_f / flay.hashes[hash].size }.max
|
||||
unless max >= threshold
|
||||
raise "Adjust flay threshold down to #{max}"
|
||||
end
|
||||
|
||||
total = flay.masses.reduce(0.0) { |total, (hash, mass)| total + (mass.to_f / flay.hashes[hash].size) }
|
||||
unless total == total_score
|
||||
raise "Flay total is now #{total}, but expected #{total_score}"
|
||||
end
|
||||
|
||||
# run flay a second time with the threshold set
|
||||
flay = Flay.new(:fuzzy => false, :verbose => false, :mass => threshold.succ)
|
||||
flay.process(*files)
|
||||
|
||||
if flay.masses.any?
|
||||
flay.report
|
||||
raise "#{flay.masses.size} chunks of code have a duplicate mass > #{threshold}"
|
||||
end
|
||||
end
|
||||
else
|
||||
task :flay do
|
||||
$stderr.puts 'Flay has inconsistend results accros ruby implementations. It is only enabled on 1.8.7, fix and remove guard'
|
||||
end
|
||||
end
|
||||
rescue LoadError
|
||||
task :flay do
|
||||
abort 'Flay is not available. In order to run flay, you must: gem install flay'
|
||||
end
|
||||
end
|
43
tasks/metrics/flog.rake
Normal file
43
tasks/metrics/flog.rake
Normal file
|
@ -0,0 +1,43 @@
|
|||
begin
|
||||
require 'flog'
|
||||
require 'yaml'
|
||||
|
||||
class Float
|
||||
def round_to(n)
|
||||
(self * 10**n).round.to_f * 10**-n
|
||||
end
|
||||
end
|
||||
|
||||
config = YAML.load_file(File.expand_path('../../../config/flog.yml', __FILE__)).freeze
|
||||
threshold = config.fetch('threshold').to_f.round_to(1)
|
||||
|
||||
# original code by Marty Andrews:
|
||||
# http://blog.martyandrews.net/2009/05/enforcing-ruby-code-quality.html
|
||||
desc 'Analyze for code complexity'
|
||||
task :flog do
|
||||
flog = Flog.new
|
||||
flog.flog Array(config.fetch('path', 'lib'))
|
||||
|
||||
totals = flog.totals.select { |name, score| name[-5, 5] != '#none' }.
|
||||
map { |name, score| [ name, score.round_to(1) ] }.
|
||||
sort_by { |name, score| score }
|
||||
|
||||
max = totals.last[1]
|
||||
unless max >= threshold
|
||||
raise "Adjust flog score down to #{max}"
|
||||
end
|
||||
|
||||
bad_methods = totals.select { |name, score| score > threshold }
|
||||
if bad_methods.any?
|
||||
bad_methods.reverse_each do |name, score|
|
||||
puts '%8.1f: %s' % [ score, name ]
|
||||
end
|
||||
|
||||
raise "#{bad_methods.size} methods have a flog complexity > #{threshold}"
|
||||
end
|
||||
end
|
||||
rescue LoadError
|
||||
task :flog do
|
||||
abort 'Flog is not available. In order to run flog, you must: gem install flog'
|
||||
end
|
||||
end
|
208
tasks/metrics/heckle.rake
Normal file
208
tasks/metrics/heckle.rake
Normal file
|
@ -0,0 +1,208 @@
|
|||
$LOAD_PATH.unshift(File.expand_path('../../../lib', __FILE__))
|
||||
|
||||
# original code by Ashley Moran:
|
||||
# http://aviewfromafar.net/2007/11/1/rake-task-for-heckling-your-specs
|
||||
|
||||
begin
|
||||
require 'pathname'
|
||||
require 'backports'
|
||||
require 'active_support/inflector'
|
||||
require 'heckle'
|
||||
require 'mspec'
|
||||
require 'mspec/utils/name_map'
|
||||
|
||||
SKIP_METHODS = %w[ blank_slate_method_added ].freeze
|
||||
|
||||
class NameMap
|
||||
def file_name(method, constant)
|
||||
map = MAP[method]
|
||||
name = if map
|
||||
map[constant] || map[:default]
|
||||
else
|
||||
method.
|
||||
gsub('?','_ques').
|
||||
gsub('!','_bang').
|
||||
gsub('=','_assign')
|
||||
end
|
||||
"#{name}_spec.rb"
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Heckle each module and class'
|
||||
task :heckle => :rcov do
|
||||
unless Ruby2Ruby::VERSION == '1.2.2'
|
||||
raise "ruby2ruby version #{Ruby2Ruby::VERSION} may not work properly, 1.2.2 *only* is recommended for use with heckle"
|
||||
end
|
||||
|
||||
require 'veritas-mongo-adapter'
|
||||
|
||||
root_module_regexp = Regexp.union('Mutant')
|
||||
|
||||
spec_dir = Pathname('spec/unit')
|
||||
|
||||
NameMap::MAP.each do |op, method|
|
||||
next if method.kind_of?(Hash)
|
||||
NameMap::MAP[op] = { :default => method }
|
||||
end
|
||||
|
||||
aliases = Hash.new { |h,mod| h[mod] = Hash.new { |h,method| h[method] = method } }
|
||||
map = NameMap.new
|
||||
|
||||
heckle_caught_modules = Hash.new { |hash, key| hash[key] = [] }
|
||||
unhandled_mutations = 0
|
||||
|
||||
ObjectSpace.each_object(Module) do |mod|
|
||||
next unless mod.name =~ /\A#{root_module_regexp}(?::|\z)/
|
||||
|
||||
spec_prefix = spec_dir.join(mod.name.underscore)
|
||||
|
||||
specs = []
|
||||
|
||||
# get the public class methods
|
||||
metaclass = class << mod; self end
|
||||
ancestors = metaclass.ancestors
|
||||
|
||||
spec_class_methods = mod.singleton_methods(false)
|
||||
|
||||
spec_class_methods.reject! do |method|
|
||||
%w[ yaml_new yaml_tag_subclasses? included nesting constants ].include?(method.to_s)
|
||||
end
|
||||
|
||||
if mod.ancestors.include?(Singleton)
|
||||
spec_class_methods.reject! { |method| method.to_s == 'instance' }
|
||||
end
|
||||
|
||||
# get the protected and private class methods
|
||||
other_class_methods = metaclass.protected_instance_methods(false) |
|
||||
metaclass.private_instance_methods(false)
|
||||
|
||||
ancestors.each do |ancestor|
|
||||
other_class_methods -= ancestor.protected_instance_methods(false) |
|
||||
ancestor.private_instance_methods(false)
|
||||
end
|
||||
|
||||
other_class_methods.reject! do |method|
|
||||
method.to_s == 'allocate' || SKIP_METHODS.include?(method.to_s)
|
||||
end
|
||||
|
||||
other_class_methods.reject! do |method|
|
||||
next unless spec_class_methods.any? { |specced| specced.to_s == $1 }
|
||||
|
||||
spec_class_methods << method
|
||||
end
|
||||
|
||||
# get the instances methods
|
||||
spec_methods = mod.public_instance_methods(false)
|
||||
|
||||
other_methods = mod.protected_instance_methods(false) |
|
||||
mod.private_instance_methods(false)
|
||||
|
||||
other_methods.reject! do |method|
|
||||
next unless spec_methods.any? { |specced| specced.to_s == $1 }
|
||||
|
||||
spec_methods << method
|
||||
end
|
||||
|
||||
# map the class methods to spec files
|
||||
spec_class_methods.each do |method|
|
||||
method = aliases[mod.name][method]
|
||||
next if SKIP_METHODS.include?(method.to_s)
|
||||
|
||||
spec_file = spec_prefix.join('class_methods').join(map.file_name(method, mod.name))
|
||||
|
||||
unless spec_file.file?
|
||||
raise "No spec file #{spec_file} for #{mod}.#{method}"
|
||||
next
|
||||
end
|
||||
|
||||
specs << [ ".#{method}", [ spec_file ] ]
|
||||
end
|
||||
|
||||
# map the instance methods to spec files
|
||||
spec_methods.each do |method|
|
||||
method = aliases[mod.name][method]
|
||||
next if SKIP_METHODS.include?(method.to_s)
|
||||
|
||||
spec_file = spec_prefix.join(map.file_name(method, mod.name))
|
||||
|
||||
unless spec_file.file?
|
||||
raise "No spec file #{spec_file} for #{mod}##{method}"
|
||||
next
|
||||
end
|
||||
|
||||
specs << [ "##{method}", [ spec_file ] ]
|
||||
end
|
||||
|
||||
# non-public methods are considered covered if they can be mutated
|
||||
# and any spec fails for the current or descendant modules
|
||||
other_methods.each do |method|
|
||||
descedant_specs = []
|
||||
|
||||
ObjectSpace.each_object(Module) do |descedant|
|
||||
next unless descedant.name =~ /\A#{root_module_regexp}(?::|\z)/ && mod >= descedant
|
||||
descedant_spec_prefix = spec_dir.join(descedant.name.underscore)
|
||||
descedant_specs << descedant_spec_prefix
|
||||
|
||||
if method.to_s == 'initialize'
|
||||
descedant_specs.concat(Pathname.glob(descedant_spec_prefix.join('class_methods/new_spec.rb')))
|
||||
end
|
||||
end
|
||||
|
||||
specs << [ "##{method}", descedant_specs ]
|
||||
end
|
||||
|
||||
other_class_methods.each do |method|
|
||||
descedant_specs = []
|
||||
|
||||
ObjectSpace.each_object(Module) do |descedant|
|
||||
next unless descedant.name =~ /\A#{root_module_regexp}(?::|\z)/ && mod >= descedant
|
||||
descedant_specs << spec_dir.join(descedant.name.underscore).join('class_methods')
|
||||
end
|
||||
|
||||
specs << [ ".#{method}", descedant_specs ]
|
||||
end
|
||||
|
||||
specs.sort.each do |(method, spec_files)|
|
||||
puts "Heckling #{mod}#{method}"
|
||||
IO.popen("spec #{spec_files.join(' ')} --heckle '#{mod}#{method}'") do |pipe|
|
||||
while line = pipe.gets
|
||||
case line = line.chomp
|
||||
when "The following mutations didn't cause test failures:"
|
||||
heckle_caught_modules[mod.name] << method
|
||||
when '+++ mutation'
|
||||
unhandled_mutations += 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if unhandled_mutations > 0
|
||||
error_message_lines = [ "*************\n" ]
|
||||
|
||||
error_message_lines << "Heckle found #{unhandled_mutations} " \
|
||||
"mutation#{"s" unless unhandled_mutations == 1} " \
|
||||
"that didn't cause spec violations\n"
|
||||
|
||||
heckle_caught_modules.each do |mod, methods|
|
||||
error_message_lines << "#{mod} contains the following " \
|
||||
'poorly-specified methods:'
|
||||
methods.each do |method|
|
||||
error_message_lines << " - #{method}"
|
||||
end
|
||||
error_message_lines << ''
|
||||
end
|
||||
|
||||
error_message_lines << 'Get your act together and come back ' \
|
||||
'when your specs are doing their job!'
|
||||
|
||||
raise error_message_lines.join("\n")
|
||||
else
|
||||
puts 'Well done! Your code withstood a heckling.'
|
||||
end
|
||||
end
|
||||
rescue LoadError
|
||||
task :heckle => :spec do
|
||||
$stderr.puts 'Heckle or mspec is not available. In order to run heckle, you must: gem install heckle mspec'
|
||||
end
|
||||
end
|
29
tasks/metrics/metric_fu.rake
Normal file
29
tasks/metrics/metric_fu.rake
Normal file
|
@ -0,0 +1,29 @@
|
|||
begin
|
||||
require 'metric_fu'
|
||||
require 'json'
|
||||
|
||||
# XXX: temporary hack until metric_fu is fixed
|
||||
MetricFu::Saikuro.class_eval { include FileUtils }
|
||||
|
||||
MetricFu::Configuration.run do |config|
|
||||
config.rcov = {
|
||||
:environment => 'test',
|
||||
:test_files => %w[ spec/**/*_spec.rb ],
|
||||
:rcov_opts => %w[
|
||||
--sort coverage
|
||||
--no-html
|
||||
--text-coverage
|
||||
--no-color
|
||||
--profile
|
||||
--exclude spec/,^/
|
||||
--include lib:spec
|
||||
],
|
||||
}
|
||||
end
|
||||
rescue LoadError
|
||||
namespace :metrics do
|
||||
task :all do
|
||||
$stderr.puts 'metric_fu is not available. In order to run metrics:all, you must: gem install metric_fu'
|
||||
end
|
||||
end
|
||||
end
|
15
tasks/metrics/reek.rake
Normal file
15
tasks/metrics/reek.rake
Normal file
|
@ -0,0 +1,15 @@
|
|||
begin
|
||||
require 'reek/rake/task'
|
||||
|
||||
if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'rbx'
|
||||
task :reek do
|
||||
$stderr.puts 'Reek fails under rubinius, fix rubinius and remove guard'
|
||||
end
|
||||
else
|
||||
Reek::Rake::Task.new
|
||||
end
|
||||
rescue LoadError
|
||||
task :reek do
|
||||
$stderr.puts 'Reek is not available. In order to run reek, you must: gem install reek'
|
||||
end
|
||||
end
|
15
tasks/metrics/roodi.rake
Normal file
15
tasks/metrics/roodi.rake
Normal file
|
@ -0,0 +1,15 @@
|
|||
begin
|
||||
require 'roodi'
|
||||
require 'rake/tasklib'
|
||||
require 'roodi_task'
|
||||
|
||||
RoodiTask.new do |t|
|
||||
t.verbose = false
|
||||
t.config = File.expand_path('../../../config/roodi.yml', __FILE__)
|
||||
t.patterns = %w[ lib/**/*.rb ]
|
||||
end
|
||||
rescue LoadError
|
||||
task :roodi do
|
||||
abort 'Roodi is not available. In order to run roodi, you must: gem install roodi'
|
||||
end
|
||||
end
|
23
tasks/metrics/yardstick.rake
Normal file
23
tasks/metrics/yardstick.rake
Normal file
|
@ -0,0 +1,23 @@
|
|||
begin
|
||||
require 'pathname'
|
||||
require 'yardstick'
|
||||
require 'yardstick/rake/measurement'
|
||||
require 'yardstick/rake/verify'
|
||||
require 'yaml'
|
||||
|
||||
config = YAML.load_file(File.expand_path('../../../config/yardstick.yml', __FILE__))
|
||||
|
||||
# yardstick_measure task
|
||||
Yardstick::Rake::Measurement.new
|
||||
|
||||
# verify_measurements task
|
||||
Yardstick::Rake::Verify.new do |verify|
|
||||
verify.threshold = config.fetch('threshold')
|
||||
end
|
||||
rescue LoadError
|
||||
%w[ yardstick_measure verify_measurements ].each do |name|
|
||||
task name.to_s do
|
||||
abort "Yardstick is not available. In order to run #{name}, you must: gem install yardstick"
|
||||
end
|
||||
end
|
||||
end
|
45
tasks/spec.rake
Normal file
45
tasks/spec.rake
Normal file
|
@ -0,0 +1,45 @@
|
|||
begin
|
||||
|
||||
begin
|
||||
require 'rspec/core/rake_task'
|
||||
rescue LoadError
|
||||
require 'spec/rake/spectask'
|
||||
|
||||
module RSpec
|
||||
module Core
|
||||
RakeTask = Spec::Rake::SpecTask
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc 'run all specs'
|
||||
task :spec => %w[ spec:unit spec:integration ]
|
||||
|
||||
namespace :spec do
|
||||
RSpec::Core::RakeTask.new(:integration) do |t|
|
||||
t.pattern = 'spec/integration/**/*_spec.rb'
|
||||
end
|
||||
|
||||
RSpec::Core::RakeTask.new(:unit) do |t|
|
||||
t.pattern = 'spec/unit/**/*_spec.rb'
|
||||
end
|
||||
end
|
||||
rescue LoadError
|
||||
task :spec do
|
||||
abort 'rspec is not available. In order to run spec, you must: gem install rspec'
|
||||
end
|
||||
end
|
||||
|
||||
begin
|
||||
desc "Generate code coverage"
|
||||
RSpec::Core::RakeTask.new(:rcov) do |t|
|
||||
t.rcov = true
|
||||
t.rcov_opts = File.read('spec/rcov.opts').split(/\s+/)
|
||||
end
|
||||
rescue LoadError
|
||||
task :rcov do
|
||||
abort 'rcov is not available. In order to run rcov, you must: gem install rcov'
|
||||
end
|
||||
end
|
||||
|
||||
task :test => 'spec'
|
9
tasks/yard.rake
Normal file
9
tasks/yard.rake
Normal file
|
@ -0,0 +1,9 @@
|
|||
begin
|
||||
require 'yard'
|
||||
|
||||
YARD::Rake::YardocTask.new
|
||||
rescue LoadError
|
||||
task :yard do
|
||||
abort 'YARD is not available. In order to run yard, you must: gem install yard'
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue