reek 2.0.4 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +13 -0
- data/.rubocop.yml +66 -0
- data/.ruby-gemset +1 -0
- data/.travis.yml +25 -0
- data/CHANGELOG +6 -0
- data/CONTRIBUTING.md +106 -0
- data/Gemfile +14 -0
- data/README.md +16 -21
- data/bin/reek +2 -2
- data/config/cucumber.yml +3 -0
- data/config/defaults.reek +1 -1
- data/features/command_line_interface/smell_selection.feature +4 -8
- data/features/command_line_interface/smells_count.feature +25 -32
- data/features/command_line_interface/stdin.feature +2 -2
- data/features/configuration_files/masking_smells.feature +30 -41
- data/features/configuration_files/overrides_defaults.feature +5 -3
- data/features/configuration_loading.feature +26 -23
- data/features/programmatic_access.feature +24 -0
- data/features/rake_task/rake_task.feature +25 -22
- data/features/reports/json.feature +24 -26
- data/features/reports/reports.feature +77 -103
- data/features/reports/yaml.feature +26 -20
- data/features/ruby_api/api.feature +4 -3
- data/features/samples.feature +21 -20
- data/features/step_definitions/.rubocop.yml +5 -0
- data/features/step_definitions/reek_steps.rb +16 -28
- data/features/step_definitions/sample_file_steps.rb +158 -0
- data/features/support/env.rb +16 -27
- data/lib/reek.rb +3 -3
- data/lib/reek/cli/application.rb +4 -4
- data/lib/reek/cli/command.rb +1 -1
- data/lib/reek/cli/input.rb +2 -4
- data/lib/reek/cli/option_interpreter.rb +9 -9
- data/lib/reek/cli/options.rb +5 -4
- data/lib/reek/cli/reek_command.rb +3 -3
- data/lib/reek/cli/report/formatter.rb +2 -2
- data/lib/reek/cli/report/heading_formatter.rb +1 -1
- data/lib/reek/cli/report/location_formatter.rb +1 -1
- data/lib/reek/cli/report/report.rb +4 -4
- data/lib/reek/configuration/app_configuration.rb +1 -1
- data/lib/reek/configuration/configuration_file_finder.rb +17 -32
- data/lib/reek/core/code_context.rb +1 -1
- data/lib/reek/core/method_context.rb +6 -2
- data/lib/reek/core/module_context.rb +2 -2
- data/lib/reek/core/singleton_method_context.rb +1 -1
- data/lib/reek/core/smell_repository.rb +3 -2
- data/lib/reek/core/tree_walker.rb +4 -4
- data/lib/reek/examiner.rb +4 -4
- data/lib/reek/smells/attribute.rb +3 -3
- data/lib/reek/smells/boolean_parameter.rb +2 -2
- data/lib/reek/smells/class_variable.rb +2 -2
- data/lib/reek/smells/control_parameter.rb +2 -2
- data/lib/reek/smells/data_clump.rb +2 -3
- data/lib/reek/smells/duplicate_method_call.rb +2 -2
- data/lib/reek/smells/feature_envy.rb +6 -2
- data/lib/reek/smells/irresponsible_module.rb +3 -3
- data/lib/reek/smells/long_parameter_list.rb +3 -3
- data/lib/reek/smells/long_yield_list.rb +2 -2
- data/lib/reek/smells/module_initialize.rb +2 -2
- data/lib/reek/smells/nested_iterators.rb +2 -2
- data/lib/reek/smells/nil_check.rb +2 -2
- data/lib/reek/smells/prima_donna_method.rb +2 -2
- data/lib/reek/smells/repeated_conditional.rb +3 -2
- data/lib/reek/smells/smell_detector.rb +2 -2
- data/lib/reek/smells/too_many_instance_variables.rb +2 -2
- data/lib/reek/smells/too_many_methods.rb +2 -2
- data/lib/reek/smells/too_many_statements.rb +2 -2
- data/lib/reek/smells/uncommunicative_method_name.rb +2 -2
- data/lib/reek/smells/uncommunicative_module_name.rb +2 -2
- data/lib/reek/smells/uncommunicative_parameter_name.rb +2 -2
- data/lib/reek/smells/uncommunicative_variable_name.rb +2 -2
- data/lib/reek/smells/unused_parameters.rb +2 -2
- data/lib/reek/smells/utility_function.rb +8 -9
- data/lib/reek/source/ast_node.rb +1 -1
- data/lib/reek/source/ast_node_class_map.rb +6 -6
- data/lib/reek/source/sexp_extensions.rb +11 -2
- data/lib/reek/source/source_code.rb +10 -2
- data/lib/reek/source/source_locator.rb +1 -3
- data/lib/reek/source/source_repository.rb +3 -4
- data/lib/reek/source/tree_dresser.rb +2 -2
- data/lib/reek/spec.rb +3 -3
- data/lib/reek/spec/should_reek.rb +3 -3
- data/lib/reek/spec/should_reek_of.rb +1 -1
- data/lib/reek/spec/should_reek_only_of.rb +3 -3
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +18 -24
- data/spec/factories/factories.rb +1 -1
- data/spec/gem/updates_spec.rb +1 -1
- data/spec/gem/yard_spec.rb +1 -1
- data/spec/quality/reek_source_spec.rb +1 -1
- data/spec/reek/cli/html_report_spec.rb +6 -9
- data/spec/reek/cli/json_report_spec.rb +6 -6
- data/spec/reek/cli/option_interperter_spec.rb +5 -5
- data/spec/reek/cli/text_report_spec.rb +16 -19
- data/spec/reek/cli/yaml_report_spec.rb +7 -10
- data/spec/reek/configuration/app_configuration_spec.rb +23 -25
- data/spec/reek/configuration/configuration_file_finder_spec.rb +46 -21
- data/spec/reek/core/code_context_spec.rb +17 -19
- data/spec/reek/core/method_context_spec.rb +15 -14
- data/spec/reek/core/module_context_spec.rb +5 -7
- data/spec/reek/core/object_refs_spec.rb +4 -6
- data/spec/reek/core/singleton_method_context_spec.rb +5 -7
- data/spec/reek/core/smell_configuration_spec.rb +5 -7
- data/spec/reek/core/smell_repository_spec.rb +8 -8
- data/spec/reek/core/stop_context_spec.rb +4 -7
- data/spec/reek/core/tree_walker_spec.rb +5 -7
- data/spec/reek/core/warning_collector_spec.rb +5 -7
- data/spec/reek/examiner_spec.rb +10 -12
- data/spec/reek/smell_warning_spec.rb +7 -9
- data/spec/reek/smells/attribute_spec.rb +6 -6
- data/spec/reek/smells/boolean_parameter_spec.rb +4 -4
- data/spec/reek/smells/class_variable_spec.rb +6 -6
- data/spec/reek/smells/control_parameter_spec.rb +4 -4
- data/spec/reek/smells/data_clump_spec.rb +4 -4
- data/spec/reek/smells/duplicate_method_call_spec.rb +6 -6
- data/spec/reek/smells/feature_envy_spec.rb +9 -10
- data/spec/reek/smells/irresponsible_module_spec.rb +7 -7
- data/spec/reek/smells/long_parameter_list_spec.rb +5 -5
- data/spec/reek/smells/long_yield_list_spec.rb +5 -5
- data/spec/reek/smells/module_initialize_spec.rb +3 -3
- data/spec/reek/smells/nested_iterators_spec.rb +4 -4
- data/spec/reek/smells/nil_check_spec.rb +5 -5
- data/spec/reek/smells/prima_donna_method_spec.rb +7 -4
- data/spec/reek/smells/repeated_conditional_spec.rb +12 -11
- data/spec/reek/smells/smell_detector_shared.rb +4 -5
- data/spec/reek/smells/too_many_instance_variables_spec.rb +4 -4
- data/spec/reek/smells/too_many_methods_spec.rb +11 -7
- data/spec/reek/smells/too_many_statements_spec.rb +6 -5
- data/spec/reek/smells/uncommunicative_method_name_spec.rb +4 -4
- data/spec/reek/smells/uncommunicative_module_name_spec.rb +7 -7
- data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +5 -5
- data/spec/reek/smells/uncommunicative_variable_name_spec.rb +9 -6
- data/spec/reek/smells/unused_parameters_spec.rb +3 -3
- data/spec/reek/smells/utility_function_spec.rb +41 -37
- data/spec/reek/source/code_comment_spec.rb +19 -17
- data/spec/reek/source/object_source_spec.rb +1 -3
- data/spec/reek/source/reference_collector_spec.rb +5 -6
- data/spec/reek/source/sexp_extensions_spec.rb +9 -11
- data/spec/reek/source/sexp_formatter_spec.rb +7 -8
- data/spec/reek/source/sexp_node_spec.rb +3 -5
- data/spec/reek/source/source_code_spec.rb +9 -9
- data/spec/reek/source/tree_dresser_spec.rb +4 -6
- data/spec/reek/spec/should_reek_of_spec.rb +11 -10
- data/spec/reek/spec/should_reek_only_of_spec.rb +4 -7
- data/spec/reek/spec/should_reek_spec.rb +4 -7
- data/spec/samples/{overrides/masked/lower.reek → masked_by_dotfile/.reek} +3 -1
- data/spec/spec_helper.rb +4 -4
- data/tasks/develop.rake +1 -1
- data/tasks/reek.rake +1 -1
- metadata +72 -86
- data/features/support/hooks.rb +0 -15
- data/lib/reek/source.rb +0 -16
- data/lib/reek/source/core_extras.rb +0 -46
- data/lib/reek/source/source_file.rb +0 -16
- data/spec/samples/config/allow_duplication.reek +0 -3
- data/spec/samples/config/deeper_nested_iterators.reek +0 -3
- data/spec/samples/configuration_loading/minimal_dirty.rb +0 -4
- data/spec/samples/configuration_loading/reek-test-run-disable_smells.reek +0 -7
- data/spec/samples/configuration_loading/reek-test-run-enable_smells.reek +0 -7
- data/spec/samples/corrupt_config_file/corrupt.reek +0 -1
- data/spec/samples/corrupt_config_file/dirty.rb +0 -8
- data/spec/samples/demo/demo.rb +0 -8
- data/spec/samples/empty_config_file/dirty.rb +0 -8
- data/spec/samples/empty_config_file/empty.reek +0 -0
- data/spec/samples/inline_config/dirty.rb +0 -16
- data/spec/samples/inline_config/masked.reek +0 -7
- data/spec/samples/mask_some/dirty.rb +0 -8
- data/spec/samples/mask_some/some.reek +0 -8
- data/spec/samples/masked/dirty.rb +0 -8
- data/spec/samples/masked/masked.reek +0 -5
- data/spec/samples/minimal_smelly_and_masked/config.reek +0 -7
- data/spec/samples/minimal_smelly_and_masked/minimal_dirty.rb +0 -4
- data/spec/samples/mixed_results/clean_one.rb +0 -7
- data/spec/samples/mixed_results/clean_three.rb +0 -7
- data/spec/samples/mixed_results/clean_two.rb +0 -7
- data/spec/samples/mixed_results/dirty_one.rb +0 -8
- data/spec/samples/mixed_results/dirty_two.rb +0 -8
- data/spec/samples/not_quite_masked/dirty.rb +0 -8
- data/spec/samples/not_quite_masked/masked.reek +0 -5
- data/spec/samples/not_quite_masked/smelly.rb +0 -3
- data/spec/samples/one_smelly_file/dirty.rb +0 -3
- data/spec/samples/overrides/masked/dirty.rb +0 -8
- data/spec/samples/overrides/upper.reek +0 -5
- data/spec/samples/overrides_defaults/camel_case.rb +0 -14
- data/spec/samples/overrides_defaults/config.reek +0 -6
- data/spec/samples/standard_smelly/dirty.rb +0 -8
- data/spec/samples/standard_smelly/minimal_dirty.rb +0 -4
- data/spec/samples/three_smelly_files/dirty_one.rb +0 -3
- data/spec/samples/three_smelly_files/dirty_three.rb +0 -5
- data/spec/samples/three_smelly_files/dirty_two.rb +0 -4
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative 'smell_detector'
|
2
|
+
require_relative '../smell_warning'
|
3
3
|
|
4
4
|
module Reek
|
5
5
|
module Smells
|
@@ -30,6 +30,9 @@ module Reek
|
|
30
30
|
# Currently +FeatureEnvy+ reports any method that refers to self less
|
31
31
|
# often than it refers to (ie. send messages to) some other object.
|
32
32
|
#
|
33
|
+
# If the method doesn't reference self at all, +UtilityFunction+ is
|
34
|
+
# reported instead.
|
35
|
+
#
|
33
36
|
class FeatureEnvy < SmellDetector
|
34
37
|
def self.smell_category
|
35
38
|
'LowCohesion'
|
@@ -42,6 +45,7 @@ module Reek
|
|
42
45
|
# @return [Array<SmellWarning>]
|
43
46
|
#
|
44
47
|
def examine_context(method_ctx)
|
48
|
+
return [] unless method_ctx.references_self?
|
45
49
|
method_ctx.envious_receivers.map do |ref, occurs|
|
46
50
|
target = ref.to_s
|
47
51
|
SmellWarning.new self,
|
@@ -1,6 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require_relative 'smell_detector'
|
2
|
+
require_relative '../smell_warning'
|
3
|
+
require_relative '../core/smell_configuration'
|
4
4
|
|
5
5
|
module Reek
|
6
6
|
module Smells
|
@@ -1,6 +1,6 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require_relative 'smell_detector'
|
2
|
+
require_relative '../smell_warning'
|
3
|
+
require_relative '../source/reference_collector'
|
4
4
|
|
5
5
|
module Reek
|
6
6
|
module Smells
|
@@ -32,13 +32,16 @@ module Reek
|
|
32
32
|
# reified into a class, and the utility method will most
|
33
33
|
# likely belong there.
|
34
34
|
#
|
35
|
+
# If the method does refer to self, but refers to some other object more,
|
36
|
+
# +FeatureEnvy+ is reported instead.
|
37
|
+
#
|
35
38
|
class UtilityFunction < SmellDetector
|
36
39
|
# The name of the config field that sets the maximum number of
|
37
40
|
# calls permitted within a helper method. Any method with more than
|
38
41
|
# this number of method calls on other objects will be considered a
|
39
42
|
# candidate Utility Function.
|
40
43
|
HELPER_CALLS_LIMIT_KEY = 'max_helper_calls'
|
41
|
-
DEFAULT_HELPER_CALLS_LIMIT =
|
44
|
+
DEFAULT_HELPER_CALLS_LIMIT = 0
|
42
45
|
|
43
46
|
def self.smell_category
|
44
47
|
'LowCohesion'
|
@@ -61,7 +64,7 @@ module Reek
|
|
61
64
|
#
|
62
65
|
def examine_context(method_ctx)
|
63
66
|
return [] if method_ctx.num_statements == 0
|
64
|
-
return [] if
|
67
|
+
return [] if method_ctx.references_self?
|
65
68
|
return [] if num_helper_methods(method_ctx) <= value(HELPER_CALLS_LIMIT_KEY,
|
66
69
|
method_ctx,
|
67
70
|
DEFAULT_HELPER_CALLS_LIMIT)
|
@@ -75,10 +78,6 @@ module Reek
|
|
75
78
|
|
76
79
|
private
|
77
80
|
|
78
|
-
def depends_on_instance?(exp)
|
79
|
-
Reek::Source::ReferenceCollector.new(exp).num_refs_to_self > 0
|
80
|
-
end
|
81
|
-
|
82
81
|
def num_helper_methods(method_ctx)
|
83
82
|
method_ctx.local_nodes(:send).length
|
84
83
|
end
|
data/lib/reek/source/ast_node.rb
CHANGED
@@ -4,7 +4,7 @@ module Reek
|
|
4
4
|
module Source
|
5
5
|
# Base class for AST nodes extended with utility methods. Contains some
|
6
6
|
# methods to ease the transition from Sexp to AST::Node.
|
7
|
-
class
|
7
|
+
class ASTNode < Parser::AST::Node
|
8
8
|
def initialize(type, children = [], options = {})
|
9
9
|
@comments = options.fetch(:comments, [])
|
10
10
|
super
|
@@ -1,12 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require_relative 'ast_node'
|
2
|
+
require_relative 'sexp_node'
|
3
|
+
require_relative 'sexp_extensions'
|
4
4
|
|
5
5
|
module Reek
|
6
6
|
module Source
|
7
|
-
# Maps AST node types to sublasses of
|
7
|
+
# Maps AST node types to sublasses of ASTNode extended with the relevant
|
8
8
|
# utility modules.
|
9
|
-
class
|
9
|
+
class ASTNodeClassMap
|
10
10
|
def initialize
|
11
11
|
@klass_map = {}
|
12
12
|
end
|
@@ -14,7 +14,7 @@ module Reek
|
|
14
14
|
def klass_for(type)
|
15
15
|
@klass_map[type] ||=
|
16
16
|
begin
|
17
|
-
klass = Class.new(
|
17
|
+
klass = Class.new(ASTNode)
|
18
18
|
klass.send :include, extension_map[type] if extension_map[type]
|
19
19
|
klass.send :include, SexpNode
|
20
20
|
end
|
@@ -1,9 +1,10 @@
|
|
1
|
-
|
1
|
+
require_relative 'sexp_node'
|
2
|
+
require_relative 'reference_collector'
|
2
3
|
|
3
4
|
module Reek
|
4
5
|
module Source
|
5
6
|
#
|
6
|
-
# Extension modules providing utility methods to
|
7
|
+
# Extension modules providing utility methods to ASTNode objects, depending
|
7
8
|
# on their type.
|
8
9
|
#
|
9
10
|
module SexpExtensions
|
@@ -239,6 +240,10 @@ module Reek
|
|
239
240
|
prefix = outer == '' ? '' : "#{outer}#"
|
240
241
|
"#{prefix}#{name}"
|
241
242
|
end
|
243
|
+
|
244
|
+
def depends_on_instance?
|
245
|
+
ReferenceCollector.new(self).num_refs_to_self > 0
|
246
|
+
end
|
242
247
|
end
|
243
248
|
|
244
249
|
# Utility methods for :defs nodes.
|
@@ -256,6 +261,10 @@ module Reek
|
|
256
261
|
prefix = outer == '' ? '' : "#{outer}#"
|
257
262
|
"#{prefix}#{SexpNode.format(receiver)}.#{name}"
|
258
263
|
end
|
264
|
+
|
265
|
+
def depends_on_instance?
|
266
|
+
false
|
267
|
+
end
|
259
268
|
end
|
260
269
|
|
261
270
|
# Utility methods for :if nodes.
|
@@ -1,8 +1,8 @@
|
|
1
1
|
old_verbose, $VERBOSE = $VERBOSE, nil
|
2
2
|
require 'parser/current'
|
3
3
|
$VERBOSE = old_verbose
|
4
|
-
|
5
|
-
|
4
|
+
require_relative 'tree_dresser'
|
5
|
+
require_relative 'ast_node'
|
6
6
|
|
7
7
|
module Reek
|
8
8
|
module Source
|
@@ -18,6 +18,14 @@ module Reek
|
|
18
18
|
@parser = parser
|
19
19
|
end
|
20
20
|
|
21
|
+
def self.from(source)
|
22
|
+
case source
|
23
|
+
when File then new(source.read, source.path)
|
24
|
+
when IO then new(source.readlines.join, 'STDIN')
|
25
|
+
when String then new(source, 'string')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
21
29
|
def syntax_tree
|
22
30
|
@syntax_tree ||=
|
23
31
|
begin
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'reek/source/core_extras'
|
2
|
-
|
3
1
|
module Reek
|
4
2
|
module Source
|
5
3
|
#
|
@@ -11,7 +9,7 @@ module Reek
|
|
11
9
|
end
|
12
10
|
|
13
11
|
def all_sources
|
14
|
-
valid_paths.map { |path| File.new(path)
|
12
|
+
valid_paths.map { |path| Source::SourceCode.from File.new(path) }
|
15
13
|
end
|
16
14
|
|
17
15
|
private
|
@@ -1,6 +1,5 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'reek/source/source_locator'
|
1
|
+
require_relative 'source_code'
|
2
|
+
require_relative 'source_locator'
|
4
3
|
|
5
4
|
module Reek
|
6
5
|
module Source
|
@@ -24,7 +23,7 @@ module Reek
|
|
24
23
|
when Source::SourceCode
|
25
24
|
new source.desc, [source]
|
26
25
|
else
|
27
|
-
src = source
|
26
|
+
src = Source::SourceCode.from source
|
28
27
|
new src.desc, [src]
|
29
28
|
end
|
30
29
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require_relative 'ast_node_class_map'
|
2
2
|
|
3
3
|
module Reek
|
4
4
|
module Source
|
@@ -7,7 +7,7 @@ module Reek
|
|
7
7
|
# the tree more understandable and less implementation-dependent.
|
8
8
|
#
|
9
9
|
class TreeDresser
|
10
|
-
def initialize(klass_map =
|
10
|
+
def initialize(klass_map = ASTNodeClassMap.new)
|
11
11
|
@klass_map = klass_map
|
12
12
|
end
|
13
13
|
|
data/lib/reek/spec.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative '../examiner'
|
2
|
+
require_relative '../cli/report/formatter'
|
3
3
|
|
4
4
|
module Reek
|
5
5
|
module Spec
|
@@ -17,7 +17,7 @@ module Reek
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def failure_message_when_negated
|
20
|
-
rpt =
|
20
|
+
rpt = CLI::Report::Formatter.format_list(@examiner.smells)
|
21
21
|
"Expected no smells, but got:\n#{rpt}"
|
22
22
|
end
|
23
23
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative '../examiner'
|
2
|
+
require_relative '../cli/report/formatter'
|
3
3
|
|
4
4
|
module Reek
|
5
5
|
module Spec
|
@@ -20,7 +20,7 @@ module Reek
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def failure_message
|
23
|
-
rpt =
|
23
|
+
rpt = CLI::Report::Formatter.format_list(@warnings)
|
24
24
|
"Expected #{@examiner.description} to reek only of #{@smell_category}, but got:\n#{rpt}"
|
25
25
|
end
|
26
26
|
|