reek 1.2.6 → 1.2.8
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.
- data/.yardopts +10 -0
- data/History.txt +62 -0
- data/README.md +74 -0
- data/bin/reek +2 -2
- data/config/defaults.reek +44 -5
- data/features/api.feature +20 -0
- data/features/masking_smells.feature +60 -42
- data/features/options.feature +7 -2
- data/features/rake_task.feature +29 -22
- data/features/reports.feature +9 -41
- data/features/samples.feature +184 -196
- data/features/stdin.feature +5 -8
- data/features/step_definitions/reek_steps.rb +8 -4
- data/features/support/env.rb +2 -3
- data/features/yaml.feature +85 -0
- data/lib/reek/cli/application.rb +46 -0
- data/lib/reek/cli/command_line.rb +108 -0
- data/lib/reek/cli/help_command.rb +18 -0
- data/lib/reek/cli/reek_command.rb +37 -0
- data/lib/reek/cli/report.rb +58 -0
- data/lib/reek/cli/version_command.rb +19 -0
- data/lib/reek/cli/yaml_command.rb +32 -0
- data/lib/reek/core/code_context.rb +64 -0
- data/lib/reek/core/code_parser.rb +166 -0
- data/lib/reek/core/method_context.rb +84 -0
- data/lib/reek/core/module_context.rb +20 -0
- data/lib/reek/core/object_refs.rb +51 -0
- data/lib/reek/core/singleton_method_context.rb +20 -0
- data/lib/reek/core/smell_configuration.rb +62 -0
- data/lib/reek/core/sniffer.rb +105 -0
- data/lib/reek/core/stop_context.rb +30 -0
- data/lib/reek/core/warning_collector.rb +27 -0
- data/lib/reek/examiner.rb +104 -0
- data/lib/reek/rake/task.rb +142 -0
- data/lib/reek/smell_warning.rb +73 -23
- data/lib/reek/smells/attribute.rb +26 -21
- data/lib/reek/smells/boolean_parameter.rb +38 -0
- data/lib/reek/smells/class_variable.rb +22 -9
- data/lib/reek/smells/control_couple.rb +40 -16
- data/lib/reek/smells/data_clump.rb +114 -23
- data/lib/reek/smells/duplication.rb +55 -15
- data/lib/reek/smells/feature_envy.rb +16 -7
- data/lib/reek/smells/irresponsible_module.rb +37 -0
- data/lib/reek/smells/large_class.rb +37 -19
- data/lib/reek/smells/long_method.rb +20 -9
- data/lib/reek/smells/long_parameter_list.rb +22 -10
- data/lib/reek/smells/long_yield_list.rb +43 -7
- data/lib/reek/smells/nested_iterators.rb +68 -8
- data/lib/reek/smells/simulated_polymorphism.rb +26 -15
- data/lib/reek/smells/smell_detector.rb +29 -51
- data/lib/reek/smells/uncommunicative_method_name.rb +74 -0
- data/lib/reek/smells/uncommunicative_module_name.rb +74 -0
- data/lib/reek/smells/uncommunicative_parameter_name.rb +79 -0
- data/lib/reek/smells/uncommunicative_variable_name.rb +89 -0
- data/lib/reek/smells/utility_function.rb +51 -12
- data/lib/reek/smells.rb +29 -0
- data/lib/reek/source/code_comment.rb +37 -0
- data/lib/reek/source/config_file.rb +72 -0
- data/lib/reek/source/core_extras.rb +46 -0
- data/lib/reek/source/reference_collector.rb +28 -0
- data/lib/reek/source/sexp_formatter.rb +17 -0
- data/lib/reek/source/source_code.rb +44 -0
- data/lib/reek/source/source_file.rb +32 -0
- data/lib/reek/source/source_locator.rb +42 -0
- data/lib/reek/source/tree_dresser.rb +204 -0
- data/lib/reek/source.rb +18 -0
- data/lib/reek/spec/should_reek.rb +31 -0
- data/lib/reek/spec/should_reek_of.rb +37 -0
- data/lib/reek/spec/should_reek_only_of.rb +37 -0
- data/lib/reek/spec.rb +51 -0
- data/lib/reek.rb +8 -4
- data/reek.gemspec +9 -7
- data/spec/matchers/smell_of_matcher.rb +58 -0
- data/spec/reek/{help_command_spec.rb → cli/help_command_spec.rb} +3 -4
- data/spec/reek/cli/reek_command_spec.rb +46 -0
- data/spec/reek/cli/report_spec.rb +30 -0
- data/spec/reek/{version_command_spec.rb → cli/version_command_spec.rb} +3 -3
- data/spec/reek/cli/yaml_command_spec.rb +47 -0
- data/spec/reek/core/code_context_spec.rb +145 -0
- data/spec/reek/{code_parser_spec.rb → core/code_parser_spec.rb} +7 -6
- data/spec/reek/{config_spec.rb → core/config_spec.rb} +2 -6
- data/spec/reek/{method_context_spec.rb → core/method_context_spec.rb} +16 -36
- data/spec/reek/core/module_context_spec.rb +27 -0
- data/spec/reek/{object_refs_spec.rb → core/object_refs_spec.rb} +5 -6
- data/spec/reek/core/singleton_method_context_spec.rb +9 -0
- data/spec/reek/core/smell_configuration_spec.rb +11 -0
- data/spec/reek/core/stop_context_spec.rb +17 -0
- data/spec/reek/core/warning_collector_spec.rb +27 -0
- data/spec/reek/examiner_spec.rb +103 -0
- data/spec/reek/smell_warning_spec.rb +74 -82
- data/spec/reek/smells/attribute_spec.rb +42 -23
- data/spec/reek/smells/behaves_like_variable_detector.rb +2 -2
- data/spec/reek/smells/boolean_parameter_spec.rb +66 -0
- data/spec/reek/smells/class_variable_spec.rb +60 -75
- data/spec/reek/smells/control_couple_spec.rb +37 -32
- data/spec/reek/smells/data_clump_spec.rb +63 -24
- data/spec/reek/smells/duplication_spec.rb +106 -57
- data/spec/reek/smells/feature_envy_spec.rb +113 -92
- data/spec/reek/smells/irresponsible_module_spec.rb +58 -0
- data/spec/reek/smells/large_class_spec.rb +67 -57
- data/spec/reek/smells/long_method_spec.rb +40 -10
- data/spec/reek/smells/long_parameter_list_spec.rb +50 -28
- data/spec/reek/smells/long_yield_list_spec.rb +57 -0
- data/spec/reek/smells/nested_iterators_spec.rb +115 -7
- data/spec/reek/smells/simulated_polymorphism_spec.rb +56 -20
- data/spec/reek/smells/smell_detector_shared.rb +42 -0
- data/spec/reek/smells/uncommunicative_method_name_spec.rb +42 -0
- data/spec/reek/smells/uncommunicative_module_name_spec.rb +66 -0
- data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +71 -0
- data/spec/reek/smells/uncommunicative_variable_name_spec.rb +120 -0
- data/spec/reek/smells/utility_function_spec.rb +50 -4
- data/spec/reek/source/code_comment_spec.rb +82 -0
- data/spec/reek/source/object_source_spec.rb +20 -0
- data/spec/reek/source/reference_collector_spec.rb +53 -0
- data/spec/reek/{adapters/source_spec.rb → source/source_code_spec.rb} +7 -8
- data/spec/reek/source/tree_dresser_spec.rb +270 -0
- data/spec/reek/spec/should_reek_of_spec.rb +76 -0
- data/spec/reek/spec/should_reek_only_of_spec.rb +89 -0
- data/spec/reek/{adapters → spec}/should_reek_spec.rb +8 -32
- data/spec/samples/all_but_one_masked/clean_one.rb +1 -0
- data/spec/samples/all_but_one_masked/dirty.rb +1 -0
- data/spec/samples/all_but_one_masked/masked.reek +5 -1
- data/spec/samples/clean_due_to_masking/clean_one.rb +1 -0
- data/spec/samples/clean_due_to_masking/clean_three.rb +1 -0
- data/spec/samples/clean_due_to_masking/clean_two.rb +1 -0
- data/spec/samples/clean_due_to_masking/dirty_one.rb +1 -1
- data/spec/samples/clean_due_to_masking/dirty_two.rb +1 -1
- data/spec/samples/clean_due_to_masking/masked.reek +5 -1
- data/spec/samples/config/allow_duplication.reek +3 -0
- data/spec/samples/config/deeper_nested_iterators.reek +3 -0
- data/spec/samples/corrupt_config_file/dirty.rb +1 -1
- data/spec/samples/demo/demo.rb +8 -0
- data/spec/samples/empty_config_file/dirty.rb +2 -1
- data/spec/samples/exceptions.reek +1 -1
- data/spec/samples/inline_config/dirty.rb +16 -0
- data/spec/samples/inline_config/masked.reek +7 -0
- data/spec/samples/mask_some/dirty.rb +8 -0
- data/spec/samples/mask_some/some.reek +8 -0
- data/spec/samples/masked/dirty.rb +2 -1
- data/spec/samples/masked/masked.reek +3 -1
- data/spec/samples/mixed_results/clean_one.rb +1 -0
- data/spec/samples/mixed_results/clean_three.rb +1 -0
- data/spec/samples/mixed_results/clean_two.rb +1 -0
- data/spec/samples/mixed_results/dirty_one.rb +1 -0
- data/spec/samples/mixed_results/dirty_two.rb +1 -0
- data/spec/samples/not_quite_masked/dirty.rb +2 -1
- data/spec/samples/not_quite_masked/masked.reek +1 -1
- data/spec/samples/overrides/masked/dirty.rb +2 -1
- data/spec/samples/overrides/masked/lower.reek +3 -1
- data/spec/samples/three_clean_files/clean_one.rb +1 -0
- data/spec/samples/three_clean_files/clean_three.rb +1 -0
- data/spec/samples/three_clean_files/clean_two.rb +1 -0
- data/spec/samples/two_smelly_files/dirty_one.rb +2 -1
- data/spec/samples/two_smelly_files/dirty_two.rb +2 -1
- data/spec/spec_helper.rb +10 -2
- data/tasks/reek.rake +2 -2
- data/tasks/test.rake +12 -3
- metadata +121 -79
- data/README.rdoc +0 -84
- data/features/profile.feature +0 -34
- data/lib/reek/adapters/application.rb +0 -46
- data/lib/reek/adapters/command_line.rb +0 -77
- data/lib/reek/adapters/config_file.rb +0 -31
- data/lib/reek/adapters/core_extras.rb +0 -64
- data/lib/reek/adapters/rake_task.rb +0 -121
- data/lib/reek/adapters/report.rb +0 -86
- data/lib/reek/adapters/source.rb +0 -72
- data/lib/reek/adapters/spec.rb +0 -133
- data/lib/reek/block_context.rb +0 -62
- data/lib/reek/class_context.rb +0 -41
- data/lib/reek/code_context.rb +0 -68
- data/lib/reek/code_parser.rb +0 -203
- data/lib/reek/configuration.rb +0 -57
- data/lib/reek/detector_stack.rb +0 -37
- data/lib/reek/help_command.rb +0 -14
- data/lib/reek/if_context.rb +0 -18
- data/lib/reek/masking_collection.rb +0 -33
- data/lib/reek/method_context.rb +0 -138
- data/lib/reek/module_context.rb +0 -49
- data/lib/reek/name.rb +0 -57
- data/lib/reek/object_refs.rb +0 -49
- data/lib/reek/reek_command.rb +0 -28
- data/lib/reek/sexp_formatter.rb +0 -10
- data/lib/reek/singleton_method_context.rb +0 -26
- data/lib/reek/smells/uncommunicative_name.rb +0 -84
- data/lib/reek/sniffer.rb +0 -177
- data/lib/reek/stop_context.rb +0 -35
- data/lib/reek/tree_dresser.rb +0 -82
- data/lib/reek/version_command.rb +0 -14
- data/lib/reek/yield_call_context.rb +0 -12
- data/spec/reek/adapters/report_spec.rb +0 -31
- data/spec/reek/adapters/should_reek_of_spec.rb +0 -138
- data/spec/reek/adapters/should_reek_only_of_spec.rb +0 -87
- data/spec/reek/block_context_spec.rb +0 -65
- data/spec/reek/class_context_spec.rb +0 -161
- data/spec/reek/code_context_spec.rb +0 -182
- data/spec/reek/configuration_spec.rb +0 -12
- data/spec/reek/if_context_spec.rb +0 -17
- data/spec/reek/masking_collection_spec.rb +0 -236
- data/spec/reek/module_context_spec.rb +0 -46
- data/spec/reek/name_spec.rb +0 -37
- data/spec/reek/object_source_spec.rb +0 -23
- data/spec/reek/reek_command_spec.rb +0 -45
- data/spec/reek/singleton_method_context_spec.rb +0 -16
- data/spec/reek/smells/smell_detector_spec.rb +0 -36
- data/spec/reek/smells/uncommunicative_name_spec.rb +0 -146
- data/spec/reek/sniffer_spec.rb +0 -11
- data/spec/reek/stop_context_spec.rb +0 -33
- data/spec/reek/tree_dresser_spec.rb +0 -20
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
|
|
2
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'source', 'reference_collector')
|
|
3
|
+
|
|
4
|
+
include Reek::Source
|
|
5
|
+
|
|
6
|
+
describe ReferenceCollector do
|
|
7
|
+
|
|
8
|
+
context 'counting refs to self' do
|
|
9
|
+
def refs_to_self(src)
|
|
10
|
+
ReferenceCollector.new(src.to_reek_source.syntax_tree).num_refs_to_self
|
|
11
|
+
end
|
|
12
|
+
it 'with no refs to self' do
|
|
13
|
+
refs_to_self('def no_envy(arga) arga.barg end').should == 0
|
|
14
|
+
end
|
|
15
|
+
it 'counts a call to super' do
|
|
16
|
+
refs_to_self('def simple() super; end').should == 1
|
|
17
|
+
end
|
|
18
|
+
it 'counts a local call' do
|
|
19
|
+
refs_to_self('def simple() to_s; end').should == 1
|
|
20
|
+
end
|
|
21
|
+
it 'counts a use of self' do
|
|
22
|
+
refs_to_self('def simple() lv = self; end').should == 1
|
|
23
|
+
end
|
|
24
|
+
it 'counts a call with self as receiver' do
|
|
25
|
+
refs_to_self('def simple() self.to_s; end').should == 1
|
|
26
|
+
end
|
|
27
|
+
it 'counts uses of an ivar' do
|
|
28
|
+
refs_to_self('def no_envy() @item.to_a; @item = 4; @item end').should == 3
|
|
29
|
+
end
|
|
30
|
+
it 'counts an ivar passed to a method' do
|
|
31
|
+
refs_to_self('def no_envy(arga) arga.barg(@item); arga end').should == 1
|
|
32
|
+
end
|
|
33
|
+
it 'ignores global variables' do
|
|
34
|
+
refs_to_self('def no_envy(arga) $s2.to_a; $s2[arga] end').should == 0
|
|
35
|
+
end
|
|
36
|
+
it 'ignores global variables' do
|
|
37
|
+
src = <<EOS
|
|
38
|
+
def accept(t, pat = /.*/nm, &block)
|
|
39
|
+
if pat
|
|
40
|
+
pat.respond_to?(:match) or raise TypeError, "has no `match'"
|
|
41
|
+
else
|
|
42
|
+
pat = t if t.respond_to?(:match)
|
|
43
|
+
end
|
|
44
|
+
unless block
|
|
45
|
+
block = pat.method(:convert).to_proc if pat.respond_to?(:convert)
|
|
46
|
+
end
|
|
47
|
+
@atype[t] = [pat, block]
|
|
48
|
+
end
|
|
49
|
+
EOS
|
|
50
|
+
refs_to_self(src).should == 2
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
require File.dirname(__FILE__)
|
|
2
|
-
|
|
3
|
-
require 'reek/adapters/source'
|
|
1
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
|
|
4
2
|
require 'stringio'
|
|
3
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'source', 'source_code')
|
|
5
4
|
|
|
6
|
-
include Reek
|
|
5
|
+
include Reek::Source
|
|
7
6
|
|
|
8
|
-
describe
|
|
7
|
+
describe SourceCode do
|
|
9
8
|
context 'when the parser fails' do
|
|
10
9
|
before :each do
|
|
11
10
|
@catcher = StringIO.new
|
|
12
|
-
@old_err_io = (
|
|
11
|
+
@old_err_io = (SourceCode.err_io = @catcher)
|
|
13
12
|
parser = mock('parser')
|
|
14
13
|
@error_message = 'Error message'
|
|
15
14
|
parser.should_receive(:parse).and_raise(SyntaxError.new(@error_message))
|
|
16
15
|
@source_name = 'Test source'
|
|
17
|
-
@src =
|
|
16
|
+
@src = SourceCode.new('', @source_name, parser)
|
|
18
17
|
end
|
|
19
18
|
it 'raises a SyntaxError' do
|
|
20
19
|
@src.syntax_tree
|
|
@@ -35,7 +34,7 @@ describe Source do
|
|
|
35
34
|
@catcher.string.should match(@error_message)
|
|
36
35
|
end
|
|
37
36
|
after :each do
|
|
38
|
-
|
|
37
|
+
SourceCode.err_io = @old_err_io
|
|
39
38
|
end
|
|
40
39
|
end
|
|
41
40
|
end
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
|
|
2
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'source', 'tree_dresser')
|
|
3
|
+
|
|
4
|
+
include Reek::Source
|
|
5
|
+
|
|
6
|
+
describe TreeDresser do
|
|
7
|
+
before(:each) do
|
|
8
|
+
@dresser = TreeDresser.new
|
|
9
|
+
end
|
|
10
|
+
it 'maps :if to IfNode' do
|
|
11
|
+
@dresser.extensions_for(:if).should == 'IfNode'
|
|
12
|
+
end
|
|
13
|
+
it 'maps :call to CallNode' do
|
|
14
|
+
@dresser.extensions_for(:call).should == 'CallNode'
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe SexpNode do
|
|
19
|
+
context 'format' do
|
|
20
|
+
it 'formats self' do
|
|
21
|
+
@node = s(:self)
|
|
22
|
+
@node.extend(SexpNode)
|
|
23
|
+
@node.format_ruby.should == 'self'
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
context 'hash' do
|
|
28
|
+
it 'hashes equal for equal sexps' do
|
|
29
|
+
node1 = ast(:defn, s(:const2, :Fred, :jim), s(:call, :+, s(:lit, 4), :fred))
|
|
30
|
+
node2 = ast(:defn, s(:const2, :Fred, :jim), s(:call, :+, s(:lit, 4), :fred))
|
|
31
|
+
node1.hash.should == node2.hash
|
|
32
|
+
end
|
|
33
|
+
it 'hashes diferent for diferent sexps' do
|
|
34
|
+
node1 = ast(:defn, s(:const2, :Fred, :jim), s(:call, :+, s(:lit, 4), :fred))
|
|
35
|
+
node2 = ast(:defn, s(:const2, :Fred, :jim), s(:call, :+, s(:lit, 3), :fred))
|
|
36
|
+
node1.hash.should_not == node2.hash
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe SexpExtensions::DefnNode do
|
|
42
|
+
context 'with no parameters' do
|
|
43
|
+
before :each do
|
|
44
|
+
@node = s(:defn, :hello, s(:args))
|
|
45
|
+
@node.extend(SexpExtensions::DefnNode)
|
|
46
|
+
end
|
|
47
|
+
it 'has no parameters' do
|
|
48
|
+
@node.parameters.should == s(:args)
|
|
49
|
+
end
|
|
50
|
+
it 'has no parameter names' do
|
|
51
|
+
@node.parameter_names.should == s()
|
|
52
|
+
end
|
|
53
|
+
it 'includes outer scope in its full name' do
|
|
54
|
+
@node.full_name('Fred').should == 'Fred#hello'
|
|
55
|
+
end
|
|
56
|
+
it 'includes no marker in its full name with empty outer scope' do
|
|
57
|
+
@node.full_name('').should == 'hello'
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
context 'with 1 parameter' do
|
|
62
|
+
before :each do
|
|
63
|
+
@node = s(:defn, :hello, s(:args, :param))
|
|
64
|
+
@node.extend(SexpExtensions::DefnNode)
|
|
65
|
+
end
|
|
66
|
+
it 'has 1 parameter' do
|
|
67
|
+
@node.parameters.should == s(:args, :param)
|
|
68
|
+
end
|
|
69
|
+
it 'has 1 parameter name' do
|
|
70
|
+
@node.parameter_names.should == s(:param)
|
|
71
|
+
end
|
|
72
|
+
it 'includes outer scope in its full name' do
|
|
73
|
+
@node.full_name('Fred').should == 'Fred#hello'
|
|
74
|
+
end
|
|
75
|
+
it 'includes no marker in its full name with empty outer scope' do
|
|
76
|
+
@node.full_name('').should == 'hello'
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
context 'with a block' do
|
|
81
|
+
before :each do
|
|
82
|
+
@node = s(:defn, :hello, s(:args, :param, :"&blk"))
|
|
83
|
+
@node.extend(SexpExtensions::DefnNode)
|
|
84
|
+
end
|
|
85
|
+
it 'has 1 parameter' do
|
|
86
|
+
@node.parameters.should == s(:args, :param, :"&blk")
|
|
87
|
+
end
|
|
88
|
+
it 'has 1 parameter name' do
|
|
89
|
+
@node.parameter_names.should == s(:param, :"&blk")
|
|
90
|
+
end
|
|
91
|
+
it 'includes outer scope in its full name' do
|
|
92
|
+
@node.full_name('Fred').should == 'Fred#hello'
|
|
93
|
+
end
|
|
94
|
+
it 'includes no marker in its full name with empty outer scope' do
|
|
95
|
+
@node.full_name('').should == 'hello'
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
context 'with 1 defaulted parameter' do
|
|
100
|
+
before :each do
|
|
101
|
+
@node = s(:defn, :hello, s(:args, :param, s(:block, s(:lasgn, :param, s(:array)))))
|
|
102
|
+
@node.extend(SexpExtensions::DefnNode)
|
|
103
|
+
end
|
|
104
|
+
it 'has 1 parameter' do
|
|
105
|
+
@node.parameters.should == s(:args, :param)
|
|
106
|
+
end
|
|
107
|
+
it 'has 1 parameter name' do
|
|
108
|
+
@node.parameter_names.should == s(:param)
|
|
109
|
+
end
|
|
110
|
+
it 'includes outer scope in its full name' do
|
|
111
|
+
@node.full_name('Fred').should == 'Fred#hello'
|
|
112
|
+
end
|
|
113
|
+
it 'includes no marker in its full name with empty outer scope' do
|
|
114
|
+
@node.full_name('').should == 'hello'
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
describe SexpExtensions::DefsNode do
|
|
120
|
+
context 'with no parameters' do
|
|
121
|
+
before :each do
|
|
122
|
+
@node = s(:defs, :obj, :hello, s(:args))
|
|
123
|
+
@node.extend(SexpExtensions::DefsNode)
|
|
124
|
+
end
|
|
125
|
+
it 'has no parameters' do
|
|
126
|
+
@node.parameters.should == s(:args)
|
|
127
|
+
end
|
|
128
|
+
it 'has no parameter names' do
|
|
129
|
+
@node.parameter_names.should == s()
|
|
130
|
+
end
|
|
131
|
+
it 'includes outer scope in its full name' do
|
|
132
|
+
@node.full_name('Fred').should == 'Fred#obj.hello'
|
|
133
|
+
end
|
|
134
|
+
it 'includes no marker in its full name with empty outer scope' do
|
|
135
|
+
@node.full_name('').should == 'obj.hello'
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
context 'with 1 parameter' do
|
|
140
|
+
before :each do
|
|
141
|
+
@node = s(:defs, :obj, :hello, s(:args, :param))
|
|
142
|
+
@node.extend(SexpExtensions::DefsNode)
|
|
143
|
+
end
|
|
144
|
+
it 'has 1 parameter' do
|
|
145
|
+
@node.parameters.should == s(:args, :param)
|
|
146
|
+
end
|
|
147
|
+
it 'has 1 parameter name' do
|
|
148
|
+
@node.parameter_names.should == s(:param)
|
|
149
|
+
end
|
|
150
|
+
it 'includes outer scope in its full name' do
|
|
151
|
+
@node.full_name('Fred').should == 'Fred#obj.hello'
|
|
152
|
+
end
|
|
153
|
+
it 'includes no marker in its full name with empty outer scope' do
|
|
154
|
+
@node.full_name('').should == 'obj.hello'
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
context 'with a block' do
|
|
159
|
+
before :each do
|
|
160
|
+
@node = s(:defs, :obj, :hello, s(:args, :param, :"&blk"))
|
|
161
|
+
@node.extend(SexpExtensions::DefsNode)
|
|
162
|
+
end
|
|
163
|
+
it 'has 1 parameter' do
|
|
164
|
+
@node.parameters.should == s(:args, :param, :"&blk")
|
|
165
|
+
end
|
|
166
|
+
it 'has 1 parameter name' do
|
|
167
|
+
@node.parameter_names.should == s(:param, :"&blk")
|
|
168
|
+
end
|
|
169
|
+
it 'includes outer scope in its full name' do
|
|
170
|
+
@node.full_name('Fred').should == 'Fred#obj.hello'
|
|
171
|
+
end
|
|
172
|
+
it 'includes no marker in its full name with empty outer scope' do
|
|
173
|
+
@node.full_name('').should == 'obj.hello'
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
context 'with 1 defaulted parameter' do
|
|
178
|
+
before :each do
|
|
179
|
+
@node = s(:defs, :obj, :hello, s(:args, :param, s(:block, s(:lasgn, :param, s(:array)))))
|
|
180
|
+
@node.extend(SexpExtensions::DefsNode)
|
|
181
|
+
end
|
|
182
|
+
it 'has 1 parameter' do
|
|
183
|
+
@node.parameters.should == s(:args, :param)
|
|
184
|
+
end
|
|
185
|
+
it 'has 1 parameter name' do
|
|
186
|
+
@node.parameter_names.should == s(:param)
|
|
187
|
+
end
|
|
188
|
+
it 'includes outer scope in its full name' do
|
|
189
|
+
@node.full_name('Fred').should == 'Fred#obj.hello'
|
|
190
|
+
end
|
|
191
|
+
it 'includes no marker in its full name with empty outer scope' do
|
|
192
|
+
@node.full_name('').should == 'obj.hello'
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
describe SexpExtensions::IterNode do
|
|
198
|
+
context 'with no parameters' do
|
|
199
|
+
before :each do
|
|
200
|
+
@node = s(:iter, s(), nil, s())
|
|
201
|
+
@node.extend(SexpExtensions::IterNode)
|
|
202
|
+
end
|
|
203
|
+
it 'has no parameters' do
|
|
204
|
+
@node.parameters.should == []
|
|
205
|
+
end
|
|
206
|
+
it 'has no parameter names' do
|
|
207
|
+
@node.parameter_names.should == []
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
context 'with 1 parameter' do
|
|
212
|
+
before :each do
|
|
213
|
+
@node = s(:iter, s(), s(:lasgn, :param), s())
|
|
214
|
+
@node.extend(SexpExtensions::IterNode)
|
|
215
|
+
end
|
|
216
|
+
it 'has 1 parameter' do
|
|
217
|
+
@node.parameters.should == s(:lasgn, :param)
|
|
218
|
+
end
|
|
219
|
+
it 'has 1 parameter name' do
|
|
220
|
+
@node.parameter_names.should == s(:param)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
context 'with 2 parameters' do
|
|
225
|
+
before :each do
|
|
226
|
+
@node = s(:iter, s(), s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y))), s())
|
|
227
|
+
@node.extend(SexpExtensions::IterNode)
|
|
228
|
+
end
|
|
229
|
+
it 'has 1 parameter' do
|
|
230
|
+
@node.parameters.should == s(:masgn, s(:array, s(:lasgn, :x), s(:lasgn, :y)))
|
|
231
|
+
end
|
|
232
|
+
it 'has 1 parameter name' do
|
|
233
|
+
@node.parameter_names.should == [:x, :y]
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
describe SexpExtensions::ModuleNode do
|
|
239
|
+
context 'with a simple name' do
|
|
240
|
+
subject do
|
|
241
|
+
mod = ast(:module, :Fred, nil)
|
|
242
|
+
mod
|
|
243
|
+
end
|
|
244
|
+
its(:name) { should == :Fred }
|
|
245
|
+
its(:simple_name) { should == :Fred }
|
|
246
|
+
its(:text_name) { should == 'Fred' }
|
|
247
|
+
it 'has a simple full_name' do
|
|
248
|
+
subject.full_name('').should == 'Fred'
|
|
249
|
+
end
|
|
250
|
+
it 'has a fq full_name' do
|
|
251
|
+
subject.full_name('Blimey::O::Reilly').should == 'Blimey::O::Reilly::Fred'
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
context 'with a scoped name' do
|
|
256
|
+
subject do
|
|
257
|
+
mod = ast(:module, s(:colon2, s(:const, :Foo), :Bar), nil)
|
|
258
|
+
mod
|
|
259
|
+
end
|
|
260
|
+
its(:name) { should == s(:colon2, s(:const, :Foo), :Bar) }
|
|
261
|
+
its(:simple_name) { should == :Bar }
|
|
262
|
+
its(:text_name) { should == 'Foo::Bar' }
|
|
263
|
+
it 'has a simple full_name' do
|
|
264
|
+
subject.full_name('').should == 'Foo::Bar'
|
|
265
|
+
end
|
|
266
|
+
it 'has a fq full_name' do
|
|
267
|
+
subject.full_name('Blimey::O::Reilly').should == 'Blimey::O::Reilly::Foo::Bar'
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
|
|
2
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'spec')
|
|
3
|
+
|
|
4
|
+
include Reek
|
|
5
|
+
include Reek::Spec
|
|
6
|
+
|
|
7
|
+
describe ShouldReekOf do
|
|
8
|
+
context 'rdoc demo example' do
|
|
9
|
+
before :each do
|
|
10
|
+
@ruby = 'def double_thing() @other.thing.foo + @other.thing.foo end'
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it 'reports duplicate calls to @other.thing' do
|
|
14
|
+
@ruby.should reek_of(:Duplication, /@other.thing[^\.]/)
|
|
15
|
+
end
|
|
16
|
+
it 'reports duplicate calls to @other.thing.foo' do
|
|
17
|
+
@ruby.should reek_of(:Duplication, /@other.thing.foo/)
|
|
18
|
+
end
|
|
19
|
+
it 'does not report any feature envy' do
|
|
20
|
+
@ruby.should_not reek_of(:FeatureEnvy)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context 'checking code in a string' do
|
|
25
|
+
before :each do
|
|
26
|
+
@clean_code = 'def good() true; end'
|
|
27
|
+
@smelly_code = 'def x() y = 4; end'
|
|
28
|
+
@matcher = ShouldReekOf.new(:UncommunicativeVariableName, [/x/, /y/])
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'matches a smelly String' do
|
|
32
|
+
@matcher.matches?(@smelly_code).should be_true
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it 'doesnt match a fragrant String' do
|
|
36
|
+
@matcher.matches?(@clean_code).should be_false
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it 'reports the smells when should_not fails' do
|
|
40
|
+
@matcher.matches?(@smelly_code).should be_true
|
|
41
|
+
@matcher.failure_message_for_should_not.should match('UncommunicativeVariableName')
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
context 'checking code in a Dir' do
|
|
46
|
+
before :each do
|
|
47
|
+
@clean_dir = Dir['spec/samples/three_clean_files/*.rb']
|
|
48
|
+
@smelly_dir = Dir['spec/samples/two_smelly_files/*.rb']
|
|
49
|
+
@matcher = ShouldReekOf.new(:UncommunicativeVariableName, [/Dirty/, /@s/])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'matches a smelly String' do
|
|
53
|
+
@matcher.matches?(@smelly_dir).should be_true
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'doesnt match a fragrant String' do
|
|
57
|
+
@matcher.matches?(@clean_dir).should be_false
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
context 'checking code in a File' do
|
|
62
|
+
before :each do
|
|
63
|
+
@clean_file = File.new(Dir['spec/samples/three_clean_files/*.rb'][0])
|
|
64
|
+
@smelly_file = File.new(Dir['spec/samples/two_smelly_files/*.rb'][0])
|
|
65
|
+
@matcher = ShouldReekOf.new(:UncommunicativeVariableName, [/Dirty/, /@s/])
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it 'matches a smelly String' do
|
|
69
|
+
@matcher.matches?(@smelly_file).should be_true
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it 'doesnt match a fragrant String' do
|
|
73
|
+
@matcher.matches?(@clean_file).should be_false
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
|
|
2
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'spec')
|
|
3
|
+
|
|
4
|
+
include Reek
|
|
5
|
+
include Reek::Spec
|
|
6
|
+
|
|
7
|
+
describe ShouldReekOnlyOf do
|
|
8
|
+
before :each do
|
|
9
|
+
@expected_smell_class = :NestedIterators
|
|
10
|
+
@expected_context_name = 'SmellyClass#big_method'
|
|
11
|
+
@matcher = ShouldReekOnlyOf.new(@expected_smell_class, [/#{@expected_context_name}/])
|
|
12
|
+
@examiner = mock('examiner', :null_object => true)
|
|
13
|
+
@examiner.should_receive(:smells).and_return {smells}
|
|
14
|
+
@match = @matcher.matches_examiner?(@examiner)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
shared_examples_for 'no match' do
|
|
18
|
+
it 'does not match' do
|
|
19
|
+
@match.should be_false
|
|
20
|
+
end
|
|
21
|
+
context 'when a match was expected' do
|
|
22
|
+
before :each do
|
|
23
|
+
@source = 'the_path/to_a/source_file.rb'
|
|
24
|
+
@examiner.should_receive(:description).and_return(@source)
|
|
25
|
+
end
|
|
26
|
+
it 'reports the source' do
|
|
27
|
+
@matcher.failure_message_for_should.should match(@source)
|
|
28
|
+
end
|
|
29
|
+
it 'reports the expected smell class' do
|
|
30
|
+
@matcher.failure_message_for_should.should match(@expected_smell_class.to_s)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context 'with no smells' do
|
|
36
|
+
def smells
|
|
37
|
+
[]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it_should_behave_like 'no match'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
context 'with 1 non-matching smell' do
|
|
44
|
+
def smells
|
|
45
|
+
[SmellWarning.new('ControlCouple', 'context', [1], 'any old message')]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it_should_behave_like 'no match'
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context 'with 2 non-matching smells' do
|
|
52
|
+
def smells
|
|
53
|
+
[
|
|
54
|
+
SmellWarning.new('ControlCouple', 'context', [1], 'any old message'),
|
|
55
|
+
SmellWarning.new('FeatureEnvy', 'context', [1], 'any old message')
|
|
56
|
+
]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it_should_behave_like 'no match'
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context 'with 1 non-matching and 1 matching smell' do
|
|
63
|
+
def smells
|
|
64
|
+
[
|
|
65
|
+
SmellWarning.new('ControlCouple', 'context', [1], 'any old message'),
|
|
66
|
+
SmellWarning.new(@expected_smell_class.to_s, 'context', [1], "message mentioning #{@expected_context_name}")
|
|
67
|
+
]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it_should_behave_like 'no match'
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context 'with 1 matching smell' do
|
|
74
|
+
def smells
|
|
75
|
+
[SmellWarning.new(@expected_smell_class.to_s, nil, [1], "message mentioning #{@expected_context_name}")]
|
|
76
|
+
end
|
|
77
|
+
it 'matches' do
|
|
78
|
+
@match.should be_true
|
|
79
|
+
end
|
|
80
|
+
it 'reports the expected smell when no match was expected' do
|
|
81
|
+
@matcher.failure_message_for_should_not.should match(@expected_smell_class.to_s)
|
|
82
|
+
end
|
|
83
|
+
it 'reports the source when no match was expected' do
|
|
84
|
+
source = 'the_path/to_a/source_file.rb'
|
|
85
|
+
@examiner.should_receive(:description).and_return(source)
|
|
86
|
+
@matcher.failure_message_for_should_not.should match(source)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
require File.dirname(__FILE__)
|
|
2
|
-
|
|
3
|
-
require 'reek/adapters/report'
|
|
4
|
-
require 'reek/adapters/spec'
|
|
1
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'spec_helper')
|
|
2
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'spec')
|
|
5
3
|
|
|
6
4
|
include Reek
|
|
7
5
|
include Reek::Spec
|
|
@@ -22,8 +20,8 @@ describe ShouldReek, 'checking code in a string' do
|
|
|
22
20
|
end
|
|
23
21
|
|
|
24
22
|
it 'reports the smells when should_not fails' do
|
|
25
|
-
@matcher.matches?(@smelly_code)
|
|
26
|
-
@matcher.failure_message_for_should_not.should
|
|
23
|
+
@matcher.matches?(@smelly_code)
|
|
24
|
+
@matcher.failure_message_for_should_not.should match('UncommunicativeName')
|
|
27
25
|
end
|
|
28
26
|
end
|
|
29
27
|
|
|
@@ -43,8 +41,8 @@ describe ShouldReek, 'checking code in a Dir' do
|
|
|
43
41
|
end
|
|
44
42
|
|
|
45
43
|
it 'reports the smells when should_not fails' do
|
|
46
|
-
@matcher.matches?(@smelly_dir)
|
|
47
|
-
@matcher.failure_message_for_should_not.should
|
|
44
|
+
@matcher.matches?(@smelly_dir)
|
|
45
|
+
@matcher.failure_message_for_should_not.should match('UncommunicativeName')
|
|
48
46
|
end
|
|
49
47
|
end
|
|
50
48
|
|
|
@@ -64,29 +62,7 @@ describe ShouldReek, 'checking code in a File' do
|
|
|
64
62
|
end
|
|
65
63
|
|
|
66
64
|
it 'reports the smells when should_not fails' do
|
|
67
|
-
@matcher.matches?(@smelly_file)
|
|
68
|
-
@matcher.failure_message_for_should_not.should
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
describe ShouldReek, 'report formatting' do
|
|
73
|
-
before :each do
|
|
74
|
-
sn_clean = 'def clean() @thing = 4; end'.sniff
|
|
75
|
-
sn_dirty = 'def dirty() thing.cool + thing.cool; end'.sniff
|
|
76
|
-
sniffers = SnifferSet.new([sn_clean, sn_dirty], '')
|
|
77
|
-
@matcher = ShouldReek.new
|
|
78
|
-
@matcher.matches?(sniffers)
|
|
79
|
-
@lines = @matcher.failure_message_for_should_not.split("\n").map {|str| str.chomp}
|
|
80
|
-
@error_message = @lines.shift
|
|
81
|
-
@smells = @lines.grep(/^ /)
|
|
82
|
-
@headers = (@lines - @smells)
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
it 'mentions every smell in the report' do
|
|
86
|
-
@smells.should have(2).warnings
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
it 'doesnt mention the clean files' do
|
|
90
|
-
@headers.should have(1).headers
|
|
65
|
+
@matcher.matches?(@smelly_file)
|
|
66
|
+
@matcher.failure_message_for_should_not.should match('UncommunicativeName')
|
|
91
67
|
end
|
|
92
68
|
end
|