kevinrutherford-reek 0.3.1.4

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 (70) hide show
  1. data/History.txt +92 -0
  2. data/README.txt +6 -0
  3. data/Rakefile +7 -0
  4. data/bin/reek +19 -0
  5. data/lib/reek/block_context.rb +37 -0
  6. data/lib/reek/class_context.rb +73 -0
  7. data/lib/reek/code_context.rb +47 -0
  8. data/lib/reek/code_parser.rb +204 -0
  9. data/lib/reek/exceptions.reek +13 -0
  10. data/lib/reek/if_context.rb +25 -0
  11. data/lib/reek/method_context.rb +85 -0
  12. data/lib/reek/module_context.rb +34 -0
  13. data/lib/reek/name.rb +42 -0
  14. data/lib/reek/object_refs.rb +53 -0
  15. data/lib/reek/options.rb +92 -0
  16. data/lib/reek/rake_task.rb +121 -0
  17. data/lib/reek/report.rb +42 -0
  18. data/lib/reek/sexp_formatter.rb +52 -0
  19. data/lib/reek/singleton_method_context.rb +27 -0
  20. data/lib/reek/smell_warning.rb +49 -0
  21. data/lib/reek/smells/control_couple.rb +61 -0
  22. data/lib/reek/smells/duplication.rb +50 -0
  23. data/lib/reek/smells/feature_envy.rb +58 -0
  24. data/lib/reek/smells/large_class.rb +50 -0
  25. data/lib/reek/smells/long_method.rb +43 -0
  26. data/lib/reek/smells/long_parameter_list.rb +43 -0
  27. data/lib/reek/smells/long_yield_list.rb +18 -0
  28. data/lib/reek/smells/nested_iterators.rb +28 -0
  29. data/lib/reek/smells/smell_detector.rb +66 -0
  30. data/lib/reek/smells/smells.rb +85 -0
  31. data/lib/reek/smells/uncommunicative_name.rb +80 -0
  32. data/lib/reek/smells/utility_function.rb +34 -0
  33. data/lib/reek/source.rb +116 -0
  34. data/lib/reek/spec.rb +130 -0
  35. data/lib/reek/stop_context.rb +62 -0
  36. data/lib/reek/yield_call_context.rb +14 -0
  37. data/lib/reek.rb +8 -0
  38. data/spec/integration/reek_source_spec.rb +20 -0
  39. data/spec/integration/script_spec.rb +55 -0
  40. data/spec/reek/class_context_spec.rb +198 -0
  41. data/spec/reek/code_context_spec.rb +92 -0
  42. data/spec/reek/code_parser_spec.rb +44 -0
  43. data/spec/reek/config_spec.rb +42 -0
  44. data/spec/reek/module_context_spec.rb +38 -0
  45. data/spec/reek/object_refs_spec.rb +129 -0
  46. data/spec/reek/options_spec.rb +13 -0
  47. data/spec/reek/report_spec.rb +48 -0
  48. data/spec/reek/sexp_formatter_spec.rb +31 -0
  49. data/spec/reek/singleton_method_context_spec.rb +17 -0
  50. data/spec/reek/smells/control_couple_spec.rb +23 -0
  51. data/spec/reek/smells/duplication_spec.rb +81 -0
  52. data/spec/reek/smells/feature_envy_spec.rb +129 -0
  53. data/spec/reek/smells/large_class_spec.rb +86 -0
  54. data/spec/reek/smells/long_method_spec.rb +59 -0
  55. data/spec/reek/smells/long_parameter_list_spec.rb +92 -0
  56. data/spec/reek/smells/nested_iterators_spec.rb +33 -0
  57. data/spec/reek/smells/smell_spec.rb +24 -0
  58. data/spec/reek/smells/uncommunicative_name_spec.rb +118 -0
  59. data/spec/reek/smells/utility_function_spec.rb +96 -0
  60. data/spec/samples/inline.rb +704 -0
  61. data/spec/samples/inline_spec.rb +40 -0
  62. data/spec/samples/optparse.rb +1788 -0
  63. data/spec/samples/optparse_spec.rb +100 -0
  64. data/spec/samples/redcloth.rb +1130 -0
  65. data/spec/samples/redcloth_spec.rb +93 -0
  66. data/spec/spec.opts +1 -0
  67. data/spec/spec_helper.rb +15 -0
  68. data/tasks/reek.rake +20 -0
  69. data/tasks/rspec.rake +22 -0
  70. metadata +167 -0
@@ -0,0 +1,43 @@
1
+ require 'reek/smells/smell_detector'
2
+ require 'reek/smell_warning'
3
+
4
+ module Reek
5
+ module Smells
6
+
7
+ #
8
+ # A Long Parameter List occurs when a method has more than one
9
+ # or two parameters, or when a method yields more than one or
10
+ # two objects to an associated block.
11
+ #
12
+ # Currently +LongParameterList+ reports any method or block with too
13
+ # many parameters.
14
+ #
15
+ class LongParameterList < SmellDetector
16
+
17
+ # The name of the config field that sets the maximum number of
18
+ # parameters permitted in any method or block.
19
+ MAX_ALLOWED_PARAMS_KEY = 'max_params'
20
+
21
+ def self.default_config
22
+ super.adopt(MAX_ALLOWED_PARAMS_KEY => 3)
23
+ end
24
+
25
+ def initialize(config)
26
+ super
27
+ @max_params = config['max_params']
28
+ @action = 'has'
29
+ end
30
+
31
+ #
32
+ # Checks the number of parameters in the given scope.
33
+ # Any smells found are added to the +report+.
34
+ #
35
+ def examine_context(ctx, report)
36
+ num_params = ctx.parameters.length
37
+ return false if num_params <= @max_params
38
+ report << SmellWarning.new(self, ctx,
39
+ "#{@action} #{num_params} parameters")
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,18 @@
1
+ require 'reek/smells/smell_detector'
2
+
3
+ module Reek
4
+ module Smells
5
+
6
+ class LongYieldList < LongParameterList
7
+
8
+ def self.contexts # :nodoc:
9
+ [:yield]
10
+ end
11
+
12
+ def initialize(config)
13
+ super
14
+ @action = 'yields'
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,28 @@
1
+ require 'reek/smells/smell_detector'
2
+ require 'reek/smell_warning'
3
+
4
+ module Reek
5
+ module Smells
6
+
7
+ #
8
+ # A Nested Iterator occurs when a block contains another block.
9
+ #
10
+ # +NestedIterators+ reports failing methods only once.
11
+ #
12
+ class NestedIterators < SmellDetector
13
+
14
+ def self.contexts # :nodoc:
15
+ [:iter]
16
+ end
17
+
18
+ #
19
+ # Checks whether the given +block+ is inside another.
20
+ # Any smells found are added to the +report+.
21
+ #
22
+ def examine_context(block, report)
23
+ return false unless block.nested_block?
24
+ report << SmellWarning.new(self, block, 'is nested')
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,66 @@
1
+ class Class
2
+ def name_words
3
+ class_name = name.split(/::/)[-1]
4
+ class_name.gsub(/([a-z])([A-Z])/) { |sub| "#{$1} #{$2}"}.split
5
+ end
6
+ end
7
+
8
+ module Reek
9
+ module Smells
10
+
11
+ class SmellDetector
12
+
13
+ # The name of the config field that lists the names of code contexts
14
+ # that should not be checked. Add this field to the config for each
15
+ # smell that should ignore this code element.
16
+ EXCLUDE_KEY = 'exclude'
17
+
18
+ # The name fo the config field that specifies whether a smell is
19
+ # enabled. Set to +true+ or +false+.
20
+ ENABLED_KEY = 'enabled'
21
+
22
+ def self.class_name
23
+ self.name.split(/::/)[-1]
24
+ end
25
+
26
+ def self.contexts # :nodoc:
27
+ [:defn, :defs]
28
+ end
29
+
30
+ def self.default_config
31
+ {
32
+ ENABLED_KEY => true,
33
+ EXCLUDE_KEY => []
34
+ }
35
+ end
36
+
37
+ def self.listen(hooks, config)
38
+ detector = new(config[class_name])
39
+ contexts.each { |ctx| hooks[ctx] << detector }
40
+ end
41
+
42
+ def initialize(config)
43
+ @enabled = config[ENABLED_KEY]
44
+ @exceptions = config[EXCLUDE_KEY]
45
+ end
46
+
47
+ def examine(context, report)
48
+ before = report.size
49
+ examine_context(context, report) if @enabled and !exception?(context)
50
+ report.length > before
51
+ end
52
+
53
+ def examine_context(context, report)
54
+ end
55
+
56
+ def exception?(context)
57
+ return false if @exceptions.nil? or @exceptions.length == 0
58
+ context.matches?(@exceptions)
59
+ end
60
+
61
+ def smell_name
62
+ self.class.name_words.join(' ')
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,85 @@
1
+ require 'reek/smells/control_couple'
2
+ require 'reek/smells/duplication'
3
+ require 'reek/smells/feature_envy'
4
+ require 'reek/smells/large_class'
5
+ require 'reek/smells/long_method'
6
+ require 'reek/smells/long_parameter_list'
7
+ require 'reek/smells/long_yield_list'
8
+ require 'reek/smells/nested_iterators'
9
+ require 'reek/smells/uncommunicative_name'
10
+ require 'reek/smells/utility_function'
11
+ require 'yaml'
12
+
13
+ class Hash
14
+ def value_merge!(other)
15
+ other.keys.each do |key|
16
+ self[key].adopt!(other[key])
17
+ end
18
+ self
19
+ end
20
+
21
+ def adopt!(other)
22
+ other.keys.each do |key|
23
+ ov = other[key]
24
+ if Array === ov and has_key?(key)
25
+ self[key] += ov
26
+ else
27
+ self[key] = ov
28
+ end
29
+ end
30
+ self
31
+ end
32
+
33
+ def adopt(other)
34
+ self.deep_copy.adopt!(other)
35
+ end
36
+
37
+ def deep_copy
38
+ YAML::load(YAML::dump(self))
39
+ end
40
+ end
41
+
42
+ module Reek
43
+ class SmellConfig
44
+
45
+ SMELL_CLASSES = [
46
+ Smells::ControlCouple,
47
+ Smells::Duplication,
48
+ Smells::FeatureEnvy,
49
+ Smells::LargeClass,
50
+ Smells::LongMethod,
51
+ Smells::LongParameterList,
52
+ Smells::LongYieldList,
53
+ Smells::NestedIterators,
54
+ Smells::UncommunicativeName,
55
+ Smells::UtilityFunction,
56
+ ]
57
+
58
+ def initialize
59
+ defaults_file = File.join(File.dirname(__FILE__), '..', '..', '..', 'config', 'defaults.reek')
60
+ @config = YAML.load_file(defaults_file)
61
+ end
62
+
63
+ def smell_listeners()
64
+ result = Hash.new {|hash,key| hash[key] = [] }
65
+ SMELL_CLASSES.each { |smell| smell.listen(result, @config) }
66
+ return result
67
+ end
68
+
69
+ def load_local(file)
70
+ path = File.expand_path(file)
71
+ all_reekfiles(path).each do |rfile|
72
+ cf = YAML.load_file(rfile)
73
+ @config.value_merge!(cf)
74
+ end
75
+ self
76
+ end
77
+
78
+ def all_reekfiles(path)
79
+ return [] unless File.exist?(path)
80
+ parent = File.dirname(path)
81
+ return [] if path == parent
82
+ all_reekfiles(parent) + Dir["#{path}/*.reek"]
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,80 @@
1
+ require 'reek/smells/smell_detector'
2
+ require 'reek/smell_warning'
3
+
4
+ module Reek
5
+ module Smells
6
+
7
+ #
8
+ # An Uncommunicative Name is a name that doesn't communicate its intent
9
+ # well enough.
10
+ #
11
+ # Poor names make it hard for the reader to build a mental picture
12
+ # of what's going on in the code. They can also be mis-interpreted;
13
+ # and they hurt the flow of reading, because the reader must slow
14
+ # down to interpret the names.
15
+ #
16
+ # Currently +UncommunicativeName+ checks for
17
+ # * 1-character names
18
+ # * names consisting of a single character followed by a number
19
+ #
20
+ class UncommunicativeName < SmellDetector
21
+
22
+ # The name of the config field that lists the regexps of
23
+ # smelly names to be rejected.
24
+ REJECT_KEY = 'reject'
25
+
26
+ # The name of the config field that lists the specific names that are
27
+ # to be treated as exceptions; these names will not be reported as
28
+ # uncommunicative.
29
+ ACCEPT_KEY = 'accept'
30
+
31
+ def self.default_config
32
+ super.adopt(
33
+ REJECT_KEY => [/^.[0-9]*$/],
34
+ ACCEPT_KEY => ['Inline::C']
35
+ )
36
+ end
37
+
38
+ def self.contexts # :nodoc:
39
+ [:module, :class, :defn, :defs, :iter]
40
+ end
41
+
42
+ def initialize(config = UncommunicativeName.default_config)
43
+ super
44
+ @reject = config[REJECT_KEY]
45
+ @accept = config[ACCEPT_KEY]
46
+ end
47
+
48
+ #
49
+ # Checks the given +context+ for uncommunicative names.
50
+ # Any smells found are added to the +report+.
51
+ #
52
+ def examine_context(context, report)
53
+ consider_name(context, report)
54
+ consider_variables(context, report)
55
+ end
56
+
57
+ def consider_variables(context, report) # :nodoc:
58
+ context.variable_names.each do |name|
59
+ next unless is_bad_name?(name)
60
+ report << SmellWarning.new(self, context,
61
+ "has the variable name '#{name}'")
62
+ end
63
+ end
64
+
65
+ def consider_name(context, report) # :nodoc:
66
+ name = context.name
67
+ return false if @accept.include?(context.to_s) # TODO: fq_name() ?
68
+ return false unless is_bad_name?(name)
69
+ report << SmellWarning.new(self, context,
70
+ "has the name '#{name}'")
71
+ end
72
+
73
+ def is_bad_name?(name) # :nodoc:
74
+ var = name.effective_name
75
+ return false if var == '*' or @accept.include?(var)
76
+ @reject.detect {|patt| patt === var}
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,34 @@
1
+ require 'reek/smells/smell_detector'
2
+ require 'reek/smell_warning'
3
+
4
+ module Reek
5
+ module Smells
6
+
7
+ #
8
+ # A Utility Function is any instance method that has no
9
+ # dependency on the state of the instance.
10
+ #
11
+ # Currently +UtilityFunction+ will warn about any method that:
12
+ #
13
+ # * is non-empty
14
+ # * does not override an inherited method
15
+ # * calls at least one method on another object
16
+ # * doesn't use any of self's instance variables
17
+ # * doesn't use any of self's methods
18
+ #
19
+ class UtilityFunction < SmellDetector
20
+
21
+ #
22
+ # Checks whether the given +method+ is a utility function.
23
+ # Any smells found are added to the +report+.
24
+ #
25
+ def examine_context(method, report)
26
+ return false if method.calls.keys.length == 0 or
27
+ method.num_statements == 0 or
28
+ method.depends_on_instance?
29
+ report << SmellWarning.new(self, method,
30
+ "doesn't depend on instance state")
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,116 @@
1
+ require 'reek/code_parser'
2
+ require 'reek/report'
3
+ require 'reek/smells/smells'
4
+
5
+ module Reek
6
+
7
+ #
8
+ # A +Source+ object represents a chunk of Ruby source code.
9
+ #
10
+ # The various class methods are factories that will create +Source+
11
+ # instances from various types of input.
12
+ #
13
+ class Source
14
+
15
+ #
16
+ # Factory method: creates a +Source+ object by reading Ruby code from
17
+ # the +IO+ stream. The stream is consumed upto end-of-file, but the
18
+ # source code is not parsed until +report+ is called. +desc+ provides
19
+ # a string description to be used in the header of formatted reports.
20
+ #
21
+ def self.from_io(ios, desc)
22
+ code = ios.readlines.join
23
+ return new(code, desc)
24
+ end
25
+
26
+ #
27
+ # Factory method: creates a +Source+ object by reading Ruby code from
28
+ # the +code+ string. The code is not parsed until +report+ is called.
29
+ #
30
+ def self.from_s(code)
31
+ return new(code, 'string')
32
+ end
33
+
34
+ #
35
+ # Factory method: creates a +Source+ object by reading Ruby code from
36
+ # File +file+. The source code is not parsed until +report+ is called.
37
+ #
38
+ def self.from_f(file)
39
+ from_path(file.path)
40
+ end
41
+
42
+ #
43
+ # Factory method: creates a +Source+ object by reading Ruby code from
44
+ # the named file. The source code is not parsed until +report+ is called.
45
+ #
46
+ def self.from_path(filename)
47
+ code = IO.readlines(filename).join
48
+ return new(code, filename, File.dirname(filename))
49
+ end
50
+
51
+ #
52
+ # Factory method: creates a +Source+ object from an array of file paths.
53
+ # No source code is actually parsed until the report is accessed.
54
+ #
55
+ def self.from_pathlist(paths)
56
+ sources = paths.map {|path| Source.from_path(path) }
57
+ SourceList.new(sources)
58
+ end
59
+
60
+ def initialize(code, desc, dir = '.') # :nodoc:
61
+ @source = code
62
+ @dir = dir
63
+ @desc = desc
64
+ end
65
+
66
+ #
67
+ # Returns a +Report+ listing the smells found in this source. The first
68
+ # call to +report+ parses the source code and constructs a list of
69
+ # +SmellWarning+s found; subsequent calls simply return this same list.
70
+ #
71
+ def report
72
+ unless @report
73
+ @report = Report.new
74
+ smells = SmellConfig.new.load_local(@dir).smell_listeners
75
+ CodeParser.new(@report, smells).check_source(@source)
76
+ end
77
+ @report
78
+ end
79
+
80
+ def smelly?
81
+ report.length > 0
82
+ end
83
+
84
+ #
85
+ # Checks this source for instances of +smell_class+, and returns +true+
86
+ # only if one of them has a report string matching all of the +patterns+.
87
+ #
88
+ def has_smell?(smell_class, patterns)
89
+ report.any? { |smell| smell.matches?(smell_class, patterns) }
90
+ end
91
+
92
+ def to_s
93
+ @desc
94
+ end
95
+ end
96
+
97
+ #
98
+ # Represents a list of Sources as if they were a single source.
99
+ #
100
+ class SourceList
101
+ def initialize(sources)
102
+ @sources = sources
103
+ end
104
+
105
+ def smelly?
106
+ @sources.any? {|source| source.smelly? }
107
+ end
108
+
109
+ def report
110
+ @sources.select {|src| src.smelly? }.map do |src|
111
+ warnings = src.report
112
+ "\"#{src}\" -- #{warnings.length} warnings:\n#{warnings.to_s}\n"
113
+ end.join("\n")
114
+ end
115
+ end
116
+ end
data/lib/reek/spec.rb ADDED
@@ -0,0 +1,130 @@
1
+ require 'reek/source'
2
+
3
+ module Reek
4
+
5
+ #
6
+ # Provides matchers for Rspec, making it easy to check code quality.
7
+ #
8
+ # === Examples
9
+ #
10
+ # Here's a spec that ensures there are no smell warnings in the current project:
11
+ #
12
+ # describe 'source code quality' do
13
+ # Dir['lib/**/*.rb'].each do |path|
14
+ # it "reports no smells in #{path}" do
15
+ # File.new(path).should_not reek
16
+ # end
17
+ # end
18
+ # end
19
+ #
20
+ # Here's a simple check of a code fragment:
21
+ #
22
+ # 'def equals(other) other.thing == self.thing end'.should_not reek
23
+ #
24
+ # And a more complex example, making use of one of the factory methods for
25
+ # +Source+ so that the code is parsed and analysed only once:
26
+ #
27
+ # ruby = 'def double_thing() @other.thing.foo + @other.thing.foo end'.to_source
28
+ # ruby.should reek_of(:Duplication, /@other.thing[^\.]/)
29
+ # ruby.should reek_of(:Duplication, /@other.thing.foo/)
30
+ # ruby.should_not reek_of(:FeatureEnvy)
31
+ #
32
+ module Spec
33
+ class ShouldReek # :nodoc:
34
+ def matches?(actual)
35
+ @source = actual.to_source
36
+ @source.smelly?
37
+ end
38
+ def failure_message_for_should
39
+ "Expected source to reek, but it didn't"
40
+ end
41
+ def failure_message_for_should_not
42
+ "Expected no smells, but got:\n#{@source.report}"
43
+ end
44
+ end
45
+
46
+ #
47
+ # Returns +true+ if and only if the target source code contains smells.
48
+ #
49
+ def reek
50
+ ShouldReek.new
51
+ end
52
+
53
+ class ShouldReekOf # :nodoc:
54
+ def initialize(klass, patterns)
55
+ @klass = klass
56
+ @patterns = patterns
57
+ end
58
+ def matches?(actual)
59
+ @source = actual.to_source
60
+ @source.has_smell?(@klass, @patterns)
61
+ end
62
+ def failure_message_for_should
63
+ "Expected #{@source} to reek of #{@klass}, but it didn't"
64
+ end
65
+ def failure_message_for_should_not
66
+ "Expected #{@source} not to reek of #{@klass}, but got:\n#{@source.report}"
67
+ end
68
+ end
69
+
70
+ #
71
+ # Checks the target source code for instances of +smell_class+,
72
+ # and returns +true+ only if one of them has a report string matching
73
+ # all of the +patterns+.
74
+ #
75
+ def reek_of(smell_class, *patterns)
76
+ ShouldReekOf.new(smell_class, patterns)
77
+ end
78
+
79
+ class ShouldReekOnlyOf # :nodoc:
80
+ def initialize(klass, patterns)
81
+ @klass = klass
82
+ @patterns = patterns
83
+ end
84
+ def matches?(actual)
85
+ @source = actual.to_source
86
+ @source.report.length == 1 and @source.has_smell?(@klass, @patterns)
87
+ end
88
+ def failure_message_for_should
89
+ "Expected source to reek only of #{@klass}, but got:\n#{@source.report}"
90
+ end
91
+ def failure_message_for_should_not
92
+ "Expected source not to reek only of #{@klass}, but it did"
93
+ end
94
+ end
95
+
96
+ #
97
+ # As for reek_of, but the matched smell warning must be the only warning of
98
+ # any kind in the target source code's Reek report.
99
+ #
100
+ def reek_only_of(smell_class, *patterns)
101
+ ShouldReekOnlyOf.new(smell_class, patterns)
102
+ end
103
+ end
104
+ end
105
+
106
+ class File
107
+ def to_source
108
+ Reek::Source.from_f(self)
109
+ end
110
+ end
111
+
112
+ class String
113
+ def to_source
114
+ Reek::Source.from_s(self)
115
+ end
116
+ end
117
+
118
+ class Array
119
+ def to_source
120
+ Reek::Source.from_pathlist(self)
121
+ end
122
+ end
123
+
124
+ module Reek
125
+ class Source
126
+ def to_source
127
+ self
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,62 @@
1
+ module Reek
2
+ class StopContext
3
+
4
+ def initialize
5
+ @refs = ObjectRefs.new
6
+ @myself = Object
7
+ end
8
+
9
+ def count_statements(num)
10
+ 0
11
+ end
12
+
13
+ def find_module(name)
14
+ sym = name.to_s
15
+ @myself.const_defined?(sym) ? @myself.const_get(sym) : nil
16
+ end
17
+
18
+ def has_parameter(sym)
19
+ false
20
+ end
21
+
22
+ def inside_a_block?
23
+ false
24
+ end
25
+
26
+ def is_overriding_method?(name)
27
+ false
28
+ end
29
+
30
+ def num_statements
31
+ 0
32
+ end
33
+
34
+ def refs
35
+ @refs
36
+ end
37
+
38
+ def record_depends_on_self
39
+ false
40
+ end
41
+
42
+ def record_call_to(exp)
43
+ nil
44
+ end
45
+
46
+ def record_method(name)
47
+ end
48
+
49
+ def record_parameter(sym)
50
+ end
51
+
52
+ def record_instance_variable(sym)
53
+ end
54
+
55
+ def record_local_variable(sym)
56
+ end
57
+
58
+ def outer_name
59
+ ''
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,14 @@
1
+ require 'reek/code_context'
2
+
3
+ module Reek
4
+ class YieldCallContext < CodeContext
5
+ attr_reader :parameters
6
+
7
+ def initialize(outer, exp)
8
+ super
9
+ @parameters = []
10
+ args = exp[1]
11
+ @parameters = args[0...-1] if args
12
+ end
13
+ end
14
+ end
data/lib/reek.rb ADDED
@@ -0,0 +1,8 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'reek/report'
4
+ require 'reek/smells/smells'
5
+
6
+ module Reek # :doc:
7
+ VERSION = '0.3.1.4'
8
+ end