reek 3.0.3 → 3.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d10cc19d7d47e9a5094aaf117aac55072abe9064
4
- data.tar.gz: db2544839858ea0cad619f8bef26c77e0ebb9745
3
+ metadata.gz: 02b11e29be1e78d0ca3b5c5bb7e209d215a34142
4
+ data.tar.gz: 2fbda696128728c307a65abe0c61479bccc197ea
5
5
  SHA512:
6
- metadata.gz: 0b29e3d3b6fcdcd5399b3d6faa881c88a226626589f5fff426c62e550c836b53b74280117a0dd9e362a9921b5fac4b2b86762714388d5a48ed425b0425c703e5
7
- data.tar.gz: 7bc7a0108f69942487dc213fa76a5f43c09780d8c162151c0a66351aaa5520cafc2c4de5946050034827b3c6dcea5ad7abe728e709c6481efd62c0031df1b732
6
+ metadata.gz: 08a97e6cba42ad58c4f6691d89cf4267ce79777095766859421ef6853b98f51c44521988f977e2d78d6dd1ebcdb56bc9b88e53e1fdc0af204f1aba22fe38be8c
7
+ data.tar.gz: 6074cc6366979c9e75722d8359fbdba75a2539eba9b3ffad21b5eaee59fa4ae7789d717ea6044b128577ccf13010a49caf69156eef34f239594cc592354eb2d1
data/.gitignore CHANGED
@@ -11,3 +11,4 @@ Gemfile.lock
11
11
  tags
12
12
  .pryrc
13
13
  .tags*
14
+ .DS_Store
@@ -13,8 +13,8 @@ rvm:
13
13
  - ruby-head
14
14
  matrix:
15
15
  include:
16
- - rvm: jruby-19mode
17
- env: JRUBY_OPTS='--server -Xcompile.invokedynamic=false'
16
+ - rvm: jruby
17
+ env: JRUBY_OPTS='--2.0 --server -Xcompile.invokedynamic=false'
18
18
  - rvm: jruby-head
19
19
  env: JRUBY_OPTS='--server -Xcompile.invokedynamic=false'
20
20
  allow_failures:
data/CHANGELOG CHANGED
@@ -1,3 +1,7 @@
1
+ == 3.0.4
2
+
3
+ * (troessner) Fix wiki-link cli option.
4
+
1
5
  == 3.0.3
2
6
 
3
7
  * (troessner) Fix finding sources when using just the current directory.
@@ -45,13 +45,7 @@ bundle
45
45
  bundle exec rake
46
46
  ```
47
47
 
48
- Once you’re sure your copy of reek works (and that there are no
49
- failing tests on the "develop" branch) create your own branch from our "develop" branch.
50
-
51
- We are using the popular [gitflow branch model](http://nvie.com/posts/a-successful-git-branching-model/) and
52
- require contributions to follow to this model as well.
53
- This probably sounds more complicated than it is, for you this just means that you should branch off
54
- of our "develop" branch for your pull request, not master (which is the default already):
48
+ Once you’re sure your copy of reek works create your own feature branch from our "master" branch:
55
49
 
56
50
  ```
57
51
  git checkout -b your_feature_or_fix_name
@@ -81,8 +75,6 @@ Then go to your GitHub fork and [make a pull
81
75
  request](https://help.github.com/articles/creating-a-pull-request/)
82
76
  to the original repository.
83
77
 
84
-
85
-
86
78
  ## Review and Fixes
87
79
 
88
80
  Try to gauge and let us know in the pull request whether what
@@ -105,7 +97,15 @@ If there were any fixes to your pull request we’ll ask you to
105
97
  all of the commits into one:
106
98
 
107
99
  ```
108
- git rebase -i develop
100
+ git rebase -i master
109
101
  # squash squash squash
110
102
  git push -f origin
111
103
  ```
104
+
105
+ ## Versioning policy
106
+
107
+ We are following [semantic versioning](http://semver.org/).
108
+
109
+ ## Breaking changes
110
+
111
+ If you're working on a change that is breaking backwards-compatibility according to our versioning policy from above just go ahead with your pull request like normal. We'll discuss this then in the pull request and help you to point your pull request to the right branch.
@@ -190,9 +190,9 @@ Feature: Correctly formatted reports
190
190
  And it reports:
191
191
  """
192
192
  smelly.rb -- 3 warnings:
193
- [4, 5]:Smelly#m calls @foo.bar 2 times (DuplicateMethodCall) [https://github.com/troessner/reek/wiki/Duplicate-Method-Call]
194
- [4, 5]:Smelly#m calls puts(@foo.bar) 2 times (DuplicateMethodCall) [https://github.com/troessner/reek/wiki/Duplicate-Method-Call]
195
- [3]:Smelly#m has the name 'm' (UncommunicativeMethodName) [https://github.com/troessner/reek/wiki/Uncommunicative-Method-Name]
193
+ [4, 5]:Smelly#m calls @foo.bar 2 times (DuplicateMethodCall) [https://github.com/troessner/reek/blob/master/docs/Duplicate-Method-Call.md]
194
+ [4, 5]:Smelly#m calls puts(@foo.bar) 2 times (DuplicateMethodCall) [https://github.com/troessner/reek/blob/master/docs/Duplicate-Method-Call.md]
195
+ [3]:Smelly#m has the name 'm' (UncommunicativeMethodName) [https://github.com/troessner/reek/blob/master/docs/Uncommunicative-Method-Name.md]
196
196
  """
197
197
 
198
198
  Examples:
@@ -207,9 +207,9 @@ Feature: Correctly formatted reports
207
207
  And it reports:
208
208
  """
209
209
  smelly.rb -- 3 warnings:
210
- Smelly#m calls @foo.bar 2 times (DuplicateMethodCall) [https://github.com/troessner/reek/wiki/Duplicate-Method-Call]
211
- Smelly#m calls puts(@foo.bar) 2 times (DuplicateMethodCall) [https://github.com/troessner/reek/wiki/Duplicate-Method-Call]
212
- Smelly#m has the name 'm' (UncommunicativeMethodName) [https://github.com/troessner/reek/wiki/Uncommunicative-Method-Name]
210
+ Smelly#m calls @foo.bar 2 times (DuplicateMethodCall) [https://github.com/troessner/reek/blob/master/docs/Duplicate-Method-Call.md]
211
+ Smelly#m calls puts(@foo.bar) 2 times (DuplicateMethodCall) [https://github.com/troessner/reek/blob/master/docs/Duplicate-Method-Call.md]
212
+ Smelly#m has the name 'm' (UncommunicativeMethodName) [https://github.com/troessner/reek/blob/master/docs/Uncommunicative-Method-Name.md]
213
213
  """
214
214
 
215
215
  Examples:
@@ -27,7 +27,7 @@ end
27
27
 
28
28
  Given(/^the "(.*?)" sample file exists$/) do |file_name|
29
29
  full_path = File.expand_path file_name, 'spec/samples'
30
- in_current_dir { FileUtils.cp full_path, file_name }
30
+ in_current_directory { FileUtils.cp full_path, file_name }
31
31
  end
32
32
 
33
33
  Given(/^a directory called 'clean_files' containing some clean files$/) do
@@ -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_dir, 'home')))
138
+ set_env('HOME', File.expand_path(File.join(current_directory, 'home')))
139
139
  write_file('home/config.reek', <<-EOS.strip_heredoc)
140
140
  ---
141
141
  DuplicateMethodCall:
@@ -16,7 +16,7 @@ class ReekWorld
16
16
  end
17
17
 
18
18
  def reek_with_pipe(stdin, args)
19
- run_interactive("reek --no-color #{args}")
19
+ run "reek --no-color #{args}"
20
20
  type(stdin)
21
21
  close_input
22
22
  end
@@ -34,7 +34,7 @@ module Reek
34
34
  end
35
35
 
36
36
  def line
37
- loc.line
37
+ loc.line unless loc.nil?
38
38
  end
39
39
 
40
40
  # @deprecated
@@ -1,33 +1,30 @@
1
1
  module Reek
2
+ # @api private
2
3
  module AST
4
+ ObjectRef = Struct.new(:name, :line)
3
5
  #
4
6
  # Manages and counts the references out of a method to other objects.
5
7
  #
6
- # @api private
7
- class ObjectRefs # :nodoc:
8
+ class ObjectRefs
8
9
  def initialize
9
- @refs = Hash.new(0)
10
+ @refs = Hash.new { |refs, name| refs[name] = [] }
10
11
  end
11
12
 
12
- def record_reference_to(exp)
13
- @refs[exp] += 1
13
+ def most_popular
14
+ max = @refs.values.map(&:size).max
15
+ @refs.select { |_name, refs| refs.size == max }
14
16
  end
15
17
 
16
- def references_to(exp)
17
- @refs[exp]
18
+ def record_reference_to(name, line: nil)
19
+ @refs[name] << ObjectRef.new(name, line)
18
20
  end
19
21
 
20
- def max_refs
21
- @refs.values.max || 0
22
- end
23
-
24
- def max_keys
25
- max = max_refs
26
- @refs.select { |_key, val| val == max }
22
+ def references_to(name)
23
+ @refs[name]
27
24
  end
28
25
 
29
26
  def self_is_max?
30
- max_keys.length == 0 || @refs[:self] == max_refs
27
+ @refs.empty? || most_popular.keys.include?(:self)
31
28
  end
32
29
  end
33
30
  end
@@ -249,6 +249,70 @@ module Reek
249
249
  end
250
250
  end
251
251
 
252
+ # Checking if a method is a singleton method.
253
+ module SingletonMethod
254
+ 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
292
+ end
293
+
294
+ # Ruby allows us to make a method a singleton_method using the
295
+ # class << self syntax.
296
+ #
297
+ # To check for this we check if the parent node is of type :sclass.
298
+ #
299
+ # @return [Boolean]
300
+ def singleton_method_via_class_self_notation?
301
+ return unless parent
302
+ parent.type == :sclass
303
+ 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
+ end
315
+
252
316
  # Utility methods for :def nodes.
253
317
  module DefNode
254
318
  def name() self[1] end
@@ -257,7 +321,7 @@ module Reek
257
321
  def body
258
322
  self[3]
259
323
  end
260
- include MethodNodeBase
324
+
261
325
  def full_name(outer)
262
326
  prefix = outer == '' ? '' : "#{outer}#"
263
327
  "#{prefix}#{name}"
@@ -267,10 +331,8 @@ module Reek
267
331
  ReferenceCollector.new(self).num_refs_to_self > 0
268
332
  end
269
333
 
270
- def singleton_method?
271
- # This catches the case where methods are defined within the "class << self" syntax.
272
- parent.type == :sclass if parent
273
- end
334
+ include MethodNodeBase
335
+ include SingletonMethod
274
336
  end
275
337
 
276
338
  # Utility methods for :defs nodes.
@@ -1,8 +1,6 @@
1
1
  require 'forwardable'
2
2
  require_relative 'input'
3
- require_relative '../report/report'
4
- require_relative '../report/formatter'
5
- require_relative '../report/heading_formatter'
3
+ require_relative '../report'
6
4
 
7
5
  module Reek
8
6
  module CLI
@@ -31,48 +29,24 @@ module Reek
31
29
  heading_formatter: heading_formatter)
32
30
  end
33
31
 
34
- # TODO: Move report type mapping into Report
35
32
  def report_class
36
- case @options.report_format
37
- when :yaml
38
- Report::YAMLReport
39
- when :json
40
- Report::JSONReport
41
- when :html
42
- Report::HTMLReport
43
- when :xml
44
- Report::XMLReport
45
- else # :text
46
- Report::TextReport
47
- end
33
+ Report.report_class(@options.report_format)
48
34
  end
49
35
 
50
36
  def warning_formatter
51
- klass = if @options.show_links
52
- Report::WikiLinkWarningFormatter
53
- else
54
- Report::SimpleWarningFormatter
55
- end
56
- klass.new(location_formatter)
37
+ warning_formatter_class.new(location_formatter)
38
+ end
39
+
40
+ def warning_formatter_class
41
+ Report.warning_formatter_class(@options.show_links ? :wiki_links : :simple)
57
42
  end
58
43
 
59
44
  def location_formatter
60
- case @options.location_format
61
- when :single_line
62
- Report::SingleLineLocationFormatter
63
- when :plain
64
- Report::BlankLocationFormatter
65
- else # :numbers
66
- Report::DefaultLocationFormatter
67
- end
45
+ Report.location_formatter(@options.location_format)
68
46
  end
69
47
 
70
48
  def heading_formatter
71
- if @options.show_empty
72
- Report::HeadingFormatter::Verbose
73
- else
74
- Report::HeadingFormatter::Quiet
75
- end
49
+ Report.heading_formatter(@options.show_empty ? :verbose : :quiet)
76
50
  end
77
51
 
78
52
  def sort_by_issue_count
@@ -15,7 +15,9 @@ module Reek
15
15
  def initialize(argv = [])
16
16
  @argv = argv
17
17
  @parser = OptionParser.new
18
- @options = OpenStruct.new(colored: color_support?,
18
+ @options = OpenStruct.new(report_format: :text,
19
+ location_format: :numbers,
20
+ colored: color_support?,
19
21
  smells_to_detect: [])
20
22
  set_up_parser
21
23
  end
@@ -43,11 +43,11 @@ module Reek
43
43
  receiver ||= [:self]
44
44
  case receiver[0]
45
45
  when :lvasgn
46
- @refs.record_reference_to(receiver.name)
46
+ @refs.record_reference_to(receiver.name, line: exp.line)
47
47
  when :lvar
48
- @refs.record_reference_to(receiver.name) unless meth == :new
48
+ @refs.record_reference_to(receiver.name, line: exp.line) unless meth == :new
49
49
  when :self
50
- @refs.record_reference_to(:self)
50
+ @refs.record_reference_to(:self, line: exp.line)
51
51
  end
52
52
  end
53
53
 
@@ -56,8 +56,8 @@ module Reek
56
56
  end
57
57
 
58
58
  def envious_receivers
59
- return [] if @refs.self_is_max?
60
- @refs.max_keys
59
+ return {} if @refs.self_is_max?
60
+ @refs.most_popular
61
61
  end
62
62
 
63
63
  def references_self?
@@ -20,6 +20,17 @@ module Reek
20
20
  def descriptively_commented?
21
21
  CodeComment.new(exp.leading_comment).descriptive?
22
22
  end
23
+
24
+ # A namespace module is a module (or class) that is only there for namespacing
25
+ # purposes, and thus contains only nested constants, modules or classes.
26
+ #
27
+ # However, if the module is empty, it is not considered a namespace module.
28
+ #
29
+ # @return true if the module is a namespace module
30
+ def namespace_module?
31
+ contents = exp.children.last
32
+ contents && contents.find_nodes([:def, :defs], [:class, :module]).empty?
33
+ end
23
34
  end
24
35
  end
25
36
  end
@@ -8,7 +8,7 @@ module Reek
8
8
  # @api private
9
9
  class SingletonMethodContext < MethodContext
10
10
  def envious_receivers
11
- []
11
+ {}
12
12
  end
13
13
  end
14
14
  end
@@ -0,0 +1,71 @@
1
+ require_relative 'report/report'
2
+ require_relative 'report/formatter'
3
+ require_relative 'report/heading_formatter'
4
+
5
+ module Reek
6
+ # Reek reporting functionality.
7
+ module Report
8
+ module_function
9
+
10
+ # @api private
11
+ REPORT_CLASSES = {
12
+ yaml: YAMLReport,
13
+ json: JSONReport,
14
+ html: HTMLReport,
15
+ xml: XMLReport,
16
+ text: TextReport
17
+ }
18
+
19
+ # @api private
20
+ LOCATION_FORMATTERS = {
21
+ single_line: SingleLineLocationFormatter,
22
+ plain: BlankLocationFormatter,
23
+ numbers: DefaultLocationFormatter
24
+ }
25
+
26
+ # @api private
27
+ HEADING_FORMATTERS = {
28
+ verbose: HeadingFormatter::Verbose,
29
+ quiet: HeadingFormatter::Quiet }
30
+
31
+ # @api private
32
+ WARNING_FORMATTER_CLASSES = {
33
+ wiki_links: WikiLinkWarningFormatter,
34
+ simple: SimpleWarningFormatter
35
+ }
36
+
37
+ # Map report format symbol to a report class.
38
+ #
39
+ # @param [Symbol] report_format The format to map
40
+ #
41
+ # @return The mapped report class
42
+ #
43
+ # @api private
44
+ def report_class(report_format)
45
+ REPORT_CLASSES.fetch(report_format) do
46
+ raise "Unknown report format: #{report_format}"
47
+ end
48
+ end
49
+
50
+ # @api private
51
+ def location_formatter(location_format)
52
+ LOCATION_FORMATTERS.fetch(location_format) do
53
+ raise "Unknown location format: #{location_format}"
54
+ end
55
+ end
56
+
57
+ # @api private
58
+ def heading_formatter(heading_format)
59
+ HEADING_FORMATTERS.fetch(heading_format) do
60
+ raise "Unknown heading format: #{heading_format}"
61
+ end
62
+ end
63
+
64
+ # @api private
65
+ def warning_formatter_class(warning_format)
66
+ WARNING_FORMATTER_CLASSES.fetch(warning_format) do
67
+ raise "Unknown warning format: #{warning_format}"
68
+ end
69
+ end
70
+ end
71
+ end
@@ -51,11 +51,11 @@ module Reek
51
51
  #
52
52
  # @api private
53
53
  class WikiLinkWarningFormatter < SimpleWarningFormatter
54
- BASE_URL_FOR_HELP_LINK = 'https://github.com/troessner/reek/wiki/'
54
+ BASE_URL_FOR_HELP_LINK = 'https://github.com/troessner/reek/blob/master/docs/'
55
55
 
56
56
  def format(warning)
57
57
  "#{super} " \
58
- "[#{explanatory_link(warning)}]"
58
+ "[#{explanatory_link(warning)}.md]"
59
59
  end
60
60
 
61
61
  def explanatory_link(warning)
@@ -14,6 +14,10 @@ module Reek
14
14
  @report_formatter = report_formatter
15
15
  end
16
16
 
17
+ def show_header?(_examiner)
18
+ raise NotImplementedError
19
+ end
20
+
17
21
  def header(examiner)
18
22
  if show_header?(examiner)
19
23
  report_formatter.header examiner
@@ -129,13 +129,10 @@ module Reek
129
129
  class HTMLReport < Base
130
130
  require 'erb'
131
131
 
132
- def show
133
- path = File.expand_path('../../../../assets/html_output.html.erb',
134
- __FILE__)
135
- File.open('reek.html', 'w+') do |file|
136
- file.puts ERB.new(File.read(path)).result(binding)
137
- end
138
- print("Html file saved\n")
132
+ def show(target_path = 'reek.html')
133
+ template_path = File.expand_path('../html_report.html.erb', __FILE__)
134
+ File.write target_path, ERB.new(File.read(template_path)).result(binding)
135
+ puts 'HTML file saved'
139
136
  end
140
137
  end
141
138
 
@@ -48,13 +48,12 @@ module Reek
48
48
  #
49
49
  def examine_context(method_ctx)
50
50
  return [] unless method_ctx.references_self?
51
- method_ctx.envious_receivers.map do |ref, occurs|
52
- target = ref.to_s
51
+ method_ctx.envious_receivers.map do |name, refs|
53
52
  SmellWarning.new self,
54
53
  context: method_ctx.full_name,
55
- lines: [method_ctx.exp.line],
56
- message: "refers to #{target} more than self",
57
- parameters: { name: target, count: occurs }
54
+ lines: refs.map(&:line),
55
+ message: "refers to #{name} more than self",
56
+ parameters: { name: name.to_s, count: refs.size }
58
57
  end
59
58
  end
60
59
  end
@@ -10,12 +10,8 @@ module Reek
10
10
  # See {file:docs/Irresponsible-Module.md} for details.
11
11
  # @api private
12
12
  class IrresponsibleModule < SmellDetector
13
- def self.contexts # :nodoc:
14
- [:class]
15
- end
16
-
17
- def descriptive # :nodoc:
18
- @descriptive ||= {}
13
+ def self.contexts
14
+ [:class, :module]
19
15
  end
20
16
 
21
17
  #
@@ -24,13 +20,19 @@ module Reek
24
20
  # @return [Array<SmellWarning>]
25
21
  #
26
22
  def examine_context(ctx)
27
- return [] if descriptive?(ctx)
23
+ return [] if descriptive?(ctx) || ctx.namespace_module?
28
24
  expression = ctx.exp
29
25
  [SmellWarning.new(self,
30
26
  context: ctx.full_name,
31
27
  lines: [expression.line],
32
28
  message: 'has no descriptive comment',
33
- parameters: { name: expression.text_name })]
29
+ parameters: { name: expression.text_name })]
30
+ end
31
+
32
+ private
33
+
34
+ def descriptive
35
+ @descriptive ||= {}
34
36
  end
35
37
 
36
38
  def descriptive?(ctx)
@@ -3,6 +3,6 @@ module Reek
3
3
  # This module holds the Reek version informations
4
4
  #
5
5
  module Version
6
- STRING = '3.0.3'
6
+ STRING = '3.0.4'
7
7
  end
8
8
  end
@@ -27,12 +27,12 @@ Gem::Specification.new do |s|
27
27
  s.add_runtime_dependency 'unparser', '~> 0.2.2'
28
28
 
29
29
  s.add_development_dependency 'activesupport', '~> 4.2'
30
- s.add_development_dependency 'aruba', '~> 0.6.2'
30
+ s.add_development_dependency 'aruba', '~> 0.7.2'
31
31
  s.add_development_dependency 'ataru', '~> 0.2.0'
32
32
  s.add_development_dependency 'bundler', '~> 1.1'
33
33
  s.add_development_dependency 'cucumber', '~> 2.0'
34
34
  s.add_development_dependency 'factory_girl', '~> 4.0'
35
35
  s.add_development_dependency 'rake', '~> 10.0'
36
36
  s.add_development_dependency 'rspec', '~> 3.0'
37
- s.add_development_dependency 'rubocop', '~> 0.30.0'
37
+ s.add_development_dependency 'rubocop', '~> 0.32.1'
38
38
  end
@@ -8,24 +8,24 @@ RSpec.describe Reek::AST::ObjectRefs do
8
8
 
9
9
  context 'when empty' do
10
10
  it 'should report no refs to self' do
11
- expect(@refs.references_to(:self)).to eq(0)
11
+ expect(@refs.references_to(:self)).to be_empty
12
12
  end
13
13
  end
14
14
 
15
15
  context 'with references to a, b, and a' do
16
16
  context 'with no refs to self' do
17
17
  before(:each) do
18
- @refs.record_reference_to('a')
19
- @refs.record_reference_to('b')
20
- @refs.record_reference_to('a')
18
+ @refs.record_reference_to(:a)
19
+ @refs.record_reference_to(:b)
20
+ @refs.record_reference_to(:a)
21
21
  end
22
22
 
23
23
  it 'should report no refs to self' do
24
- expect(@refs.references_to(:self)).to eq(0)
24
+ expect(@refs.references_to(:self)).to be_empty
25
25
  end
26
26
 
27
27
  it 'should report :a as the max' do
28
- expect(@refs.max_keys).to eq('a' => 2)
28
+ expect(@refs.most_popular).to include(:a)
29
29
  end
30
30
 
31
31
  it 'should not report self as the max' do
@@ -38,12 +38,12 @@ RSpec.describe Reek::AST::ObjectRefs do
38
38
  end
39
39
 
40
40
  it 'should report 1 ref to self' do
41
- expect(@refs.references_to(:self)).to eq(1)
41
+ expect(@refs.references_to(:self).size).to eq(1)
42
42
  end
43
43
 
44
44
  it 'should not report self among the max' do
45
- expect(@refs.max_keys).to include('a')
46
- expect(@refs.max_keys).not_to include(:self)
45
+ expect(@refs.most_popular).to include(:a)
46
+ expect(@refs.most_popular).not_to include(:self)
47
47
  end
48
48
 
49
49
  it 'should not report self as the max' do
@@ -57,19 +57,19 @@ RSpec.describe Reek::AST::ObjectRefs do
57
57
  before(:each) do
58
58
  @refs.record_reference_to(:self)
59
59
  @refs.record_reference_to(:self)
60
- @refs.record_reference_to('a')
60
+ @refs.record_reference_to(:a)
61
61
  @refs.record_reference_to(:self)
62
- @refs.record_reference_to('b')
63
- @refs.record_reference_to('a')
62
+ @refs.record_reference_to(:b)
63
+ @refs.record_reference_to(:a)
64
64
  @refs.record_reference_to(:self)
65
65
  end
66
66
 
67
67
  it 'should report all refs to self' do
68
- expect(@refs.references_to(:self)).to eq(4)
68
+ expect(@refs.references_to(:self).size).to eq(4)
69
69
  end
70
70
 
71
71
  it 'should report self among the max' do
72
- expect(@refs.max_keys).to eq(self: 4)
72
+ expect(@refs.most_popular).to include(:self)
73
73
  end
74
74
 
75
75
  it 'should report self as the max' do
@@ -79,20 +79,20 @@ RSpec.describe Reek::AST::ObjectRefs do
79
79
 
80
80
  context 'when self is not the only max' do
81
81
  before(:each) do
82
- @refs.record_reference_to('a')
82
+ @refs.record_reference_to(:a)
83
83
  @refs.record_reference_to(:self)
84
84
  @refs.record_reference_to(:self)
85
- @refs.record_reference_to('b')
86
- @refs.record_reference_to('a')
85
+ @refs.record_reference_to(:b)
86
+ @refs.record_reference_to(:a)
87
87
  end
88
88
 
89
89
  it 'should report all refs to self' do
90
- expect(@refs.references_to(:self)).to eq(2)
90
+ expect(@refs.references_to(:self).size).to eq(2)
91
91
  end
92
92
 
93
93
  it 'should report self among the max' do
94
- expect(@refs.max_keys).to include('a')
95
- expect(@refs.max_keys).to include(:self)
94
+ expect(@refs.most_popular).to include(:a)
95
+ expect(@refs.most_popular).to include(:self)
96
96
  end
97
97
 
98
98
  it 'should report self as the max' do
@@ -102,19 +102,19 @@ RSpec.describe Reek::AST::ObjectRefs do
102
102
 
103
103
  context 'when self is not among the max' do
104
104
  before(:each) do
105
- @refs.record_reference_to('a')
106
- @refs.record_reference_to('b')
107
- @refs.record_reference_to('a')
108
- @refs.record_reference_to('b')
105
+ @refs.record_reference_to(:a)
106
+ @refs.record_reference_to(:b)
107
+ @refs.record_reference_to(:a)
108
+ @refs.record_reference_to(:b)
109
109
  end
110
110
 
111
111
  it 'should report all refs to self' do
112
- expect(@refs.references_to(:self)).to eq(0)
112
+ expect(@refs.references_to(:self).size).to eq(0)
113
113
  end
114
114
 
115
115
  it 'should not report self among the max' do
116
- expect(@refs.max_keys).to include('a')
117
- expect(@refs.max_keys).to include('b')
116
+ expect(@refs.most_popular).to include(:a)
117
+ expect(@refs.most_popular).to include(:b)
118
118
  end
119
119
 
120
120
  it 'should not report self as the max' do
@@ -4,12 +4,17 @@ require_relative '../../../lib/reek/cli/options'
4
4
  require_relative '../../../lib/reek/report/report'
5
5
 
6
6
  RSpec.describe Reek::CLI::OptionInterpreter do
7
- let(:options) { OpenStruct.new }
8
- let(:instance) { Reek::CLI::OptionInterpreter.new(options) }
9
-
10
7
  describe '#reporter' do
11
- it 'returns a Report::TextReport instance by default' do
12
- expect(instance.reporter).to be_instance_of Reek::Report::TextReport
8
+ let(:instance) { Reek::CLI::OptionInterpreter.new(options) }
9
+
10
+ context 'with a valid set of options' do
11
+ let(:options) do
12
+ OpenStruct.new(report_format: :text,
13
+ location_format: :plain)
14
+ end
15
+ it 'returns an object of the correct subclass of Report::Base' do
16
+ expect(instance.reporter).to be_instance_of Reek::Report::TextReport
17
+ end
13
18
  end
14
19
  end
15
20
  end
@@ -3,17 +3,26 @@ require_relative '../../spec_helper'
3
3
  require_relative '../../../lib/reek/cli/options'
4
4
 
5
5
  RSpec.describe Reek::CLI::Options do
6
- describe '#initialize' do
7
- it 'should enable colors when stdout is a TTY' do
8
- allow($stdout).to receive_messages(tty?: false)
9
- options = Reek::CLI::Options.new.parse
10
- expect(options.colored).to be false
11
- end
6
+ describe '#parse' do
7
+ context 'with no arguments passed' do
8
+ let(:options) { Reek::CLI::Options.new.parse }
9
+ it 'enables colors when stdout is a TTY' do
10
+ allow($stdout).to receive_messages(tty?: false)
11
+ expect(options.colored).to be false
12
+ end
13
+
14
+ it 'does not enable colors when stdout is not a TTY' do
15
+ allow($stdout).to receive_messages(tty?: true)
16
+ expect(options.colored).to be true
17
+ end
18
+
19
+ it 'sets a valid default value for report_format' do
20
+ expect(options.report_format).to eq :text
21
+ end
12
22
 
13
- it 'should not enable colors when stdout is not a TTY' do
14
- allow($stdout).to receive_messages(tty?: true)
15
- options = Reek::CLI::Options.new.parse
16
- expect(options.colored).to be true
23
+ it 'sets a valid default value for location_format' do
24
+ expect(options.location_format).to eq :numbers
25
+ end
17
26
  end
18
27
  end
19
28
  end
@@ -33,7 +33,7 @@ RSpec.describe Reek::Context::MethodContext do
33
33
  end
34
34
 
35
35
  it 'should ignore explicit calls to self' do
36
- mc.refs.record_reference_to [:lvar, :other]
36
+ mc.refs.record_reference_to :other
37
37
  mc.record_call_to s(:send, s(:self), :thing)
38
38
  expect(mc.envious_receivers).to be_empty
39
39
  end
@@ -46,7 +46,7 @@ RSpec.describe Reek::Context::MethodContext do
46
46
 
47
47
  it 'should record envious calls' do
48
48
  mc.record_call_to s(:send, s(:lvar, :bar), :baz)
49
- expect(mc.envious_receivers).to eq(bar: 1)
49
+ expect(mc.envious_receivers).to include(:bar)
50
50
  end
51
51
  end
52
52
  end
@@ -1,3 +1,4 @@
1
+ require 'tempfile'
1
2
  require_relative '../../spec_helper'
2
3
  require_relative '../../../lib/reek/examiner'
3
4
  require_relative '../../../lib/reek/report/report'
@@ -13,13 +14,10 @@ RSpec.describe Reek::Report::HTMLReport do
13
14
  end
14
15
 
15
16
  it 'has the text 0 total warnings' do
16
- instance.show
17
-
18
- file = File.expand_path('../../../../reek.html', __FILE__)
19
- text = File.read(file)
20
- File.delete(file)
21
-
22
- expect(text).to include('0 total warnings')
17
+ tempfile = Tempfile.new(['Reek::Report::HTMLReport.', '.html'])
18
+ response = "HTML file saved\n"
19
+ expect { instance.show tempfile.path }.to output(response).to_stdout
20
+ expect(tempfile.read).to include('0 total warnings')
23
21
  end
24
22
  end
25
23
  end
@@ -260,7 +260,6 @@ RSpec.describe Reek::Smells::FeatureEnvy do
260
260
  end
261
261
 
262
262
  it 'reports the referring lines' do
263
- skip
264
263
  expect(@smells[0].lines).to eq([2, 4, 5])
265
264
  end
266
265
  end
@@ -4,6 +4,16 @@ require_relative '../../../lib/reek/smells/irresponsible_module'
4
4
  require_relative 'smell_detector_shared'
5
5
 
6
6
  RSpec.describe Reek::Smells::IrresponsibleModule do
7
+ it 'reports a class without a comment' do
8
+ src = 'class BadClass; end'
9
+ expect(src).to reek_of :IrresponsibleModule, name: 'BadClass'
10
+ end
11
+
12
+ it 'reports a module without a comment' do
13
+ src = 'module BadClass; end'
14
+ expect(src).to reek_of :IrresponsibleModule, name: 'BadClass'
15
+ end
16
+
7
17
  it 'does not report re-opened modules' do
8
18
  src = <<-EOS
9
19
  # Abstract base class
@@ -22,11 +32,6 @@ RSpec.describe Reek::Smells::IrresponsibleModule do
22
32
  expect(src).not_to reek_of(:IrresponsibleModule)
23
33
  end
24
34
 
25
- it 'reports a class without a comment' do
26
- src = 'class BadClass; end'
27
- expect(src).to reek_of :IrresponsibleModule, name: 'BadClass'
28
- end
29
-
30
35
  it 'reports a class with an empty comment' do
31
36
  src = <<-EOS
32
37
  #
@@ -61,6 +66,80 @@ RSpec.describe Reek::Smells::IrresponsibleModule do
61
66
  expect(src).to reek_of :IrresponsibleModule, name: 'Foo::Bar'
62
67
  end
63
68
 
69
+ it 'does not report modules used only as namespaces' do
70
+ src = <<-EOS
71
+ module Foo
72
+ # Describes Bar
73
+ class Bar
74
+ def baz
75
+ end
76
+ end
77
+ end
78
+ EOS
79
+ expect(src).not_to reek_of(:IrresponsibleModule)
80
+ end
81
+
82
+ it 'does not report classes used only as namespaces' do
83
+ src = <<-EOS
84
+ class Foo
85
+ # Describes Bar
86
+ module Bar
87
+ def qux
88
+ end
89
+ end
90
+ end
91
+ EOS
92
+ expect(src).not_to reek_of(:IrresponsibleModule)
93
+ end
94
+
95
+ it 'reports modules that have both nested modules and methods' do
96
+ src = <<-EOS
97
+ module Foo
98
+ def foofoo
99
+ end
100
+ # Describes Bar
101
+ module Bar
102
+ end
103
+ end
104
+ EOS
105
+ expect(src).to reek_of(:IrresponsibleModule)
106
+ end
107
+
108
+ it 'reports modules that have both nested modules and singleton methods' do
109
+ src = <<-EOS
110
+ module Foo
111
+ def self.foofoo
112
+ end
113
+ # Describes Bar
114
+ module Bar
115
+ end
116
+ end
117
+ EOS
118
+ expect(src).to reek_of(:IrresponsibleModule)
119
+ end
120
+
121
+ it 'reports modules that have both nested modules and methods on the singleton class' do
122
+ src = <<-EOS
123
+ module Foo
124
+ class << self
125
+ def foofoo
126
+ end
127
+ end
128
+ # Describes Bar
129
+ module Bar
130
+ end
131
+ end
132
+ EOS
133
+ expect(src).to reek_of(:IrresponsibleModule)
134
+ end
135
+
136
+ it 'reports classes that have a defined superclass' do
137
+ src = <<-EOS
138
+ class Foo < Bar; end
139
+ EOS
140
+ expect(src).to reek_of(:IrresponsibleModule)
141
+ end
142
+
64
143
  context 'when a smell is reported' do
65
144
  before do
66
145
  @source_name = 'dummy_source'
@@ -62,6 +62,24 @@ RSpec.describe Reek::Smells::UtilityFunction do
62
62
  src = 'module M; def self.simple(a) a.to_s; end; end'
63
63
  expect(src).not_to reek_of(:UtilityFunction)
64
64
  end
65
+
66
+ context 'by using `module_function`' do
67
+ it 'should not report UtilityFunction' do
68
+ src = 'class C; def m(a) a.to_s; end; module_function :m; end'
69
+ expect(src).not_to reek_of(:UtilityFunction)
70
+ end
71
+
72
+ it 'should not report UtilityFunction also when using multiple arguments' do
73
+ src = <<-EOS
74
+ class C
75
+ def m1(a) a.to_s; end
76
+ def m2(a) a.to_s; end
77
+ module_function :m1, m2
78
+ end
79
+ EOS
80
+ expect(src).not_to reek_of(:UtilityFunction)
81
+ end
82
+ end
65
83
  end
66
84
 
67
85
  context 'with no calls' do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: reek
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.3
4
+ version: 3.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Rutherford
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-07-04 00:00:00.000000000 Z
13
+ date: 2015-07-10 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: parser
@@ -74,14 +74,14 @@ dependencies:
74
74
  requirements:
75
75
  - - "~>"
76
76
  - !ruby/object:Gem::Version
77
- version: 0.6.2
77
+ version: 0.7.2
78
78
  type: :development
79
79
  prerelease: false
80
80
  version_requirements: !ruby/object:Gem::Requirement
81
81
  requirements:
82
82
  - - "~>"
83
83
  - !ruby/object:Gem::Version
84
- version: 0.6.2
84
+ version: 0.7.2
85
85
  - !ruby/object:Gem::Dependency
86
86
  name: ataru
87
87
  requirement: !ruby/object:Gem::Requirement
@@ -172,14 +172,14 @@ dependencies:
172
172
  requirements:
173
173
  - - "~>"
174
174
  - !ruby/object:Gem::Version
175
- version: 0.30.0
175
+ version: 0.32.1
176
176
  type: :development
177
177
  prerelease: false
178
178
  version_requirements: !ruby/object:Gem::Requirement
179
179
  requirements:
180
180
  - - "~>"
181
181
  - !ruby/object:Gem::Version
182
- version: 0.30.0
182
+ version: 0.32.1
183
183
  description: |2
184
184
  Reek is a tool that examines Ruby classes, modules and methods and reports
185
185
  any code smells it finds.
@@ -202,7 +202,6 @@ files:
202
202
  - License.txt
203
203
  - README.md
204
204
  - Rakefile
205
- - assets/html_output.html.erb
206
205
  - bin/reek
207
206
  - config/cucumber.yml
208
207
  - config/defaults.reek
@@ -290,8 +289,10 @@ files:
290
289
  - lib/reek/context/singleton_method_context.rb
291
290
  - lib/reek/examiner.rb
292
291
  - lib/reek/rake/task.rb
292
+ - lib/reek/report.rb
293
293
  - lib/reek/report/formatter.rb
294
294
  - lib/reek/report/heading_formatter.rb
295
+ - lib/reek/report/html_report.html.erb
295
296
  - lib/reek/report/location_formatter.rb
296
297
  - lib/reek/report/report.rb
297
298
  - lib/reek/smells.rb