reek 3.0.4 → 3.1

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +6 -0
  3. data/README.md +41 -20
  4. data/features/configuration_files/directory_specific_directives.feature +280 -0
  5. data/features/configuration_files/masking_smells.feature +0 -14
  6. data/features/step_definitions/sample_file_steps.rb +2 -2
  7. data/lib/reek/ast/sexp_extensions.rb +72 -60
  8. data/lib/reek/cli/application.rb +2 -5
  9. data/lib/reek/cli/reek_command.rb +1 -1
  10. data/lib/reek/configuration/app_configuration.rb +115 -61
  11. data/lib/reek/configuration/configuration_file_finder.rb +19 -0
  12. data/lib/reek/context/code_context.rb +102 -29
  13. data/lib/reek/context/method_context.rb +11 -48
  14. data/lib/reek/context/module_context.rb +2 -6
  15. data/lib/reek/context/root_context.rb +7 -14
  16. data/lib/reek/examiner.rb +15 -10
  17. data/lib/reek/report/report.rb +5 -4
  18. data/lib/reek/smells/boolean_parameter.rb +1 -1
  19. data/lib/reek/smells/duplicate_method_call.rb +1 -5
  20. data/lib/reek/smells/irresponsible_module.rb +2 -2
  21. data/lib/reek/smells/smell_repository.rb +30 -16
  22. data/lib/reek/smells/utility_function.rb +1 -1
  23. data/lib/reek/source/source_code.rb +10 -6
  24. data/lib/reek/source/source_locator.rb +27 -26
  25. data/lib/reek/spec.rb +8 -6
  26. data/lib/reek/spec/should_reek.rb +6 -2
  27. data/lib/reek/spec/should_reek_of.rb +5 -2
  28. data/lib/reek/spec/should_reek_only_of.rb +1 -1
  29. data/lib/reek/tree_walker.rb +49 -21
  30. data/lib/reek/version.rb +1 -1
  31. data/spec/reek/ast/sexp_extensions_spec.rb +4 -12
  32. data/spec/reek/configuration/app_configuration_spec.rb +80 -52
  33. data/spec/reek/configuration/configuration_file_finder_spec.rb +27 -15
  34. data/spec/reek/context/code_context_spec.rb +66 -17
  35. data/spec/reek/context/method_context_spec.rb +66 -64
  36. data/spec/reek/context/root_context_spec.rb +3 -1
  37. data/spec/reek/context/singleton_method_context_spec.rb +1 -2
  38. data/spec/reek/examiner_spec.rb +5 -8
  39. data/spec/reek/report/xml_report_spec.rb +3 -2
  40. data/spec/reek/smells/attribute_spec.rb +12 -17
  41. data/spec/reek/smells/duplicate_method_call_spec.rb +17 -25
  42. data/spec/reek/smells/feature_envy_spec.rb +4 -5
  43. data/spec/reek/smells/irresponsible_module_spec.rb +43 -0
  44. data/spec/reek/smells/nested_iterators_spec.rb +12 -26
  45. data/spec/reek/smells/too_many_statements_spec.rb +2 -210
  46. data/spec/reek/smells/utility_function_spec.rb +49 -5
  47. data/spec/reek/source/source_locator_spec.rb +39 -43
  48. data/spec/reek/spec/should_reek_of_spec.rb +3 -2
  49. data/spec/reek/spec/should_reek_spec.rb +25 -17
  50. data/spec/reek/tree_walker_spec.rb +214 -23
  51. data/spec/samples/configuration/full_configuration.reek +9 -0
  52. data/spec/spec_helper.rb +10 -10
  53. metadata +4 -3
  54. data/features/configuration_files/overrides_defaults.feature +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 02b11e29be1e78d0ca3b5c5bb7e209d215a34142
4
- data.tar.gz: 2fbda696128728c307a65abe0c61479bccc197ea
3
+ metadata.gz: c490c79513c93451a148336881db8ffec7665e7e
4
+ data.tar.gz: 88059b5d7db2a76be01ca26339e3753f1ef4fa68
5
5
  SHA512:
6
- metadata.gz: 08a97e6cba42ad58c4f6691d89cf4267ce79777095766859421ef6853b98f51c44521988f977e2d78d6dd1ebcdb56bc9b88e53e1fdc0af204f1aba22fe38be8c
7
- data.tar.gz: 6074cc6366979c9e75722d8359fbdba75a2539eba9b3ffad21b5eaee59fa4ae7789d717ea6044b128577ccf13010a49caf69156eef34f239594cc592354eb2d1
6
+ metadata.gz: a93e6367ce746f4c1fba78e8ca91e035b9f3f9624316f329c1f5640415649816dfcc5608427ec113ac4c66aceb7f3eaed800af0c11a8931ebfc828e0a1931413
7
+ data.tar.gz: 24b764ba2d1a15fefe32702567f55cdf49270aaf00c78b6cab50420ebad3b96651d450c210934b8e76e50da2048b14e0b496c4a861ebeb98f4a6d6fedfdac21c
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ == 3.1
2
+
3
+ * (troessner) Make smells configurable on a directory base
4
+ * (mvz) Handle modules defined by constant assignment
5
+ * (mvz) Handle modifier style use of module_function for UtilityFunction
6
+
1
7
  == 3.0.4
2
8
 
3
9
  * (troessner) Fix wiki-link cli option.
data/README.md CHANGED
@@ -144,42 +144,63 @@ of how many `*.reek` files you might have on your filesystem.
144
144
 
145
145
  #### Configuration options
146
146
 
147
- The first thing you probably want to check out are the
148
- [Basic Smell Options](docs/Basic-Smell-Options.md)
149
- which are supported by every smell type. Certain smell
150
- types offer a configuration that goes beyond that
151
- of the basic smell options, for instance
152
- [Data Clump](docs/Data-Clump.md).
153
- All options that go beyond the [Basic Smell Options](docs/Basic-Smell-Options.md)
154
- should be documented in the corresponding smell type wiki page,
155
- but if you want to get a quick and full overview over all possible
156
- configurations you can always check out [the `config/default.reek`
157
- file in this repository](config/defaults.reek).
158
-
159
- Here's an excerpt of a `reek` configuration file from a commercial project:
147
+ We put a lot of effort into making `reek`'s configuration as self explanatory as possible so the
148
+ best way to understand it is by looking at a simple
149
+ example (e.g. `config.reek` in your project directory):
160
150
 
161
151
  ```yaml
162
152
  ---
153
+
154
+ ### Generic smell configuration
155
+
156
+ # You can disable smells completely
163
157
  IrresponsibleModule:
164
158
  enabled: false
165
159
 
160
+ # You can use filters to silence reek warnings.
161
+ # Either because you simply disagree with reek (we are not the police) or
162
+ # because you want to fix this at a later point in time.
166
163
  NestedIterators:
167
164
  exclude:
168
- - "ActiveModelErrorAdder#self.run" # should be refactored
169
- - "BookingRequests::Transfer#remote_validation"
170
- - "BookingRequestsController#vehicle_options" # respond_to block
171
- - "Content::Base#self.expose_fields" # unavoidable due to metaprogramming
165
+ - "MyWorker#self.class_method" # should be refactored
166
+ - "AnotherWorker#instance_method" # should be refactored as well
172
167
 
168
+ # A lot of smells allow fine tuning their configuration. You can look up all available options
169
+ # in the corresponding smell documentation in /docs. In most cases you probably can just go
170
+ # with the defaults we set in config/defaults.reek.
173
171
  DataClump:
174
172
  max_copies: 3
175
173
  min_clump_size: 3
176
174
 
175
+ ### Directory specific configuration
176
+
177
+ # You can configure smells on a per-directory base.
178
+ # E.g. the classic Rails case: controllers smell of NestedIterators (see /docs/Nested-Iterators.md) and
179
+ # helpers smell of UtilityFunction (see docs/Utility-Function.md)
180
+ "web_app/app/controllers":
181
+ NestedIterators:
182
+ enabled: false
183
+ "web_app/app/helpers":
184
+ UtilityFunction:
185
+ enabled: false
186
+
187
+ ### Excluding directories
188
+
189
+ # Directories below will not be scanned at all
177
190
  exclude_paths:
178
- - app/views
179
- - app/controllers
191
+ - lib/legacy
192
+ - lib/rake/legacy_tasks
180
193
  ```
181
194
 
182
- Additionally to the smell configuration you can exclude whole directories from scans using `exclude_paths` as you can see at the end of the configuration above.
195
+ Note you do not need a configuration file at all. If you're fine with all the [defaults](config/defaults.reek) we set you can skip this completely.
196
+
197
+ For more details please check out the [Basic Smell Options](docs/Basic-Smell-Options.md)
198
+ which are supported by every smell type. As you can see above, certain smell
199
+ types offer a configuration that goes beyond that of the basic smell options, for instance
200
+ [Data Clump](docs/Data-Clump.md).
201
+ All options that go beyond the [Basic Smell Options](docs/Basic-Smell-Options.md)
202
+ are documented in the corresponding smell type /docs page (if you want to get a quick overview over all possible
203
+ configurations you can also check out [the `config/default.reek` file in this repository](config/defaults.reek).
183
204
 
184
205
  ### Source code comments
185
206
 
@@ -0,0 +1,280 @@
1
+ Feature: Directory directives
2
+ In order to have a more fine-grained control over what reek reports
3
+ And to enable domain specific modes (like a Ruby on Rails mode)
4
+ As a user
5
+ I want to be able to configure reek using directory directives
6
+
7
+ Scenario: Configure multiple directories
8
+ Given a file named "web_app/config.reek" with:
9
+ """
10
+ ---
11
+ "web_app/app/controllers":
12
+ IrresponsibleModule:
13
+ enabled: false
14
+ NestedIterators:
15
+ enabled: false
16
+ "web_app/app/helpers":
17
+ IrresponsibleModule:
18
+ enabled: false
19
+ UtilityFunction:
20
+ enabled: false
21
+ """
22
+ And a file named "web_app/app/controllers/users_controller.rb" with:
23
+ """
24
+ class UsersController < ApplicationController
25
+ def show
26
+ respond_with do |format|
27
+ format.json { @user.to_custom_json }
28
+ format.xlm { @user.to_fancy_xml }
29
+ end
30
+ end
31
+ end
32
+ """
33
+ And a file named "web_app/app/helpers/application_helper.rb" with:
34
+ """
35
+ module ApplicationHelper
36
+ def current_year
37
+ Time.zone.now.year
38
+ end
39
+ end
40
+ """
41
+ And a file named "web_app/app/models/user.rb" with:
42
+ """
43
+ class User < ActiveRecord::Base
44
+ def logged_in_with_role(r)
45
+ true
46
+ end
47
+ end
48
+ """
49
+ When I run `reek -c web_app/config.reek web_app/`
50
+ Then it reports:
51
+ """
52
+ web_app/app/models/user.rb -- 2 warnings:
53
+ [1]:User has no descriptive comment (IrresponsibleModule)
54
+ [2]:User#logged_in_with_role has unused parameter 'r' (UnusedParameters)
55
+ 2 total warnings
56
+ """
57
+
58
+ Scenario: Ignore trailing slashes
59
+ Given a file named "web_app/config.reek" with:
60
+ """
61
+ ---
62
+ "controllers/":
63
+ IrresponsibleModule:
64
+ enabled: false
65
+ """
66
+ And a file named "controllers/users_controller.rb" with:
67
+ """
68
+ class UsersController
69
+ def show
70
+ end
71
+ end
72
+ """
73
+ When I run `reek -c web_app/config.reek controllers`
74
+ Then it reports nothing
75
+
76
+ Scenario: Partially mask smells in different directories
77
+ Given a file named "web_app/config.reek" with:
78
+ """
79
+ ---
80
+ "web_app/app/controllers":
81
+ IrresponsibleModule:
82
+ enabled: true
83
+ "web_app/app/helpers":
84
+ IrresponsibleModule:
85
+ enabled: false
86
+ UtilityFunction:
87
+ enabled: false
88
+ "web_app/app/models":
89
+ IrresponsibleModule:
90
+ enabled: false
91
+ """
92
+ And a file named "web_app/app/controllers/users_controller.rb" with:
93
+ """
94
+ class UsersController < ApplicationController
95
+ def show
96
+ respond_with do |format|
97
+ format.json { @user.to_custom_json }
98
+ end
99
+ end
100
+ end
101
+ """
102
+ And a file named "web_app/app/helpers/application_helper.rb" with:
103
+ """
104
+ module ApplicationHelper
105
+ def current_year
106
+ Time.zone.now.year
107
+ end
108
+ end
109
+ """
110
+ And a file named "web_app/app/models/user.rb" with:
111
+ """
112
+ class User < ActiveRecord::Base
113
+ def logged_in_with_role(r)
114
+ true
115
+ end
116
+ end
117
+ """
118
+ When I run `reek -c web_app/config.reek web_app/`
119
+ Then it reports:
120
+ """
121
+ web_app/app/controllers/users_controller.rb -- 2 warnings:
122
+ [1]:UsersController has no descriptive comment (IrresponsibleModule)
123
+ [4]:UsersController#show contains iterators nested 2 deep (NestedIterators)
124
+ web_app/app/models/user.rb -- 1 warning:
125
+ [2]:User#logged_in_with_role has unused parameter 'r' (UnusedParameters)
126
+ 3 total warnings
127
+ """
128
+
129
+ Scenario: Use the default directive if there is no directory directive
130
+ Given a file named "config.reek" with:
131
+ """
132
+ ---
133
+ "web_app/app/controllers":
134
+ IrresponsibleModule:
135
+ enabled: true
136
+ NestedIterators:
137
+ enabled: false
138
+ IrresponsibleModule:
139
+ enabled: false
140
+ NestedIterators:
141
+ enabled: true
142
+ """
143
+ And a file named "web_app/app/controllers/users_controller.rb" with:
144
+ """
145
+ class UsersController < ApplicationController
146
+ def show
147
+ respond_with do |format|
148
+ format.json { @user.to_custom_json }
149
+ end
150
+ end
151
+ end
152
+ """
153
+ And a file named "other/projects_controller.rb" with:
154
+ """
155
+ class ProjectController < ApplicationController
156
+ def show
157
+ respond_with do |format|
158
+ format.json { @project.to_custom_json }
159
+ end
160
+ end
161
+ end
162
+ """
163
+ When I run `reek -c config.reek other/ web_app/`
164
+ Then it reports:
165
+ """
166
+ other/projects_controller.rb -- 1 warning:
167
+ [4]:ProjectController#show contains iterators nested 2 deep (NestedIterators)
168
+ web_app/app/controllers/users_controller.rb -- 1 warning:
169
+ [1]:UsersController has no descriptive comment (IrresponsibleModule)
170
+ 2 total warnings
171
+ """
172
+
173
+ Scenario: Abort on non-existent directory
174
+ Given a file named "config.reek" with:
175
+ """
176
+ ---
177
+ "does/not/exist":
178
+ NestedIterators:
179
+ enabled: false
180
+ """
181
+ When I run `reek -c config.reek lib/`
182
+ Then the exit status indicates an error
183
+ And stderr reports:
184
+ """
185
+ Configuration error: Directory `does/not/exist` does not exist
186
+
187
+ """
188
+
189
+ Scenario: Abort on non-existent smell type in directory directive
190
+ Given a file named "config.reek" with:
191
+ """
192
+ ---
193
+ "dummy_directory":
194
+ # Typo: Should be NestedIterators
195
+ IteratorsNested:
196
+ enabled: false
197
+ """
198
+ And a file named "dummy_directory/dummy.rb" with:
199
+ """
200
+ class Dummy
201
+ end
202
+ """
203
+
204
+ When I run `reek -c config.reek dummy_directory/`
205
+ Then the exit status indicates an error
206
+ And stderr reports:
207
+ """
208
+ You are trying to configure smell type IteratorsNested but we can't find one with that name.
209
+ Please make sure you spelled it right (see 'config/defaults.reek' in the reek
210
+ repository for a list of all available smell types.
211
+
212
+ """
213
+
214
+ Scenario: Abort on file as directory directive
215
+ Given a file named "config.reek" with:
216
+ """
217
+ ---
218
+ "dummy_directory/dummy.rb":
219
+ NestedIterators:
220
+ enabled: false
221
+ """
222
+ And a file named "dummy_directory/dummy.rb" with:
223
+ """
224
+ class Dummy
225
+ end
226
+ """
227
+ When I run `reek -c config.reek dummy_directory/`
228
+ Then the exit status indicates an error
229
+ And stderr reports:
230
+ """
231
+ Configuration error: `dummy_directory/dummy.rb` is supposed to be a directory but is a file
232
+
233
+ """
234
+
235
+ Scenario: In case of overlapping configurations, pick the most appropriate one
236
+ Given a file named "config.reek" with:
237
+ """
238
+ ---
239
+ "foo/bar/baz":
240
+ IrresponsibleModule:
241
+ enabled: false
242
+ NestedIterators:
243
+ enabled: true
244
+ "foo/bar":
245
+ IrresponsibleModule:
246
+ enabled: true
247
+ NestedIterators:
248
+ enabled: false
249
+ """
250
+ And a file named "foo/bar/baz/klass.rb" with:
251
+ """
252
+ class Klass
253
+ def meth
254
+ respond_to do
255
+ answer_to do
256
+ end
257
+ end
258
+ end
259
+ end
260
+ """
261
+ And a file named "foo/bar/klazz.rb" with:
262
+ """
263
+ class Klazz
264
+ def meth
265
+ respond_to do
266
+ answer_to do
267
+ end
268
+ end
269
+ end
270
+ end
271
+ """
272
+ When I run `reek -c config.reek foo/`
273
+ Then it reports:
274
+ """
275
+ foo/bar/baz/klass.rb -- 1 warning:
276
+ [4]:Klass#meth contains iterators nested 2 deep (NestedIterators)
277
+ foo/bar/klazz.rb -- 1 warning:
278
+ [1]:Klazz has no descriptive comment (IrresponsibleModule)
279
+ 2 total warnings
280
+ """
@@ -3,20 +3,6 @@ Feature: Masking smells using config files
3
3
  As a developer
4
4
  I want to mask some smells using config files
5
5
 
6
- Scenario: empty config file is ignored
7
- Given a smelly file called 'smelly.rb'
8
- And an empty configuration file called 'empty.reek'
9
- When I run reek -c empty.reek smelly.rb
10
- Then it reports the error 'Warning: Invalid configuration file "empty.reek" -- Empty file'
11
- And the exit status indicates smells
12
- And it reports:
13
- """
14
- smelly.rb -- 3 warnings:
15
- [4, 5]:Smelly#m calls @foo.bar 2 times (DuplicateMethodCall)
16
- [4, 5]:Smelly#m calls puts(@foo.bar) 2 times (DuplicateMethodCall)
17
- [3]:Smelly#m has the name 'm' (UncommunicativeMethodName)
18
- """
19
-
20
6
  Scenario: corrupt config file prevents normal output
21
7
  Given a smelly file called 'smelly.rb'
22
8
  And a corrupt configuration file called 'corrupt.reek'
@@ -26,7 +26,7 @@ Given(/^a smelly file with inline masking called 'inline.rb'$/) do
26
26
  end
27
27
 
28
28
  Given(/^the "(.*?)" sample file exists$/) do |file_name|
29
- full_path = File.expand_path file_name, 'spec/samples'
29
+ full_path = Pathname.new("#{__dir__}/../../spec/samples/#{file_name}")
30
30
  in_current_directory { FileUtils.cp full_path, file_name }
31
31
  end
32
32
 
@@ -135,7 +135,7 @@ When(/^I run "reek (.*?)" in the subdirectory$/) do |args|
135
135
  end
136
136
 
137
137
  Given(/^a masking configuration file in the HOME directory$/) do
138
- set_env('HOME', File.expand_path(File.join(current_directory, 'home')))
138
+ set_env 'HOME', Pathname.new("#{current_directory}/home").expand_path.to_s
139
139
  write_file('home/config.reek', <<-EOS.strip_heredoc)
140
140
  ---
141
141
  DuplicateMethodCall:
@@ -169,9 +169,9 @@ module Reek
169
169
 
170
170
  # Utility methods for :send nodes.
171
171
  module SendNode
172
- def receiver() self[1] end
173
- def method_name() self[2] end
174
- def args() self[3..-1] end
172
+ def receiver; children.first; end
173
+ def method_name() children[1]; end
174
+ def args() children[2..-1] end
175
175
 
176
176
  def participants
177
177
  ([receiver] + args).compact
@@ -180,8 +180,14 @@ module Reek
180
180
  def arg_names
181
181
  args.map { |arg| arg[1] }
182
182
  end
183
+
184
+ def object_creation_call?
185
+ method_name == :new
186
+ end
183
187
  end
184
188
 
189
+ Op_AsgnNode = SendNode
190
+
185
191
  # Base module for utility methods for nodes representing variables.
186
192
  module VariableBase
187
193
  def name() self[1] end
@@ -252,43 +258,7 @@ module Reek
252
258
  # Checking if a method is a singleton method.
253
259
  module SingletonMethod
254
260
  def singleton_method?
255
- singleton_method_via_class_self_notation? ||
256
- singleton_method_via_module_function?
257
- end
258
-
259
- # Ruby allows us to make a method a singleton_method after having defined the
260
- # method via `module_function`.
261
- #
262
- # To check if we used "module_function" for a method we need to check on the parent
263
- # level of the method in question if there is a call to "module_function".
264
- # Given someting like
265
- # class C
266
- # def m; 3 + 7; end
267
- # module_function :m
268
- # end
269
- # the AST (truncated, without the class definition) would look like this:
270
- # (def :m
271
- # (args)
272
- # (send
273
- # (int 3) :+
274
- # (int 7)))
275
- # (send nil :module_function
276
- # (sym :m))))
277
- # With multiple arguments to module_function this gets more complicated:
278
- # (send nil :module_function
279
- # (sym :m1)
280
- # (send nil :m2))
281
- #
282
- # @return [Boolean]
283
- def singleton_method_via_module_function?
284
- return unless parent
285
- module_function_calls(parent).any? do |module_function_call|
286
- method_name_nodes = module_function_call.children[2..-1]
287
- method_names = method_name_nodes.map do |node|
288
- node.children.last
289
- end
290
- method_names.include?(name)
291
- end
261
+ singleton_method_via_class_self_notation?
292
262
  end
293
263
 
294
264
  # Ruby allows us to make a method a singleton_method using the
@@ -301,16 +271,6 @@ module Reek
301
271
  return unless parent
302
272
  parent.type == :sclass
303
273
  end
304
-
305
- private
306
-
307
- def module_function_calls(parent)
308
- parent.children.select do |elem|
309
- elem.is_a?(::Parser::AST::Node) &&
310
- elem.type == :send &&
311
- elem.children[1] == :module_function
312
- end
313
- end
314
274
  end
315
275
 
316
276
  # Utility methods for :def nodes.
@@ -346,6 +306,7 @@ module Reek
346
306
  end
347
307
 
348
308
  include MethodNodeBase
309
+
349
310
  def full_name(outer)
350
311
  prefix = outer == '' ? '' : "#{outer}#"
351
312
  "#{prefix}#{SexpFormatter.format(receiver)}.#{name}"
@@ -389,21 +350,45 @@ module Reek
389
350
  end
390
351
  end
391
352
 
392
- # Utility methods for :module nodes.
393
- module ModuleNode
394
- def name() self[1] end
353
+ # Base module for utility methods for module nodes.
354
+ module ModuleNodeBase
355
+ # The full name of the module or class, including the name of any
356
+ # module or class it is nested inside of.
357
+ #
358
+ # For example, given code like this:
359
+ #
360
+ # module Foo
361
+ # class Bar::Baz
362
+ # end
363
+ # end
364
+ #
365
+ # The full name for the inner class will be 'Foo::Bar::Baz'. To return
366
+ # the correct name, the name of the outer context has to be passed into this method.
367
+ #
368
+ # @param outer [String] full name of the wrapping module or class
369
+ # @return the module's full name
370
+ def full_name(outer)
371
+ prefix = outer == '' ? '' : "#{outer}::"
372
+ "#{prefix}#{name}"
373
+ end
395
374
 
375
+ # The final section of the module or class name. For example, for a
376
+ # module with name 'Foo::Bar' this will return 'Bar'; for a module with
377
+ # name 'Foo' this will return 'Foo'.
378
+ #
379
+ # @return [String] the final section of the name
396
380
  def simple_name
397
- name.is_a?(::Parser::AST::Node) ? name.simple_name : name
381
+ name.split('::').last
398
382
  end
383
+ end
399
384
 
400
- def full_name(outer)
401
- prefix = outer == '' ? '' : "#{outer}::"
402
- "#{prefix}#{text_name}"
403
- end
385
+ # Utility methods for :module nodes.
386
+ module ModuleNode
387
+ include ModuleNodeBase
404
388
 
405
- def text_name
406
- SexpFormatter.format(name)
389
+ # @return [String] name as given in the module statement
390
+ def name
391
+ SexpFormatter.format(children.first)
407
392
  end
408
393
  end
409
394
 
@@ -413,6 +398,33 @@ module Reek
413
398
  def superclass() self[2] end
414
399
  end
415
400
 
401
+ # Utility methods for :casgn nodes.
402
+ module CasgnNode
403
+ include ModuleNodeBase
404
+
405
+ MODULE_DEFINERS = [:Class, :Struct]
406
+
407
+ def defines_module?
408
+ call = case value.type
409
+ when :block
410
+ value.call
411
+ when :send
412
+ value
413
+ end
414
+ call &&
415
+ call.object_creation_call? &&
416
+ MODULE_DEFINERS.include?(call.receiver.simple_name)
417
+ end
418
+
419
+ def name
420
+ SexpFormatter.format(children[1])
421
+ end
422
+
423
+ def value
424
+ children.last
425
+ end
426
+ end
427
+
416
428
  # Utility methods for :yield nodes.
417
429
  module YieldNode
418
430
  def args() self[1..-1] end