reek 6.0.1 → 6.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (237) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +9 -0
  3. data/.github/workflows/ruby.yml +52 -0
  4. data/.rubocop.yml +2 -20
  5. data/.rubocop_todo.yml +27 -20
  6. data/CHANGELOG.md +22 -0
  7. data/CONTRIBUTING.md +3 -0
  8. data/Dockerfile +1 -1
  9. data/Gemfile +6 -6
  10. data/README.md +1 -1
  11. data/bin/code_climate_reek +2 -3
  12. data/lib/reek.rb +1 -0
  13. data/lib/reek/ast/ast_node_class_map.rb +1 -1
  14. data/lib/reek/ast/node.rb +1 -1
  15. data/lib/reek/cli/options.rb +1 -1
  16. data/lib/reek/configuration/app_configuration.rb +4 -3
  17. data/lib/reek/configuration/directory_directives.rb +2 -2
  18. data/lib/reek/configuration/excluded_paths.rb +2 -1
  19. data/lib/reek/context/code_context.rb +1 -1
  20. data/lib/reek/context/module_context.rb +3 -1
  21. data/lib/reek/context/refinement_context.rb +16 -0
  22. data/lib/reek/context_builder.rb +16 -2
  23. data/lib/reek/report/code_climate/code_climate_configuration.yml +1 -1
  24. data/lib/reek/report/code_climate/code_climate_formatter.rb +1 -3
  25. data/lib/reek/smell_detectors/base_detector.rb +1 -1
  26. data/lib/reek/smell_detectors/boolean_parameter.rb +3 -1
  27. data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +1 -1
  28. data/lib/reek/smell_warning.rb +2 -3
  29. data/lib/reek/source/source_locator.rb +14 -13
  30. data/lib/reek/version.rb +1 -1
  31. data/reek.gemspec +14 -3
  32. metadata +29 -232
  33. data/.travis.yml +0 -36
  34. data/docs/API.md +0 -174
  35. data/docs/Attribute.md +0 -39
  36. data/docs/Basic-Smell-Options.md +0 -85
  37. data/docs/Boolean-Parameter.md +0 -54
  38. data/docs/Class-Variable.md +0 -40
  39. data/docs/Code-Smells.md +0 -39
  40. data/docs/Command-Line-Options.md +0 -119
  41. data/docs/Control-Couple.md +0 -26
  42. data/docs/Control-Parameter.md +0 -32
  43. data/docs/Data-Clump.md +0 -46
  44. data/docs/Duplicate-Method-Call.md +0 -264
  45. data/docs/Feature-Envy.md +0 -93
  46. data/docs/How-To-Write-New-Detectors.md +0 -132
  47. data/docs/How-reek-works-internally.md +0 -114
  48. data/docs/Instance-Variable-Assumption.md +0 -163
  49. data/docs/Irresponsible-Module.md +0 -47
  50. data/docs/Large-Class.md +0 -16
  51. data/docs/Long-Parameter-List.md +0 -39
  52. data/docs/Long-Yield-List.md +0 -37
  53. data/docs/Manual-Dispatch.md +0 -30
  54. data/docs/Missing-Safe-Method.md +0 -92
  55. data/docs/Module-Initialize.md +0 -62
  56. data/docs/Nested-Iterators.md +0 -59
  57. data/docs/Nil-Check.md +0 -47
  58. data/docs/RSpec-matchers.md +0 -129
  59. data/docs/Rake-Task.md +0 -66
  60. data/docs/Reek-4-to-Reek-5-migration.md +0 -188
  61. data/docs/Reek-Driven-Development.md +0 -46
  62. data/docs/Repeated-Conditional.md +0 -47
  63. data/docs/Simulated-Polymorphism.md +0 -16
  64. data/docs/Smell-Suppression.md +0 -96
  65. data/docs/Style-Guide.md +0 -19
  66. data/docs/Subclassed-From-Core-Class.md +0 -79
  67. data/docs/Too-Many-Constants.md +0 -37
  68. data/docs/Too-Many-Instance-Variables.md +0 -43
  69. data/docs/Too-Many-Methods.md +0 -56
  70. data/docs/Too-Many-Statements.md +0 -54
  71. data/docs/Uncommunicative-Method-Name.md +0 -94
  72. data/docs/Uncommunicative-Module-Name.md +0 -92
  73. data/docs/Uncommunicative-Name.md +0 -18
  74. data/docs/Uncommunicative-Parameter-Name.md +0 -90
  75. data/docs/Uncommunicative-Variable-Name.md +0 -96
  76. data/docs/Unused-Parameters.md +0 -28
  77. data/docs/Unused-Private-Method.md +0 -101
  78. data/docs/Utility-Function.md +0 -56
  79. data/docs/Versioning-Policy.md +0 -7
  80. data/docs/YAML-Reports.md +0 -93
  81. data/docs/defaults.reek.yml +0 -129
  82. data/docs/templates/default/docstring/html/public_api_marker.erb +0 -3
  83. data/docs/templates/default/docstring/setup.rb +0 -37
  84. data/docs/templates/default/fulldoc/html/css/common.css +0 -1
  85. data/docs/yard_plugin.rb +0 -17
  86. data/features/command_line_interface/basic_usage.feature +0 -15
  87. data/features/command_line_interface/options.feature +0 -123
  88. data/features/command_line_interface/show_progress.feature +0 -33
  89. data/features/command_line_interface/smell_selection.feature +0 -15
  90. data/features/command_line_interface/smells_count.feature +0 -38
  91. data/features/command_line_interface/stdin.feature +0 -65
  92. data/features/configuration_files/accept_setting.feature +0 -87
  93. data/features/configuration_files/directory_specific_directives.feature +0 -274
  94. data/features/configuration_files/exclude_directives.feature +0 -35
  95. data/features/configuration_files/exclude_paths_directives.feature +0 -42
  96. data/features/configuration_files/masking_smells.feature +0 -94
  97. data/features/configuration_files/mix_accept_reject_setting.feature +0 -84
  98. data/features/configuration_files/reject_setting.feature +0 -89
  99. data/features/configuration_files/schema_validation.feature +0 -59
  100. data/features/configuration_files/show_configuration_file.feature +0 -44
  101. data/features/configuration_files/unused_private_method.feature +0 -68
  102. data/features/configuration_loading.feature +0 -91
  103. data/features/configuration_via_source_comments/erroneous_source_comments.feature +0 -68
  104. data/features/configuration_via_source_comments/well_formed_source_comments.feature +0 -116
  105. data/features/locales.feature +0 -32
  106. data/features/programmatic_access.feature +0 -41
  107. data/features/rake_task/rake_task.feature +0 -138
  108. data/features/reports/codeclimate.feature +0 -59
  109. data/features/reports/json.feature +0 -59
  110. data/features/reports/reports.feature +0 -219
  111. data/features/reports/yaml.feature +0 -52
  112. data/features/rspec_matcher.feature +0 -41
  113. data/features/samples.feature +0 -305
  114. data/features/step_definitions/.rubocop.yml +0 -5
  115. data/features/step_definitions/reek_steps.rb +0 -102
  116. data/features/step_definitions/sample_file_steps.rb +0 -63
  117. data/features/support/env.rb +0 -33
  118. data/features/todo_list.feature +0 -108
  119. data/samples/checkstyle.xml +0 -7
  120. data/samples/clean_source/clean.rb +0 -6
  121. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +0 -29
  122. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +0 -30
  123. data/samples/configuration/corrupt.reek +0 -1
  124. data/samples/configuration/empty.reek +0 -0
  125. data/samples/configuration/full_configuration.reek +0 -13
  126. data/samples/configuration/full_mask.reek +0 -6
  127. data/samples/configuration/home/home.reek.yml +0 -4
  128. data/samples/configuration/partial_mask.reek +0 -4
  129. data/samples/configuration/regular_configuration/.reek.yml +0 -4
  130. data/samples/configuration/regular_configuration/empty_sub_directory/.gitignore +0 -0
  131. data/samples/configuration/with_excluded_paths.reek +0 -5
  132. data/samples/no_config_file/.keep +0 -0
  133. data/samples/paths.rb +0 -5
  134. data/samples/smelly_source/inline.rb +0 -704
  135. data/samples/smelly_source/optparse.rb +0 -1788
  136. data/samples/smelly_source/redcloth.rb +0 -1130
  137. data/samples/smelly_source/ruby.rb +0 -368
  138. data/samples/smelly_source/smelly.rb +0 -7
  139. data/samples/source_with_exclude_paths/ignore_me/uncommunicative_method_name.rb +0 -5
  140. data/samples/source_with_exclude_paths/nested/ignore_me_as_well/irresponsible_module.rb +0 -2
  141. data/samples/source_with_exclude_paths/nested/uncommunicative_parameter_name.rb +0 -6
  142. data/samples/source_with_exclude_paths/nested/uncommunicative_variable_name.rb +0 -6
  143. data/samples/source_with_hidden_directories/.hidden/hidden.rb +0 -1
  144. data/samples/source_with_hidden_directories/not_hidden.rb +0 -1
  145. data/samples/source_with_non_ruby_files/gibberish +0 -1
  146. data/samples/source_with_non_ruby_files/python_source.py +0 -1
  147. data/samples/source_with_non_ruby_files/ruby.rb +0 -6
  148. data/spec/performance/reek/smell_detectors/runtime_speed_spec.rb +0 -17
  149. data/spec/quality/documentation_spec.rb +0 -40
  150. data/spec/quality/reek_source_spec.rb +0 -11
  151. data/spec/reek/ast/node_spec.rb +0 -211
  152. data/spec/reek/ast/object_refs_spec.rb +0 -83
  153. data/spec/reek/ast/reference_collector_spec.rb +0 -47
  154. data/spec/reek/ast/sexp_extensions_spec.rb +0 -498
  155. data/spec/reek/cli/application_spec.rb +0 -168
  156. data/spec/reek/cli/command/report_command_spec.rb +0 -44
  157. data/spec/reek/cli/command/todo_list_command_spec.rb +0 -86
  158. data/spec/reek/cli/options_spec.rb +0 -51
  159. data/spec/reek/cli/silencer_spec.rb +0 -28
  160. data/spec/reek/code_comment_spec.rb +0 -184
  161. data/spec/reek/configuration/app_configuration_spec.rb +0 -195
  162. data/spec/reek/configuration/configuration_file_finder_spec.rb +0 -230
  163. data/spec/reek/configuration/default_directive_spec.rb +0 -13
  164. data/spec/reek/configuration/directory_directives_spec.rb +0 -122
  165. data/spec/reek/configuration/excluded_paths_spec.rb +0 -16
  166. data/spec/reek/configuration/rake_task_converter_spec.rb +0 -33
  167. data/spec/reek/configuration/schema_validator_spec.rb +0 -165
  168. data/spec/reek/context/code_context_spec.rb +0 -192
  169. data/spec/reek/context/ghost_context_spec.rb +0 -60
  170. data/spec/reek/context/method_context_spec.rb +0 -72
  171. data/spec/reek/context/module_context_spec.rb +0 -55
  172. data/spec/reek/context/root_context_spec.rb +0 -12
  173. data/spec/reek/context/statement_counter_spec.rb +0 -24
  174. data/spec/reek/context_builder_spec.rb +0 -457
  175. data/spec/reek/detector_repository_spec.rb +0 -22
  176. data/spec/reek/documentation_link_spec.rb +0 -20
  177. data/spec/reek/errors/base_error_spec.rb +0 -13
  178. data/spec/reek/examiner_spec.rb +0 -309
  179. data/spec/reek/logging_error_handler_spec.rb +0 -24
  180. data/spec/reek/rake/task_spec.rb +0 -56
  181. data/spec/reek/report/code_climate/code_climate_configuration_spec.rb +0 -22
  182. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +0 -126
  183. data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +0 -51
  184. data/spec/reek/report/code_climate/code_climate_report_spec.rb +0 -56
  185. data/spec/reek/report/html_report_spec.rb +0 -19
  186. data/spec/reek/report/json_report_spec.rb +0 -58
  187. data/spec/reek/report/location_formatter_spec.rb +0 -32
  188. data/spec/reek/report/progress_formatter_spec.rb +0 -68
  189. data/spec/reek/report/text_report_spec.rb +0 -89
  190. data/spec/reek/report/xml_report_spec.rb +0 -24
  191. data/spec/reek/report/yaml_report_spec.rb +0 -55
  192. data/spec/reek/report_spec.rb +0 -28
  193. data/spec/reek/smell_configuration_spec.rb +0 -56
  194. data/spec/reek/smell_detectors/attribute_spec.rb +0 -197
  195. data/spec/reek/smell_detectors/base_detector_spec.rb +0 -50
  196. data/spec/reek/smell_detectors/boolean_parameter_spec.rb +0 -93
  197. data/spec/reek/smell_detectors/class_variable_spec.rb +0 -106
  198. data/spec/reek/smell_detectors/control_parameter_spec.rb +0 -300
  199. data/spec/reek/smell_detectors/data_clump_spec.rb +0 -134
  200. data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +0 -211
  201. data/spec/reek/smell_detectors/feature_envy_spec.rb +0 -295
  202. data/spec/reek/smell_detectors/instance_variable_assumption_spec.rb +0 -96
  203. data/spec/reek/smell_detectors/irresponsible_module_spec.rb +0 -226
  204. data/spec/reek/smell_detectors/long_parameter_list_spec.rb +0 -61
  205. data/spec/reek/smell_detectors/long_yield_list_spec.rb +0 -49
  206. data/spec/reek/smell_detectors/manual_dispatch_spec.rb +0 -75
  207. data/spec/reek/smell_detectors/missing_safe_method_spec.rb +0 -68
  208. data/spec/reek/smell_detectors/module_initialize_spec.rb +0 -77
  209. data/spec/reek/smell_detectors/nested_iterators_spec.rb +0 -333
  210. data/spec/reek/smell_detectors/nil_check_spec.rb +0 -100
  211. data/spec/reek/smell_detectors/repeated_conditional_spec.rb +0 -100
  212. data/spec/reek/smell_detectors/subclassed_from_core_class_spec.rb +0 -77
  213. data/spec/reek/smell_detectors/too_many_constants_spec.rb +0 -144
  214. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +0 -132
  215. data/spec/reek/smell_detectors/too_many_methods_spec.rb +0 -54
  216. data/spec/reek/smell_detectors/too_many_statements_spec.rb +0 -90
  217. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +0 -78
  218. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +0 -78
  219. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +0 -147
  220. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +0 -201
  221. data/spec/reek/smell_detectors/unused_parameters_spec.rb +0 -114
  222. data/spec/reek/smell_detectors/unused_private_method_spec.rb +0 -205
  223. data/spec/reek/smell_detectors/utility_function_spec.rb +0 -293
  224. data/spec/reek/smell_warning_spec.rb +0 -137
  225. data/spec/reek/source/source_code_spec.rb +0 -79
  226. data/spec/reek/source/source_locator_spec.rb +0 -166
  227. data/spec/reek/spec/should_reek_of_spec.rb +0 -153
  228. data/spec/reek/spec/should_reek_only_of_spec.rb +0 -91
  229. data/spec/reek/spec/should_reek_spec.rb +0 -52
  230. data/spec/reek/spec/smell_matcher_spec.rb +0 -87
  231. data/spec/reek/tree_dresser_spec.rb +0 -46
  232. data/spec/spec_helper.rb +0 -110
  233. data/tasks/configuration.rake +0 -19
  234. data/tasks/console.rake +0 -5
  235. data/tasks/reek.rake +0 -6
  236. data/tasks/rubocop.rake +0 -11
  237. 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).