Skip to content

Commit

Permalink
Fixed :: name scoping for classes
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinrutherford committed Mar 17, 2009
1 parent 1c7b723 commit e476c5d
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 19 deletions.
14 changes: 10 additions & 4 deletions lib/reek/class_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@ def is_overriding_method?(sym)

module Reek
class ClassContext < CodeContext

def ClassContext.create(outer, exp)
res = Name.resolve(exp[1], outer)
ClassContext.new(res[0], res[1], exp[2])
end

attr_accessor :name

def initialize(outer, exp)
super
@name = Name.new(exp[1])
@superclass = exp[2]
def initialize(outer, name, superclass = nil)
super(outer, nil)
@name = name
@superclass = superclass
@parsed_methods = []
@instance_variables = []
end
Expand Down
6 changes: 4 additions & 2 deletions lib/reek/code_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,12 @@ def process_module(exp)
end

def process_class(exp)
@element = ClassContext.new(@element, exp)
orig = @element
@element = ClassContext.create(@element, exp)
exp[3..-1].each { |sub| process(sub) } unless @element.is_struct?
@smells[:class].each {|smell| smell.examine(@element, @report) }
pop(exp)
@element = orig
s(exp)
end

def process_defn(exp)
Expand Down
14 changes: 14 additions & 0 deletions lib/reek/name.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@ module Reek
class Name
include Comparable

def self.resolve(exp, context)
return [context, new(exp)] unless Array === exp
case exp[0]
when :colon2
mod = resolve(exp[1], context)[0]
return [mod, new(exp[2])]
when :const
mod = ModuleContext.new(context, exp)
return [mod, new(exp[2])]
else
return [context, new(exp[1])]
end
end

def initialize(sym)
@name = sym.to_s
end
Expand Down
12 changes: 6 additions & 6 deletions spec/reek/class_context_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def below() end

describe 'of loaded class' do
before :each do
@ctx = ClassContext.new(StopContext.new, [0, :Below])
@ctx = ClassContext.create(StopContext.new, [0, :Below])
end

it 'should recognise non-overridden method' do
Expand All @@ -97,14 +97,14 @@ def below() end
end

it 'should recognise methods in current codebase' do
ctx = ClassContext.new(StopContext.new, [0, :FeatureEnvy])
ctx = ClassContext.create(StopContext.new, [0, :FeatureEnvy])
ctx.is_overriding_method?('examine_context').should == true
end
end

describe 'of non-loaded class' do
before :each do
@ctx = ClassContext.new(StopContext.new, [0, :Missing])
@ctx = ClassContext.create(StopContext.new, [0, :Missing])
end

it 'should recognise non-overridden method' do
Expand All @@ -120,7 +120,7 @@ def below() end

describe 'Integration defect:' do
it 'should not report UtilityFunction for FeatureEnvy#examine_context' do
kelement = ClassContext.new(StopContext.new, [0, :FeatureEnvy, s(:const, :SmellDetector)])
kelement = ClassContext.create(StopContext.new, [0, :FeatureEnvy, s(:const, :SmellDetector)])
meth = Name.new(:examine_context)
kelement.is_overriding_method?(meth).should == true
melement = MethodContext.new(kelement, [0, :examine_context])
Expand All @@ -142,9 +142,9 @@ class Klass2
before :each do
@stop = StopContext.new
@mod1 = ModuleContext.new(@stop, [0, :Mod1])
@klass1 = ClassContext.new(@mod1, [0, :Klass1])
@klass1 = ClassContext.create(@mod1, [0, :Klass1])
@mod2 = ModuleContext.new(@klass1, [0, :Mod2])
@klass2 = ClassContext.new(@mod2, [0, :Klass2])
@klass2 = ClassContext.create(@mod2, [0, :Klass2])
end

describe StopContext do
Expand Down
4 changes: 2 additions & 2 deletions spec/reek/code_context_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,15 @@ def stop.bananas(arg1, arg2) arg1 + arg2 + 43 end
it 'should recognise its fq name in a collection of names' do
element = StopContext.new
element = ModuleContext.new(element, [0, :mod])
element = ClassContext.new(element, [0, :klass])
element = ClassContext.create(element, [0, :klass])
element.matches?(['banana', 'mod']).should == true
element.matches?(['banana', 'mod::klass']).should == true
end

it 'should recognise its fq name in a collection of names' do
element = StopContext.new
element = ModuleContext.new(element, [0, :mod])
element = ClassContext.new(element, [0, :klass])
element = ClassContext.create(element, [0, :klass])
element.matches?([/banana/, /mod/]).should == true
element.matches?([/banana/, /mod::klass/]).should == true
end
Expand Down
2 changes: 0 additions & 2 deletions spec/reek/smells/feature_envy_spec.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
require File.dirname(__FILE__) + '/../../spec_helper.rb'

require 'spec/reek/code_checks'
require 'reek/smells/feature_envy'

Expand Down
16 changes: 13 additions & 3 deletions spec/reek/smells/large_class_spec.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
require File.dirname(__FILE__) + '/../../spec_helper.rb'

require 'spec/reek/code_checks'
require 'reek/code_parser'
require 'reek/report'
require 'reek/smells/large_class'

include CodeChecks
include Reek
include Reek::Smells

Expand Down Expand Up @@ -47,7 +47,7 @@ def method6() @var6; end

describe 'when exceptions are listed' do
before :each do
@ctx = ClassContext.new(StopContext.new, [0, :Humungous])
@ctx = ClassContext.create(StopContext.new, [0, :Humungous])
30.times { |num| @ctx.record_method("method#{num}") }
@config = LargeClass.default_config
end
Expand All @@ -74,3 +74,13 @@ def method6() @var6; end
end
end
end

describe LargeClass do
check 'should not report empty class in another module',
'class Treetop::Runtime::SyntaxNode; end', []

it 'should deal with :: scoped names' do
element = ClassContext.create(StopContext.new, [:colon2, [:colon2, [:const, :Treetop], :Runtime], :SyntaxNode])
element.num_methods.should == 0
end
end

0 comments on commit e476c5d

Please sign in to comment.