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,30 @@
|
|
|
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', 'examiner')
|
|
3
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'cli', 'report')
|
|
4
|
+
|
|
5
|
+
include Reek
|
|
6
|
+
include Reek::Cli
|
|
7
|
+
|
|
8
|
+
describe QuietReport, " when empty" do
|
|
9
|
+
context 'empty source' do
|
|
10
|
+
it 'has an empty quiet_report' do
|
|
11
|
+
examiner = Examiner.new('')
|
|
12
|
+
QuietReport.new(examiner).report.should == ''
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
context 'with a couple of smells' do
|
|
17
|
+
before :each do
|
|
18
|
+
examiner = Examiner.new('def simple(a) a[3] end')
|
|
19
|
+
rpt = QuietReport.new(examiner)
|
|
20
|
+
@lines = rpt.report.split("\n")
|
|
21
|
+
end
|
|
22
|
+
it 'has a header and a list of smells' do
|
|
23
|
+
@lines.should have_at_least(3).lines
|
|
24
|
+
end
|
|
25
|
+
it 'should mention every smell name' do
|
|
26
|
+
@lines[0].should match('[Utility Function]')
|
|
27
|
+
@lines[1].should match('[Feature Envy]')
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
require File.dirname(__FILE__)
|
|
2
|
-
|
|
3
|
-
require 'reek/version_command'
|
|
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', 'cli', 'version_command')
|
|
4
3
|
|
|
5
4
|
include Reek
|
|
5
|
+
include Reek::Cli
|
|
6
6
|
|
|
7
7
|
describe VersionCommand do
|
|
8
8
|
before :each do
|
|
@@ -0,0 +1,47 @@
|
|
|
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', 'cli', 'yaml_command')
|
|
3
|
+
|
|
4
|
+
include Reek
|
|
5
|
+
include Reek::Cli
|
|
6
|
+
|
|
7
|
+
describe YamlCommand do
|
|
8
|
+
before :each do
|
|
9
|
+
@view = mock('view', :null_object => true)
|
|
10
|
+
@examiner = mock('examiner')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
context 'with no smells' do
|
|
14
|
+
before :each do
|
|
15
|
+
@examiner.should_receive(:smells).and_return([])
|
|
16
|
+
@cmd = YamlCommand.new([@examiner])
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'displays nothing on the view' do
|
|
20
|
+
@view.should_not_receive(:output)
|
|
21
|
+
@cmd.execute(@view)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'tells the view it succeeded' do
|
|
25
|
+
@view.should_receive(:report_success)
|
|
26
|
+
@cmd.execute(@view)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context 'with smells' do
|
|
31
|
+
before :each do
|
|
32
|
+
@smell = SmellWarning.new('UncommunicativeName', "self", 27, "self")
|
|
33
|
+
@examiner.should_receive(:smells).and_return([@smell])
|
|
34
|
+
@cmd = YamlCommand.new([@examiner])
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'displays the correct text on the view' do
|
|
38
|
+
@view.should_receive(:output).with(/UncommunicativeName/)
|
|
39
|
+
@cmd.execute(@view)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'tells the view it found smells' do
|
|
43
|
+
@view.should_receive(:report_smells)
|
|
44
|
+
@cmd.execute(@view)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,145 @@
|
|
|
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', 'core', 'method_context')
|
|
3
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'module_context')
|
|
4
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'stop_context')
|
|
5
|
+
|
|
6
|
+
include Reek::Core
|
|
7
|
+
|
|
8
|
+
describe CodeContext do
|
|
9
|
+
context 'name recognition' do
|
|
10
|
+
before :each do
|
|
11
|
+
@exp_name = 'random_name' # SMELL: could use a String.random here
|
|
12
|
+
@full_name = "::::::::::::::::::::#{@exp_name}"
|
|
13
|
+
@exp = mock('exp')
|
|
14
|
+
@exp.should_receive(:name).any_number_of_times.and_return(@exp_name)
|
|
15
|
+
@exp.should_receive(:full_name).any_number_of_times.and_return(@full_name)
|
|
16
|
+
@exp.should_receive(:comments).any_number_of_times.and_return('')
|
|
17
|
+
@ctx = CodeContext.new(nil, @exp)
|
|
18
|
+
end
|
|
19
|
+
it 'gets its short name from the exp' do
|
|
20
|
+
@ctx.name.should == @exp_name
|
|
21
|
+
end
|
|
22
|
+
it 'does not match an empty list' do
|
|
23
|
+
@ctx.matches?([]).should == false
|
|
24
|
+
end
|
|
25
|
+
it 'does not match when its own short name is not given' do
|
|
26
|
+
@ctx.matches?(['banana']).should == false
|
|
27
|
+
end
|
|
28
|
+
it 'recognises its own short name' do
|
|
29
|
+
@ctx.matches?(['banana', @exp_name]).should == true
|
|
30
|
+
end
|
|
31
|
+
it 'recognises its short name as a regex' do
|
|
32
|
+
@ctx.matches?([/banana/, /#{@exp_name}/]).should == true
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context 'when there is an outer' do
|
|
36
|
+
before :each do
|
|
37
|
+
@outer_name = 'another_random sting'
|
|
38
|
+
outer = mock('outer')
|
|
39
|
+
outer.should_receive(:full_name).at_least(:once).and_return(@outer_name)
|
|
40
|
+
outer.should_receive(:config).and_return({})
|
|
41
|
+
@ctx = CodeContext.new(outer, @exp)
|
|
42
|
+
end
|
|
43
|
+
it 'creates the correct full name' do
|
|
44
|
+
@ctx.full_name.should == "#{@full_name}"
|
|
45
|
+
end
|
|
46
|
+
it 'recognises its own full name' do
|
|
47
|
+
@ctx.matches?(['banana', @full_name]).should == true
|
|
48
|
+
end
|
|
49
|
+
it 'recognises its full name as a regex' do
|
|
50
|
+
@ctx.matches?([/banana/, /#{@full_name}/]).should == true
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context 'generics' do
|
|
56
|
+
it 'should pass unknown method calls down the stack' do
|
|
57
|
+
stop = StopContext.new
|
|
58
|
+
def stop.bananas(arg1, arg2) arg1 + arg2 + 43 end
|
|
59
|
+
element = ModuleContext.new(stop, 'mod', ast(:module, :mod, nil))
|
|
60
|
+
element = MethodContext.new(element, ast(:defn, :bad))
|
|
61
|
+
element.bananas(17, -5).should == 55
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
context 'enumerating syntax elements' do
|
|
66
|
+
context 'in an empty module' do
|
|
67
|
+
before :each do
|
|
68
|
+
@module_name = 'Emptiness'
|
|
69
|
+
src = "module #{@module_name}; end"
|
|
70
|
+
ast = src.to_reek_source.syntax_tree
|
|
71
|
+
@ctx = CodeContext.new(nil, ast)
|
|
72
|
+
end
|
|
73
|
+
it 'yields no calls' do
|
|
74
|
+
@ctx.each_node(:call, []) {|exp| raise "#{exp} yielded by empty module!"}
|
|
75
|
+
end
|
|
76
|
+
it 'yields one module' do
|
|
77
|
+
mods = 0
|
|
78
|
+
@ctx.each_node(:module, []) {|exp| mods += 1}
|
|
79
|
+
mods.should == 1
|
|
80
|
+
end
|
|
81
|
+
it "yields the module's full AST" do
|
|
82
|
+
@ctx.each_node(:module, []) {|exp| exp[1].should == @module_name.to_sym}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
context 'with no block' do
|
|
86
|
+
it 'returns an empty array of ifs' do
|
|
87
|
+
@ctx.each_node(:if, []).should be_empty
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
context 'with a nested element' do
|
|
93
|
+
before :each do
|
|
94
|
+
@module_name = 'Loneliness'
|
|
95
|
+
@method_name = 'calloo'
|
|
96
|
+
src = "module #{@module_name}; def #{@method_name}; puts('hello') end; end"
|
|
97
|
+
ast = src.to_reek_source.syntax_tree
|
|
98
|
+
@ctx = CodeContext.new(nil, ast)
|
|
99
|
+
end
|
|
100
|
+
it 'yields no ifs' do
|
|
101
|
+
@ctx.each_node(:if, []) {|exp| raise "#{exp} yielded by empty module!"}
|
|
102
|
+
end
|
|
103
|
+
it 'yields one module' do
|
|
104
|
+
@ctx.each_node(:module, []).length.should == 1
|
|
105
|
+
end
|
|
106
|
+
it "yields the module's full AST" do
|
|
107
|
+
@ctx.each_node(:module, []) {|exp| exp[1].should == @module_name.to_sym}
|
|
108
|
+
end
|
|
109
|
+
it 'yields one method' do
|
|
110
|
+
@ctx.each_node(:defn, []).length.should == 1
|
|
111
|
+
end
|
|
112
|
+
it "yields the method's full AST" do
|
|
113
|
+
@ctx.each_node(:defn, []) {|exp| exp[1].should == @method_name.to_sym}
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
context 'pruning the traversal' do
|
|
117
|
+
it 'ignores the call inside the method' do
|
|
118
|
+
@ctx.each_node(:call, [:defn]).should be_empty
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it 'finds 3 ifs in a class' do
|
|
124
|
+
src = <<EOS
|
|
125
|
+
class Scrunch
|
|
126
|
+
def first
|
|
127
|
+
return @field == :sym ? 0 : 3;
|
|
128
|
+
end
|
|
129
|
+
def second
|
|
130
|
+
if @field == :sym
|
|
131
|
+
@other += " quarts"
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
def third
|
|
135
|
+
raise 'flu!' unless @field == :sym
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
EOS
|
|
139
|
+
|
|
140
|
+
ast = src.to_reek_source.syntax_tree
|
|
141
|
+
ctx = CodeContext.new(nil, ast)
|
|
142
|
+
ctx.each_node(:if, []).length.should == 3
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
require File.dirname(__FILE__)
|
|
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', 'core', 'code_parser')
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
include Reek
|
|
4
|
+
include Reek::Core
|
|
6
5
|
|
|
7
6
|
describe CodeParser, "with no method definitions" do
|
|
8
7
|
it 'reports no problems for empty source code' do
|
|
9
8
|
''.should_not reek
|
|
10
9
|
end
|
|
11
10
|
it 'reports no problems for empty class' do
|
|
12
|
-
'class
|
|
11
|
+
'# clean class for testing purposes
|
|
12
|
+
class Fred; end'.should_not reek
|
|
13
13
|
end
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
describe CodeParser, 'with a global method definition' do
|
|
17
17
|
it 'reports no problems for simple method' do
|
|
18
|
-
'def Outermost::fred() true; end'
|
|
18
|
+
src = 'def Outermost::fred() true; end'
|
|
19
|
+
src.should_not reek
|
|
19
20
|
end
|
|
20
21
|
end
|
|
21
22
|
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
require File.dirname(__FILE__)
|
|
2
|
-
|
|
3
|
-
require 'reek/sniffer'
|
|
4
|
-
require 'yaml'
|
|
5
|
-
|
|
6
|
-
include Reek
|
|
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', 'core', 'sniffer')
|
|
7
3
|
|
|
8
4
|
describe Hash do
|
|
9
5
|
before :each do
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
require File.dirname(__FILE__)
|
|
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', 'core', 'method_context')
|
|
3
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'stop_context')
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
require 'reek/stop_context'
|
|
5
|
-
|
|
6
|
-
include Reek
|
|
5
|
+
include Reek::Core
|
|
7
6
|
|
|
8
7
|
describe MethodContext, 'matching' do
|
|
9
8
|
before :each do
|
|
10
|
-
|
|
9
|
+
exp = mock('exp', :null_object => true)
|
|
10
|
+
exp.should_receive(:full_name).at_least(:once).and_return('mod')
|
|
11
|
+
@element = MethodContext.new(StopContext.new, exp)
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
it 'should recognise itself in a collection of names' do
|
|
@@ -21,46 +22,25 @@ describe MethodContext, 'matching' do
|
|
|
21
22
|
end
|
|
22
23
|
end
|
|
23
24
|
|
|
24
|
-
describe MethodContext, 'matching fq names' do
|
|
25
|
-
before :each do
|
|
26
|
-
element = StopContext.new
|
|
27
|
-
element = ModuleContext.new(element, Name.new(:mod), s(:module, :mod, nil))
|
|
28
|
-
element = ClassContext.new(element, Name.new(:klass), s())
|
|
29
|
-
@element = MethodContext.new(element, s(0, :meth))
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
it 'should recognise itself in a collection of names' do
|
|
33
|
-
@element.matches?(['banana', 'meth']).should == true
|
|
34
|
-
@element.matches?(['banana', 'klass#meth']).should == true
|
|
35
|
-
@element.matches?(['banana']).should == false
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
it 'should recognise itself in a collection of names' do
|
|
39
|
-
@element.matches?([/banana/, /meth/]).should == true
|
|
40
|
-
@element.matches?([/banana/, /klass#meth/]).should == true
|
|
41
|
-
@element.matches?([/banana/]).should == false
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
25
|
describe MethodContext do
|
|
46
26
|
it 'should record ivars as refs to self' do
|
|
47
|
-
mctx = MethodContext.new(StopContext.new,
|
|
27
|
+
mctx = MethodContext.new(StopContext.new, ast(:defn, :feed))
|
|
48
28
|
mctx.envious_receivers.should == []
|
|
49
|
-
mctx.record_call_to(
|
|
29
|
+
mctx.record_call_to(ast(:call, s(:ivar, :@cow), :feed_to))
|
|
50
30
|
mctx.envious_receivers.should == []
|
|
51
31
|
end
|
|
52
32
|
|
|
53
33
|
it 'should count calls to self' do
|
|
54
|
-
mctx = MethodContext.new(StopContext.new,
|
|
34
|
+
mctx = MethodContext.new(StopContext.new, ast(:defn, :equals))
|
|
55
35
|
mctx.refs.record_ref([:lvar, :other])
|
|
56
|
-
mctx.record_call_to(
|
|
36
|
+
mctx.record_call_to(ast(:call, s(:self), :thing))
|
|
57
37
|
mctx.envious_receivers.should be_empty
|
|
58
38
|
end
|
|
59
39
|
|
|
60
40
|
it 'should recognise a call on self' do
|
|
61
41
|
mc = MethodContext.new(StopContext.new, s(:defn, :deep))
|
|
62
|
-
mc.record_call_to(
|
|
63
|
-
mc.record_call_to(
|
|
42
|
+
mc.record_call_to(ast(:call, s(:lvar, :text), :each, s(:arglist)))
|
|
43
|
+
mc.record_call_to(ast(:call, nil, :shelve, s(:arglist)))
|
|
64
44
|
mc.envious_receivers.should be_empty
|
|
65
45
|
end
|
|
66
46
|
end
|
|
@@ -85,7 +65,7 @@ describe MethodParameters, 'default assignments' do
|
|
|
85
65
|
@defaults = assignments_from(src)
|
|
86
66
|
end
|
|
87
67
|
it 'returns the param-value pair' do
|
|
88
|
-
@defaults[
|
|
68
|
+
@defaults[0].should == s(:argb, s(:lit, 456))
|
|
89
69
|
end
|
|
90
70
|
it 'returns the nothing else' do
|
|
91
71
|
@defaults.length.should == 1
|
|
@@ -98,8 +78,8 @@ describe MethodParameters, 'default assignments' do
|
|
|
98
78
|
@defaults = assignments_from(src)
|
|
99
79
|
end
|
|
100
80
|
it 'returns both param-value pairs' do
|
|
101
|
-
@defaults[
|
|
102
|
-
@defaults[
|
|
81
|
+
@defaults[0].should == s(:arga, s(:lit, 123))
|
|
82
|
+
@defaults[1].should == s(:argb, s(:lit, 456))
|
|
103
83
|
end
|
|
104
84
|
it 'returns nothing else' do
|
|
105
85
|
@defaults.length.should == 2
|
|
@@ -0,0 +1,27 @@
|
|
|
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', 'core', 'module_context')
|
|
3
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'stop_context')
|
|
4
|
+
|
|
5
|
+
include Reek::Core
|
|
6
|
+
|
|
7
|
+
describe ModuleContext do
|
|
8
|
+
it 'should report module name for smell in method' do
|
|
9
|
+
'module Fred; def simple(x) true; end; end'.should reek_of(:UncommunicativeParameterName, /x/, /simple/)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'should not report module with empty class' do
|
|
13
|
+
'# module for test
|
|
14
|
+
module Fred
|
|
15
|
+
# module for test
|
|
16
|
+
class Jim; end; end'.should_not reek
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe ModuleContext do
|
|
21
|
+
it 'should recognise global constant' do
|
|
22
|
+
'# module for test
|
|
23
|
+
module ::Global
|
|
24
|
+
# module for test
|
|
25
|
+
class Inside; end; end'.should_not reek
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
require File.dirname(__FILE__)
|
|
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', 'core', 'object_refs')
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
include Reek
|
|
4
|
+
include Reek::Core
|
|
6
5
|
|
|
7
6
|
describe ObjectRefs, 'when empty' do
|
|
8
7
|
before(:each) do
|
|
@@ -27,7 +26,7 @@ describe ObjectRefs, 'with no refs to self' do
|
|
|
27
26
|
end
|
|
28
27
|
|
|
29
28
|
it 'should report :a as the max' do
|
|
30
|
-
@refs.max_keys.should ==
|
|
29
|
+
@refs.max_keys.should == {'a' => 2}
|
|
31
30
|
end
|
|
32
31
|
|
|
33
32
|
it 'should not report self as the max' do
|
|
@@ -75,7 +74,7 @@ describe ObjectRefs, 'with many refs to self' do
|
|
|
75
74
|
end
|
|
76
75
|
|
|
77
76
|
it 'should report self among the max' do
|
|
78
|
-
@refs.max_keys.should ==
|
|
77
|
+
@refs.max_keys.should == {Sexp.from_array([:lit, :self]) => 4}
|
|
79
78
|
end
|
|
80
79
|
|
|
81
80
|
it 'should report self as the max' do
|
|
@@ -0,0 +1,9 @@
|
|
|
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', 'core', 'module_context')
|
|
3
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'singleton_method_context')
|
|
4
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'core', 'stop_context')
|
|
5
|
+
|
|
6
|
+
include Reek::Core
|
|
7
|
+
|
|
8
|
+
describe SingletonMethodContext do
|
|
9
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
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', 'core', 'smell_configuration')
|
|
3
|
+
|
|
4
|
+
include Reek::Core
|
|
5
|
+
|
|
6
|
+
describe SmellConfiguration do
|
|
7
|
+
it 'returns the default value when key not found' do
|
|
8
|
+
cf = SmellConfiguration.new({})
|
|
9
|
+
cf.value('fred', nil, 27).should == 27
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
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', 'core', 'stop_context')
|
|
3
|
+
|
|
4
|
+
include Reek
|
|
5
|
+
include Reek::Core
|
|
6
|
+
|
|
7
|
+
describe StopContext do
|
|
8
|
+
before :each do
|
|
9
|
+
@stop = StopContext.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
context 'full_name' do
|
|
13
|
+
it "reports full context" do
|
|
14
|
+
@stop.full_name.should == ''
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
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', 'core', 'warning_collector')
|
|
3
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__))))), 'lib', 'reek', 'smell_warning')
|
|
4
|
+
|
|
5
|
+
include Reek::Core
|
|
6
|
+
|
|
7
|
+
describe WarningCollector do
|
|
8
|
+
before(:each) do
|
|
9
|
+
@collector = WarningCollector.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
context 'when empty' do
|
|
13
|
+
it 'reports no warnings' do
|
|
14
|
+
@collector.warnings.should == []
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
context 'with one warning' do
|
|
19
|
+
before :each do
|
|
20
|
+
@warning = Reek::SmellWarning.new('ControlCouple', 'fred', [1,2,3], 'hello')
|
|
21
|
+
@collector.found_smell(@warning)
|
|
22
|
+
end
|
|
23
|
+
it 'reports that warning' do
|
|
24
|
+
@collector.warnings.should == [@warning]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
require File.join(File.dirname(File.dirname(File.expand_path(__FILE__))), 'spec_helper')
|
|
2
|
+
require File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), 'lib', 'reek', 'examiner')
|
|
3
|
+
|
|
4
|
+
include Reek
|
|
5
|
+
|
|
6
|
+
shared_examples_for 'supports the deprecated api' do
|
|
7
|
+
it 'returns all smells as active' do
|
|
8
|
+
@examiner.all_active_smells.should == @examiner.smells
|
|
9
|
+
end
|
|
10
|
+
it 'returns all smells as active' do
|
|
11
|
+
@examiner.all_smells.should == @examiner.smells
|
|
12
|
+
end
|
|
13
|
+
it 'counts all smells as active smells' do
|
|
14
|
+
@examiner.num_active_smells.should == @examiner.smells.length
|
|
15
|
+
end
|
|
16
|
+
it 'never reports masked smells' do
|
|
17
|
+
@examiner.num_masked_smells.should == 0
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
shared_examples_for 'no smells found' do
|
|
22
|
+
it 'is not smelly' do
|
|
23
|
+
@examiner.should_not be_smelly
|
|
24
|
+
end
|
|
25
|
+
it 'finds no smells' do
|
|
26
|
+
@examiner.smells.length.should == 0
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it_should_behave_like 'supports the deprecated api'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
shared_examples_for 'one smell found' do
|
|
33
|
+
it 'is smelly' do
|
|
34
|
+
@examiner.should be_smelly
|
|
35
|
+
end
|
|
36
|
+
it 'reports the smell' do
|
|
37
|
+
@examiner.smells.length.should == 1
|
|
38
|
+
end
|
|
39
|
+
it 'reports the correct smell' do
|
|
40
|
+
@examiner.smells[0].smell_class.should == @expected_first_smell
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it_should_behave_like 'supports the deprecated api'
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe Examiner do
|
|
47
|
+
before :each do
|
|
48
|
+
@expected_first_smell = 'NestedIterators'
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
context 'with a fragrant String' do
|
|
52
|
+
before :each do
|
|
53
|
+
@examiner = Examiner.new('def good() true; end')
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it_should_behave_like 'no smells found'
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
context 'with a smelly String' do
|
|
60
|
+
before :each do
|
|
61
|
+
@examiner = Examiner.new('def fine() y = 4; end')
|
|
62
|
+
@expected_first_smell = 'UncommunicativeName'
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it_should_behave_like 'one smell found'
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
context 'with a smelly Dir' do
|
|
69
|
+
before :each do
|
|
70
|
+
smelly_dir = Dir['spec/samples/all_but_one_masked/*.rb']
|
|
71
|
+
@examiner = Examiner.new(smelly_dir)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it_should_behave_like 'one smell found'
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
context 'with a fragrant Dir' do
|
|
78
|
+
before :each do
|
|
79
|
+
clean_dir = Dir['spec/samples/three_clean_files/*.rb']
|
|
80
|
+
@examiner = Examiner.new(clean_dir)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it_should_behave_like 'no smells found'
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
context 'with a smelly File' do
|
|
87
|
+
before :each do
|
|
88
|
+
smelly_file = File.new(Dir['spec/samples/all_but_one_masked/d*.rb'][0])
|
|
89
|
+
@examiner = Examiner.new(smelly_file)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it_should_behave_like 'one smell found'
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
context 'with a fragrant File' do
|
|
96
|
+
before :each do
|
|
97
|
+
clean_file = File.new(Dir['spec/samples/three_clean_files/*.rb'][0])
|
|
98
|
+
@examiner = Examiner.new(clean_file)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it_should_behave_like 'no smells found'
|
|
102
|
+
end
|
|
103
|
+
end
|