descendants_tracker 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,17 +0,0 @@
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
- subject.should eql(object.memoized(:hash))
16
- end
17
- end
@@ -1,7 +0,0 @@
1
- # encoding: utf-8
2
-
3
- shared_examples_for 'an idempotent method' do
4
- it 'is idempotent' do
5
- should equal(instance_eval(&self.class.subject))
6
- end
7
- end
@@ -1,9 +0,0 @@
1
- # encoding: utf-8
2
-
3
- shared_examples_for 'an invertible method' do
4
- it_should_behave_like 'an idempotent method'
5
-
6
- it 'is invertible' do
7
- subject.inverse.should equal(object)
8
- end
9
- end
@@ -1,9 +0,0 @@
1
- # encoding: utf-8
2
-
3
- desc 'Run metrics with Heckle'
4
- task :ci => %w[ ci:metrics metrics:heckle ]
5
-
6
- namespace :ci do
7
- desc 'Run metrics (except heckle) and spec'
8
- task :metrics => %w[ spec metrics:verify_measurements metrics:flog metrics:flay metrics:reek metrics:roodi metrics:all ]
9
- end
@@ -1,45 +0,0 @@
1
- # encoding: utf-8
2
-
3
- begin
4
- require 'flay'
5
- require 'yaml'
6
-
7
- config = YAML.load_file(File.expand_path('../../../config/flay.yml', __FILE__)).freeze
8
- threshold = config.fetch('threshold').to_i
9
- total_score = config.fetch('total_score').to_f
10
- files = Flay.expand_dirs_to_files(config.fetch('path', 'lib')).sort
11
-
12
- namespace :metrics do
13
- # original code by Marty Andrews:
14
- # http://blog.martyandrews.net/2009/05/enforcing-ruby-code-quality.html
15
- desc 'Analyze for code duplication'
16
- task :flay do
17
- # run flay once without a threshold to ensure the max mass matches the threshold
18
- flay = Flay.new(:fuzzy => false, :verbose => false, :mass => 0)
19
- flay.process(*files)
20
-
21
- max = (flay.masses.map { |hash, mass| mass.to_f / flay.hashes[hash].size }.max) || 0
22
- unless max >= threshold
23
- raise "Adjust flay threshold down to #{max}"
24
- end
25
-
26
- total = flay.masses.reduce(0.0) { |total, (hash, mass)| total + (mass.to_f / flay.hashes[hash].size) }
27
- unless total == total_score
28
- raise "Flay total is now #{total}, but expected #{total_score}"
29
- end
30
-
31
- # run flay a second time with the threshold set
32
- flay = Flay.new(:fuzzy => false, :verbose => false, :mass => threshold.succ)
33
- flay.process(*files)
34
-
35
- if flay.masses.any?
36
- flay.report
37
- raise "#{flay.masses.size} chunks of code have a duplicate mass > #{threshold}"
38
- end
39
- end
40
- end
41
- rescue LoadError
42
- task :flay do
43
- $stderr.puts 'Flay is not available. In order to run flay, you must: gem install flay'
44
- end
45
- end
@@ -1,49 +0,0 @@
1
- # encoding: utf-8
2
-
3
- begin
4
- require 'flog'
5
- require 'yaml'
6
-
7
- class Float
8
- def round_to(n)
9
- (self * 10**n).round.to_f * 10**-n
10
- end
11
- end
12
-
13
- config = YAML.load_file(File.expand_path('../../../config/flog.yml', __FILE__)).freeze
14
- threshold = config.fetch('threshold').to_f.round_to(1)
15
-
16
- namespace :metrics do
17
- # original code by Marty Andrews:
18
- # http://blog.martyandrews.net/2009/05/enforcing-ruby-code-quality.html
19
- desc 'Analyze for code complexity'
20
- task :flog do
21
- flog = Flog.new
22
- flog.flog Array(config.fetch('path', 'lib'))
23
-
24
- totals = flog.totals.select { |name, score| name[-5, 5] != '#none' }.
25
- map { |name, score| [ name, score.round_to(1) ] }.
26
- sort_by { |name, score| score }
27
-
28
- if totals.any?
29
- max = totals.last[1]
30
- unless max >= threshold
31
- raise "Adjust flog score down to #{max}"
32
- end
33
- end
34
-
35
- bad_methods = totals.select { |name, score| score > threshold }
36
- if bad_methods.any?
37
- bad_methods.reverse_each do |name, score|
38
- puts '%8.1f: %s' % [ score, name ]
39
- end
40
-
41
- raise "#{bad_methods.size} methods have a flog complexity > #{threshold}"
42
- end
43
- end
44
- end
45
- rescue LoadError
46
- task :flog do
47
- $stderr.puts 'Flog is not available. In order to run flog, you must: gem install flog'
48
- end
49
- end
@@ -1,208 +0,0 @@
1
- # encoding: utf-8
2
-
3
- $LOAD_PATH.unshift(File.expand_path('../../../lib', __FILE__))
4
-
5
- # original code by Ashley Moran:
6
- # http://aviewfromafar.net/2007/11/1/rake-task-for-heckling-your-specs
7
-
8
- begin
9
- require 'pathname'
10
- require 'heckle'
11
- require 'mspec'
12
- require 'mspec/utils/name_map'
13
-
14
- SKIP_METHODS = %w[ blank_slate_method_added ].freeze
15
-
16
- class NameMap
17
- def file_name(method, constant)
18
- map = MAP[method]
19
- name = if map
20
- map[constant] || map[:default]
21
- else
22
- method.gsub(/[?!=]\z/, '')
23
- end
24
- "#{name}_spec.rb"
25
- end
26
- end
27
-
28
- namespace :metrics do
29
- desc 'Heckle each module and class'
30
- task :heckle => :coverage do
31
- unless Ruby2Ruby::VERSION == '1.2.2'
32
- raise "ruby2ruby version #{Ruby2Ruby::VERSION} may not work properly, 1.2.2 *only* is recommended for use with heckle"
33
- end
34
-
35
- require 'descendants_tracker'
36
-
37
- root_module_regexp = Regexp.union('DescendantsTracker')
38
-
39
- spec_dir = Pathname('spec/unit')
40
-
41
- NameMap::MAP.each do |op, method|
42
- next if method.kind_of?(Hash)
43
- NameMap::MAP[op] = { :default => method }
44
- end
45
-
46
- aliases = Hash.new { |h,mod| h[mod] = Hash.new { |h,method| h[method] = method } }
47
- map = NameMap.new
48
-
49
- heckle_caught_modules = Hash.new { |hash, key| hash[key] = [] }
50
- uncovered_methods = 0
51
-
52
- ObjectSpace.each_object(Module) do |mod|
53
- next unless mod.name =~ /\A#{root_module_regexp}(?::|\z)/
54
-
55
- spec_prefix = spec_dir.join(mod.name.underscore)
56
-
57
- specs = []
58
-
59
- # get the public class methods
60
- metaclass = class << mod; self end
61
- ancestors = metaclass.ancestors
62
-
63
- spec_class_methods = mod.singleton_methods(false)
64
-
65
- spec_class_methods.reject! do |method|
66
- %w[ yaml_new yaml_tag_subclasses? included nesting constants ].include?(method.to_s)
67
- end
68
-
69
- if mod.ancestors.include?(Singleton)
70
- spec_class_methods.reject! { |method| method.to_s == 'instance' }
71
- end
72
-
73
- # get the protected and private class methods
74
- other_class_methods = metaclass.protected_instance_methods(false) |
75
- metaclass.private_instance_methods(false)
76
-
77
- ancestors.each do |ancestor|
78
- other_class_methods -= ancestor.protected_instance_methods(false) |
79
- ancestor.private_instance_methods(false)
80
- end
81
-
82
- other_class_methods.reject! do |method|
83
- method.to_s == 'allocate' || SKIP_METHODS.include?(method.to_s)
84
- end
85
-
86
- other_class_methods.reject! do |method|
87
- next unless spec_class_methods.any? { |specced| specced.to_s == $1 }
88
-
89
- spec_class_methods << method
90
- end
91
-
92
- spec_class_methods -= other_class_methods
93
-
94
- # get the instances methods
95
- spec_methods = mod.public_instance_methods(false)
96
-
97
- other_methods = mod.protected_instance_methods(false) |
98
- mod.private_instance_methods(false)
99
-
100
- other_methods.reject! do |method|
101
- next unless spec_methods.any? { |specced| specced.to_s == $1 }
102
-
103
- spec_methods << method
104
- end
105
-
106
- # map the class methods to spec files
107
- spec_class_methods.each do |method|
108
- method = aliases[mod.name][method]
109
- next if SKIP_METHODS.include?(method.to_s)
110
-
111
- spec_file = spec_prefix.join('class_methods').join(map.file_name(method, mod.name))
112
-
113
- unless spec_file.file?
114
- raise "No spec file #{spec_file} for #{mod}.#{method}"
115
- end
116
-
117
- specs << [ ".#{method}", [ spec_file ] ]
118
- end
119
-
120
- # map the instance methods to spec files
121
- spec_methods.each do |method|
122
- method = aliases[mod.name][method]
123
- next if SKIP_METHODS.include?(method.to_s)
124
-
125
- spec_file = spec_prefix.join(map.file_name(method, mod.name))
126
-
127
- unless spec_file.file?
128
- raise "No spec file #{spec_file} for #{mod}##{method}"
129
- end
130
-
131
- specs << [ "##{method}", [ spec_file ] ]
132
- end
133
-
134
- # non-public methods are considered covered if they can be mutated
135
- # and any spec fails for the current or descendant modules
136
- other_methods.each do |method|
137
- descedant_specs = []
138
-
139
- ObjectSpace.each_object(Module) do |descedant|
140
- next unless descedant.name =~ /\A#{root_module_regexp}(?::|\z)/ && mod >= descedant
141
- descedant_spec_prefix = spec_dir.join(descedant.name.underscore)
142
- descedant_specs << descedant_spec_prefix
143
-
144
- if method.to_s == 'initialize'
145
- descedant_specs.concat(Pathname.glob(descedant_spec_prefix.join('class_methods/new_spec.rb')))
146
- end
147
- end
148
-
149
- specs << [ "##{method}", descedant_specs ]
150
- end
151
-
152
- other_class_methods.each do |method|
153
- descedant_specs = []
154
-
155
- ObjectSpace.each_object(Module) do |descedant|
156
- next unless descedant.name =~ /\A#{root_module_regexp}(?::|\z)/ && mod >= descedant
157
- descedant_specs << spec_dir.join(descedant.name.underscore).join('class_methods')
158
- end
159
-
160
- specs << [ ".#{method}", descedant_specs ]
161
- end
162
-
163
- specs.sort.each do |(method, spec_files)|
164
- puts "Heckling #{mod}#{method}"
165
- IO.popen("spec #{spec_files.join(' ')} --heckle '#{mod}#{method}'") do |pipe|
166
- while line = pipe.gets
167
- case line = line.chomp
168
- when "The following mutations didn't cause test failures:"
169
- heckle_caught_modules[mod.name] << method
170
- uncovered_methods += 1
171
- end
172
- end
173
- end
174
- end
175
- end
176
-
177
- if uncovered_methods > 0
178
- error_message_lines = [ "*************\n" ]
179
-
180
- error_message_lines << "Heckle found #{uncovered_methods} " \
181
- "method#{"s" unless uncovered_methods == 1} " \
182
- "where mutations didn't cause spec violations\n"
183
-
184
- heckle_caught_modules.each do |mod, methods|
185
- error_message_lines << "#{mod} contains the following " \
186
- 'poorly-specified methods:'
187
- methods.each do |method|
188
- error_message_lines << " - #{method}"
189
- end
190
- error_message_lines << ''
191
- end
192
-
193
- error_message_lines << 'Get your act together and come back ' \
194
- 'when your specs are doing their job!'
195
-
196
- raise error_message_lines.join("\n")
197
- else
198
- puts 'Well done! Your code withstood a heckling.'
199
- end
200
- end
201
- end
202
- rescue LoadError
203
- namespace :metrics do
204
- task :heckle => :coverage do
205
- $stderr.puts 'Heckle or mspec is not available. In order to run heckle, you must: gem install heckle mspec'
206
- end
207
- end
208
- end
@@ -1,31 +0,0 @@
1
- # encoding: utf-8
2
-
3
- begin
4
- require 'metric_fu'
5
- require 'json'
6
-
7
- # XXX: temporary hack until metric_fu is fixed
8
- MetricFu::Saikuro.class_eval { include FileUtils }
9
-
10
- MetricFu::Configuration.run do |config|
11
- config.rcov = {
12
- :environment => 'test',
13
- :test_files => %w[ spec/**/*_spec.rb ],
14
- :rcov_opts => %w[
15
- --sort coverage
16
- --no-html
17
- --text-coverage
18
- --no-color
19
- --profile
20
- --exclude spec/,^/
21
- --include lib:spec
22
- ],
23
- }
24
- end
25
- rescue LoadError
26
- namespace :metrics do
27
- task :all do
28
- $stderr.puts 'metric_fu is not available. In order to run metrics:all, you must: gem install metric_fu'
29
- end
30
- end
31
- end
@@ -1,21 +0,0 @@
1
- # encoding: utf-8
2
-
3
- begin
4
- require 'reek/rake/task'
5
-
6
- RBX_18_MODE = RUBY_VERSION < '1.9' && defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
7
-
8
- namespace :metrics do
9
- Reek::Rake::Task.new do |t|
10
- # reek has some problems under rbx in 1.8 mode that cause the underlying
11
- # script to raise an exception. Rather than halt the "rake ci" process due
12
- # to one bug, we choose to ignore it in this specific case until reek can be
13
- # fixed.
14
- t.fail_on_error = ! RBX_18_MODE # always true, except under rbx 18 mode
15
- end
16
- end
17
- rescue LoadError
18
- task :reek do
19
- $stderr.puts 'Reek is not available. In order to run reek, you must: gem install reek'
20
- end
21
- end
@@ -1,19 +0,0 @@
1
- # encoding: utf-8
2
-
3
- begin
4
- require 'roodi'
5
- require 'rake/tasklib'
6
- require 'roodi_task'
7
-
8
- namespace :metrics do
9
- RoodiTask.new do |t|
10
- t.verbose = false
11
- t.config = File.expand_path('../../../config/roodi.yml', __FILE__)
12
- t.patterns = %w[ lib/**/*.rb ]
13
- end
14
- end
15
- rescue LoadError
16
- task :roodi do
17
- $stderr.puts 'Roodi is not available. In order to run roodi, you must: gem install roodi'
18
- end
19
- end
@@ -1,25 +0,0 @@
1
- # encoding: utf-8
2
-
3
- begin
4
- require 'yardstick/rake/measurement'
5
- require 'yardstick/rake/verify'
6
- require 'yaml'
7
-
8
- config = YAML.load_file(File.expand_path('../../../config/yardstick.yml', __FILE__))
9
-
10
- namespace :metrics do
11
- # yardstick_measure task
12
- Yardstick::Rake::Measurement.new
13
-
14
- # verify_measurements task
15
- Yardstick::Rake::Verify.new do |verify|
16
- verify.threshold = config.fetch('threshold')
17
- end
18
- end
19
- rescue LoadError
20
- %w[ yardstick_measure verify_measurements ].each do |name|
21
- task name.to_s do
22
- $stderr.puts "Yardstick is not available. In order to run #{name}, you must: gem install yardstick"
23
- end
24
- end
25
- end