reek 6.0.2 → 6.1.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.
Files changed (238) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +9 -0
  3. data/.github/workflows/ruby.yml +57 -0
  4. data/.rubocop.yml +5 -3
  5. data/.rubocop_todo.yml +6 -4
  6. data/CHANGELOG.md +26 -0
  7. data/CONTRIBUTING.md +3 -0
  8. data/Dockerfile +1 -1
  9. data/Gemfile +7 -7
  10. data/README.md +1 -1
  11. data/bin/code_climate_reek +2 -3
  12. data/lib/reek/ast/ast_node_class_map.rb +1 -1
  13. data/lib/reek/ast/node.rb +1 -1
  14. data/lib/reek/ast/sexp_extensions/arguments.rb +11 -0
  15. data/lib/reek/ast/sexp_extensions/case.rb +1 -1
  16. data/lib/reek/ast/sexp_extensions/if.rb +1 -1
  17. data/lib/reek/ast/sexp_extensions/send.rb +1 -1
  18. data/lib/reek/cli/command/todo_list_command.rb +1 -1
  19. data/lib/reek/cli/options.rb +1 -1
  20. data/lib/reek/code_comment.rb +22 -17
  21. data/lib/reek/configuration/excluded_paths.rb +2 -1
  22. data/lib/reek/context/code_context.rb +1 -1
  23. data/lib/reek/context/refinement_context.rb +16 -0
  24. data/lib/reek/context_builder.rb +17 -3
  25. data/lib/reek/rake/task.rb +1 -1
  26. data/lib/reek/report/code_climate/code_climate_formatter.rb +1 -3
  27. data/lib/reek/smell_detectors/base_detector.rb +1 -1
  28. data/lib/reek/smell_warning.rb +1 -1
  29. data/lib/reek/source/source_locator.rb +1 -3
  30. data/lib/reek/spec/should_reek_of.rb +6 -4
  31. data/lib/reek/version.rb +2 -2
  32. data/reek.gemspec +28 -25
  33. metadata +13 -240
  34. data/.travis.yml +0 -40
  35. data/docs/API.md +0 -174
  36. data/docs/Attribute.md +0 -39
  37. data/docs/Basic-Smell-Options.md +0 -85
  38. data/docs/Boolean-Parameter.md +0 -54
  39. data/docs/Class-Variable.md +0 -40
  40. data/docs/Code-Smells.md +0 -39
  41. data/docs/Command-Line-Options.md +0 -119
  42. data/docs/Control-Couple.md +0 -26
  43. data/docs/Control-Parameter.md +0 -32
  44. data/docs/Data-Clump.md +0 -46
  45. data/docs/Duplicate-Method-Call.md +0 -264
  46. data/docs/Feature-Envy.md +0 -93
  47. data/docs/How-To-Write-New-Detectors.md +0 -132
  48. data/docs/How-reek-works-internally.md +0 -114
  49. data/docs/Instance-Variable-Assumption.md +0 -163
  50. data/docs/Irresponsible-Module.md +0 -47
  51. data/docs/Large-Class.md +0 -16
  52. data/docs/Long-Parameter-List.md +0 -39
  53. data/docs/Long-Yield-List.md +0 -37
  54. data/docs/Manual-Dispatch.md +0 -30
  55. data/docs/Missing-Safe-Method.md +0 -92
  56. data/docs/Module-Initialize.md +0 -62
  57. data/docs/Nested-Iterators.md +0 -59
  58. data/docs/Nil-Check.md +0 -47
  59. data/docs/RSpec-matchers.md +0 -129
  60. data/docs/Rake-Task.md +0 -66
  61. data/docs/Reek-4-to-Reek-5-migration.md +0 -188
  62. data/docs/Reek-Driven-Development.md +0 -46
  63. data/docs/Repeated-Conditional.md +0 -47
  64. data/docs/Simulated-Polymorphism.md +0 -16
  65. data/docs/Smell-Suppression.md +0 -96
  66. data/docs/Style-Guide.md +0 -19
  67. data/docs/Subclassed-From-Core-Class.md +0 -79
  68. data/docs/Too-Many-Constants.md +0 -37
  69. data/docs/Too-Many-Instance-Variables.md +0 -43
  70. data/docs/Too-Many-Methods.md +0 -56
  71. data/docs/Too-Many-Statements.md +0 -54
  72. data/docs/Uncommunicative-Method-Name.md +0 -94
  73. data/docs/Uncommunicative-Module-Name.md +0 -92
  74. data/docs/Uncommunicative-Name.md +0 -18
  75. data/docs/Uncommunicative-Parameter-Name.md +0 -90
  76. data/docs/Uncommunicative-Variable-Name.md +0 -96
  77. data/docs/Unused-Parameters.md +0 -28
  78. data/docs/Unused-Private-Method.md +0 -101
  79. data/docs/Utility-Function.md +0 -56
  80. data/docs/Versioning-Policy.md +0 -7
  81. data/docs/YAML-Reports.md +0 -93
  82. data/docs/defaults.reek.yml +0 -129
  83. data/docs/templates/default/docstring/html/public_api_marker.erb +0 -3
  84. data/docs/templates/default/docstring/setup.rb +0 -37
  85. data/docs/templates/default/fulldoc/html/css/common.css +0 -1
  86. data/docs/yard_plugin.rb +0 -17
  87. data/features/command_line_interface/basic_usage.feature +0 -15
  88. data/features/command_line_interface/options.feature +0 -123
  89. data/features/command_line_interface/show_progress.feature +0 -33
  90. data/features/command_line_interface/smell_selection.feature +0 -15
  91. data/features/command_line_interface/smells_count.feature +0 -38
  92. data/features/command_line_interface/stdin.feature +0 -65
  93. data/features/configuration_files/accept_setting.feature +0 -87
  94. data/features/configuration_files/directory_specific_directives.feature +0 -274
  95. data/features/configuration_files/exclude_directives.feature +0 -35
  96. data/features/configuration_files/exclude_paths_directives.feature +0 -42
  97. data/features/configuration_files/masking_smells.feature +0 -94
  98. data/features/configuration_files/mix_accept_reject_setting.feature +0 -84
  99. data/features/configuration_files/reject_setting.feature +0 -89
  100. data/features/configuration_files/schema_validation.feature +0 -59
  101. data/features/configuration_files/show_configuration_file.feature +0 -44
  102. data/features/configuration_files/unused_private_method.feature +0 -68
  103. data/features/configuration_loading.feature +0 -91
  104. data/features/configuration_via_source_comments/erroneous_source_comments.feature +0 -68
  105. data/features/configuration_via_source_comments/well_formed_source_comments.feature +0 -116
  106. data/features/locales.feature +0 -32
  107. data/features/programmatic_access.feature +0 -41
  108. data/features/rake_task/rake_task.feature +0 -138
  109. data/features/reports/codeclimate.feature +0 -59
  110. data/features/reports/json.feature +0 -59
  111. data/features/reports/reports.feature +0 -219
  112. data/features/reports/yaml.feature +0 -52
  113. data/features/rspec_matcher.feature +0 -41
  114. data/features/samples.feature +0 -305
  115. data/features/step_definitions/.rubocop.yml +0 -5
  116. data/features/step_definitions/reek_steps.rb +0 -102
  117. data/features/step_definitions/sample_file_steps.rb +0 -63
  118. data/features/support/env.rb +0 -33
  119. data/features/todo_list.feature +0 -108
  120. data/samples/checkstyle.xml +0 -7
  121. data/samples/clean_source/clean.rb +0 -6
  122. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +0 -29
  123. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +0 -30
  124. data/samples/configuration/corrupt.reek +0 -1
  125. data/samples/configuration/empty.reek +0 -0
  126. data/samples/configuration/full_configuration.reek +0 -13
  127. data/samples/configuration/full_mask.reek +0 -6
  128. data/samples/configuration/home/home.reek.yml +0 -4
  129. data/samples/configuration/partial_mask.reek +0 -4
  130. data/samples/configuration/regular_configuration/.reek.yml +0 -4
  131. data/samples/configuration/regular_configuration/empty_sub_directory/.gitignore +0 -0
  132. data/samples/configuration/with_excluded_paths.reek +0 -5
  133. data/samples/no_config_file/.keep +0 -0
  134. data/samples/paths.rb +0 -5
  135. data/samples/smelly_source/inline.rb +0 -704
  136. data/samples/smelly_source/optparse.rb +0 -1788
  137. data/samples/smelly_source/redcloth.rb +0 -1130
  138. data/samples/smelly_source/ruby.rb +0 -368
  139. data/samples/smelly_source/smelly.rb +0 -7
  140. data/samples/source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb +0 -5
  141. data/samples/source_with_exclude_paths/nested/ignore_me_as_well/irresponsible_module.rb +0 -2
  142. data/samples/source_with_exclude_paths/nested/uncommunicative_parameter_name.rb +0 -6
  143. data/samples/source_with_exclude_paths/nested/uncommunicative_variable_name.rb +0 -6
  144. data/samples/source_with_hidden_directories/.hidden/hidden.rb +0 -1
  145. data/samples/source_with_hidden_directories/not_hidden.rb +0 -1
  146. data/samples/source_with_non_ruby_files/gibberish +0 -1
  147. data/samples/source_with_non_ruby_files/python_source.py +0 -1
  148. data/samples/source_with_non_ruby_files/ruby.rb +0 -6
  149. data/spec/performance/reek/smell_detectors/runtime_speed_spec.rb +0 -15
  150. data/spec/quality/documentation_spec.rb +0 -41
  151. data/spec/quality/reek_source_spec.rb +0 -11
  152. data/spec/reek/ast/node_spec.rb +0 -211
  153. data/spec/reek/ast/object_refs_spec.rb +0 -83
  154. data/spec/reek/ast/reference_collector_spec.rb +0 -47
  155. data/spec/reek/ast/sexp_extensions_spec.rb +0 -498
  156. data/spec/reek/cli/application_spec.rb +0 -168
  157. data/spec/reek/cli/command/report_command_spec.rb +0 -44
  158. data/spec/reek/cli/command/todo_list_command_spec.rb +0 -86
  159. data/spec/reek/cli/options_spec.rb +0 -51
  160. data/spec/reek/cli/silencer_spec.rb +0 -28
  161. data/spec/reek/code_comment_spec.rb +0 -184
  162. data/spec/reek/configuration/app_configuration_spec.rb +0 -195
  163. data/spec/reek/configuration/configuration_file_finder_spec.rb +0 -230
  164. data/spec/reek/configuration/default_directive_spec.rb +0 -13
  165. data/spec/reek/configuration/directory_directives_spec.rb +0 -122
  166. data/spec/reek/configuration/excluded_paths_spec.rb +0 -16
  167. data/spec/reek/configuration/rake_task_converter_spec.rb +0 -33
  168. data/spec/reek/configuration/schema_validator_spec.rb +0 -165
  169. data/spec/reek/context/code_context_spec.rb +0 -192
  170. data/spec/reek/context/ghost_context_spec.rb +0 -60
  171. data/spec/reek/context/method_context_spec.rb +0 -72
  172. data/spec/reek/context/module_context_spec.rb +0 -55
  173. data/spec/reek/context/root_context_spec.rb +0 -12
  174. data/spec/reek/context/statement_counter_spec.rb +0 -24
  175. data/spec/reek/context_builder_spec.rb +0 -457
  176. data/spec/reek/detector_repository_spec.rb +0 -22
  177. data/spec/reek/documentation_link_spec.rb +0 -20
  178. data/spec/reek/errors/base_error_spec.rb +0 -13
  179. data/spec/reek/examiner_spec.rb +0 -309
  180. data/spec/reek/logging_error_handler_spec.rb +0 -24
  181. data/spec/reek/rake/task_spec.rb +0 -56
  182. data/spec/reek/report/code_climate/code_climate_configuration_spec.rb +0 -22
  183. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +0 -126
  184. data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +0 -51
  185. data/spec/reek/report/code_climate/code_climate_report_spec.rb +0 -56
  186. data/spec/reek/report/html_report_spec.rb +0 -19
  187. data/spec/reek/report/json_report_spec.rb +0 -58
  188. data/spec/reek/report/location_formatter_spec.rb +0 -32
  189. data/spec/reek/report/progress_formatter_spec.rb +0 -68
  190. data/spec/reek/report/text_report_spec.rb +0 -89
  191. data/spec/reek/report/xml_report_spec.rb +0 -24
  192. data/spec/reek/report/yaml_report_spec.rb +0 -55
  193. data/spec/reek/report_spec.rb +0 -28
  194. data/spec/reek/smell_configuration_spec.rb +0 -56
  195. data/spec/reek/smell_detectors/attribute_spec.rb +0 -197
  196. data/spec/reek/smell_detectors/base_detector_spec.rb +0 -50
  197. data/spec/reek/smell_detectors/boolean_parameter_spec.rb +0 -93
  198. data/spec/reek/smell_detectors/class_variable_spec.rb +0 -106
  199. data/spec/reek/smell_detectors/control_parameter_spec.rb +0 -300
  200. data/spec/reek/smell_detectors/data_clump_spec.rb +0 -134
  201. data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +0 -211
  202. data/spec/reek/smell_detectors/feature_envy_spec.rb +0 -295
  203. data/spec/reek/smell_detectors/instance_variable_assumption_spec.rb +0 -96
  204. data/spec/reek/smell_detectors/irresponsible_module_spec.rb +0 -226
  205. data/spec/reek/smell_detectors/long_parameter_list_spec.rb +0 -61
  206. data/spec/reek/smell_detectors/long_yield_list_spec.rb +0 -49
  207. data/spec/reek/smell_detectors/manual_dispatch_spec.rb +0 -75
  208. data/spec/reek/smell_detectors/missing_safe_method_spec.rb +0 -68
  209. data/spec/reek/smell_detectors/module_initialize_spec.rb +0 -77
  210. data/spec/reek/smell_detectors/nested_iterators_spec.rb +0 -333
  211. data/spec/reek/smell_detectors/nil_check_spec.rb +0 -100
  212. data/spec/reek/smell_detectors/repeated_conditional_spec.rb +0 -100
  213. data/spec/reek/smell_detectors/subclassed_from_core_class_spec.rb +0 -77
  214. data/spec/reek/smell_detectors/too_many_constants_spec.rb +0 -144
  215. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +0 -132
  216. data/spec/reek/smell_detectors/too_many_methods_spec.rb +0 -54
  217. data/spec/reek/smell_detectors/too_many_statements_spec.rb +0 -90
  218. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +0 -78
  219. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +0 -78
  220. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +0 -147
  221. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +0 -201
  222. data/spec/reek/smell_detectors/unused_parameters_spec.rb +0 -114
  223. data/spec/reek/smell_detectors/unused_private_method_spec.rb +0 -205
  224. data/spec/reek/smell_detectors/utility_function_spec.rb +0 -293
  225. data/spec/reek/smell_warning_spec.rb +0 -137
  226. data/spec/reek/source/source_code_spec.rb +0 -79
  227. data/spec/reek/source/source_locator_spec.rb +0 -166
  228. data/spec/reek/spec/should_reek_of_spec.rb +0 -153
  229. data/spec/reek/spec/should_reek_only_of_spec.rb +0 -91
  230. data/spec/reek/spec/should_reek_spec.rb +0 -52
  231. data/spec/reek/spec/smell_matcher_spec.rb +0 -87
  232. data/spec/reek/tree_dresser_spec.rb +0 -46
  233. data/spec/spec_helper.rb +0 -110
  234. data/tasks/configuration.rake +0 -18
  235. data/tasks/console.rake +0 -5
  236. data/tasks/reek.rake +0 -6
  237. data/tasks/rubocop.rake +0 -11
  238. data/tasks/test.rake +0 -32
data/docs/Feature-Envy.md DELETED
@@ -1,93 +0,0 @@
1
- # Feature Envy
2
-
3
- ## Introduction
4
-
5
- _Feature Envy_ occurs when a code fragment references another object more often than it references itself, or when several clients do the same series of manipulations on a particular type of object.
6
-
7
- _Feature Envy_ reduces the code's ability to communicate intent: code that "belongs" on one class but which is located in another can be hard to find, and may upset the "System of Names" in the host class.
8
-
9
- _Feature Envy_ also affects the design's flexibility: A code fragment that is in the wrong class creates couplings that may not be natural within the application's domain, and creates a loss of cohesion in the unwilling host class.
10
-
11
- _Feature Envy_ often arises because it must manipulate other objects (usually its arguments) to get them into a useful form, and one force preventing them (the arguments) doing this themselves is that the common knowledge lives outside the arguments, or the arguments are of too basic a type to justify extending that type. Therefore there must be something which 'knows' about the contents or purposes of the arguments. That thing would have to be more than just a basic type, because the basic types are either containers which don't know about their contents, or they are single objects which can't capture their relationship with their fellows of the same type. So, this thing with the extra knowledge should be reified into a class, and the utility method will most likely belong there.
12
-
13
- ## Example
14
-
15
- Running Reek on:
16
-
17
- ```Ruby
18
- class Warehouse
19
- def sale_price(item)
20
- (item.price - item.rebate) * @vat
21
- end
22
- end
23
- ```
24
-
25
- would report:
26
-
27
- ```Bash
28
- Warehouse#sale_price refers to item more than self (FeatureEnvy)
29
- ```
30
-
31
- since this:
32
-
33
- ```Ruby
34
- (item.price - item.rebate)
35
- ```
36
-
37
- belongs to the Item class, not the Warehouse.
38
-
39
- ## Current Support in Reek
40
-
41
- _Feature Envy_ reports any method that refers to self less often than it refers to (ie. send messages to) some other object.
42
-
43
- ## Edge cases
44
-
45
- Be aware that there are some edge cases like this code:
46
-
47
- ```Ruby
48
- class Foo
49
- def initialize
50
- @map = {
51
- a: ->(arg) { arg.css('table') },
52
- b: ->(arg) { arg.css('div') },
53
- c: ->(arg) { arg.css('span') }
54
- }
55
- end
56
- end
57
- ```
58
-
59
- Reek cannot reliably detect that each call's receiver is a different arg and will report:
60
-
61
- ```
62
- [4, 5, 6]:FeatureEnvy: Foo#initialize refers to 'arg' more than self (maybe move it to another class?)
63
- ```
64
-
65
- If you're running into this problem you can disable this smell detector for this method either via
66
- configuration:
67
-
68
- ```Yaml
69
- ---
70
- FeatureEnvy:
71
- exclude:
72
- - 'Foo#bar'
73
- ```
74
-
75
- or via source code comment:
76
-
77
- ```Ruby
78
- class Foo
79
- # :reek:FeatureEnvy
80
- def initialize
81
- @map = {
82
- # ....
83
- end
84
- end
85
- ```
86
-
87
- ## Differences to _Utility Function_
88
-
89
- _Feature Envy_ is only triggered if there are some references to self and _[Utility Function](Utility-Function.md)_ is triggered if there are no references to self.
90
-
91
- ## Configuration
92
-
93
- _Feature Envy_ supports the [Basic Smell Options](Basic-Smell-Options.md).
@@ -1,132 +0,0 @@
1
- ## How to write new detectors
2
-
3
- ### Outline what you have in mind
4
-
5
- Before starting to code you should discuss the overall idea for your new smell detector with
6
- us in a corresponding github issue.
7
- We all should have a solid understanding of what this detector actually reports, the edgecases
8
- it covers and the overall rationale behind it.
9
-
10
- ### Structure
11
-
12
- All smell detectors reside in `lib/reek/smell_detectors` and have the following base structure:
13
-
14
- ```Ruby
15
- require_relative 'base_detector'
16
- require_relative 'smell_warning'
17
-
18
- module Reek
19
- module SmellDetectors
20
- #
21
- # Here goes your introduction for this detector.
22
- #
23
- # See {file:docs/Your-Detector.md} for details.
24
- class YourDetector < BaseDetector
25
- def self.contexts
26
- [:class] # In case you're operating on class contexts only - just an example.
27
- end
28
-
29
- #
30
- # Here you should document what you expect the detector's context to look
31
- # like.
32
- #
33
- # @return [Array<SmellWarning>]
34
- #
35
- def sniff
36
- # "found_smells" below is just an abstraction for
37
- # "find the smells in question" and iterate over them.
38
- # This can just be a method but it can also be a more sophisticated set up.
39
- # Check out other smell detectors to get a feeling for what to do here.
40
- found_smells.map do |smell|
41
- # "smell_warning" is defined in BaseDetector and should be used by you
42
- # to construct smell warnings
43
- smell_warning(
44
- lines: [], # lines on which the smell was detected
45
- message: "...", # the message that is printed on STDOUT
46
- # whatever you interpolate into the "message" should go into
47
- # parameters below - if you do not interpolate anything you
48
- # can omit this
49
- parameters: { })
50
- end
51
- end
52
- end
53
-
54
- private
55
-
56
- # Here goes everything you need for finding smells.
57
- end
58
- end
59
- end
60
- ```
61
-
62
- For your detector to be properly loaded you need to require it in `lib/reek/smell_detectors.rb` as well.
63
-
64
- ### defaults.reek.yml
65
-
66
- After you ran
67
-
68
- ```
69
- bundle exec rake
70
- ```
71
-
72
- for the first time with your shiny new detector in place the `docs/defaults.reek.yml`
73
- file should have been updated automatically. Make sure you don't forget to check
74
- in those changes as well.
75
-
76
- ### Documentation
77
-
78
- * Above every `SmellDetector::sniff` method it should be documented what the expected AST is
79
- * Every detector should have a separate documentation page in /docs. You can
80
- take any arbitrary existing smell detector documentation page as template (since
81
- they all have the same structure already)
82
- * The detector should be listed under [Code Smells](docs/Code-Smells.md)
83
- * Depending on what your detector does it might make sense to add it to other doc pages as
84
- well e.g. [Simulated Polymorphism](docs/Simulated-Polymorphism.md)
85
-
86
- ### Rspec examples
87
-
88
- All smell detector specs start out with 2 generic examples like below - the second one
89
- only if it makes sense.
90
- Here's what it looks like for `UncommunicativeVariableName`:
91
-
92
- ```Ruby
93
- it 'reports the right values' do
94
- src = <<-RUBY
95
- def alfa
96
- bravo = 5
97
- end
98
- RUBY
99
-
100
- expect(src).to reek_of(:UncommunicativeVariableName,
101
- lines: [2],
102
- context: 'alfa',
103
- message: "has the variable name 'bravo'",
104
- source: 'string',
105
- name: 'bravo')
106
- end
107
-
108
- it 'does count all occurences' do
109
- src = <<-RUBY
110
- def alfa
111
- bravo = 3
112
- charlie = 7
113
- end
114
- RUBY
115
-
116
- expect(src).to reek_of(:UncommunicativeVariableName,
117
- lines: [2],
118
- name: 'bravo')
119
- expect(src).to reek_of(:UncommunicativeVariableName,
120
- lines: [3],
121
- name: 'charlie')
122
- end
123
- ```
124
-
125
- The following examples should then cover the detector specific features.
126
-
127
- ### Cucumber features
128
-
129
- We are trying to write as few Cucumber features as possible.
130
- Normally, there should be no need to write a new feature for a new smell detector.
131
- If you feel like this is necessary in this case, please discuss this with us via
132
- github issue or in your work-in-progress pull request before doing anything.
@@ -1,114 +0,0 @@
1
- # How Reek works internally
2
-
3
-
4
- ## The big picture
5
-
6
- ```
7
- ["class C; end" | reek] [reek lib/*.rb] [expect(files).not_to reek_of(:LargeClass)]
8
- \ | |
9
- \ | |
10
- \ | |
11
- \ creates a | |
12
- \ | |
13
- \ | |
14
- \ | |
15
- \ | |
16
- \---------- Application (cli/application.rb) + |
17
- Options (cli/options) |
18
- | |
19
- | |
20
- | |
21
- | |
22
- creates a | |
23
- | |
24
- | |
25
- | |
26
- | |
27
- ReekCommand (cli/reek_command) |
28
- * uses a reporter (report/report) |
29
- * uses a SourceLocator (source/source_locator) |
30
- / | \ |
31
- / | \ |
32
- / | \ |
33
- Source Source Source (source/source_code) |
34
- | | | |
35
- | | | |
36
- | | | |
37
- Examiner | Examiner |
38
- | |
39
- | |
40
- Examiner (core/examiner) --------------------------------------
41
- * generates the AST out of the given source
42
- * adorns the generated AST via a TreeDresser (core/tree_dresser)
43
- * initializes a DetectorRepository with all relevant smells (smells/detector_repository)
44
- * builds a tree of Contexts using ContextBuilder
45
- * tells the DetectorRepository above to run each of its smell detectors above on each of the contexts
46
- / | \
47
- / | \
48
- / | \
49
- UtilityFunction FeatureEnvy TooManyMethods
50
- \ | /
51
- \ | /
52
- \ | /
53
- DetectorRepository
54
- |
55
- |
56
- |
57
- Application output
58
-
59
- ## A closer look at how an Examiner works
60
-
61
- The core foundation of Reek and its API is the Examiner.
62
- As you can see above, the Examiner is run for every source it gets passed and then runs the configured SmellDetectors.
63
- The overall workflow is like this:
64
-
65
- Examiner
66
- |
67
- |
68
- |
69
- Initialize DetectorRepository only with eligible SmellDetectors
70
- |
71
- |
72
- |
73
- Generate the AST out of the given source using SourceCode#syntax_tree, which works like this:
74
-
75
- - We generate a "rough" AST using the "parser" gem
76
- - We then obtain the comments from the source code separately
77
- - We pass this unprocessed AST and the comment_map to TreeDresser#dress which
78
- returns an instance of Reek::AST::SexpNode with type-dependent SexpExtensions mixed in.
79
-
80
- An example should make this more palpable.
81
- Given:
82
-
83
- class C
84
- def m
85
- puts 'nada'
86
- end
87
- end
88
-
89
- The AST generated by the parser gem (consisting of Parser::AST::Node) looks like this:
90
-
91
- (class
92
- (const nil :C)
93
- nil
94
- (def :m
95
- (args)
96
- (send nil :puts
97
- (str "nada"))))
98
-
99
- TreeDresser#dress would transform this into a very similar tree, but this time not consisting
100
- of Parser::AST::Node but of Reek::AST::SexpNode and with node-dependent SexpExtensions
101
- mixed in (noted in []):
102
-
103
- (class [AST::SexpExtensions::ClassNode, AST::SexpExtensions::ModuleNode]
104
- (const nil :C) [AST::SexpExtensions::ConstNode]
105
- nil
106
- (def :m [AST::SexpExtensions::DefNode, AST::SexpExtensions::MethodNodeBase]
107
- (args) [AST::SexpExtensions::ArgsNode]
108
- (send nil :puts [AST::SexpExtensions::SendNode]
109
- (str "nada"))))
110
- |
111
- |
112
- |
113
- A ContextBuilder then traverses this now adorned tree again and
114
- runs all SmellDetectors from the DetectorRepository above
@@ -1,163 +0,0 @@
1
- # Instance Variable Assumption
2
-
3
- ## Introduction
4
-
5
- Classes should not assume that instance variables are set or present outside of the current class definition.
6
-
7
- Good:
8
-
9
- ```Ruby
10
- class Foo
11
- def initialize
12
- @bar = :foo
13
- end
14
-
15
- def foo?
16
- @bar == :foo
17
- end
18
- end
19
- ```
20
-
21
- Good as well:
22
-
23
- ```Ruby
24
- class Foo
25
- def foo?
26
- bar == :foo
27
- end
28
-
29
- def bar
30
- @bar ||= :foo
31
- end
32
- end
33
- ```
34
-
35
- Bad:
36
-
37
- ```Ruby
38
- class Foo
39
- def go_foo!
40
- @bar = :foo
41
- end
42
-
43
- def foo?
44
- @bar == :foo
45
- end
46
- end
47
- ```
48
-
49
- ## Example
50
-
51
- Running Reek on:
52
-
53
- ```Ruby
54
- class Dummy
55
- def test
56
- @ivar
57
- end
58
- end
59
- ```
60
-
61
- would report:
62
-
63
- ```Bash
64
- [1]:InstanceVariableAssumption: Dummy assumes too much for instance variable @ivar
65
- ```
66
-
67
- Note that this example would trigger this smell warning as well:
68
-
69
- ```Ruby
70
- class Parent
71
- def initialize(omg)
72
- @omg = omg
73
- end
74
- end
75
-
76
- class Child < Parent
77
- def foo
78
- @omg
79
- end
80
- end
81
- ```
82
-
83
- The way to address the smell warning is that you should create an `attr_reader` to use `@omg` in the subclass and not access `@omg` directly like this:
84
-
85
- ```Ruby
86
- class Parent
87
- attr_reader :omg
88
-
89
- def initialize(omg)
90
- @omg = omg
91
- end
92
- end
93
-
94
- class Child < Parent
95
- def foo
96
- omg
97
- end
98
- end
99
- ```
100
-
101
- Directly accessing instance variables is considered a smell because it [breaks encapsulation](http://designisrefactoring.com/2015/03/29/organizing-data-self-encapsulation/) and makes it harder to reason about code.
102
-
103
- If you don't want to expose those methods as public API just make them private like this:
104
-
105
- ```Ruby
106
- class Parent
107
- def initialize(omg)
108
- @omg = omg
109
- end
110
-
111
- private
112
- attr_reader :omg
113
- end
114
-
115
- class Child < Parent
116
- def foo
117
- omg
118
- end
119
- end
120
- ```
121
-
122
-
123
- ## Current Support in Reek
124
-
125
- An instance variable must:
126
-
127
- * be set in the constructor
128
- * or be accessed through a method with lazy initialization / memoization.
129
-
130
- If not, _Instance Variable Assumption_ will be reported.
131
-
132
- ## Using Instance Variable Assumption in a Rails context
133
-
134
- In ActiveRecord it seems common to use callbacks like `after_initialize` to initialize instance variables as
135
- outlined [here](https://stackoverflow.com/questions/41165520/overriding-applicationrecord-initialize-bad-idea)
136
- or [here](http://blog.dalethatcher.com/2008/03/rails-dont-override-initialize-on.html)
137
- instead of overriding the `initialize` method.
138
- If an instance variable is initialized in such a callback Reek will report it correspondingly.
139
-
140
- This would smell for instance:
141
-
142
- ```Ruby
143
- class Sample < ApplicationRecord
144
- after_initialize do
145
- @my_var = false
146
- end
147
- end
148
- ```
149
-
150
- Since Reek cannot reliably detect that is used in a Rails context we recommend to disable this detector
151
- for "app/models" like this:
152
-
153
- ```Yaml
154
- directories:
155
- # Your other configuration....
156
- "app/models":
157
- InstanceVariableAssumption:
158
- enabled: false
159
- ```
160
-
161
- ## Configuration
162
-
163
- _Instance Variable Assumption_ supports the [Basic Smell Options](Basic-Smell-Options.md).
@@ -1,47 +0,0 @@
1
- # Irresponsible Module
2
-
3
- ## Introduction
4
-
5
- Classes and modules are the units of reuse and release. It is therefore
6
- considered good practice to annotate every class and module with a brief
7
- comment outlining its responsibilities.
8
-
9
- For further guideline on how to write good documentation in Ruby, see these
10
- links:
11
- - [Rails API documentation guidelines](http://edgeguides.rubyonrails.org/api_documentation_guidelines.html)
12
- - [Comments tell you why](https://blog.codinghorror.com/code-tells-you-how-comments-tell-you-why/)
13
-
14
- ## Example
15
-
16
- Given
17
-
18
- ```Ruby
19
- class Dummy
20
- # Do things...
21
- end
22
- ```
23
-
24
- Reek would emit the following warning:
25
-
26
- ```
27
- test.rb -- 1 warning:
28
- [1]:IrresponsibleModule: Dummy has no descriptive comment
29
- ```
30
-
31
- Fixing this is simple - just an explaining comment:
32
-
33
- ```Ruby
34
- # The Dummy class is responsible for ...
35
- class Dummy
36
- # Do things...
37
- end
38
- ```
39
-
40
- ## Current Support in Reek
41
-
42
- _Irresponsible Module_ checks classes and modules, including those
43
- created through `Struct.new` and `Class.new` and directly assigned to a constant.
44
-
45
- ## Configuration
46
-
47
- _Irresponsible Module_ supports only the [Basic Smell Options](Basic-Smell-Options.md).
data/docs/Large-Class.md DELETED
@@ -1,16 +0,0 @@
1
- # Large Class
2
-
3
- ## Introduction
4
-
5
- A _Large Class_ is a class or module that has a large number of instance
6
- variables, methods or lines of code in any one piece of its specification.
7
- (That is, this smell relates to pieces of the class's specification, not to the
8
- size of the corresponding instance of `Class`.)
9
-
10
- ## Current Support in Reek
11
-
12
- Reek offers three checks in this category.
13
-
14
- * [Too Many Constants](Too-Many-Constants.md)
15
- * [Too Many Instance Variables](Too-Many-Instance-Variables.md)
16
- * [Too Many Methods](Too-Many-Methods.md)
@@ -1,39 +0,0 @@
1
- # Long Parameter List
2
-
3
- ## Introduction
4
-
5
- A _Long Parameter List_ occurs when a method has a lot of parameters.
6
-
7
- ## Example
8
-
9
- Given
10
-
11
- ```Ruby
12
- class Dummy
13
- def long_list(foo,bar,baz,fling,flung)
14
- puts foo,bar,baz,fling,flung
15
- end
16
- end
17
- ```
18
-
19
- Reek would report the following warning:
20
-
21
- ```
22
- test.rb -- 1 warning:
23
- [2]:Dummy#long_list has 5 parameters (LongParameterList)
24
- ```
25
-
26
- A common solution to this problem would be the introduction of parameter objects.
27
-
28
- ## Current Support in Reek
29
-
30
- _Long Parameter List_ reports any method or block with more than 3 parameters.
31
-
32
- ## Configuration
33
-
34
- Reek's _Long Parameter List_ detector supports the
35
- [Basic Smell Options](Basic-Smell-Options.md), plus:
36
-
37
- | Option | Value | Effect |
38
- | -------------|---------|---------|
39
- | `max_params` | integer | The maximum number of parameters allowed in a method or block before a warning is issued. Defaults to 3. |
@@ -1,37 +0,0 @@
1
- # Long Yield List
2
-
3
- ## Introduction
4
-
5
- A _Long Yield List_ occurs when a method yields a lot of arguments to the block
6
- it gets passed. It is a special case of [Long Parameter List](Long-Parameter-List.md).
7
-
8
- ## Example
9
-
10
- ```Ruby
11
- class Dummy
12
- def yields_a_lot(foo,bar,baz,fling,flung)
13
- yield foo,bar,baz,fling,flung
14
- end
15
- end
16
- ```
17
-
18
- Reek would report the following warning:
19
-
20
- ```
21
- test.rb -- 1 warning:
22
- [4]:Dummy#yields_a_lot yields 5 parameters (LongYieldList)
23
- ```
24
-
25
- A common solution to this problem would be the introduction of parameter objects.
26
-
27
- ## Current Support in Reek
28
-
29
- Currently _Long Yield List_ reports any method or block with more than 3 parameters.
30
-
31
- ## Configuration
32
-
33
- Reek's _Long Yield List_ detector supports the [Basic Smell Options](Basic-Smell-Options.md), plus:
34
-
35
- | Option | Value | Effect |
36
- | -------------|---------|---------|
37
- | `max_params` | integer | The maximum number of parameters allowed in a method or block before a warning is issued. Defaults to 3. |
@@ -1,30 +0,0 @@
1
- ## Introduction
2
-
3
- Reek reports a _Manual Dispatch_ smell if it finds source code that manually checks whether an object responds to a method before that method is called. Manual dispatch is a type of [Simulated Polymorphism](Simulated-Polymorphism.md) which leads to code that is harder to reason about, debug, and refactor.
4
-
5
- ## Example
6
-
7
- ```Ruby
8
- class MyManualDispatcher
9
- attr_reader :foo
10
-
11
- def initialize(foo)
12
- @foo = foo
13
- end
14
-
15
- def call
16
- foo.bar if foo.respond_to?(:bar)
17
- end
18
- end
19
- ```
20
-
21
- Reek would emit the following warning:
22
-
23
- ```
24
- test.rb -- 1 warning:
25
- [9]: MyManualDispatcher manually dispatches method call (ManualDispatch)
26
- ```
27
-
28
- ## Configuration
29
-
30
- _Manual Dispatch_ offers the [Basic Smell Options](Basic-Smell-Options.md).