skeptic 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +17 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +21 -0
- data/Rakefile +52 -0
- data/VERSION +1 -0
- data/bin/skeptic +42 -0
- data/features/skeptic.feature +76 -0
- data/features/step_definitions/skeptic_steps.rb +0 -0
- data/features/support/aruba.rb +1 -0
- data/features/support/env.rb +13 -0
- data/lib/skeptic/critic.rb +36 -0
- data/lib/skeptic/environment.rb +32 -0
- data/lib/skeptic/rules/lines_per_method.rb +59 -0
- data/lib/skeptic/rules/max_nesting_depth.rb +122 -0
- data/lib/skeptic/rules/methods_per_class.rb +69 -0
- data/lib/skeptic/rules/no_semicolons.rb +30 -0
- data/lib/skeptic/scope.rb +60 -0
- data/lib/skeptic/sexp_visitor.rb +65 -0
- data/lib/skeptic.rb +12 -0
- data/spec/skeptic/critic_spec.rb +66 -0
- data/spec/skeptic/environment_spec.rb +48 -0
- data/spec/skeptic/rules/lines_per_method_spec.rb +67 -0
- data/spec/skeptic/rules/max_nesting_depth_spec.rb +134 -0
- data/spec/skeptic/rules/methods_per_class_spec.rb +90 -0
- data/spec/skeptic/rules/no_semicolons_spec.rb +49 -0
- data/spec/skeptic/scope_spec.rb +32 -0
- data/spec/spec_helper.rb +12 -0
- metadata +158 -0
@@ -0,0 +1,65 @@
|
|
1
|
+
module Skeptic
|
2
|
+
module SexpVisitor
|
3
|
+
def self.included(receiver)
|
4
|
+
receiver.send :include, InstanceMethods
|
5
|
+
receiver.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def handlers
|
10
|
+
@handlers ||= {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def on(*types, &block)
|
14
|
+
types.each do |type|
|
15
|
+
handlers[type] = block
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module InstanceMethods
|
21
|
+
private
|
22
|
+
|
23
|
+
def visit(sexp)
|
24
|
+
if Symbol === sexp[0] and self.class.handlers.has_key? sexp[0]
|
25
|
+
type, *args = *sexp
|
26
|
+
handler = self.class.handlers[type]
|
27
|
+
|
28
|
+
with_sexp_type(type) { instance_exec *args, &handler }
|
29
|
+
else
|
30
|
+
range = sexp[0].kind_of?(Symbol) ? 1..-1 : 0..-1
|
31
|
+
|
32
|
+
sexp[range].each do |subtree|
|
33
|
+
visit subtree if subtree.kind_of?(Array) and not subtree[0].kind_of?(Fixnum)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def env
|
39
|
+
@env ||= Environment.new
|
40
|
+
end
|
41
|
+
|
42
|
+
def with_sexp_type(type)
|
43
|
+
@current_sexp_type, old_sexp_type = type, @current_sexp_type
|
44
|
+
yield
|
45
|
+
@current_sexp_type = old_sexp_type
|
46
|
+
end
|
47
|
+
|
48
|
+
def sexp_type
|
49
|
+
@current_sexp_type
|
50
|
+
end
|
51
|
+
|
52
|
+
def extract_name(tree)
|
53
|
+
type, first, second = *tree
|
54
|
+
case type
|
55
|
+
when :const_path_ref then "#{extract_name(first)}::#{extract_name(second)}"
|
56
|
+
when :const_ref then extract_name(first)
|
57
|
+
when :var_ref then extract_name(first)
|
58
|
+
when :@const then first
|
59
|
+
when :@ident then first
|
60
|
+
else '<unknown>'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/skeptic.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'ripper'
|
2
|
+
|
3
|
+
require 'skeptic/environment'
|
4
|
+
require 'skeptic/scope'
|
5
|
+
require 'skeptic/sexp_visitor'
|
6
|
+
|
7
|
+
require 'skeptic/rules/max_nesting_depth'
|
8
|
+
require 'skeptic/rules/methods_per_class'
|
9
|
+
require 'skeptic/rules/lines_per_method'
|
10
|
+
require 'skeptic/rules/no_semicolons'
|
11
|
+
|
12
|
+
require 'skeptic/critic'
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Skeptic
|
4
|
+
describe Critic do
|
5
|
+
let(:critic) { Critic.new }
|
6
|
+
|
7
|
+
it "can locate semicolons in the code" do
|
8
|
+
criticize 'foo; bar', no_semicolons: true
|
9
|
+
|
10
|
+
expect_criticism 'You have a semicolon at line 1, column 3', 'No semicolons as expression separators'
|
11
|
+
end
|
12
|
+
|
13
|
+
it "can locate deep levels of nesting" do
|
14
|
+
criticize <<-RUBY, max_nesting_depth: 1
|
15
|
+
class Foo
|
16
|
+
def bar
|
17
|
+
while true
|
18
|
+
if false
|
19
|
+
really?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
RUBY
|
25
|
+
|
26
|
+
expect_criticism 'Foo#bar has 2 levels of nesting: while > if', 'Maximum nesting depth (1)'
|
27
|
+
end
|
28
|
+
|
29
|
+
it "can locate classes with too many methods" do
|
30
|
+
criticize <<-RUBY, methods_per_class: 1
|
31
|
+
class Foo
|
32
|
+
def bar; end
|
33
|
+
def baz; end
|
34
|
+
end
|
35
|
+
RUBY
|
36
|
+
|
37
|
+
expect_criticism 'Foo has 2 methods: #bar, #baz', 'Number of methods per class (1)'
|
38
|
+
end
|
39
|
+
|
40
|
+
it "can locate methods that are too long" do
|
41
|
+
criticize <<-RUBY, lines_per_method: 1
|
42
|
+
class Foo
|
43
|
+
def bar
|
44
|
+
one
|
45
|
+
two
|
46
|
+
three
|
47
|
+
end
|
48
|
+
end
|
49
|
+
RUBY
|
50
|
+
|
51
|
+
expect_criticism 'Foo#bar is 3 lines long', 'Number of lines per method (1)'
|
52
|
+
end
|
53
|
+
|
54
|
+
def criticize(code, options)
|
55
|
+
options.each do |key, value|
|
56
|
+
critic.send "#{key}=", value
|
57
|
+
end
|
58
|
+
|
59
|
+
critic.criticize code
|
60
|
+
end
|
61
|
+
|
62
|
+
def expect_criticism(message, type)
|
63
|
+
critic.criticism.should include [message, type]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Skeptic
|
4
|
+
describe Environment do
|
5
|
+
let(:env) { Environment.new }
|
6
|
+
|
7
|
+
it "maps names to objects" do
|
8
|
+
env[:foo] = 42
|
9
|
+
env[:foo].should eq 42
|
10
|
+
end
|
11
|
+
|
12
|
+
it "returns nil for names that are not set" do
|
13
|
+
env[:foo].should be_nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it "allows environments to be extender" do
|
17
|
+
env.push foo: 2
|
18
|
+
env[:foo].should eq 2
|
19
|
+
end
|
20
|
+
|
21
|
+
it "allows environments to be unextended" do
|
22
|
+
env[:foo] = 1
|
23
|
+
env.push foo: 2
|
24
|
+
env.pop
|
25
|
+
env[:foo].should eq 1
|
26
|
+
end
|
27
|
+
|
28
|
+
it "looks up undefined names in the closure" do
|
29
|
+
env[:foo] = 1
|
30
|
+
env.push
|
31
|
+
env[:foo].should eq 1
|
32
|
+
end
|
33
|
+
|
34
|
+
it "can be extended for a block" do
|
35
|
+
executed_block = false
|
36
|
+
|
37
|
+
env[:foo] = 1
|
38
|
+
env.scoped do
|
39
|
+
env[:foo] = 2
|
40
|
+
env[:foo].should eq 2
|
41
|
+
executed_block = true
|
42
|
+
end
|
43
|
+
|
44
|
+
executed_block.should be_true
|
45
|
+
env[:foo].should eq 1
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Skeptic
|
4
|
+
module Rules
|
5
|
+
describe LinesPerMethod do
|
6
|
+
describe "calculating method size" do
|
7
|
+
it "can count the size of a method" do
|
8
|
+
code = <<-RUBY
|
9
|
+
class Foo
|
10
|
+
def bar
|
11
|
+
first
|
12
|
+
second
|
13
|
+
end
|
14
|
+
end
|
15
|
+
RUBY
|
16
|
+
|
17
|
+
analyze(code).size_of('Foo#bar').should eq 2
|
18
|
+
end
|
19
|
+
|
20
|
+
it "does not count empty lines" do
|
21
|
+
expect_line_count 2, <<-RUBY
|
22
|
+
foo
|
23
|
+
|
24
|
+
bar
|
25
|
+
RUBY
|
26
|
+
end
|
27
|
+
|
28
|
+
it "does not count lines containing one end" do
|
29
|
+
expect_line_count 2, <<-RUBY
|
30
|
+
if foo
|
31
|
+
bar
|
32
|
+
end
|
33
|
+
RUBY
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "reporting" do
|
38
|
+
it "can tell which methods are too long" do
|
39
|
+
analyzer = analyze 1, <<-RUBY
|
40
|
+
class Foo
|
41
|
+
def bar
|
42
|
+
one
|
43
|
+
two
|
44
|
+
three
|
45
|
+
end
|
46
|
+
end
|
47
|
+
RUBY
|
48
|
+
|
49
|
+
analyzer.violations.should include 'Foo#bar is 3 lines long'
|
50
|
+
end
|
51
|
+
|
52
|
+
it "reports under 'Number of lines per method'" do
|
53
|
+
LinesPerMethod.new(2).name.should eq 'Number of lines per method (2)'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def expect_line_count(count, code)
|
58
|
+
code = "class Foo\ndef bar\n#{code}\nend\nend"
|
59
|
+
analyze(code).size_of('Foo#bar').should eq count
|
60
|
+
end
|
61
|
+
|
62
|
+
def analyze(limit = nil, code)
|
63
|
+
LinesPerMethod.new(limit).apply_to nil, Ripper.sexp(code)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Skeptic
|
4
|
+
module Rules
|
5
|
+
describe MaxNestingDepth do
|
6
|
+
describe "structure analysis" do
|
7
|
+
it "counts all conditional forms as a level of nesting" do
|
8
|
+
expect_deepest_nesting :if, 'if condition?; action; end'
|
9
|
+
expect_deepest_nesting :if, 'if condition? then action end'
|
10
|
+
expect_deepest_nesting :if, 'action if condition?'
|
11
|
+
expect_deepest_nesting :unless, 'action unless condition?'
|
12
|
+
expect_deepest_nesting :unless, 'unless condition?; action; end'
|
13
|
+
expect_deepest_nesting :unless, 'unless condition? then action end'
|
14
|
+
expect_deepest_nesting :if, :if, 'a if b? if c?'
|
15
|
+
end
|
16
|
+
|
17
|
+
it "counts else blocks as a level of nesting" do
|
18
|
+
expect_deepest_nesting :if, :unless, 'if a?; else; foo unless b? end'
|
19
|
+
expect_deepest_nesting :if, :unless, 'if a?; elsif? b?; else; foo unless c? end'
|
20
|
+
expect_deepest_nesting :unless, :if, 'unless a?; else; foo if b? end'
|
21
|
+
end
|
22
|
+
|
23
|
+
it "counts elsif blocks as a level of nesting" do
|
24
|
+
expect_deepest_nesting :if, :unless, 'if a?; elsif b?; foo unless c?; end'
|
25
|
+
expect_deepest_nesting :if, :unless, 'if a?; elsif b?; foo unless c?; else; end'
|
26
|
+
end
|
27
|
+
|
28
|
+
it "counts unbound loops as a level of nesting" do
|
29
|
+
expect_deepest_nesting :while, :if, 'while a?; b if c? end'
|
30
|
+
expect_deepest_nesting :while, :if, '(a if b?) while c?'
|
31
|
+
expect_deepest_nesting :until, :if, 'until a?; b if c? end'
|
32
|
+
expect_deepest_nesting :until, :if, '(a if b?) until c?'
|
33
|
+
end
|
34
|
+
|
35
|
+
it "counts blocks as a level of nesting" do
|
36
|
+
expect_deepest_nesting :iter, :if, 'a { b if c? }'
|
37
|
+
expect_deepest_nesting :iter, :if, 'a(1) { b if c? }'
|
38
|
+
expect_deepest_nesting :iter, :if, 'a do; b if c?; end'
|
39
|
+
expect_deepest_nesting :iter, :if, 'a(1) do; b if c?; end'
|
40
|
+
|
41
|
+
expect_deepest_nesting :iter, :if, 'loop { a if b }'
|
42
|
+
end
|
43
|
+
|
44
|
+
it "counts lambdas as a level of nesting" do
|
45
|
+
expect_deepest_nesting :iter, :if, 'lambda { a if b }'
|
46
|
+
expect_deepest_nesting :iter, :if, 'Proc.new { a if b }'
|
47
|
+
expect_deepest_nesting :lambda, :if, '-> { a if b }'
|
48
|
+
end
|
49
|
+
|
50
|
+
it "counts for loops as a level of nesting" do
|
51
|
+
expect_deepest_nesting :for, :if, 'for a in b; c if d; end'
|
52
|
+
end
|
53
|
+
|
54
|
+
it "counts case statements as a level of nesting" do
|
55
|
+
expect_deepest_nesting :case, :if, 'case a; when b; c if d?; end'
|
56
|
+
expect_deepest_nesting :case, :if, 'case a; when b; when c; d if e?; end'
|
57
|
+
expect_deepest_nesting :case, :if, 'case a; when b; else; d if e?; end'
|
58
|
+
end
|
59
|
+
|
60
|
+
it "counts begin blocks as a level of nesting" do
|
61
|
+
expect_deepest_nesting :begin, :if, 'begin; a if b; end'
|
62
|
+
end
|
63
|
+
|
64
|
+
it "does not count the method invocation as a block" do
|
65
|
+
expect_a_nesting :if, 'a((b if c)) { d }'
|
66
|
+
expect_a_nesting :iter, :if, 'a.b { c if d? }.e { g }'
|
67
|
+
expect_a_nesting :iter, :unless, 'a.b { c unless d? }.c { }'
|
68
|
+
end
|
69
|
+
|
70
|
+
it "does not count the if condition as a level of nesting" do
|
71
|
+
expect_a_nesting :iter, 'a if b { c }'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "nesting location" do
|
76
|
+
it "recognizes top-level code" do
|
77
|
+
expect_scope nil, nil, :if, 'a if b'
|
78
|
+
end
|
79
|
+
|
80
|
+
it "recognizes class definitions" do
|
81
|
+
expect_scope 'A', nil, :if, 'class A; a if b; end'
|
82
|
+
expect_scope 'A::B', nil, :if, 'class A::B; a if b; end'
|
83
|
+
end
|
84
|
+
|
85
|
+
it "recognizes method definitions" do
|
86
|
+
expect_scope nil, 'a', :if, 'def a; b if c; end'
|
87
|
+
expect_scope 'A', 'b', :if, 'class A; def b; c if d; end; end'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "reporting" do
|
92
|
+
it "can report methods that contain a deep level of nesting" do
|
93
|
+
analyzer = analyze 1, <<-RUBY
|
94
|
+
class Foo
|
95
|
+
def bar
|
96
|
+
while true
|
97
|
+
if false
|
98
|
+
really?
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
RUBY
|
104
|
+
|
105
|
+
analyzer.violations.should include 'Foo#bar has 2 levels of nesting: while > if'
|
106
|
+
end
|
107
|
+
|
108
|
+
it "reports under 'Maximum nesting depth'" do
|
109
|
+
MaxNestingDepth.new(2).name.should eq 'Maximum nesting depth (2)'
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def nestings(code)
|
114
|
+
analyze(code).nestings
|
115
|
+
end
|
116
|
+
|
117
|
+
def expect_scope(class_name, method_name, *levels, code)
|
118
|
+
analyze(code).nestings.should include Scope.new(class_name, method_name, levels)
|
119
|
+
end
|
120
|
+
|
121
|
+
def expect_a_nesting(*levels, code)
|
122
|
+
analyze(code).nestings.should include Scope.new(nil, nil, levels)
|
123
|
+
end
|
124
|
+
|
125
|
+
def expect_deepest_nesting(*levels, code)
|
126
|
+
analyze(code).nestings.max_by(&:depth).should eq Scope.new(nil, nil, levels)
|
127
|
+
end
|
128
|
+
|
129
|
+
def analyze(limit = nil, code)
|
130
|
+
MaxNestingDepth.new(limit).apply_to nil, Ripper.sexp(code)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Skeptic
|
4
|
+
module Rules
|
5
|
+
describe MethodsPerClass do
|
6
|
+
describe "counting methods" do
|
7
|
+
it "counts methods defined in classes" do
|
8
|
+
expect_method_count 'Foo', 2, <<-RUBY
|
9
|
+
class Foo
|
10
|
+
def bar; end
|
11
|
+
def baz; end
|
12
|
+
end
|
13
|
+
RUBY
|
14
|
+
end
|
15
|
+
|
16
|
+
it "counts methods defined in modules" do
|
17
|
+
expect_method_count 'Foo', 2, <<-RUBY
|
18
|
+
module Foo
|
19
|
+
def bar; end
|
20
|
+
def baz; end
|
21
|
+
end
|
22
|
+
RUBY
|
23
|
+
end
|
24
|
+
|
25
|
+
it "counts method defined when the class is reopened" do
|
26
|
+
expect_method_count 'Foo', 2, <<-RUBY
|
27
|
+
class Foo; def bar; end; end
|
28
|
+
class Foo; def baz; end; end
|
29
|
+
RUBY
|
30
|
+
end
|
31
|
+
|
32
|
+
it "counts redefining the method as a new method" do
|
33
|
+
expect_method_count 'Foo', 2, <<-RUBY
|
34
|
+
class Foo
|
35
|
+
def bar; end
|
36
|
+
def bar; end
|
37
|
+
end
|
38
|
+
RUBY
|
39
|
+
end
|
40
|
+
|
41
|
+
it "works with multiple classes" do
|
42
|
+
counter = analyze <<-RUBY
|
43
|
+
class Foo; def name; end; end
|
44
|
+
class Bar; def name; end; end
|
45
|
+
RUBY
|
46
|
+
|
47
|
+
counter.methods_in('Foo').should eq 1
|
48
|
+
counter.methods_in('Bar').should eq 1
|
49
|
+
end
|
50
|
+
|
51
|
+
it "recognizes qualified module names" do
|
52
|
+
expect_method_count 'Foo::Bar', 1, <<-RUBY
|
53
|
+
class Foo::Bar; def baz; end; end
|
54
|
+
RUBY
|
55
|
+
end
|
56
|
+
|
57
|
+
it "recognizes modules nested under other modules" do
|
58
|
+
expect_method_count 'Foo::Bar', 1, <<-RUBY
|
59
|
+
class Foo; module Bar; def baz; end; end; end
|
60
|
+
RUBY
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "reporting" do
|
65
|
+
it "reports classes, violating the rule" do
|
66
|
+
analyzer = analyze 1, <<-RUBY
|
67
|
+
class Foo
|
68
|
+
def bar; end
|
69
|
+
def baz; end
|
70
|
+
end
|
71
|
+
RUBY
|
72
|
+
|
73
|
+
analyzer.violations.should include 'Foo has 2 methods: #bar, #baz'
|
74
|
+
end
|
75
|
+
|
76
|
+
it "reports under 'Number of methods per class'" do
|
77
|
+
MethodsPerClass.new(42).name.should eq 'Number of methods per class (42)'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def analyze(limit = nil, code)
|
82
|
+
MethodsPerClass.new(limit).apply_to nil, Ripper.sexp(code)
|
83
|
+
end
|
84
|
+
|
85
|
+
def expect_method_count(class_name, count, code)
|
86
|
+
analyze(code).methods_in(class_name).should eq count
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Skeptic
|
4
|
+
module Rules
|
5
|
+
describe NoSemicolons do
|
6
|
+
describe "detecting semicolons" do
|
7
|
+
it "complains if it finds a semicolon in the code" do
|
8
|
+
expect_complaint 'foo; bar'
|
9
|
+
expect_complaint 'this; that; other'
|
10
|
+
expect_complaint '"#{foo;bar}"'
|
11
|
+
end
|
12
|
+
|
13
|
+
it "does not complain for semicolons in literals" do
|
14
|
+
expect_fine_and_dandy '"foo;"'
|
15
|
+
expect_fine_and_dandy '";"'
|
16
|
+
expect_fine_and_dandy '/;/'
|
17
|
+
end
|
18
|
+
|
19
|
+
it "can tell the locations of the semicolons" do
|
20
|
+
analyze("foo;\n;bar").semicolon_locations.should =~ [[1, 3], [2, 0]]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "reporting" do
|
25
|
+
it "points out file locations with semicolons" do
|
26
|
+
analyzer = analyze 'foo; bar'
|
27
|
+
|
28
|
+
analyzer.violations.should include 'You have a semicolon at line 1, column 3'
|
29
|
+
end
|
30
|
+
|
31
|
+
it "reports under 'No semicolons'" do
|
32
|
+
NoSemicolons.new(true).name.should eq 'No semicolons as expression separators'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def expect_fine_and_dandy(code)
|
37
|
+
analyze(code).semicolon_locations.should be_empty
|
38
|
+
end
|
39
|
+
|
40
|
+
def expect_complaint(code)
|
41
|
+
analyze(code).semicolon_locations.should_not be_empty
|
42
|
+
end
|
43
|
+
|
44
|
+
def analyze(code)
|
45
|
+
NoSemicolons.new(true).apply_to Ripper.lex(code), nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Skeptic
|
4
|
+
describe Scope do
|
5
|
+
it "contains levels of nesting" do
|
6
|
+
Scope.new(nil, nil, [:for, :if]).levels.should eq [:for, :if]
|
7
|
+
Scope.new(nil, nil, []).levels.should eq []
|
8
|
+
Scope.new.levels.should eq []
|
9
|
+
end
|
10
|
+
|
11
|
+
it "can be compared to another scope" do
|
12
|
+
Scope.new(nil, nil, [:for, :if]).should eq Scope.new(nil, nil, [:for, :if])
|
13
|
+
Scope.new(nil, nil, []).should_not eq Scope.new(nil, nil, [:if])
|
14
|
+
Scope.new('Bar', nil).should_not eq Scope.new('Foo', nil)
|
15
|
+
Scope.new(nil, 'bar').should_not eq Scope.new(nil, 'foo')
|
16
|
+
end
|
17
|
+
|
18
|
+
it "can be extended and unextended" do
|
19
|
+
Scope.new.push(:if).should eq Scope.new(nil, nil, [:if])
|
20
|
+
Scope.new(nil, nil, [:for, :if]).pop.should eq Scope.new(nil, nil, [:for])
|
21
|
+
|
22
|
+
Scope.new.in_class('Foo').should eq Scope.new('Foo')
|
23
|
+
Scope.new.in_method('bar').should eq Scope.new(nil, 'bar')
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can tell its depth" do
|
27
|
+
Scope.new(nil, nil, [:for]).depth.should eq 1
|
28
|
+
Scope.new(nil, nil, [:for, :if]).depth.should eq 2
|
29
|
+
Scope.new(nil, nil, [:for, :if, :if]).depth.should eq 3
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'skeptic'
|
5
|
+
|
6
|
+
# Requires supporting files with custom matchers and macros, etc,
|
7
|
+
# in ./support/ and its subdirectories.
|
8
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
|
12
|
+
end
|