reek 2.0.4 → 3.0.0
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.
- checksums.yaml +4 -4
- data/.gitignore +13 -0
- data/.rubocop.yml +47 -0
- data/.travis.yml +31 -0
- data/.yardopts +3 -6
- data/CHANGELOG +24 -0
- data/CONTRIBUTING.md +111 -0
- data/Gemfile +16 -0
- data/README.md +112 -59
- data/bin/reek +2 -2
- data/config/cucumber.yml +3 -0
- data/config/defaults.reek +0 -1
- data/docs/API.md +79 -0
- data/docs/Attribute.md +43 -0
- data/docs/Basic-Smell-Options.md +44 -0
- data/docs/Boolean-Parameter.md +52 -0
- data/docs/Class-Variable.md +40 -0
- data/docs/Code-Smells.md +34 -0
- data/docs/Command-Line-Options.md +84 -0
- data/docs/Configuration-Files.md +49 -0
- data/docs/Control-Couple.md +22 -0
- data/docs/Control-Parameter.md +29 -0
- data/docs/Data-Clump.md +44 -0
- data/docs/Duplicate-Method-Call.md +49 -0
- data/docs/Feature-Envy.md +49 -0
- data/docs/How-reek-works-internally.md +114 -0
- data/docs/Irresponsible-Module.md +39 -0
- data/docs/Large-Class.md +20 -0
- data/docs/Long-Parameter-List.md +38 -0
- data/docs/Long-Yield-List.md +36 -0
- data/docs/Module-Initialize.md +62 -0
- data/docs/Nested-Iterators.md +38 -0
- data/docs/Nil-Check.md +39 -0
- data/docs/Prima-Donna-Method.md +53 -0
- data/docs/RSpec-matchers.md +137 -0
- data/docs/Rake-Task.md +58 -0
- data/docs/Reek-Driven-Development.md +37 -0
- data/docs/Repeated-Conditional.md +44 -0
- data/docs/Simulated-Polymorphism.md +16 -0
- data/docs/Smell-Suppression.md +32 -0
- data/docs/Too-Many-Instance-Variables.md +43 -0
- data/docs/Too-Many-Methods.md +55 -0
- data/docs/Too-Many-Statements.md +50 -0
- data/docs/Uncommunicative-Method-Name.md +24 -0
- data/docs/Uncommunicative-Module-Name.md +23 -0
- data/docs/Uncommunicative-Name.md +16 -0
- data/docs/Uncommunicative-Parameter-Name.md +24 -0
- data/docs/Uncommunicative-Variable-Name.md +24 -0
- data/docs/Unused-Parameters.md +27 -0
- data/docs/Utility-Function.md +44 -0
- data/docs/Versioning-Policy.md +7 -0
- data/docs/YAML-Reports.md +111 -0
- data/docs/yard_plugin.rb +14 -0
- data/features/{ruby_api/api.feature → command_line_interface/basic_usage.feature} +6 -5
- data/features/command_line_interface/options.feature +1 -0
- 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 +43 -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/samples.feature +26 -31
- 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/{source → ast}/ast_node_class_map.rb +11 -12
- data/lib/reek/ast/node.rb +132 -0
- data/lib/reek/{core → ast}/object_refs.rb +2 -1
- data/lib/reek/ast/reference_collector.rb +32 -0
- data/lib/reek/{source → ast}/sexp_extensions.rb +43 -7
- data/lib/reek/ast/sexp_formatter.rb +31 -0
- data/lib/reek/cli/application.rb +5 -4
- data/lib/reek/cli/command.rb +2 -1
- data/lib/reek/cli/input.rb +6 -5
- data/lib/reek/cli/option_interpreter.rb +13 -9
- data/lib/reek/cli/options.rb +16 -8
- data/lib/reek/cli/reek_command.rb +4 -3
- data/lib/reek/cli/silencer.rb +14 -0
- data/lib/reek/{core → cli}/warning_collector.rb +2 -1
- data/lib/reek/code_comment.rb +36 -0
- data/lib/reek/configuration/app_configuration.rb +18 -3
- data/lib/reek/configuration/configuration_file_finder.rb +18 -32
- data/lib/reek/{core → context}/code_context.rb +8 -6
- data/lib/reek/{core → context}/method_context.rb +11 -5
- data/lib/reek/{core → context}/module_context.rb +9 -4
- data/lib/reek/{core/stop_context.rb → context/root_context.rb} +4 -2
- data/lib/reek/{core → context}/singleton_method_context.rb +3 -6
- data/lib/reek/examiner.rb +32 -29
- data/lib/reek/report/formatter.rb +70 -0
- data/lib/reek/report/heading_formatter.rb +45 -0
- data/lib/reek/report/location_formatter.rb +35 -0
- data/lib/reek/report/report.rb +198 -0
- data/lib/reek/smells/attribute.rb +41 -11
- data/lib/reek/smells/boolean_parameter.rb +4 -2
- data/lib/reek/smells/class_variable.rb +4 -2
- data/lib/reek/smells/control_parameter.rb +4 -2
- data/lib/reek/smells/data_clump.rb +4 -3
- data/lib/reek/smells/duplicate_method_call.rb +15 -5
- data/lib/reek/smells/feature_envy.rb +8 -2
- data/lib/reek/smells/irresponsible_module.rb +13 -8
- data/lib/reek/smells/long_parameter_list.rb +6 -4
- data/lib/reek/smells/long_yield_list.rb +4 -2
- data/lib/reek/smells/module_initialize.rb +4 -2
- data/lib/reek/smells/nested_iterators.rb +4 -2
- data/lib/reek/smells/nil_check.rb +6 -3
- data/lib/reek/smells/prima_donna_method.rb +21 -12
- data/lib/reek/smells/repeated_conditional.rb +7 -4
- data/lib/reek/{core → smells}/smell_configuration.rb +3 -1
- data/lib/reek/smells/smell_detector.rb +11 -5
- data/lib/reek/{core → smells}/smell_repository.rb +9 -5
- data/lib/reek/smells/smell_warning.rb +101 -0
- data/lib/reek/smells/too_many_instance_variables.rb +4 -2
- data/lib/reek/smells/too_many_methods.rb +4 -2
- data/lib/reek/smells/too_many_statements.rb +4 -2
- data/lib/reek/smells/uncommunicative_method_name.rb +4 -2
- data/lib/reek/smells/uncommunicative_module_name.rb +4 -2
- data/lib/reek/smells/uncommunicative_parameter_name.rb +4 -2
- data/lib/reek/smells/uncommunicative_variable_name.rb +4 -2
- data/lib/reek/smells/unused_parameters.rb +4 -2
- data/lib/reek/smells/utility_function.rb +11 -22
- data/lib/reek/smells.rb +24 -11
- data/lib/reek/source/source_code.rb +69 -12
- data/lib/reek/source/source_locator.rb +34 -19
- data/lib/reek/spec/should_reek.rb +4 -3
- data/lib/reek/spec/should_reek_of.rb +2 -1
- data/lib/reek/spec/should_reek_only_of.rb +4 -3
- data/lib/reek/spec.rb +3 -3
- data/lib/reek/tree_dresser.rb +32 -0
- data/lib/reek/tree_walker.rb +182 -0
- data/lib/reek/version.rb +1 -1
- data/lib/reek.rb +3 -3
- data/reek.gemspec +18 -25
- data/spec/factories/factories.rb +4 -2
- data/spec/gem/updates_spec.rb +1 -1
- data/spec/gem/yard_spec.rb +2 -2
- data/spec/quality/reek_source_spec.rb +3 -3
- data/spec/reek/{source/sexp_node_spec.rb → ast/node_spec.rb} +4 -6
- data/spec/reek/{core → ast}/object_refs_spec.rb +4 -6
- data/spec/reek/{source → ast}/reference_collector_spec.rb +27 -19
- data/spec/reek/{source → ast}/sexp_extensions_spec.rb +7 -19
- data/spec/reek/{source → ast}/sexp_formatter_spec.rb +13 -8
- data/spec/reek/cli/option_interpreter_spec.rb +15 -0
- data/spec/reek/cli/options_spec.rb +19 -0
- data/spec/reek/cli/warning_collector_spec.rb +28 -0
- data/spec/reek/{source/code_comment_spec.rb → code_comment_spec.rb} +19 -17
- data/spec/reek/configuration/app_configuration_spec.rb +37 -26
- data/spec/reek/configuration/configuration_file_finder_spec.rb +67 -21
- data/spec/reek/{core → context}/code_context_spec.rb +18 -21
- data/spec/reek/{core → context}/method_context_spec.rb +33 -27
- data/spec/reek/{core → context}/module_context_spec.rb +5 -7
- data/spec/reek/context/root_context_spec.rb +14 -0
- data/spec/reek/context/singleton_method_context_spec.rb +17 -0
- data/spec/reek/examiner_spec.rb +9 -50
- data/spec/reek/{cli → report}/html_report_spec.rb +6 -9
- data/spec/reek/report/json_report_spec.rb +20 -0
- data/spec/reek/{cli → report}/text_report_spec.rb +16 -19
- data/spec/reek/report/xml_report_spec.rb +34 -0
- data/spec/reek/report/yaml_report_spec.rb +20 -0
- data/spec/reek/smells/attribute_spec.rb +93 -88
- data/spec/reek/smells/behaves_like_variable_detector.rb +1 -1
- data/spec/reek/smells/boolean_parameter_spec.rb +31 -5
- data/spec/reek/smells/class_variable_spec.rb +10 -10
- data/spec/reek/smells/control_parameter_spec.rb +5 -5
- data/spec/reek/smells/data_clump_spec.rb +6 -6
- data/spec/reek/smells/duplicate_method_call_spec.rb +7 -7
- data/spec/reek/smells/feature_envy_spec.rb +12 -13
- data/spec/reek/smells/irresponsible_module_spec.rb +28 -32
- data/spec/reek/smells/long_parameter_list_spec.rb +7 -7
- data/spec/reek/smells/long_yield_list_spec.rb +6 -6
- data/spec/reek/smells/module_initialize_spec.rb +4 -4
- data/spec/reek/smells/nested_iterators_spec.rb +6 -6
- data/spec/reek/smells/nil_check_spec.rb +6 -6
- data/spec/reek/smells/prima_donna_method_spec.rb +8 -5
- data/spec/reek/smells/repeated_conditional_spec.rb +18 -17
- data/spec/reek/{core → smells}/smell_configuration_spec.rb +5 -7
- data/spec/reek/smells/smell_detector_shared.rb +6 -7
- data/spec/reek/smells/smell_repository_spec.rb +29 -0
- data/spec/reek/{smell_warning_spec.rb → smells/smell_warning_spec.rb} +7 -9
- data/spec/reek/smells/too_many_instance_variables_spec.rb +5 -5
- data/spec/reek/smells/too_many_methods_spec.rb +12 -8
- data/spec/reek/smells/too_many_statements_spec.rb +10 -9
- data/spec/reek/smells/uncommunicative_method_name_spec.rb +5 -5
- data/spec/reek/smells/uncommunicative_module_name_spec.rb +8 -8
- data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +18 -6
- data/spec/reek/smells/uncommunicative_variable_name_spec.rb +10 -7
- data/spec/reek/smells/unused_parameters_spec.rb +4 -4
- data/spec/reek/smells/utility_function_spec.rb +65 -39
- data/spec/reek/source/source_code_spec.rb +10 -10
- data/spec/reek/source/source_locator_spec.rb +30 -0
- data/spec/reek/spec/should_reek_of_spec.rb +9 -25
- data/spec/reek/spec/should_reek_only_of_spec.rb +4 -7
- data/spec/reek/spec/should_reek_spec.rb +4 -32
- data/spec/reek/tree_dresser_spec.rb +16 -0
- data/spec/reek/{core/tree_walker_spec.rb → tree_walker_spec.rb} +5 -7
- data/spec/samples/checkstyle.xml +2 -0
- data/spec/samples/configuration/with_excluded_paths.reek +4 -0
- data/spec/samples/{overrides/masked/lower.reek → masked_by_dotfile/.reek} +3 -1
- data/spec/samples/source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb +5 -0
- data/spec/samples/source_with_exclude_paths/nested/ignore_me_as_well/irresponsible_module.rb +2 -0
- data/spec/samples/source_with_exclude_paths/nested/uncommunicative_parameter_name.rb +6 -0
- data/spec/samples/{ruby20_syntax.rb → unusual_syntax.rb} +8 -0
- data/spec/spec_helper.rb +21 -10
- data/tasks/develop.rake +2 -2
- data/tasks/reek.rake +1 -1
- metadata +158 -141
- data/features/support/hooks.rb +0 -15
- data/lib/reek/cli/report/formatter.rb +0 -69
- data/lib/reek/cli/report/heading_formatter.rb +0 -45
- data/lib/reek/cli/report/location_formatter.rb +0 -34
- data/lib/reek/cli/report/report.rb +0 -131
- data/lib/reek/core/tree_walker.rb +0 -180
- data/lib/reek/smell_warning.rb +0 -87
- data/lib/reek/source/ast_node.rb +0 -38
- data/lib/reek/source/code_comment.rb +0 -37
- data/lib/reek/source/core_extras.rb +0 -46
- data/lib/reek/source/reference_collector.rb +0 -27
- data/lib/reek/source/sexp_formatter.rb +0 -22
- data/lib/reek/source/sexp_node.rb +0 -79
- data/lib/reek/source/source_file.rb +0 -16
- data/lib/reek/source/source_repository.rb +0 -45
- data/lib/reek/source/tree_dresser.rb +0 -24
- data/lib/reek/source.rb +0 -16
- data/spec/reek/cli/json_report_spec.rb +0 -20
- data/spec/reek/cli/option_interperter_spec.rb +0 -14
- data/spec/reek/cli/yaml_report_spec.rb +0 -23
- data/spec/reek/core/singleton_method_context_spec.rb +0 -9
- data/spec/reek/core/smell_repository_spec.rb +0 -17
- data/spec/reek/core/stop_context_spec.rb +0 -17
- data/spec/reek/core/warning_collector_spec.rb +0 -30
- data/spec/reek/source/object_source_spec.rb +0 -20
- data/spec/reek/source/tree_dresser_spec.rb +0 -18
- 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/ruby21_syntax.rb +0 -5
- 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
- /data/spec/samples/{simple_configuration.reek → configuration/simple_configuration.reek} +0 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
require_relative '../examiner'
|
|
2
|
+
require_relative '../report/formatter'
|
|
3
3
|
|
|
4
4
|
module Reek
|
|
5
5
|
module Spec
|
|
6
6
|
#
|
|
7
7
|
# An rspec matcher that matches when the +actual+ has code smells.
|
|
8
8
|
#
|
|
9
|
+
# @api private
|
|
9
10
|
class ShouldReek # :nodoc:
|
|
10
11
|
def matches?(actual)
|
|
11
12
|
@examiner = Examiner.new(actual)
|
|
@@ -17,7 +18,7 @@ module Reek
|
|
|
17
18
|
end
|
|
18
19
|
|
|
19
20
|
def failure_message_when_negated
|
|
20
|
-
rpt =
|
|
21
|
+
rpt = Report::Formatter.format_list(@examiner.smells)
|
|
21
22
|
"Expected no smells, but got:\n#{rpt}"
|
|
22
23
|
end
|
|
23
24
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
require_relative '../examiner'
|
|
2
2
|
|
|
3
3
|
module Reek
|
|
4
4
|
module Spec
|
|
@@ -6,6 +6,7 @@ module Reek
|
|
|
6
6
|
# An rspec matcher that matches when the +actual+ has the specified
|
|
7
7
|
# code smell.
|
|
8
8
|
#
|
|
9
|
+
# @api private
|
|
9
10
|
class ShouldReekOf
|
|
10
11
|
def initialize(smell_category, smell_details = {})
|
|
11
12
|
@smell_category = normalize smell_category
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
require_relative '../examiner'
|
|
2
|
+
require_relative '../report/formatter'
|
|
3
3
|
|
|
4
4
|
module Reek
|
|
5
5
|
module Spec
|
|
@@ -7,6 +7,7 @@ module Reek
|
|
|
7
7
|
# An rspec matcher that matches when the +actual+ has the specified
|
|
8
8
|
# code smell and no others.
|
|
9
9
|
#
|
|
10
|
+
# @api private
|
|
10
11
|
class ShouldReekOnlyOf < ShouldReekOf
|
|
11
12
|
def matches?(actual)
|
|
12
13
|
matches_examiner?(Examiner.new(actual))
|
|
@@ -20,7 +21,7 @@ module Reek
|
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
def failure_message
|
|
23
|
-
rpt =
|
|
24
|
+
rpt = Report::Formatter.format_list(@warnings)
|
|
24
25
|
"Expected #{@examiner.description} to reek only of #{@smell_category}, but got:\n#{rpt}"
|
|
25
26
|
end
|
|
26
27
|
|
data/lib/reek/spec.rb
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require_relative 'ast/ast_node_class_map'
|
|
2
|
+
|
|
3
|
+
module Reek
|
|
4
|
+
#
|
|
5
|
+
# Adorns an abstract syntax tree with mix-in modules to make accessing
|
|
6
|
+
# the tree more understandable and less implementation-dependent.
|
|
7
|
+
#
|
|
8
|
+
# @api private
|
|
9
|
+
class TreeDresser
|
|
10
|
+
def initialize(klass_map = AST::ASTNodeClassMap.new)
|
|
11
|
+
@klass_map = klass_map
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Recursively enhance an AST with type-dependent mixins, and comments.
|
|
15
|
+
#
|
|
16
|
+
# See {file:docs/How-reek-works-internally.md} for the big picture of how this works.
|
|
17
|
+
#
|
|
18
|
+
# @param sexp [Parser::AST::Node] - the given sexp
|
|
19
|
+
# @param comment_map [Hash] - see the documentation for SourceCode#syntax_tree
|
|
20
|
+
# @param parent [Parser::AST::Node] - the parent sexp
|
|
21
|
+
#
|
|
22
|
+
# @return an instance of Reek::AST::Node with type-dependent sexp extensions mixed in.
|
|
23
|
+
def dress(sexp, comment_map, parent = nil)
|
|
24
|
+
return sexp unless sexp.is_a? ::Parser::AST::Node
|
|
25
|
+
type = sexp.type
|
|
26
|
+
children = sexp.children.map { |child| dress(child, comment_map, sexp) }
|
|
27
|
+
comments = comment_map[sexp]
|
|
28
|
+
@klass_map.klass_for(type).new(type, children,
|
|
29
|
+
location: sexp.loc, comments: comments, parent: parent)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
require_relative 'context/method_context'
|
|
2
|
+
require_relative 'context/module_context'
|
|
3
|
+
require_relative 'context/root_context'
|
|
4
|
+
require_relative 'context/singleton_method_context'
|
|
5
|
+
require_relative 'smells/smell_repository'
|
|
6
|
+
require_relative 'ast/node'
|
|
7
|
+
|
|
8
|
+
module Reek
|
|
9
|
+
#
|
|
10
|
+
# Traverses a Sexp abstract syntax tree and fires events whenever
|
|
11
|
+
# it encounters specific node types.
|
|
12
|
+
#
|
|
13
|
+
# SMELL: This class is responsible for counting statements and for feeding
|
|
14
|
+
# each context to the smell repository.
|
|
15
|
+
#
|
|
16
|
+
# @api private
|
|
17
|
+
class TreeWalker
|
|
18
|
+
def initialize(smell_repository = Smells::SmellRepository.new)
|
|
19
|
+
@smell_repository = smell_repository
|
|
20
|
+
@element = Context::RootContext.new
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def process(exp)
|
|
24
|
+
context_processor = "process_#{exp.type}"
|
|
25
|
+
if context_processor_exists?(context_processor)
|
|
26
|
+
send(context_processor, exp)
|
|
27
|
+
else
|
|
28
|
+
process_default exp
|
|
29
|
+
end
|
|
30
|
+
@element
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def process_default(exp)
|
|
34
|
+
exp.children.each do |child|
|
|
35
|
+
process(child) if child.is_a? AST::Node
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def process_module(exp)
|
|
40
|
+
inside_new_context(Context::ModuleContext, exp) do
|
|
41
|
+
process_default(exp)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
alias_method :process_class, :process_module
|
|
46
|
+
|
|
47
|
+
def process_def(exp)
|
|
48
|
+
inside_new_context(Context::MethodContext, exp) do
|
|
49
|
+
count_clause(exp.body)
|
|
50
|
+
process_default(exp)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def process_defs(exp)
|
|
55
|
+
inside_new_context(Context::SingletonMethodContext, exp) do
|
|
56
|
+
count_clause(exp.body)
|
|
57
|
+
process_default(exp)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def process_args(_) end
|
|
62
|
+
|
|
63
|
+
#
|
|
64
|
+
# Recording of calls to methods and self
|
|
65
|
+
#
|
|
66
|
+
|
|
67
|
+
def process_send(exp)
|
|
68
|
+
@element.record_call_to(exp)
|
|
69
|
+
process_default(exp)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
alias_method :process_attrasgn, :process_send
|
|
73
|
+
alias_method :process_op_asgn, :process_send
|
|
74
|
+
|
|
75
|
+
def process_ivar(exp)
|
|
76
|
+
@element.record_use_of_self
|
|
77
|
+
process_default(exp)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
alias_method :process_ivasgn, :process_ivar
|
|
81
|
+
|
|
82
|
+
def process_self(_)
|
|
83
|
+
@element.record_use_of_self
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
alias_method :process_zsuper, :process_self
|
|
87
|
+
|
|
88
|
+
#
|
|
89
|
+
# Statement counting
|
|
90
|
+
#
|
|
91
|
+
|
|
92
|
+
def process_block(exp)
|
|
93
|
+
count_clause(exp.block)
|
|
94
|
+
process_default(exp)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def process_begin(exp)
|
|
98
|
+
count_statement_list(exp.children)
|
|
99
|
+
@element.count_statements(-1)
|
|
100
|
+
process_default(exp)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
alias_method :process_kwbegin, :process_begin
|
|
104
|
+
|
|
105
|
+
def process_if(exp)
|
|
106
|
+
count_clause(exp[2])
|
|
107
|
+
count_clause(exp[3])
|
|
108
|
+
@element.count_statements(-1)
|
|
109
|
+
process_default(exp)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def process_while(exp)
|
|
113
|
+
count_clause(exp[2])
|
|
114
|
+
@element.count_statements(-1)
|
|
115
|
+
process_default(exp)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
alias_method :process_until, :process_while
|
|
119
|
+
|
|
120
|
+
def process_for(exp)
|
|
121
|
+
count_clause(exp[3])
|
|
122
|
+
@element.count_statements(-1)
|
|
123
|
+
process_default(exp)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def process_rescue(exp)
|
|
127
|
+
count_clause(exp[1])
|
|
128
|
+
@element.count_statements(-1)
|
|
129
|
+
process_default(exp)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def process_resbody(exp)
|
|
133
|
+
count_statement_list(exp[2..-1].compact)
|
|
134
|
+
process_default(exp)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def process_case(exp)
|
|
138
|
+
count_clause(exp.else_body)
|
|
139
|
+
@element.count_statements(-1)
|
|
140
|
+
process_default(exp)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def process_when(exp)
|
|
144
|
+
count_clause(exp.body)
|
|
145
|
+
process_default(exp)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
private
|
|
149
|
+
|
|
150
|
+
def context_processor_exists?(name)
|
|
151
|
+
respond_to?(name)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def count_clause(sexp)
|
|
155
|
+
@element.count_statements(1) if sexp
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def count_statement_list(statement_list)
|
|
159
|
+
@element.count_statements statement_list.length
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def inside_new_context(klass, exp)
|
|
163
|
+
scope = klass.new(@element, exp)
|
|
164
|
+
push(scope) do
|
|
165
|
+
yield
|
|
166
|
+
check_smells(exp.type)
|
|
167
|
+
end
|
|
168
|
+
scope
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def check_smells(type)
|
|
172
|
+
@smell_repository.examine(@element, type)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def push(scope)
|
|
176
|
+
orig = @element
|
|
177
|
+
@element = scope
|
|
178
|
+
yield
|
|
179
|
+
@element = orig
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
data/lib/reek/version.rb
CHANGED
data/lib/reek.rb
CHANGED
data/reek.gemspec
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
require 'reek/version'
|
|
2
|
+
require File.join(File.dirname(__FILE__), 'lib/reek/version')
|
|
4
3
|
|
|
5
4
|
Gem::Specification.new do |s|
|
|
6
5
|
s.name = 'reek'
|
|
@@ -15,31 +14,25 @@ Gem::Specification.new do |s|
|
|
|
15
14
|
|
|
16
15
|
s.license = 'MIT'
|
|
17
16
|
s.email = ['timo.roessner@googlemail.com']
|
|
18
|
-
s.executables = ['reek']
|
|
19
17
|
s.extra_rdoc_files = ['CHANGELOG', 'License.txt']
|
|
20
|
-
s.files =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
s.
|
|
25
|
-
s.rdoc_options = ['--main', 'README.md',
|
|
26
|
-
'-x', 'assets/|bin/|config/|features/|spec/|tasks/']
|
|
27
|
-
s.require_paths = ['lib']
|
|
28
|
-
s.rubyforge_project = 'reek'
|
|
29
|
-
s.rubygems_version = '1.3.6'
|
|
30
|
-
s.required_ruby_version = '>= 1.9.3'
|
|
18
|
+
s.files = `git ls-files -z`.split("\0")
|
|
19
|
+
s.executables = s.files.grep(%r{^bin/}).map { |path| File.basename(path) }
|
|
20
|
+
s.homepage = 'https://github.com/troessner/reek/wiki'
|
|
21
|
+
s.rdoc_options = %w(--main README.md -x assets/|bin/|config/|features/|spec/|tasks/)
|
|
22
|
+
s.required_ruby_version = '>= 2.0.0'
|
|
31
23
|
s.summary = 'Code smell detector for Ruby'
|
|
32
24
|
|
|
33
|
-
s.add_runtime_dependency
|
|
34
|
-
s.add_runtime_dependency
|
|
35
|
-
s.add_runtime_dependency
|
|
36
|
-
s.add_runtime_dependency('require_all', ['~> 1.3'])
|
|
25
|
+
s.add_runtime_dependency 'parser', '~> 2.2.2.5'
|
|
26
|
+
s.add_runtime_dependency 'rainbow', '~> 2.0'
|
|
27
|
+
s.add_runtime_dependency 'unparser', '~> 0.2.2'
|
|
37
28
|
|
|
38
|
-
s.add_development_dependency
|
|
39
|
-
s.add_development_dependency
|
|
40
|
-
s.add_development_dependency
|
|
41
|
-
s.add_development_dependency
|
|
42
|
-
s.add_development_dependency
|
|
43
|
-
s.add_development_dependency
|
|
44
|
-
s.add_development_dependency
|
|
29
|
+
s.add_development_dependency 'activesupport', '~> 4.2'
|
|
30
|
+
s.add_development_dependency 'aruba', '~> 0.6.2'
|
|
31
|
+
s.add_development_dependency 'ataru', '~> 0.2.0'
|
|
32
|
+
s.add_development_dependency 'bundler', '~> 1.1'
|
|
33
|
+
s.add_development_dependency 'cucumber', '~> 2.0'
|
|
34
|
+
s.add_development_dependency 'factory_girl', '~> 4.0'
|
|
35
|
+
s.add_development_dependency 'rake', '~> 10.0'
|
|
36
|
+
s.add_development_dependency 'rspec', '~> 3.0'
|
|
37
|
+
s.add_development_dependency 'rubocop', '~> 0.30.0'
|
|
45
38
|
end
|
data/spec/factories/factories.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
require_relative '../../lib/reek/smells'
|
|
2
|
+
require_relative '../../lib/reek/smells/smell_detector'
|
|
3
|
+
require_relative '../../lib/reek/smells/smell_warning'
|
|
2
4
|
|
|
3
5
|
FactoryGirl.define do
|
|
4
6
|
factory :smell_detector, class: Reek::Smells::SmellDetector do
|
|
@@ -13,7 +15,7 @@ FactoryGirl.define do
|
|
|
13
15
|
end
|
|
14
16
|
end
|
|
15
17
|
|
|
16
|
-
factory :smell_warning, class: Reek::SmellWarning do
|
|
18
|
+
factory :smell_warning, class: Reek::Smells::SmellWarning do
|
|
17
19
|
skip_create
|
|
18
20
|
smell_detector
|
|
19
21
|
context 'self'
|
data/spec/gem/updates_spec.rb
CHANGED
data/spec/gem/yard_spec.rb
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
require_relative '../../spec_helper'
|
|
2
|
+
require_relative '../../../lib/reek/ast/node'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
describe SexpNode do
|
|
4
|
+
RSpec.describe Reek::AST::Node do
|
|
7
5
|
context 'format' do
|
|
8
6
|
it 'formats self' do
|
|
9
7
|
@node = s(:self)
|
|
10
|
-
expect(@node.
|
|
8
|
+
expect(@node.format_to_ruby).to eq('self')
|
|
11
9
|
end
|
|
12
10
|
end
|
|
13
11
|
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
require_relative '../../spec_helper'
|
|
2
|
+
require_relative '../../../lib/reek/ast/object_refs'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
describe ObjectRefs do
|
|
4
|
+
RSpec.describe Reek::AST::ObjectRefs do
|
|
7
5
|
before(:each) do
|
|
8
|
-
@refs = ObjectRefs.new
|
|
6
|
+
@refs = Reek::AST::ObjectRefs.new
|
|
9
7
|
end
|
|
10
8
|
|
|
11
9
|
context 'when empty' do
|
|
@@ -1,51 +1,59 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
require_relative '../../spec_helper'
|
|
2
|
+
require_relative '../../../lib/reek/ast/reference_collector'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
describe ReferenceCollector do
|
|
4
|
+
RSpec.describe Reek::AST::ReferenceCollector do
|
|
7
5
|
context 'counting refs to self' do
|
|
8
6
|
def refs_to_self(src)
|
|
9
|
-
|
|
7
|
+
syntax_tree = Reek::Source::SourceCode.from(src).syntax_tree
|
|
8
|
+
described_class.new(syntax_tree).num_refs_to_self
|
|
10
9
|
end
|
|
10
|
+
|
|
11
11
|
it 'with no refs to self' do
|
|
12
12
|
expect(refs_to_self('def no_envy(arga) arga.barg end')).to eq(0)
|
|
13
13
|
end
|
|
14
|
+
|
|
14
15
|
it 'counts a call to super' do
|
|
15
16
|
expect(refs_to_self('def simple() super; end')).to eq(1)
|
|
16
17
|
end
|
|
18
|
+
|
|
17
19
|
it 'counts a local call' do
|
|
18
20
|
expect(refs_to_self('def simple() to_s; end')).to eq(1)
|
|
19
21
|
end
|
|
22
|
+
|
|
20
23
|
it 'counts a use of self' do
|
|
21
24
|
expect(refs_to_self('def simple() lv = self; end')).to eq(1)
|
|
22
25
|
end
|
|
26
|
+
|
|
23
27
|
it 'counts a call with self as receiver' do
|
|
24
28
|
expect(refs_to_self('def simple() self.to_s; end')).to eq(1)
|
|
25
29
|
end
|
|
30
|
+
|
|
26
31
|
it 'counts uses of an ivar' do
|
|
27
32
|
expect(refs_to_self('def no_envy() @item.to_a; @item = 4; @item end')).to eq(3)
|
|
28
33
|
end
|
|
34
|
+
|
|
29
35
|
it 'counts an ivar passed to a method' do
|
|
30
36
|
expect(refs_to_self('def no_envy(arga) arga.barg(@item); arga end')).to eq(1)
|
|
31
37
|
end
|
|
38
|
+
|
|
32
39
|
it 'ignores global variables' do
|
|
33
40
|
expect(refs_to_self('def no_envy(arga) $s2.to_a; $s2[arga] end')).to eq(0)
|
|
34
41
|
end
|
|
42
|
+
|
|
35
43
|
it 'ignores global variables' do
|
|
36
|
-
src =
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
EOS
|
|
44
|
+
src = <<-EOS
|
|
45
|
+
def accept(t, pat = /.*/nm, &block)
|
|
46
|
+
if pat
|
|
47
|
+
pat.respond_to?(:match) or raise TypeError, "has no `match'"
|
|
48
|
+
else
|
|
49
|
+
pat = t if t.respond_to?(:match)
|
|
50
|
+
end
|
|
51
|
+
unless block
|
|
52
|
+
block = pat.method(:convert).to_proc if pat.respond_to?(:convert)
|
|
53
|
+
end
|
|
54
|
+
@atype[t] = [pat, block]
|
|
55
|
+
end
|
|
56
|
+
EOS
|
|
49
57
|
expect(refs_to_self(src)).to eq(2)
|
|
50
58
|
end
|
|
51
59
|
end
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
require_relative '../../spec_helper'
|
|
2
|
+
require_relative '../../../lib/reek/ast/sexp_extensions'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
describe SexpExtensions::DefNode do
|
|
4
|
+
RSpec.describe Reek::AST::SexpExtensions::DefNode do
|
|
7
5
|
context 'with no parameters' do
|
|
8
6
|
before :each do
|
|
9
7
|
@node = s(:def, :hello, s(:args))
|
|
@@ -110,11 +108,6 @@ describe SexpExtensions::DefNode do
|
|
|
110
108
|
expect(@node.body).to eq s(:begin, s(:first), s(:second))
|
|
111
109
|
end
|
|
112
110
|
|
|
113
|
-
it 'has a body extended with SexpNode' do
|
|
114
|
-
b = @node.body
|
|
115
|
-
expect(b.class.included_modules.first).to eq SexpNode
|
|
116
|
-
end
|
|
117
|
-
|
|
118
111
|
it 'finds nodes in the body with #body_nodes' do
|
|
119
112
|
expect(@node.body_nodes([:first])).to eq [s(:first)]
|
|
120
113
|
end
|
|
@@ -135,7 +128,7 @@ describe SexpExtensions::DefNode do
|
|
|
135
128
|
end
|
|
136
129
|
end
|
|
137
130
|
|
|
138
|
-
describe SexpExtensions::DefsNode do
|
|
131
|
+
RSpec.describe Reek::AST::SexpExtensions::DefsNode do
|
|
139
132
|
context 'with no parameters' do
|
|
140
133
|
before :each do
|
|
141
134
|
@node = s(:defs, s(:lvar, :obj), :hello, s(:args))
|
|
@@ -241,15 +234,10 @@ describe SexpExtensions::DefsNode do
|
|
|
241
234
|
it 'has 2 body statements' do
|
|
242
235
|
expect(@node.body).to eq s(:begin, s(:first), s(:second))
|
|
243
236
|
end
|
|
244
|
-
|
|
245
|
-
it 'has a body extended with SexpNode' do
|
|
246
|
-
b = @node.body
|
|
247
|
-
expect(b.class.included_modules.first).to eq SexpNode
|
|
248
|
-
end
|
|
249
237
|
end
|
|
250
238
|
end
|
|
251
239
|
|
|
252
|
-
describe SexpExtensions::SendNode do
|
|
240
|
+
RSpec.describe Reek::AST::SexpExtensions::SendNode do
|
|
253
241
|
context 'with no parameters' do
|
|
254
242
|
before :each do
|
|
255
243
|
@node = s(:send, nil, :hello)
|
|
@@ -281,7 +269,7 @@ describe SexpExtensions::SendNode do
|
|
|
281
269
|
end
|
|
282
270
|
end
|
|
283
271
|
|
|
284
|
-
describe SexpExtensions::BlockNode do
|
|
272
|
+
RSpec.describe Reek::AST::SexpExtensions::BlockNode do
|
|
285
273
|
context 'with no parameters' do
|
|
286
274
|
before :each do
|
|
287
275
|
@node = s(:block, s(:send, nil, :map), s(:args), nil)
|
|
@@ -313,7 +301,7 @@ describe SexpExtensions::BlockNode do
|
|
|
313
301
|
end
|
|
314
302
|
end
|
|
315
303
|
|
|
316
|
-
describe SexpExtensions::ModuleNode do
|
|
304
|
+
RSpec.describe Reek::AST::SexpExtensions::ModuleNode do
|
|
317
305
|
context 'with a simple name' do
|
|
318
306
|
subject do
|
|
319
307
|
mod = ast(:module, :Fred, nil)
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
require_relative '../../spec_helper'
|
|
2
|
+
require_relative '../../../lib/reek/ast/sexp_formatter'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
describe SexpFormatter do
|
|
4
|
+
RSpec.describe Reek::AST::SexpFormatter do
|
|
7
5
|
describe '::format' do
|
|
8
6
|
it 'formats a simple s-expression' do
|
|
9
|
-
result =
|
|
7
|
+
result = described_class.format s(:lvar, :foo)
|
|
10
8
|
expect(result).to eq('foo')
|
|
11
9
|
end
|
|
12
10
|
|
|
13
11
|
it 'formats a more complex s-expression' do
|
|
14
|
-
|
|
12
|
+
ast = s(:send, nil, :foo, s(:lvar, :bar))
|
|
13
|
+
result = described_class.format(ast)
|
|
15
14
|
expect(result).to eq('foo(bar)')
|
|
16
15
|
end
|
|
17
16
|
|
|
@@ -22,9 +21,15 @@ describe SexpFormatter do
|
|
|
22
21
|
s(:begin,
|
|
23
22
|
s(:send, nil, :baz),
|
|
24
23
|
s(:send, nil, :qux)))
|
|
25
|
-
result =
|
|
24
|
+
result = described_class.format ast
|
|
26
25
|
|
|
27
26
|
expect(result).to eq 'if foo ... end'
|
|
28
27
|
end
|
|
28
|
+
|
|
29
|
+
it "doesn't reduce two-line ASTs" do
|
|
30
|
+
ast = s(:def, 'my_method', s(:args))
|
|
31
|
+
result = described_class.format ast
|
|
32
|
+
expect(result).to eq 'def my_method; end'
|
|
33
|
+
end
|
|
29
34
|
end
|
|
30
35
|
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require_relative '../../spec_helper'
|
|
2
|
+
|
|
3
|
+
require_relative '../../../lib/reek/cli/options'
|
|
4
|
+
require_relative '../../../lib/reek/report/report'
|
|
5
|
+
|
|
6
|
+
RSpec.describe Reek::CLI::OptionInterpreter do
|
|
7
|
+
let(:options) { OpenStruct.new }
|
|
8
|
+
let(:instance) { Reek::CLI::OptionInterpreter.new(options) }
|
|
9
|
+
|
|
10
|
+
describe '#reporter' do
|
|
11
|
+
it 'returns a Report::TextReport instance by default' do
|
|
12
|
+
expect(instance.reporter).to be_instance_of Reek::Report::TextReport
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|