reek 1.3.6 → 1.3.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +6 -0
- data/README.md +11 -1
- data/config/defaults.reek +1 -0
- data/features/command_line_interface/options.feature +1 -0
- data/features/rake_task/rake_task.feature +3 -0
- data/features/ruby_api/api.feature +1 -3
- data/features/samples.feature +27 -20
- data/features/support/env.rb +2 -2
- data/lib/reek/cli/application.rb +0 -4
- data/lib/reek/cli/command_line.rb +10 -12
- data/lib/reek/cli/reek_command.rb +1 -1
- data/lib/reek/cli/report.rb +36 -8
- data/lib/reek/config_file_exception.rb +3 -0
- data/lib/reek/core/code_context.rb +18 -8
- data/lib/reek/core/code_parser.rb +65 -61
- data/lib/reek/core/method_context.rb +4 -0
- data/lib/reek/core/module_context.rb +2 -2
- data/lib/reek/core/smell_repository.rb +3 -0
- data/lib/reek/core/sniffer.rb +0 -1
- data/lib/reek/core/stop_context.rb +1 -1
- data/lib/reek/smells/attribute.rb +1 -1
- data/lib/reek/smells/control_parameter.rb +79 -45
- data/lib/reek/smells/data_clump.rb +1 -1
- data/lib/reek/smells/duplicate_method_call.rb +1 -1
- data/lib/reek/smells/long_parameter_list.rb +1 -1
- data/lib/reek/smells/long_yield_list.rb +1 -1
- data/lib/reek/smells/nested_iterators.rb +1 -1
- data/lib/reek/smells/nil_check.rb +10 -5
- data/lib/reek/smells/repeated_conditional.rb +1 -1
- data/lib/reek/smells/smell_detector.rb +2 -3
- data/lib/reek/smells/too_many_instance_variables.rb +1 -1
- data/lib/reek/smells/too_many_methods.rb +1 -1
- data/lib/reek/smells/too_many_statements.rb +1 -1
- data/lib/reek/smells/uncommunicative_method_name.rb +4 -4
- data/lib/reek/smells/uncommunicative_module_name.rb +4 -4
- data/lib/reek/smells/uncommunicative_parameter_name.rb +9 -9
- data/lib/reek/smells/uncommunicative_variable_name.rb +1 -1
- data/lib/reek/smells/unused_parameters.rb +2 -6
- data/lib/reek/smells/utility_function.rb +1 -1
- data/lib/reek/source/code_comment.rb +1 -1
- data/lib/reek/source/config_file.rb +9 -8
- data/lib/reek/source/sexp_extensions.rb +2 -2
- data/lib/reek/source/sexp_node.rb +8 -5
- data/lib/reek/source/source_repository.rb +5 -0
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +3 -2
- data/spec/reek/cli/report_spec.rb +38 -8
- data/spec/reek/core/code_context_spec.rb +35 -3
- data/spec/reek/core/module_context_spec.rb +1 -1
- data/spec/reek/smells/repeated_conditional_spec.rb +1 -1
- data/spec/reek/smells/smell_detector_shared.rb +1 -2
- data/spec/reek/smells/too_many_statements_spec.rb +39 -25
- data/spec/reek/smells/uncommunicative_parameter_name_spec.rb +44 -30
- data/spec/reek/smells/unused_parameters_spec.rb +15 -11
- data/spec/reek/source/sexp_extensions_spec.rb +2 -2
- data/spec/reek/source/sexp_node_spec.rb +0 -1
- data/spec/samples/ruby20_syntax.rb +1 -5
- metadata +172 -162
- data/lib/reek/cli/yaml_command.rb +0 -32
- data/lib/reek/core/hash_extensions.rb +0 -29
- data/spec/reek/cli/yaml_command_spec.rb +0 -47
- data/spec/reek/core/config_spec.rb +0 -38
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'reek/examiner'
|
3
3
|
require 'reek/cli/report'
|
4
|
+
require 'rainbow'
|
5
|
+
require 'stringio'
|
4
6
|
|
5
7
|
include Reek
|
6
8
|
include Reek::Cli
|
@@ -17,18 +19,46 @@ describe QuietReport, " when empty" do
|
|
17
19
|
|
18
20
|
context 'with a couple of smells' do
|
19
21
|
before :each do
|
20
|
-
examiner = Examiner.new('def simple(a) a[3] end')
|
21
|
-
rpt = QuietReport.new
|
22
|
-
@result = rpt.add_examiner(examiner).gather_results.first
|
22
|
+
@examiner = Examiner.new('def simple(a) a[3] end')
|
23
|
+
@rpt = QuietReport.new(SimpleWarningFormatter, ReportFormatter, false, :text)
|
23
24
|
end
|
24
25
|
|
25
|
-
|
26
|
-
|
26
|
+
context 'with colors disabled' do
|
27
|
+
before :each do
|
28
|
+
Rainbow.enabled = false
|
29
|
+
@result = @rpt.add_examiner(@examiner).gather_results.first
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'has a header' do
|
33
|
+
@result.should match('string -- 2 warnings')
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should mention every smell name' do
|
37
|
+
@result.should match('[UncommunicativeParameterName]')
|
38
|
+
@result.should match('[Feature Envy]')
|
39
|
+
end
|
27
40
|
end
|
28
41
|
|
29
|
-
|
30
|
-
|
31
|
-
|
42
|
+
context 'with colors enabled' do
|
43
|
+
before :each do
|
44
|
+
Rainbow.enabled = true
|
45
|
+
@rpt.add_examiner(Examiner.new('def simple(a) a[3] end'))
|
46
|
+
@rpt.add_examiner(Examiner.new('def simple(a) a[3] end'))
|
47
|
+
@result = @rpt.gather_results
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'has a header in color' do
|
51
|
+
@result.first.should start_with "\e[36mstring -- \e[0m\e[33m2 warning\e[0m\e[33ms\e[0m"
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'has a footer in color' do
|
55
|
+
stdout = StringIO.new
|
56
|
+
$stdout = stdout
|
57
|
+
@rpt.show
|
58
|
+
$stdout = STDOUT
|
59
|
+
|
60
|
+
stdout.string.should end_with "\e[31m4 total warnings\n\e[0m"
|
61
|
+
end
|
32
62
|
end
|
33
63
|
end
|
34
64
|
end
|
@@ -36,8 +36,8 @@ describe CodeContext do
|
|
36
36
|
before :each do
|
37
37
|
@outer_name = 'another_random sting'
|
38
38
|
outer = double('outer')
|
39
|
-
outer.
|
40
|
-
outer.
|
39
|
+
allow(outer).to receive(:full_name).at_least(:once).and_return(@outer_name)
|
40
|
+
allow(outer).to receive(:config).and_return({})
|
41
41
|
@ctx = CodeContext.new(outer, @exp)
|
42
42
|
end
|
43
43
|
it 'creates the correct full name' do
|
@@ -56,7 +56,7 @@ describe CodeContext do
|
|
56
56
|
it 'should pass unknown method calls down the stack' do
|
57
57
|
stop = StopContext.new
|
58
58
|
def stop.bananas(arg1, arg2) arg1 + arg2 + 43 end
|
59
|
-
element = ModuleContext.new(stop,
|
59
|
+
element = ModuleContext.new(stop, ast(:module, :mod, nil))
|
60
60
|
element = MethodContext.new(element, ast(:defn, :bad))
|
61
61
|
element.bananas(17, -5).should == 55
|
62
62
|
end
|
@@ -142,4 +142,36 @@ EOS
|
|
142
142
|
ctx.each_node(:if, []).length.should == 3
|
143
143
|
end
|
144
144
|
end
|
145
|
+
|
146
|
+
describe '#config_for' do
|
147
|
+
let(:exp) { double('exp') }
|
148
|
+
let(:outer) { nil }
|
149
|
+
let(:ctx) { CodeContext.new(outer, exp) }
|
150
|
+
let(:sniffer) { double('sniffer') }
|
151
|
+
|
152
|
+
before :each do
|
153
|
+
allow(sniffer).to receive(:smell_class_name).and_return('DuplicateMethodCall')
|
154
|
+
allow(exp).to receive(:comments).and_return(
|
155
|
+
':reek:DuplicateMethodCall: { allow_calls: [ puts ] }')
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'gets its configuration from the exp comments' do
|
159
|
+
ctx.config_for(sniffer).should == {
|
160
|
+
'allow_calls' => [ 'puts' ] }
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'when there is an outer' do
|
164
|
+
let(:outer) { double('outer') }
|
165
|
+
|
166
|
+
before :each do
|
167
|
+
allow(outer).to receive(:config_for).with(sniffer).and_return(
|
168
|
+
{ 'max_calls' => 2 })
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'merges the outer config with its own configuration' do
|
172
|
+
ctx.config_for(sniffer).should == { 'allow_calls' => [ 'puts' ],
|
173
|
+
'max_calls' => 2 }
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
145
177
|
end
|
@@ -6,7 +6,7 @@ include Reek::Core
|
|
6
6
|
|
7
7
|
describe ModuleContext do
|
8
8
|
it 'should report module name for smell in method' do
|
9
|
-
'module Fred; def simple(x)
|
9
|
+
'module Fred; def simple(x) x + 1; end; end'.should reek_of(:UncommunicativeParameterName, /x/, /simple/)
|
10
10
|
end
|
11
11
|
|
12
12
|
it 'should not report module with empty class' do
|
@@ -86,7 +86,7 @@ EOS
|
|
86
86
|
@yaml.should match(/subclass:\s*RepeatedConditional/)
|
87
87
|
end
|
88
88
|
it 'reports the expression' do
|
89
|
-
@yaml.should match(/expression:\s
|
89
|
+
@yaml.should match(/expression:\s*"?\(#{@cond}\)"?/)
|
90
90
|
end
|
91
91
|
it 'reports the number of occurrences' do
|
92
92
|
@yaml.should match(/occurrences:\s*3/)
|
@@ -7,8 +7,7 @@ shared_examples_for 'SmellDetector' do
|
|
7
7
|
context 'exception matching follows the context' do
|
8
8
|
before :each do
|
9
9
|
@ctx = double('context')
|
10
|
-
|
11
|
-
@ctx.should_receive(:config).and_return({})
|
10
|
+
allow(@ctx).to receive(:config_for).and_return({})
|
12
11
|
end
|
13
12
|
it 'when false' do
|
14
13
|
@ctx.should_receive(:matches?).at_least(:once).and_return(false)
|
@@ -110,6 +110,11 @@ describe TooManyStatements do
|
|
110
110
|
method = process_method('def one() val = 4; true; end')
|
111
111
|
method.num_statements.should == 2
|
112
112
|
end
|
113
|
+
|
114
|
+
it 'counts nil returns' do
|
115
|
+
method = process_method('def one() val = 4; nil; end')
|
116
|
+
method.num_statements.should == 2
|
117
|
+
end
|
113
118
|
end
|
114
119
|
|
115
120
|
describe TooManyStatements, 'does not count control statements' do
|
@@ -123,11 +128,26 @@ describe TooManyStatements, 'does not count control statements' do
|
|
123
128
|
method.num_statements.should == 3
|
124
129
|
end
|
125
130
|
|
131
|
+
it 'counts 1 statements in an else' do
|
132
|
+
method = process_method('def one() if val == 4; callee(); else; callee(); end; end')
|
133
|
+
method.num_statements.should == 2
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'counts 3 statements in an else' do
|
137
|
+
method = process_method('def one() if val == 4; callee(); callee(); callee(); else; callee(); callee(); callee(); end; end')
|
138
|
+
method.num_statements.should == 6
|
139
|
+
end
|
140
|
+
|
126
141
|
it 'does not count empty conditional expression' do
|
127
142
|
method = process_method('def one() if val == 4; ; end; end')
|
128
143
|
method.num_statements.should == 0
|
129
144
|
end
|
130
145
|
|
146
|
+
it 'does not count empty else' do
|
147
|
+
method = process_method('def one() if val == 4; ; else; ; end; end')
|
148
|
+
method.num_statements.should == 0
|
149
|
+
end
|
150
|
+
|
131
151
|
it 'counts 1 statement in a while loop' do
|
132
152
|
method = process_method('def one() while val < 4; callee(); end; end')
|
133
153
|
method.num_statements.should == 1
|
@@ -178,18 +198,32 @@ describe TooManyStatements, 'does not count control statements' do
|
|
178
198
|
method.num_statements.should == 3
|
179
199
|
end
|
180
200
|
|
201
|
+
it 'counts 1 statement in a case else' do
|
202
|
+
method = process_method('def one() case fred; when "hi"; callee(); else; callee(); end; end')
|
203
|
+
method.num_statements.should == 2
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'counts 3 statements in a case else' do
|
207
|
+
method = process_method('def one() case fred; when "hi"; callee(); callee(); callee(); else; callee(); callee(); callee(); end; end')
|
208
|
+
method.num_statements.should == 6
|
209
|
+
end
|
210
|
+
|
181
211
|
it 'does not count empty case' do
|
182
212
|
method = process_method('def one() case fred; when "hi"; ; when "lo"; ; end; end')
|
183
213
|
method.num_statements.should == 0
|
184
214
|
end
|
185
215
|
|
186
|
-
it '
|
216
|
+
it 'does not count empty case else' do
|
217
|
+
method = process_method('def one() case fred; when "hi"; ; else; ; end; end')
|
218
|
+
method.num_statements.should == 0
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'counts 2 statement in an iterator' do
|
187
222
|
method = process_method('def one() fred.each do; callee(); end; end')
|
188
|
-
method.num_statements.should ==
|
223
|
+
method.num_statements.should == 2
|
189
224
|
end
|
190
225
|
|
191
|
-
|
192
|
-
it 'counts 4 statements in a block' do
|
226
|
+
it 'counts 4 statements in an iterator' do
|
193
227
|
method = process_method('def one() fred.each do; callee(); callee(); callee(); end; end')
|
194
228
|
method.num_statements.should == 4
|
195
229
|
end
|
@@ -198,26 +232,6 @@ describe TooManyStatements, 'does not count control statements' do
|
|
198
232
|
method = process_singleton_method('def self.foo; callee(); end')
|
199
233
|
method.num_statements.should == 1
|
200
234
|
end
|
201
|
-
|
202
|
-
it 'counts else statement' do
|
203
|
-
src = <<EOS
|
204
|
-
def parse(arg, argv, &error)
|
205
|
-
if !(val = arg) and (argv.empty? or /\A-/ =~ (val = argv[0]))
|
206
|
-
return nil, block, nil
|
207
|
-
end
|
208
|
-
opt = (val = parse_arg(val, &error))[1]
|
209
|
-
val = conv_arg(*val)
|
210
|
-
if opt and !arg
|
211
|
-
argv.shift
|
212
|
-
else
|
213
|
-
val[0] = nil
|
214
|
-
end
|
215
|
-
val
|
216
|
-
end
|
217
|
-
EOS
|
218
|
-
method = process_method(src)
|
219
|
-
method.num_statements.should == 6
|
220
|
-
end
|
221
235
|
end
|
222
236
|
|
223
237
|
describe TooManyStatements do
|
@@ -232,7 +246,7 @@ describe TooManyStatements do
|
|
232
246
|
@num_statements = 30
|
233
247
|
ctx = double('method_context').as_null_object
|
234
248
|
ctx.should_receive(:num_statements).and_return(@num_statements)
|
235
|
-
ctx.should_receive(:
|
249
|
+
ctx.should_receive(:config_for).with(TooManyStatements).and_return({})
|
236
250
|
@smells = @detector.examine_context(ctx)
|
237
251
|
end
|
238
252
|
it 'reports only 1 smell' do
|
@@ -14,49 +14,63 @@ describe UncommunicativeParameterName do
|
|
14
14
|
|
15
15
|
it_should_behave_like 'SmellDetector'
|
16
16
|
|
17
|
-
|
18
|
-
|
17
|
+
{ 'obj.' => 'with a receiveer',
|
18
|
+
'' => 'without a receiver'}.each do |host, description|
|
19
|
+
context "in a method definition #{description}" do
|
19
20
|
it 'does not recognise *' do
|
20
|
-
"def #{host}help(xray, *) basics(17) end".
|
21
|
+
"def #{host}help(xray, *) basics(17) end".
|
22
|
+
should_not smell_of(UncommunicativeParameterName)
|
21
23
|
end
|
24
|
+
|
22
25
|
it "reports parameter's name" do
|
26
|
+
src = "def #{host}help(x) basics(x) end"
|
27
|
+
src.should smell_of(UncommunicativeParameterName,
|
28
|
+
{UncommunicativeParameterName::PARAMETER_NAME_KEY => 'x'})
|
29
|
+
end
|
30
|
+
|
31
|
+
it "does not report unused parameters" do
|
23
32
|
src = "def #{host}help(x) basics(17) end"
|
24
|
-
src.
|
33
|
+
src.should_not smell_of(UncommunicativeParameterName)
|
25
34
|
end
|
26
35
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
src = "def #{host}help(#{@bad_param}) basics(17) end"
|
31
|
-
ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
|
32
|
-
@smells = @detector.examine_context(ctx)
|
33
|
-
end
|
34
|
-
it 'reports only 1 smell' do
|
35
|
-
@smells.length.should == 1
|
36
|
-
end
|
37
|
-
it 'reports uncommunicative parameter name' do
|
38
|
-
@smells[0].subclass.should == UncommunicativeParameterName::SMELL_SUBCLASS
|
39
|
-
end
|
40
|
-
it 'reports the parameter name' do
|
41
|
-
@smells[0].smell[UncommunicativeParameterName::PARAMETER_NAME_KEY].should == @bad_param
|
42
|
-
end
|
36
|
+
it 'does not report two-letter parameter names' do
|
37
|
+
"def #{host}help(ab) basics(ab) end".
|
38
|
+
should_not smell_of(UncommunicativeParameterName)
|
43
39
|
end
|
40
|
+
|
41
|
+
it 'reports names of the form "x2"' do
|
42
|
+
src = "def #{host}help(x2) basics(x2) end"
|
43
|
+
src.should smell_of(UncommunicativeParameterName,
|
44
|
+
{UncommunicativeParameterName::PARAMETER_NAME_KEY => 'x2'})
|
45
|
+
end
|
46
|
+
|
44
47
|
it 'reports long name ending in a number' do
|
45
|
-
|
46
|
-
src
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
src = "def #{host}help(param2) basics(param2) end"
|
49
|
+
src.should smell_of(UncommunicativeParameterName,
|
50
|
+
{UncommunicativeParameterName::PARAMETER_NAME_KEY => 'param2'})
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'does not report unused anonymous parameter' do
|
54
|
+
"def #{host}help(_) basics(17) end".
|
55
|
+
should_not smell_of(UncommunicativeParameterName)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'reports used anonymous parameter' do
|
59
|
+
"def #{host}help(_) basics(_) end".
|
60
|
+
should smell_of(UncommunicativeParameterName)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'reports used parameters marked as unused' do
|
64
|
+
"def #{host}help(_unused) basics(_unused) end".
|
65
|
+
should smell_of(UncommunicativeParameterName)
|
52
66
|
end
|
53
67
|
end
|
54
68
|
end
|
55
69
|
|
56
|
-
context 'looking at the
|
70
|
+
context 'looking at the smell result fields' do
|
57
71
|
before :each do
|
58
|
-
src = 'def bad(good, bad2, good_again) end'
|
59
|
-
ctx =
|
72
|
+
src = 'def bad(good, bad2, good_again); basics(good, bad2, good_again); end'
|
73
|
+
ctx = MethodContext.new(nil, src.to_reek_source.syntax_tree)
|
60
74
|
@smells = @detector.examine_context(ctx)
|
61
75
|
@warning = @smells[0]
|
62
76
|
end
|
@@ -9,54 +9,58 @@ describe UnusedParameters do
|
|
9
9
|
|
10
10
|
context 'for methods' do
|
11
11
|
|
12
|
-
it '
|
12
|
+
it 'reports nothing for no parameters' do
|
13
13
|
'def simple; true end'.should_not smell_of(UnusedParameters)
|
14
14
|
end
|
15
15
|
|
16
|
-
it '
|
16
|
+
it 'reports nothing for used parameter' do
|
17
17
|
'def simple(sum); sum end'.should_not smell_of(UnusedParameters)
|
18
18
|
end
|
19
19
|
|
20
|
-
it '
|
20
|
+
it 'reports for 1 used and 2 unused parameter' do
|
21
21
|
src = 'def simple(num,sum,denum); sum end'
|
22
22
|
src.should smell_of(UnusedParameters,
|
23
23
|
{UnusedParameters::PARAMETER_KEY => 'num'},
|
24
24
|
{UnusedParameters::PARAMETER_KEY => 'denum'})
|
25
25
|
end
|
26
26
|
|
27
|
-
it '
|
27
|
+
it 'reports for 3 used and 1 unused parameter' do
|
28
28
|
src = 'def simple(num,sum,denum,quotient); num + denum + sum end'
|
29
29
|
src.should smell_of(UnusedParameters,
|
30
30
|
{UnusedParameters::PARAMETER_KEY => 'quotient'})
|
31
31
|
end
|
32
32
|
|
33
|
-
it '
|
33
|
+
it 'reports nothing for used splatted parameter' do
|
34
34
|
'def simple(*sum); sum end'.should_not smell_of(UnusedParameters)
|
35
35
|
end
|
36
36
|
|
37
|
-
it '
|
37
|
+
it 'reports nothing for unused anonymous parameter' do
|
38
38
|
'def simple(_); end'.should_not smell_of(UnusedParameters)
|
39
39
|
end
|
40
40
|
|
41
|
-
it '
|
41
|
+
it 'reports nothing for named parameters prefixed with _' do
|
42
42
|
'def simple(_name); end'.should_not smell_of(UnusedParameters)
|
43
43
|
end
|
44
44
|
|
45
|
-
it '
|
45
|
+
it 'reports nothing for unused anonymous splatted parameter' do
|
46
46
|
'def simple(*); end'.should_not smell_of(UnusedParameters)
|
47
47
|
end
|
48
48
|
|
49
|
-
it '
|
49
|
+
it 'reports nothing when using super with implicit arguments' do
|
50
50
|
'def simple(*args); super; end'.should_not smell_of(UnusedParameters)
|
51
51
|
end
|
52
52
|
|
53
|
-
it '
|
53
|
+
it 'reports something when using super explicitely passing no arguments' do
|
54
54
|
'def simple(*args); super(); end'.should smell_of(UnusedParameters)
|
55
55
|
end
|
56
56
|
|
57
|
-
it '
|
57
|
+
it 'reports nothing when using super explicitely passing all arguments' do
|
58
58
|
'def simple(*args); super(*args); end'.should_not smell_of(UnusedParameters)
|
59
59
|
end
|
60
60
|
|
61
|
+
it 'reports nothing when using super in a nested context' do
|
62
|
+
'def simple(*args); call_other("something", super); end'.
|
63
|
+
should_not smell_of(UnusedParameters)
|
64
|
+
end
|
61
65
|
end
|
62
66
|
end
|
@@ -92,7 +92,7 @@ describe SexpExtensions::DefnNode do
|
|
92
92
|
|
93
93
|
it 'has a body extended with SexpNode' do
|
94
94
|
b = @node.body
|
95
|
-
(class << b; self; end).
|
95
|
+
(class << b; self; end).included_modules.first.should == SexpNode
|
96
96
|
end
|
97
97
|
end
|
98
98
|
end
|
@@ -186,7 +186,7 @@ describe SexpExtensions::DefsNode do
|
|
186
186
|
|
187
187
|
it 'has a body extended with SexpNode' do
|
188
188
|
b = @node.body
|
189
|
-
(class << b; self; end).
|
189
|
+
(class << b; self; end).included_modules.first.should == SexpNode
|
190
190
|
end
|
191
191
|
end
|
192
192
|
end
|