skeptic 0.0.0
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.
- 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
|