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
data/lib/reek/adapters/spec.rb
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
require 'reek/sniffer'
|
|
2
|
-
require 'reek/adapters/core_extras'
|
|
3
|
-
require 'reek/adapters/report'
|
|
4
|
-
|
|
5
|
-
module Reek
|
|
6
|
-
|
|
7
|
-
#
|
|
8
|
-
# Provides matchers for Rspec, making it easy to check code quality.
|
|
9
|
-
#
|
|
10
|
-
# If you require this module somewhere within your spec (or in your spec_helper),
|
|
11
|
-
# Reek will arrange to update Spec::Runner's config so that it knows about the
|
|
12
|
-
# matchers defined here.
|
|
13
|
-
#
|
|
14
|
-
# === Examples
|
|
15
|
-
#
|
|
16
|
-
# Here's a spec that ensures there are no smell warnings in the current project:
|
|
17
|
-
#
|
|
18
|
-
# describe 'source code quality' do
|
|
19
|
-
# Dir['lib/**/*.rb'].each do |path|
|
|
20
|
-
# it "reports no smells in #{path}" do
|
|
21
|
-
# File.new(path).should_not reek
|
|
22
|
-
# end
|
|
23
|
-
# end
|
|
24
|
-
# end
|
|
25
|
-
#
|
|
26
|
-
# And here's an even simpler way to do the same:
|
|
27
|
-
#
|
|
28
|
-
# it 'has no code smells' do
|
|
29
|
-
# Dir['lib/**/*.rb'].should_not reek
|
|
30
|
-
# end
|
|
31
|
-
#
|
|
32
|
-
# Here's a simple check of a code fragment:
|
|
33
|
-
#
|
|
34
|
-
# 'def equals(other) other.thing == self.thing end'.should_not reek
|
|
35
|
-
#
|
|
36
|
-
# And a more complex example, making use of one of the factory methods for
|
|
37
|
-
# +Source+ so that the code is parsed and analysed only once:
|
|
38
|
-
#
|
|
39
|
-
# ruby = 'def double_thing() @other.thing.foo + @other.thing.foo end'.sniff
|
|
40
|
-
# ruby.should reek_of(:Duplication, /@other.thing[^\.]/)
|
|
41
|
-
# ruby.should reek_of(:Duplication, /@other.thing.foo/)
|
|
42
|
-
# ruby.should_not reek_of(:FeatureEnvy)
|
|
43
|
-
#
|
|
44
|
-
module Spec
|
|
45
|
-
module ReekMatcher
|
|
46
|
-
def create_reporter(sniffers)
|
|
47
|
-
QuietReport.new(sniffers, false)
|
|
48
|
-
end
|
|
49
|
-
def report
|
|
50
|
-
create_reporter(@sniffer.sniffers).report
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
module_function :create_reporter
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
class ShouldReek # :nodoc:
|
|
57
|
-
include ReekMatcher
|
|
58
|
-
|
|
59
|
-
def matches?(actual)
|
|
60
|
-
@sniffer = actual.sniff
|
|
61
|
-
@sniffer.smelly?
|
|
62
|
-
end
|
|
63
|
-
def failure_message_for_should
|
|
64
|
-
"Expected #{@sniffer.desc} to reek, but it didn't"
|
|
65
|
-
end
|
|
66
|
-
def failure_message_for_should_not
|
|
67
|
-
"Expected no smells, but got:\n#{report}"
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
class ShouldReekOf # :nodoc:
|
|
72
|
-
include ReekMatcher
|
|
73
|
-
|
|
74
|
-
def initialize(klass, patterns)
|
|
75
|
-
@klass = klass
|
|
76
|
-
@patterns = patterns
|
|
77
|
-
end
|
|
78
|
-
def matches?(actual)
|
|
79
|
-
@sniffer = actual.sniff
|
|
80
|
-
@sniffer.has_smell?(@klass, @patterns)
|
|
81
|
-
end
|
|
82
|
-
def failure_message_for_should
|
|
83
|
-
"Expected #{@sniffer.desc} to reek of #{@klass}, but it didn't"
|
|
84
|
-
end
|
|
85
|
-
def failure_message_for_should_not
|
|
86
|
-
"Expected #{@sniffer.desc} not to reek of #{@klass}, but got:\n#{report}"
|
|
87
|
-
end
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
class ShouldReekOnlyOf < ShouldReekOf # :nodoc:
|
|
91
|
-
def matches?(actual)
|
|
92
|
-
@sniffer = actual.sniff
|
|
93
|
-
@sniffer.num_smells == 1 and @sniffer.has_smell?(@klass, @patterns)
|
|
94
|
-
end
|
|
95
|
-
def failure_message_for_should
|
|
96
|
-
"Expected #{@sniffer.desc} to reek only of #{@klass}, but got:\n#{report}"
|
|
97
|
-
end
|
|
98
|
-
def failure_message_for_should_not
|
|
99
|
-
"Expected #{@sniffer.desc} not to reek only of #{@klass}, but it did"
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
#
|
|
104
|
-
# Returns +true+ if and only if the target source code contains smells.
|
|
105
|
-
#
|
|
106
|
-
def reek
|
|
107
|
-
ShouldReek.new
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
#
|
|
111
|
-
# Checks the target source code for instances of +smell_class+,
|
|
112
|
-
# and returns +true+ only if one of them has a report string matching
|
|
113
|
-
# all of the +patterns+.
|
|
114
|
-
#
|
|
115
|
-
def reek_of(smell_class, *patterns)
|
|
116
|
-
ShouldReekOf.new(smell_class, patterns)
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
#
|
|
120
|
-
# As for reek_of, but the matched smell warning must be the only warning of
|
|
121
|
-
# any kind in the target source code's Reek report.
|
|
122
|
-
#
|
|
123
|
-
def reek_only_of(smell_class, *patterns)
|
|
124
|
-
ShouldReekOnlyOf.new(smell_class, patterns)
|
|
125
|
-
end
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
if Object.const_defined?(:Spec)
|
|
130
|
-
Spec::Runner.configure do |config|
|
|
131
|
-
config.include(Reek::Spec)
|
|
132
|
-
end
|
|
133
|
-
end
|
data/lib/reek/block_context.rb
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
require 'set'
|
|
2
|
-
require 'reek/code_context'
|
|
3
|
-
|
|
4
|
-
module Reek
|
|
5
|
-
|
|
6
|
-
module ParameterSet
|
|
7
|
-
def names
|
|
8
|
-
return @names if @names
|
|
9
|
-
return (@names = []) if empty?
|
|
10
|
-
arg = slice(1)
|
|
11
|
-
case slice(0)
|
|
12
|
-
when :masgn
|
|
13
|
-
@names = arg[1..-1].map {|lasgn| Name.new(lasgn[1]) }
|
|
14
|
-
when :lasgn, :iasgn
|
|
15
|
-
@names = [Name.new(arg)]
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def include?(name)
|
|
20
|
-
names.include?(name)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
class VariableContainer < CodeContext
|
|
25
|
-
|
|
26
|
-
def initialize(outer, exp)
|
|
27
|
-
super
|
|
28
|
-
@local_variables = Set.new
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def record_local_variable(sym)
|
|
32
|
-
@local_variables << Name.new(sym)
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
class BlockContext < VariableContainer
|
|
37
|
-
|
|
38
|
-
def initialize(outer, exp)
|
|
39
|
-
super
|
|
40
|
-
@name = Name.new('block')
|
|
41
|
-
@scope_connector = '/'
|
|
42
|
-
@parameters = exp[2] || []
|
|
43
|
-
@parameters.extend(ParameterSet)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def inside_a_block?
|
|
47
|
-
true
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def has_parameter(name)
|
|
51
|
-
@parameters.include?(name) or @outer.has_parameter(name)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def nested_block?
|
|
55
|
-
@outer.inside_a_block?
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def variable_names
|
|
59
|
-
@parameters.names + @local_variables.to_a
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
data/lib/reek/class_context.rb
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
require 'set'
|
|
2
|
-
require 'reek/module_context'
|
|
3
|
-
|
|
4
|
-
class Class
|
|
5
|
-
def is_overriding_method?(name)
|
|
6
|
-
sym = name.to_sym
|
|
7
|
-
mine = instance_methods(false)
|
|
8
|
-
dads = superclass.instance_methods(true)
|
|
9
|
-
(mine.include?(sym) and dads.include?(sym)) or (mine.include?(name) and dads.include?(name))
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
module Reek
|
|
14
|
-
class ClassContext < ModuleContext
|
|
15
|
-
|
|
16
|
-
attr_reader :parsed_methods
|
|
17
|
-
|
|
18
|
-
def initialize(outer, name, exp)
|
|
19
|
-
super
|
|
20
|
-
@superclass = exp[2]
|
|
21
|
-
@instance_variables = Set.new
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def is_overriding_method?(name)
|
|
25
|
-
return false unless myself
|
|
26
|
-
@myself.is_overriding_method?(name.to_s)
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def is_struct?
|
|
30
|
-
@superclass == [:const, :Struct]
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def record_instance_variable(sym)
|
|
34
|
-
@instance_variables << Name.new(sym)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def variable_names
|
|
38
|
-
@instance_variables
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
data/lib/reek/code_context.rb
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
class Module
|
|
2
|
-
|
|
3
|
-
def const_or_nil(sym)
|
|
4
|
-
const_defined?(sym) ? const_get(sym) : nil
|
|
5
|
-
end
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
module Reek
|
|
9
|
-
|
|
10
|
-
#
|
|
11
|
-
# Superclass for all types of source code context. Each instance represents
|
|
12
|
-
# a code element of some kind, and each provides behaviour relevant to that
|
|
13
|
-
# code element. CodeContexts form a tree in the same way the code does,
|
|
14
|
-
# with each context holding a reference to a unique outer context.
|
|
15
|
-
#
|
|
16
|
-
class CodeContext
|
|
17
|
-
|
|
18
|
-
attr_reader :name, :exp
|
|
19
|
-
|
|
20
|
-
def initialize(outer, exp)
|
|
21
|
-
@outer = outer
|
|
22
|
-
@exp = exp
|
|
23
|
-
@scope_connector = ''
|
|
24
|
-
@myself = nil
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def local_nodes(type, &blk)
|
|
28
|
-
each_node(type, [:class, :module], &blk)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def each_node(type, ignoring, &blk)
|
|
32
|
-
if block_given?
|
|
33
|
-
@exp.look_for(type, ignoring, &blk)
|
|
34
|
-
else
|
|
35
|
-
result = []
|
|
36
|
-
@exp.look_for(type, ignoring) {|exp| result << exp}
|
|
37
|
-
result
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
# SMELL: Temporary Field -- @name isn't always initialized
|
|
42
|
-
def matches?(strings)
|
|
43
|
-
me = @name.to_s
|
|
44
|
-
strings.any? do |str|
|
|
45
|
-
re = /#{str}/
|
|
46
|
-
re === me or re === self.full_name
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
#
|
|
51
|
-
# Bounces messages up the context tree to the first enclosing context
|
|
52
|
-
# that knows how to deal with the request.
|
|
53
|
-
#
|
|
54
|
-
def method_missing(method, *args)
|
|
55
|
-
@outer.send(method, *args)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def num_methods
|
|
59
|
-
0
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def full_name
|
|
63
|
-
outer = @outer ? @outer.full_name : ''
|
|
64
|
-
prefix = outer == '' ? '' : "#{outer}#{@scope_connector}"
|
|
65
|
-
"#{prefix}#{@name}"
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
end
|
data/lib/reek/code_parser.rb
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
require 'sexp'
|
|
2
|
-
require 'reek/block_context'
|
|
3
|
-
require 'reek/class_context'
|
|
4
|
-
require 'reek/module_context'
|
|
5
|
-
require 'reek/stop_context'
|
|
6
|
-
require 'reek/if_context'
|
|
7
|
-
require 'reek/method_context'
|
|
8
|
-
require 'reek/singleton_method_context'
|
|
9
|
-
require 'reek/yield_call_context'
|
|
10
|
-
|
|
11
|
-
module Reek
|
|
12
|
-
#
|
|
13
|
-
# Traverses a Sexp abstract syntax tree and fires events whenever
|
|
14
|
-
# it encounters specific node types.
|
|
15
|
-
#
|
|
16
|
-
class CodeParser
|
|
17
|
-
def initialize(sniffer, ctx = StopContext.new)
|
|
18
|
-
@sniffer = sniffer
|
|
19
|
-
@element = ctx
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def process(exp)
|
|
23
|
-
meth = "process_#{exp[0]}"
|
|
24
|
-
meth = :process_default unless self.respond_to?(meth)
|
|
25
|
-
self.send(meth, exp)
|
|
26
|
-
@element
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def process_default(exp)
|
|
30
|
-
exp[0..-1].each { |sub| process(sub) if Array === sub }
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def do_module_or_class(exp, context_class)
|
|
34
|
-
scope = context_class.create(@element, exp)
|
|
35
|
-
push(scope) do
|
|
36
|
-
process_default(exp) unless @element.is_struct?
|
|
37
|
-
check_smells(exp[0])
|
|
38
|
-
end
|
|
39
|
-
scope
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def process_module(exp)
|
|
43
|
-
do_module_or_class(exp, ModuleContext)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def process_class(exp)
|
|
47
|
-
do_module_or_class(exp, ClassContext)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
def process_defn(exp)
|
|
51
|
-
handle_context(MethodContext, exp[0], exp)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def process_defs(exp)
|
|
55
|
-
handle_context(SingletonMethodContext, exp[0], exp)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def process_args(exp) end
|
|
59
|
-
|
|
60
|
-
def process_attrset(exp)
|
|
61
|
-
@element.record_depends_on_self if /^@/ === exp[1].to_s
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def process_zsuper(exp)
|
|
65
|
-
@element.record_use_of_self
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def process_lit(exp)
|
|
69
|
-
val = exp[1]
|
|
70
|
-
@element.record_depends_on_self if val == :self
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def process_iter(exp)
|
|
74
|
-
process(exp[1])
|
|
75
|
-
scope = BlockContext.new(@element, exp)
|
|
76
|
-
push(scope) do
|
|
77
|
-
process_default(exp[2..-1])
|
|
78
|
-
check_smells(exp[0])
|
|
79
|
-
end
|
|
80
|
-
scope
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def process_block(exp)
|
|
84
|
-
@element.count_statements(CodeParser.count_statements(exp))
|
|
85
|
-
process_default(exp)
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
def process_yield(exp)
|
|
89
|
-
handle_context(YieldCallContext, exp[0], exp)
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def process_call(exp)
|
|
93
|
-
@element.record_call_to(exp)
|
|
94
|
-
process_default(exp)
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def process_cfunc(exp)
|
|
98
|
-
@element.record_depends_on_self
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def process_attrasgn(exp)
|
|
102
|
-
process_call(exp)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def process_op_asgn1(exp)
|
|
106
|
-
process_call(exp)
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def process_if(exp)
|
|
110
|
-
count_clause(exp[2])
|
|
111
|
-
count_clause(exp[3])
|
|
112
|
-
handle_context(IfContext, exp[0], exp)
|
|
113
|
-
@element.count_statements(-1)
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
def process_while(exp)
|
|
117
|
-
process_until(exp)
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
def process_until(exp)
|
|
121
|
-
count_clause(exp[2])
|
|
122
|
-
process_case(exp)
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def process_for(exp)
|
|
126
|
-
count_clause(exp[3])
|
|
127
|
-
process_case(exp)
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def process_rescue(exp)
|
|
131
|
-
count_clause(exp[1])
|
|
132
|
-
process_case(exp)
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
def process_resbody(exp)
|
|
136
|
-
process_when(exp)
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
def process_case(exp)
|
|
140
|
-
process_default(exp)
|
|
141
|
-
@element.count_statements(-1)
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
def process_when(exp)
|
|
145
|
-
count_clause(exp[2])
|
|
146
|
-
process_default(exp)
|
|
147
|
-
end
|
|
148
|
-
|
|
149
|
-
def process_ivar(exp)
|
|
150
|
-
process_iasgn(exp)
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def process_lasgn(exp)
|
|
154
|
-
@element.record_local_variable(exp[1])
|
|
155
|
-
process_default(exp)
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
def process_iasgn(exp)
|
|
159
|
-
@element.record_instance_variable(exp[1])
|
|
160
|
-
@element.record_depends_on_self
|
|
161
|
-
process_default(exp)
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def process_self(exp)
|
|
165
|
-
@element.record_use_of_self
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
def count_clause(sexp)
|
|
169
|
-
if sexp and !sexp.has_type?(:block)
|
|
170
|
-
@element.count_statements(1)
|
|
171
|
-
end
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
def self.count_statements(exp)
|
|
175
|
-
stmts = exp[1..-1]
|
|
176
|
-
ignore = 0
|
|
177
|
-
ignore += 1 if stmts[1] == s(:nil)
|
|
178
|
-
stmts.length - ignore
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
private
|
|
182
|
-
|
|
183
|
-
def handle_context(klass, type, exp)
|
|
184
|
-
scope = klass.new(@element, exp)
|
|
185
|
-
push(scope) do
|
|
186
|
-
process_default(exp)
|
|
187
|
-
check_smells(type)
|
|
188
|
-
end
|
|
189
|
-
scope
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
def check_smells(type)
|
|
193
|
-
@sniffer.examine(@element, type)
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
def push(context)
|
|
197
|
-
orig = @element
|
|
198
|
-
@element = context
|
|
199
|
-
yield
|
|
200
|
-
@element = orig
|
|
201
|
-
end
|
|
202
|
-
end
|
|
203
|
-
end
|
data/lib/reek/configuration.rb
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
module Reek
|
|
2
|
-
|
|
3
|
-
#
|
|
4
|
-
# Represents a single set of configuration options for a smell detector
|
|
5
|
-
#
|
|
6
|
-
class SmellConfiguration
|
|
7
|
-
|
|
8
|
-
# The name of the config field that specifies whether a smell is
|
|
9
|
-
# enabled. Set to +true+ or +false+.
|
|
10
|
-
ENABLED_KEY = 'enabled'
|
|
11
|
-
|
|
12
|
-
# The name of the config field that sets scope-specific overrides
|
|
13
|
-
# for other values in the current smell detector's configuration.
|
|
14
|
-
OVERRIDES_KEY = 'overrides'
|
|
15
|
-
|
|
16
|
-
def initialize(hash)
|
|
17
|
-
@options = hash
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def adopt!(options)
|
|
21
|
-
@options.adopt!(options)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def deep_copy
|
|
25
|
-
@options.deep_copy # SMELL: Open Secret -- returns a Hash
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# SMELL: Getter
|
|
29
|
-
def enabled?
|
|
30
|
-
@options[ENABLED_KEY]
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def overrides_for(context)
|
|
34
|
-
Overrides.new(@options.fetch(OVERRIDES_KEY, {})).for_context(context)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
# Retrieves the value, if any, for the given +key+.
|
|
38
|
-
#
|
|
39
|
-
# Returns +fall_back+ if this config has no value for the key.
|
|
40
|
-
#
|
|
41
|
-
def value(key, context, fall_back)
|
|
42
|
-
overrides_for(context).each { |conf| return conf[key] if conf.has_key?(key) }
|
|
43
|
-
return @options.fetch(key, fall_back)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
class Overrides
|
|
48
|
-
def initialize(hash)
|
|
49
|
-
@hash = hash
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def for_context(context)
|
|
53
|
-
contexts = @hash.keys.select {|ckey| context.matches?([ckey])}
|
|
54
|
-
contexts.map { |exc| @hash[exc] }
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
data/lib/reek/detector_stack.rb
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
module Reek
|
|
3
|
-
class DetectorStack
|
|
4
|
-
|
|
5
|
-
def initialize(default_detector)
|
|
6
|
-
@detectors = [default_detector]
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def push(config)
|
|
10
|
-
clone = @detectors[-1].supersede_with(config)
|
|
11
|
-
@detectors << clone
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def listen_to(hooks)
|
|
15
|
-
@detectors.each { |det| det.listen_to(hooks) }
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def report_on(report)
|
|
19
|
-
@detectors.each { |det| det.report_on(report) }
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
def num_smells
|
|
23
|
-
@detectors.inject(0) { |total, detector| total += detector.num_smells }
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def has_smell?(patterns)
|
|
27
|
-
@detectors.each { |det| return true if det.has_smell?(patterns) }
|
|
28
|
-
false
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def smelly?
|
|
32
|
-
# SMELL: Duplication: look at all those loops!
|
|
33
|
-
@detectors.each { |det| return true if det.smelly? }
|
|
34
|
-
false
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
data/lib/reek/help_command.rb
DELETED
data/lib/reek/if_context.rb
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
require 'reek/code_context'
|
|
2
|
-
|
|
3
|
-
module Reek
|
|
4
|
-
class IfContext < CodeContext
|
|
5
|
-
attr_reader :if_expr
|
|
6
|
-
|
|
7
|
-
def initialize(outer, exp)
|
|
8
|
-
super
|
|
9
|
-
@name = ''
|
|
10
|
-
@scope_connector = ''
|
|
11
|
-
@if_expr = exp[1]
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
def tests_a_parameter?
|
|
15
|
-
@if_expr[0] == :lvar and has_parameter(@if_expr[1])
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
require 'set'
|
|
2
|
-
|
|
3
|
-
#
|
|
4
|
-
# A set of items that can be "masked" or "visible". If an item is added
|
|
5
|
-
# more than once, only the "visible" copy is retained.
|
|
6
|
-
#
|
|
7
|
-
class MaskingCollection
|
|
8
|
-
def initialize
|
|
9
|
-
@visible_items = SortedSet.new
|
|
10
|
-
@masked_items = SortedSet.new
|
|
11
|
-
end
|
|
12
|
-
def found_smell(item)
|
|
13
|
-
@visible_items.add(item)
|
|
14
|
-
@masked_items.delete(item) if @masked_items.include?(item)
|
|
15
|
-
end
|
|
16
|
-
def found_masked_smell(item)
|
|
17
|
-
@masked_items.add(item) unless @visible_items.include?(item)
|
|
18
|
-
end
|
|
19
|
-
def num_visible_items
|
|
20
|
-
@visible_items.length
|
|
21
|
-
end
|
|
22
|
-
def num_masked_items
|
|
23
|
-
@masked_items.length
|
|
24
|
-
end
|
|
25
|
-
def each_item(&blk)
|
|
26
|
-
all = SortedSet.new(@visible_items)
|
|
27
|
-
all.merge(@masked_items)
|
|
28
|
-
all.each(&blk)
|
|
29
|
-
end
|
|
30
|
-
def each_visible_item(&blk)
|
|
31
|
-
@visible_items.each(&blk)
|
|
32
|
-
end
|
|
33
|
-
end
|