reek 4.7.1 → 5.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.
Files changed (260) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +17 -12
  3. data/.rubocop.yml +36 -7
  4. data/.simplecov +1 -0
  5. data/.travis.yml +3 -9
  6. data/.yardopts +1 -1
  7. data/CHANGELOG.md +59 -0
  8. data/CONTRIBUTING.md +1 -1
  9. data/Gemfile +5 -5
  10. data/README.md +134 -104
  11. data/Rakefile +16 -3
  12. data/bin/reek +1 -3
  13. data/docs/API.md +2 -9
  14. data/docs/Basic-Smell-Options.md +51 -11
  15. data/docs/Code-Smells.md +1 -1
  16. data/docs/Command-Line-Options.md +14 -4
  17. data/docs/Duplicate-Method-Call.md +49 -1
  18. data/docs/Feature-Envy.md +44 -0
  19. data/docs/How-To-Write-New-Detectors.md +7 -7
  20. data/docs/Instance-Variable-Assumption.md +1 -1
  21. data/docs/{Prima-Donna-Method.md → Missing-Safe-Method.md} +11 -9
  22. data/docs/Rake-Task.md +1 -1
  23. data/docs/Reek-4-to-Reek-5-migration.md +193 -0
  24. data/docs/Reek-Driven-Development.md +1 -1
  25. data/docs/Uncommunicative-Method-Name.md +45 -6
  26. data/docs/Uncommunicative-Module-Name.md +49 -7
  27. data/docs/Uncommunicative-Parameter-Name.md +43 -5
  28. data/docs/Uncommunicative-Variable-Name.md +73 -2
  29. data/docs/Unused-Private-Method.md +3 -3
  30. data/docs/defaults.reek.yml +129 -0
  31. data/docs/yard_plugin.rb +1 -0
  32. data/features/command_line_interface/basic_usage.feature +2 -2
  33. data/features/command_line_interface/options.feature +46 -4
  34. data/features/command_line_interface/show_progress.feature +4 -4
  35. data/features/command_line_interface/smell_selection.feature +1 -1
  36. data/features/command_line_interface/smells_count.feature +6 -6
  37. data/features/command_line_interface/stdin.feature +30 -8
  38. data/features/configuration_files/accept_setting.feature +45 -28
  39. data/features/configuration_files/directory_specific_directives.feature +80 -75
  40. data/features/configuration_files/exclude_directives.feature +11 -10
  41. data/features/configuration_files/exclude_paths_directives.feature +4 -4
  42. data/features/configuration_files/masking_smells.feature +38 -9
  43. data/features/configuration_files/mix_accept_reject_setting.feature +31 -28
  44. data/features/configuration_files/reject_setting.feature +52 -41
  45. data/features/configuration_files/schema_validation.feature +59 -0
  46. data/features/configuration_files/unused_private_method.feature +18 -16
  47. data/features/configuration_loading.feature +53 -10
  48. data/features/configuration_via_source_comments/erroneous_source_comments.feature +3 -3
  49. data/features/configuration_via_source_comments/well_formed_source_comments.feature +2 -2
  50. data/features/locales.feature +32 -0
  51. data/features/rake_task/rake_task.feature +58 -18
  52. data/features/reports/json.feature +3 -3
  53. data/features/reports/reports.feature +34 -34
  54. data/features/reports/yaml.feature +3 -3
  55. data/features/rspec_matcher.feature +40 -0
  56. data/features/samples.feature +287 -287
  57. data/features/step_definitions/reek_steps.rb +2 -2
  58. data/features/step_definitions/sample_file_steps.rb +9 -4
  59. data/features/support/env.rb +2 -11
  60. data/features/todo_list.feature +26 -23
  61. data/lib/reek/ast/builder.rb +1 -1
  62. data/lib/reek/ast/node.rb +40 -58
  63. data/lib/reek/ast/object_refs.rb +1 -1
  64. data/lib/reek/ast/reference_collector.rb +2 -4
  65. data/lib/reek/ast/sexp_extensions/case.rb +1 -1
  66. data/lib/reek/ast/sexp_extensions/if.rb +8 -1
  67. data/lib/reek/ast/sexp_extensions/logical_operators.rb +1 -1
  68. data/lib/reek/ast/sexp_extensions/methods.rb +4 -6
  69. data/lib/reek/ast/sexp_extensions/send.rb +0 -4
  70. data/lib/reek/cli/application.rb +4 -3
  71. data/lib/reek/cli/command/report_command.rb +1 -2
  72. data/lib/reek/cli/command/todo_list_command.rb +8 -8
  73. data/lib/reek/cli/options.rb +31 -16
  74. data/lib/reek/cli/silencer.rb +14 -3
  75. data/lib/reek/code_comment.rb +14 -16
  76. data/lib/reek/configuration/app_configuration.rb +32 -27
  77. data/lib/reek/configuration/configuration_converter.rb +110 -0
  78. data/lib/reek/configuration/configuration_file_finder.rb +16 -41
  79. data/lib/reek/configuration/configuration_validator.rb +12 -23
  80. data/lib/reek/configuration/default_directive.rb +17 -3
  81. data/lib/reek/configuration/directory_directives.rb +17 -11
  82. data/lib/reek/configuration/excluded_paths.rb +1 -1
  83. data/lib/reek/configuration/rake_task_converter.rb +29 -0
  84. data/lib/reek/configuration/schema.yml +210 -0
  85. data/lib/reek/configuration/schema_validator.rb +38 -0
  86. data/lib/reek/context/attribute_context.rb +3 -3
  87. data/lib/reek/context/code_context.rb +47 -43
  88. data/lib/reek/context/ghost_context.rb +0 -2
  89. data/lib/reek/context/method_context.rb +22 -15
  90. data/lib/reek/context/module_context.rb +5 -9
  91. data/lib/reek/context/root_context.rb +0 -4
  92. data/lib/reek/context/send_context.rb +2 -2
  93. data/lib/reek/context_builder.rb +43 -44
  94. data/lib/reek/detector_repository.rb +11 -11
  95. data/lib/reek/documentation_link.rb +28 -0
  96. data/lib/reek/errors/bad_detector_configuration_key_in_comment_error.rb +14 -13
  97. data/lib/reek/errors/bad_detector_in_comment_error.rb +12 -11
  98. data/lib/reek/errors/base_error.rb +3 -0
  99. data/lib/reek/errors/config_file_error.rb +11 -0
  100. data/lib/reek/errors/encoding_error.rb +43 -0
  101. data/lib/reek/errors/garbage_detector_configuration_in_comment_error.rb +13 -12
  102. data/lib/reek/errors/incomprehensible_source_error.rb +22 -24
  103. data/lib/reek/errors/syntax_error.rb +41 -0
  104. data/lib/reek/examiner.rb +24 -26
  105. data/lib/reek/logging_error_handler.rb +7 -5
  106. data/lib/reek/rake/task.rb +8 -4
  107. data/lib/reek/report/base_report.rb +8 -12
  108. data/lib/reek/report/code_climate/code_climate_configuration.rb +1 -1
  109. data/lib/reek/report/code_climate/code_climate_configuration.yml +6 -10
  110. data/lib/reek/report/documentation_link_warning_formatter.rb +17 -0
  111. data/lib/reek/report/heading_formatter.rb +54 -0
  112. data/lib/reek/report/json_report.rb +1 -1
  113. data/lib/reek/report/location_formatter.rb +40 -0
  114. data/lib/reek/report/progress_formatter.rb +79 -0
  115. data/lib/reek/report/simple_warning_formatter.rb +34 -0
  116. data/lib/reek/report/text_report.rb +1 -2
  117. data/lib/reek/report/xml_report.rb +3 -3
  118. data/lib/reek/report/yaml_report.rb +1 -1
  119. data/lib/reek/report.rb +15 -10
  120. data/lib/reek/smell_configuration.rb +2 -2
  121. data/lib/reek/smell_detectors/attribute.rb +5 -11
  122. data/lib/reek/smell_detectors/base_detector.rb +30 -26
  123. data/lib/reek/smell_detectors/boolean_parameter.rb +3 -5
  124. data/lib/reek/smell_detectors/class_variable.rb +5 -14
  125. data/lib/reek/smell_detectors/control_parameter.rb +18 -33
  126. data/lib/reek/smell_detectors/data_clump.rb +15 -9
  127. data/lib/reek/smell_detectors/duplicate_method_call.rb +23 -17
  128. data/lib/reek/smell_detectors/feature_envy.rb +9 -7
  129. data/lib/reek/smell_detectors/instance_variable_assumption.rb +14 -23
  130. data/lib/reek/smell_detectors/irresponsible_module.rb +5 -12
  131. data/lib/reek/smell_detectors/long_parameter_list.rb +10 -7
  132. data/lib/reek/smell_detectors/long_yield_list.rb +10 -7
  133. data/lib/reek/smell_detectors/manual_dispatch.rb +4 -5
  134. data/lib/reek/smell_detectors/{prima_donna_method.rb → missing_safe_method.rb} +20 -20
  135. data/lib/reek/smell_detectors/module_initialize.rb +3 -5
  136. data/lib/reek/smell_detectors/nested_iterators.rb +16 -24
  137. data/lib/reek/smell_detectors/nil_check.rb +8 -15
  138. data/lib/reek/smell_detectors/repeated_conditional.rb +13 -11
  139. data/lib/reek/smell_detectors/subclassed_from_core_class.rb +7 -8
  140. data/lib/reek/smell_detectors/too_many_constants.rb +10 -9
  141. data/lib/reek/smell_detectors/too_many_instance_variables.rb +10 -6
  142. data/lib/reek/smell_detectors/too_many_methods.rb +11 -7
  143. data/lib/reek/smell_detectors/too_many_statements.rb +10 -6
  144. data/lib/reek/smell_detectors/uncommunicative_method_name.rb +10 -11
  145. data/lib/reek/smell_detectors/uncommunicative_module_name.rb +14 -18
  146. data/lib/reek/smell_detectors/uncommunicative_parameter_name.rb +17 -22
  147. data/lib/reek/smell_detectors/uncommunicative_variable_name.rb +26 -27
  148. data/lib/reek/smell_detectors/unused_parameters.rb +4 -6
  149. data/lib/reek/smell_detectors/unused_private_method.rb +11 -18
  150. data/lib/reek/smell_detectors/utility_function.rb +12 -16
  151. data/lib/reek/smell_detectors.rb +1 -2
  152. data/lib/reek/smell_warning.rb +15 -8
  153. data/lib/reek/source/source_code.rb +57 -58
  154. data/lib/reek/source/source_locator.rb +8 -8
  155. data/lib/reek/spec/should_reek.rb +2 -2
  156. data/lib/reek/spec/should_reek_of.rb +9 -16
  157. data/lib/reek/spec/should_reek_only_of.rb +4 -4
  158. data/lib/reek/spec.rb +6 -6
  159. data/lib/reek/tree_dresser.rb +8 -8
  160. data/lib/reek/version.rb +1 -1
  161. data/reek.gemspec +5 -7
  162. data/samples/checkstyle.xml +1 -1
  163. data/samples/configuration/accepts_rejects_and_excludes_for_detectors.reek.yml +29 -0
  164. data/samples/configuration/accepts_rejects_and_excludes_for_directory_directives.reek.yml +30 -0
  165. data/samples/configuration/full_configuration.reek +8 -4
  166. data/samples/configuration/full_mask.reek +5 -4
  167. data/samples/configuration/partial_mask.reek +3 -2
  168. data/samples/configuration/regular_configuration/.reek.yml +4 -0
  169. data/samples/paths.rb +5 -4
  170. data/samples/source_with_hidden_directories/.hidden/hidden.rb +1 -0
  171. data/samples/source_with_hidden_directories/not_hidden.rb +1 -0
  172. data/spec/factories/factories.rb +2 -13
  173. data/spec/reek/ast/node_spec.rb +103 -10
  174. data/spec/reek/ast/reference_collector_spec.rb +1 -1
  175. data/spec/reek/ast/sexp_extensions_spec.rb +14 -34
  176. data/spec/reek/cli/application_spec.rb +52 -42
  177. data/spec/reek/cli/command/todo_list_command_spec.rb +6 -4
  178. data/spec/reek/cli/silencer_spec.rb +28 -0
  179. data/spec/reek/code_comment_spec.rb +31 -38
  180. data/spec/reek/configuration/app_configuration_spec.rb +46 -33
  181. data/spec/reek/configuration/configuration_file_finder_spec.rb +133 -51
  182. data/spec/reek/configuration/default_directive_spec.rb +1 -1
  183. data/spec/reek/configuration/directory_directives_spec.rb +6 -7
  184. data/spec/reek/configuration/excluded_paths_spec.rb +6 -6
  185. data/spec/reek/configuration/rake_task_converter_spec.rb +33 -0
  186. data/spec/reek/configuration/schema_validator_spec.rb +165 -0
  187. data/spec/reek/context/code_context_spec.rb +70 -106
  188. data/spec/reek/context/ghost_context_spec.rb +9 -9
  189. data/spec/reek/context/method_context_spec.rb +2 -2
  190. data/spec/reek/context/module_context_spec.rb +3 -3
  191. data/spec/reek/context/root_context_spec.rb +1 -1
  192. data/spec/reek/context_builder_spec.rb +20 -0
  193. data/spec/reek/documentation_link_spec.rb +20 -0
  194. data/spec/reek/errors/base_error_spec.rb +13 -0
  195. data/spec/reek/examiner_spec.rb +136 -29
  196. data/spec/reek/rake/task_spec.rb +25 -2
  197. data/spec/reek/report/code_climate/code_climate_fingerprint_spec.rb +82 -80
  198. data/spec/reek/report/code_climate/code_climate_formatter_spec.rb +6 -6
  199. data/spec/reek/report/json_report_spec.rb +13 -46
  200. data/spec/reek/report/{formatter/location_formatter_spec.rb → location_formatter_spec.rb} +5 -5
  201. data/spec/reek/report/{formatter/progress_formatter_spec.rb → progress_formatter_spec.rb} +4 -4
  202. data/spec/reek/report/text_report_spec.rb +4 -4
  203. data/spec/reek/report/xml_report_spec.rb +3 -3
  204. data/spec/reek/report/yaml_report_spec.rb +9 -38
  205. data/spec/reek/report_spec.rb +3 -3
  206. data/spec/reek/smell_detectors/base_detector_spec.rb +4 -5
  207. data/spec/reek/smell_detectors/boolean_parameter_spec.rb +2 -2
  208. data/spec/reek/smell_detectors/class_variable_spec.rb +26 -32
  209. data/spec/reek/smell_detectors/control_parameter_spec.rb +34 -4
  210. data/spec/reek/smell_detectors/duplicate_method_call_spec.rb +3 -3
  211. data/spec/reek/smell_detectors/feature_envy_spec.rb +47 -2
  212. data/spec/reek/smell_detectors/irresponsible_module_spec.rb +0 -11
  213. data/spec/reek/smell_detectors/{prima_donna_method_spec.rb → missing_safe_method_spec.rb} +10 -10
  214. data/spec/reek/smell_detectors/module_initialize_spec.rb +14 -0
  215. data/spec/reek/smell_detectors/nested_iterators_spec.rb +1 -1
  216. data/spec/reek/smell_detectors/too_many_constants_spec.rb +3 -3
  217. data/spec/reek/smell_detectors/too_many_instance_variables_spec.rb +1 -1
  218. data/spec/reek/smell_detectors/uncommunicative_method_name_spec.rb +6 -6
  219. data/spec/reek/smell_detectors/uncommunicative_module_name_spec.rb +6 -4
  220. data/spec/reek/smell_detectors/uncommunicative_parameter_name_spec.rb +36 -15
  221. data/spec/reek/smell_detectors/uncommunicative_variable_name_spec.rb +9 -9
  222. data/spec/reek/smell_detectors/unused_parameters_spec.rb +3 -3
  223. data/spec/reek/smell_detectors/unused_private_method_spec.rb +21 -10
  224. data/spec/reek/smell_detectors/utility_function_spec.rb +57 -5
  225. data/spec/reek/smell_warning_spec.rb +12 -8
  226. data/spec/reek/source/source_code_spec.rb +22 -21
  227. data/spec/reek/source/source_locator_spec.rb +17 -17
  228. data/spec/reek/spec/should_reek_of_spec.rb +25 -29
  229. data/spec/reek/spec/should_reek_only_of_spec.rb +2 -2
  230. data/spec/reek/spec/should_reek_spec.rb +8 -8
  231. data/spec/reek/spec/smell_matcher_spec.rb +23 -23
  232. data/spec/reek/tree_dresser_spec.rb +12 -17
  233. data/spec/spec_helper.rb +6 -17
  234. data/tasks/configuration.rake +8 -5
  235. metadata +74 -41
  236. data/defaults.reek +0 -131
  237. data/features/configuration_files/warn_about_multiple_configuration_files.feature +0 -44
  238. data/lib/reek/report/formatter/heading_formatter.rb +0 -52
  239. data/lib/reek/report/formatter/location_formatter.rb +0 -42
  240. data/lib/reek/report/formatter/progress_formatter.rb +0 -81
  241. data/lib/reek/report/formatter/simple_warning_formatter.rb +0 -35
  242. data/lib/reek/report/formatter/wiki_link_warning_formatter.rb +0 -36
  243. data/lib/reek/report/formatter.rb +0 -33
  244. data/lib/reek/smell_detectors/syntax.rb +0 -37
  245. data/samples/configuration/non_public_modifiers_mask.reek +0 -3
  246. data/samples/smelly_with_inline_mask.rb +0 -8
  247. data/samples/smelly_with_modifiers.rb +0 -12
  248. data/samples/source_with_hidden_directories/.hidden/uncommunicative_method_name.rb +0 -5
  249. data/samples/source_with_non_ruby_files/uncommunicative_parameter_name.rb +0 -6
  250. data/spec/reek/smell_detectors/syntax_spec.rb +0 -17
  251. /data/{samples/configuration/more_than_one_configuration_file/regular.reek → .reek.yml} +0 -0
  252. /data/samples/{clean.rb → clean_source/clean.rb} +0 -0
  253. /data/samples/{exceptions.reek → configuration/home/home.reek.yml} +0 -0
  254. /data/samples/configuration/{more_than_one_configuration_file/todo.reek → regular_configuration/empty_sub_directory/.gitignore} +0 -0
  255. /data/samples/{configuration/single_configuration_file/.reek → no_config_file/.keep} +0 -0
  256. /data/samples/{inline.rb → smelly_source/inline.rb} +0 -0
  257. /data/samples/{optparse.rb → smelly_source/optparse.rb} +0 -0
  258. /data/samples/{redcloth.rb → smelly_source/redcloth.rb} +0 -0
  259. /data/samples/{smelly.rb → smelly_source/smelly.rb} +0 -0
  260. /data/samples/{source_with_hidden_directories/uncommunicative_parameter_name.rb → source_with_non_ruby_files/ruby.rb} +0 -0
@@ -0,0 +1,210 @@
1
+ ---
2
+ type: map
3
+ mapping:
4
+ "detectors":
5
+ type: map
6
+ mapping: &all_detectors
7
+ Attribute:
8
+ type: map
9
+ mapping: &detector_base
10
+ "enabled":
11
+ type: bool
12
+ "exclude":
13
+ type: seq
14
+ sequence:
15
+ - type: str
16
+ BooleanParameter:
17
+ type: map
18
+ mapping:
19
+ <<: *detector_base
20
+ ClassVariable:
21
+ type: map
22
+ mapping:
23
+ <<: *detector_base
24
+ ControlParameter:
25
+ type: map
26
+ mapping:
27
+ <<: *detector_base
28
+ DataClump:
29
+ type: map
30
+ mapping:
31
+ <<: *detector_base
32
+ max_copies:
33
+ type: number
34
+ min_clump_size:
35
+ type: number
36
+ DuplicateMethodCall:
37
+ type: map
38
+ mapping:
39
+ <<: *detector_base
40
+ max_calls:
41
+ type: number
42
+ allow_calls:
43
+ type: seq
44
+ sequence:
45
+ - type: str
46
+ FeatureEnvy:
47
+ type: map
48
+ mapping:
49
+ <<: *detector_base
50
+ InstanceVariableAssumption:
51
+ type: map
52
+ mapping:
53
+ <<: *detector_base
54
+ IrresponsibleModule:
55
+ type: map
56
+ mapping:
57
+ <<: *detector_base
58
+ LongParameterList:
59
+ type: map
60
+ mapping:
61
+ <<: *detector_base
62
+ max_params:
63
+ type: number
64
+ overrides:
65
+ type: map
66
+ mapping:
67
+ initialize:
68
+ type: map
69
+ mapping:
70
+ max_params:
71
+ type: number
72
+ LongYieldList:
73
+ type: map
74
+ mapping:
75
+ <<: *detector_base
76
+ max_params:
77
+ type: number
78
+ ManualDispatch:
79
+ type: map
80
+ mapping:
81
+ <<: *detector_base
82
+ MissingSafeMethod:
83
+ type: map
84
+ mapping:
85
+ <<: *detector_base
86
+ ModuleInitialize:
87
+ type: map
88
+ mapping:
89
+ <<: *detector_base
90
+ NestedIterators:
91
+ type: map
92
+ mapping:
93
+ <<: *detector_base
94
+ max_allowed_nesting:
95
+ type: number
96
+ ignore_iterators:
97
+ type: seq
98
+ sequence:
99
+ - type: str
100
+ NilCheck:
101
+ type: map
102
+ mapping:
103
+ <<: *detector_base
104
+ RepeatedConditional:
105
+ type: map
106
+ mapping:
107
+ <<: *detector_base
108
+ max_ifs:
109
+ type: number
110
+ SubclassedFromCoreClass:
111
+ type: map
112
+ mapping:
113
+ <<: *detector_base
114
+ Syntax:
115
+ type: map
116
+ mapping:
117
+ <<: *detector_base
118
+ TooManyConstants:
119
+ type: map
120
+ mapping:
121
+ <<: *detector_base
122
+ max_constants:
123
+ type: number
124
+ TooManyInstanceVariables:
125
+ type: map
126
+ mapping:
127
+ <<: *detector_base
128
+ max_instance_variables:
129
+ type: number
130
+ TooManyMethods:
131
+ type: map
132
+ mapping:
133
+ <<: *detector_base
134
+ max_methods:
135
+ type: number
136
+ TooManyStatements:
137
+ type: map
138
+ mapping:
139
+ <<: *detector_base
140
+ max_statements:
141
+ type: number
142
+ UncommunicativeMethodName:
143
+ type: map
144
+ mapping:
145
+ <<: *detector_base
146
+ reject: &reject_settings
147
+ type: seq
148
+ sequence:
149
+ - type: str
150
+ accept: &accept_settings
151
+ type: seq
152
+ sequence:
153
+ - type: str
154
+ UncommunicativeModuleName:
155
+ type: map
156
+ mapping:
157
+ <<: *detector_base
158
+ reject: *reject_settings
159
+ accept: *accept_settings
160
+ UncommunicativeParameterName:
161
+ type: map
162
+ mapping:
163
+ <<: *detector_base
164
+ reject: *reject_settings
165
+ accept: *accept_settings
166
+ UncommunicativeVariableName:
167
+ type: map
168
+ mapping:
169
+ <<: *detector_base
170
+ reject: *reject_settings
171
+ accept: *accept_settings
172
+ UnusedParameters:
173
+ type: map
174
+ mapping:
175
+ <<: *detector_base
176
+ UnusedPrivateMethod:
177
+ type: map
178
+ mapping:
179
+ <<: *detector_base
180
+ UtilityFunction:
181
+ type: map
182
+ mapping:
183
+ <<: *detector_base
184
+ public_methods_only:
185
+ type: bool
186
+
187
+ "directories":
188
+ type: map
189
+ mapping:
190
+ # For any given key that is not matched somewhere else we'll apply the schema below.
191
+ # So this will just slurp in every directory we throw at it and then validate everything under
192
+ # it against all detectors - for instance:
193
+ #
194
+ # directories:
195
+ # "web_app/app/controllers":
196
+ # NestedIterators:
197
+ # enabled: false
198
+ # "web_app/app/helpers":
199
+ # UtilityFunction:
200
+ # enabled: false
201
+ #
202
+ # For details check out: http://www.kuwata-lab.com/kwalify/ruby/users-guide.02.html#tips-default
203
+ =:
204
+ type: map
205
+ mapping: *all_detectors
206
+
207
+ "exclude_paths":
208
+ type: seq
209
+ sequence:
210
+ - type: str
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+ require_relative '../cli/silencer'
5
+ Reek::CLI::Silencer.without_warnings { require 'kwalify' }
6
+ require_relative '../errors/config_file_error'
7
+
8
+ module Reek
9
+ module Configuration
10
+ #
11
+ # Schema validator module.
12
+ #
13
+ class SchemaValidator
14
+ SCHEMA_FILE_PATH = File.expand_path('./schema.yml', __dir__)
15
+
16
+ def initialize(configuration)
17
+ @configuration = configuration
18
+ @validator = CLI::Silencer.without_warnings do
19
+ schema_file = Kwalify::Yaml.load_file(SCHEMA_FILE_PATH)
20
+ Kwalify::Validator.new(schema_file)
21
+ end
22
+ end
23
+
24
+ def validate
25
+ errors = CLI::Silencer.without_warnings { @validator.validate @configuration }
26
+ return if !errors || errors.empty?
27
+ raise Errors::ConfigFileError, error_message(errors)
28
+ end
29
+
30
+ private
31
+
32
+ # :reek:UtilityFunction
33
+ def error_message(errors)
34
+ "We found some problems with your configuration file: #{CLI::Silencer.silently { errors.join(', ') }}"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -7,14 +7,14 @@ module Reek
7
7
  #
8
8
  # A context wrapper for attribute definitions found in a syntax tree.
9
9
  #
10
- # :reek:Attribute
10
+ # @quality :reek:Attribute
11
11
  class AttributeContext < CodeContext
12
12
  attr_accessor :visibility
13
13
 
14
- def initialize(context, exp, send_expression)
14
+ def initialize(exp, send_expression)
15
15
  @visibility = :public
16
16
  @send_expression = send_expression
17
- super context, exp
17
+ super exp
18
18
  end
19
19
 
20
20
  def full_comment
@@ -14,51 +14,19 @@ module Reek
14
14
  # code element. CodeContexts form a tree in the same way the code does,
15
15
  # with each context holding a reference to a unique outer context.
16
16
  #
17
- # :reek:TooManyMethods: { max_methods: 19 }
18
- # :reek:TooManyInstanceVariables: { max_instance_variables: 8 }
17
+ # @quality :reek:TooManyMethods { max_methods: 19 }
18
+ # @quality :reek:TooManyInstanceVariables { max_instance_variables: 8 }
19
19
  class CodeContext
20
20
  include Enumerable
21
21
  extend Forwardable
22
- delegate each_node: :exp
23
22
  delegate [:name, :type] => :exp
24
23
 
25
24
  attr_reader :children, :parent, :exp, :statement_counter
26
25
 
27
26
  # Initializes a new CodeContext.
28
27
  #
29
- # @param _parent [CodeContext, nil] The parent context
30
28
  # @param exp [Reek::AST::Node] The code described by this context
31
- #
32
- # For example, given the following code:
33
- #
34
- # class Omg
35
- # def foo(x)
36
- # puts x
37
- # end
38
- # end
39
- #
40
- # The {ContextBuilder} object first instantiates a {RootContext}, which has no parent.
41
- #
42
- # Next, it instantiates a {ModuleContext}, with +parent+ being the
43
- # {RootContext} just created, and +exp+ looking like this:
44
- #
45
- # (class
46
- # (const nil :Omg) nil
47
- # (def :foo
48
- # (args
49
- # (arg :x))
50
- # (send nil :puts
51
- # (lvar :x))))
52
- #
53
- # Finally, {ContextBuilder} will instantiate a {MethodContext}. This time,
54
- # +parent+ is the {ModuleContext} created above, and +exp+ is:
55
- #
56
- # (def :foo
57
- # (args
58
- # (arg :x))
59
- # (send nil :puts
60
- # (lvar :x)))
61
- def initialize(_parent, exp)
29
+ def initialize(exp)
62
30
  @exp = exp
63
31
  @children = []
64
32
  @statement_counter = StatementCounter.new
@@ -71,12 +39,12 @@ module Reek
71
39
  # @yield block that is executed for every node.
72
40
  #
73
41
  def local_nodes(type, ignored = [], &blk)
74
- ignored += [:casgn, :class, :module]
75
- each_node(type, ignored, &blk)
42
+ ignored |= [:class, :module]
43
+ exp.each_node(type, ignored, &blk)
76
44
  end
77
45
 
78
46
  # Iterate over `self` and child contexts.
79
- # The main difference (among others) to `each_node` is that we are traversing
47
+ # The main difference (among others) to `local_nodes` is that we are traversing
80
48
  # `CodeContexts` here, not AST nodes (see `Reek::AST::Node`).
81
49
  #
82
50
  # @yield block that is executed for every node.
@@ -91,6 +59,44 @@ module Reek
91
59
  end
92
60
  end
93
61
 
62
+ # Link the present context to its parent.
63
+ #
64
+ # @param parent [Reek::AST::Node] The parent context of the code described by this context
65
+ #
66
+ # For example, given the following code:
67
+ #
68
+ # class Omg
69
+ # def foo(x)
70
+ # puts x
71
+ # end
72
+ # end
73
+ #
74
+ # The {ContextBuilder} object first instantiates a {RootContext}, which has no parent.
75
+ #
76
+ # Next, it instantiates a {ModuleContext}, with +exp+ looking like this:
77
+ #
78
+ # (class
79
+ # (const nil :Omg) nil
80
+ # (def :foo
81
+ # (args
82
+ # (arg :x))
83
+ # (send nil :puts
84
+ # (lvar :x))))
85
+ #
86
+ # It will then call #register_with_parent on the {ModuleContext}, passing
87
+ # in the parent {RootContext}.
88
+ #
89
+ # Finally, {ContextBuilder} will instantiate a {MethodContext}. This time,
90
+ # +exp+ is:
91
+ #
92
+ # (def :foo
93
+ # (args
94
+ # (arg :x))
95
+ # (send nil :puts
96
+ # (lvar :x)))
97
+ #
98
+ # Then it will call #register_with_parent on the {MethodContext}, passing
99
+ # in the parent {ModuleContext}.
94
100
  def register_with_parent(parent)
95
101
  @parent = parent.append_child_context(self) if parent
96
102
  end
@@ -104,17 +110,15 @@ module Reek
104
110
  self
105
111
  end
106
112
 
107
- # :reek:TooManyStatements: { max_statements: 6 }
108
- # :reek:FeatureEnvy
113
+ # @quality :reek:TooManyStatements { max_statements: 6 }
114
+ # @quality :reek:FeatureEnvy
109
115
  def record_call_to(exp)
110
116
  receiver = exp.receiver
111
117
  type = receiver ? receiver.type : :self
112
118
  line = exp.line
113
119
  case type
114
120
  when :lvar, :lvasgn
115
- unless exp.object_creation_call?
116
- refs.record_reference(name: receiver.name, line: line)
117
- end
121
+ refs.record_reference(name: receiver.name, line: line) unless exp.object_creation_call?
118
122
  when :self
119
123
  refs.record_reference(name: :self, line: line)
120
124
  end
@@ -41,8 +41,6 @@ module Reek
41
41
  names: names
42
42
  end
43
43
 
44
- def track_singleton_visibility(_visibility, _names); end
45
-
46
44
  def record_use_of_self
47
45
  parent.record_use_of_self
48
46
  end
@@ -7,14 +7,15 @@ module Reek
7
7
  #
8
8
  # A context wrapper for any method definition found in a syntax tree.
9
9
  #
10
- # :reek:Attribute
10
+ # @quality :reek:Attribute
11
11
  class MethodContext < CodeContext
12
12
  attr_accessor :visibility
13
13
  attr_reader :refs
14
14
 
15
- def initialize(context, exp)
15
+ def initialize(exp, parent_exp)
16
+ @parent_exp = parent_exp
16
17
  @visibility = :public
17
- super
18
+ super exp
18
19
  end
19
20
 
20
21
  def references_self?
@@ -22,29 +23,24 @@ module Reek
22
23
  end
23
24
 
24
25
  def uses_param?(param)
25
- # local_nodes(:lvasgn) catches:
26
+ # :lvasgn catches:
27
+ #
26
28
  # def foo(bar); bar += 1; end
27
- # In this example there is no `lvar` node present.
28
29
  #
29
- # local_nodes(:lvar) catches:
30
+ # :lvar catches:
31
+ #
30
32
  # def foo(bar); other(bar); end
31
33
  # def foo(bar); tmp = other(bar); tmp[0]; end
32
34
  #
33
- # Note that in the last example the `lvar` node for `bar` is part of an `lvasgn` node for `tmp`.
34
- # This means that if we would just search for [:lvar, :lvasgn]
35
- # (e.g. via Reek::AST::Node#find_nodes) this would fail for this example since we would
36
- # stop at the `lvasgn` and not detect the contained `lvar`.
37
- # Hence we first get all `lvar` nodes followed by all `lvasgn` nodes.
38
- #
39
- (local_nodes(:lvar) + local_nodes(:lvasgn)).find { |node| node.var_name == param.to_sym }
35
+ local_nodes([:lvar, :lvasgn]).find { |node| node.var_name == param.name }
40
36
  end
41
37
 
42
- # :reek:FeatureEnvy
38
+ # @quality :reek:FeatureEnvy
43
39
  def unused_params
44
40
  exp.arguments.reject do |param|
45
41
  param.anonymous_splat? ||
46
42
  param.marked_unused? ||
47
- uses_param?(param.plain_name)
43
+ uses_param?(param)
48
44
  end
49
45
  end
50
46
 
@@ -80,6 +76,17 @@ module Reek
80
76
  def non_public_visibility?
81
77
  visibility != :public
82
78
  end
79
+
80
+ def full_comment
81
+ own = super
82
+ return own unless own.empty?
83
+ return parent_exp.full_comment if parent_exp
84
+ ''
85
+ end
86
+
87
+ private
88
+
89
+ attr_reader :parent_exp
83
90
  end
84
91
  end
85
92
  end
@@ -13,9 +13,8 @@ module Reek
13
13
  class ModuleContext < CodeContext
14
14
  attr_reader :visibility_tracker
15
15
 
16
- def initialize(context, exp)
16
+ def initialize(exp)
17
17
  super
18
-
19
18
  @visibility_tracker = VisibilityTracker.new
20
19
  end
21
20
 
@@ -44,9 +43,9 @@ module Reek
44
43
  AttributeContext
45
44
  end
46
45
 
47
- def defined_instance_methods(visibility: :public)
46
+ def defined_instance_methods(visibility: :any)
48
47
  instance_method_children.select do |context|
49
- context.visibility == visibility
48
+ visibility == :any || context.visibility == visibility
50
49
  end
51
50
  end
52
51
 
@@ -60,7 +59,7 @@ module Reek
60
59
  # @deprecated use `defined_instance_methods` instead
61
60
  #
62
61
  def node_instance_methods
63
- local_nodes(:def)
62
+ local_nodes(:def).to_a
64
63
  end
65
64
 
66
65
  def descriptively_commented?
@@ -74,7 +73,7 @@ module Reek
74
73
  #
75
74
  # @return true if the module is a namespace module
76
75
  #
77
- # :reek:FeatureEnvy
76
+ # @quality :reek:FeatureEnvy
78
77
  def namespace_module?
79
78
  return false if exp.type == :casgn
80
79
  children = exp.direct_children
@@ -85,9 +84,6 @@ module Reek
85
84
  visibility_tracker.track_visibility children: instance_method_children,
86
85
  visibility: visibility,
87
86
  names: names
88
- end
89
-
90
- def track_singleton_visibility(visibility, names)
91
87
  visibility_tracker.track_singleton_visibility children: singleton_method_children,
92
88
  visibility: visibility,
93
89
  names: names
@@ -9,10 +9,6 @@ module Reek
9
9
  # A context wrapper representing the root of an abstract syntax tree.
10
10
  #
11
11
  class RootContext < CodeContext
12
- def initialize(exp)
13
- super(nil, exp)
14
- end
15
-
16
12
  def type
17
13
  :root
18
14
  end
@@ -10,9 +10,9 @@ module Reek
10
10
  class SendContext < CodeContext
11
11
  attr_reader :name
12
12
 
13
- def initialize(context, exp, name)
13
+ def initialize(exp, name)
14
14
  @name = name
15
- super context, exp
15
+ super exp
16
16
  end
17
17
  end
18
18
  end