reek 1.3.4 → 1.3.5
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.
- checksums.yaml +4 -4
- data/CHANGELOG +5 -0
- data/README.md +27 -2
- data/features/command_line_interface/options.feature +5 -2
- data/features/command_line_interface/smells_count.feature +43 -45
- data/features/command_line_interface/stdin.feature +9 -15
- data/features/configuration_files/masking_smells.feature +9 -17
- data/features/rake_task/rake_task.feature +4 -4
- data/features/reports/reports.feature +80 -21
- data/features/samples.feature +8 -18
- data/features/step_definitions/reek_steps.rb +4 -0
- data/lib/reek/cli/application.rb +3 -6
- data/lib/reek/cli/command_line.rb +16 -6
- data/lib/reek/cli/reek_command.rb +4 -12
- data/lib/reek/cli/report.rb +61 -19
- data/lib/reek/config_file_exception.rb +5 -0
- data/lib/reek/smells/control_parameter.rb +45 -14
- data/lib/reek/smells/data_clump.rb +15 -39
- data/lib/reek/smells/duplicate_method_call.rb +76 -26
- data/lib/reek/source/config_file.rb +30 -19
- data/lib/reek/source/sexp_extensions.rb +139 -0
- data/lib/reek/source/sexp_node.rb +64 -0
- data/lib/reek/source/source_code.rb +1 -1
- data/lib/reek/source/tree_dresser.rb +30 -175
- data/lib/reek/spec/should_reek.rb +2 -5
- data/lib/reek/version.rb +1 -1
- data/reek.gemspec +1 -1
- data/spec/matchers/smell_of_matcher.rb +12 -15
- data/spec/reek/cli/report_spec.rb +10 -6
- data/spec/reek/core/code_parser_spec.rb +0 -6
- data/spec/reek/smells/control_parameter_spec.rb +195 -8
- data/spec/reek/smells/data_clump_spec.rb +28 -3
- data/spec/reek/smells/uncommunicative_method_name_spec.rb +7 -7
- data/spec/reek/source/sexp_extensions_spec.rb +290 -0
- data/spec/reek/source/sexp_node_spec.rb +28 -0
- data/spec/reek/source/source_code_spec.rb +59 -19
- data/spec/reek/source/tree_dresser_spec.rb +7 -314
- data/spec/reek/spec/should_reek_spec.rb +51 -64
- data/spec/samples/all_but_one_masked/dirty.rb +2 -2
- data/spec/samples/corrupt_config_file/dirty.rb +1 -0
- data/spec/samples/masked/dirty.rb +1 -1
- data/spec/samples/masked_by_dotfile/dirty.rb +2 -2
- data/spec/samples/no_config_file/dirty.rb +8 -0
- data/spec/samples/not_quite_masked/dirty.rb +0 -3
- data/spec/samples/three_smelly_files/dirty_one.rb +3 -0
- data/spec/samples/three_smelly_files/dirty_three.rb +5 -0
- data/spec/samples/three_smelly_files/dirty_two.rb +4 -0
- data/spec/spec_helper.rb +5 -0
- metadata +145 -137
- data/spec/reek/cli/reek_command_spec.rb +0 -46
@@ -8,11 +8,8 @@ module Reek
|
|
8
8
|
# An rspec matcher that matches when the +actual+ has code smells.
|
9
9
|
#
|
10
10
|
class ShouldReek # :nodoc:
|
11
|
-
def initialize(config_files = [])
|
12
|
-
@config_files = config_files
|
13
|
-
end
|
14
11
|
def matches?(actual)
|
15
|
-
@examiner = Examiner.new(actual
|
12
|
+
@examiner = Examiner.new(actual)
|
16
13
|
@examiner.smelly?
|
17
14
|
end
|
18
15
|
def failure_message_for_should
|
@@ -28,7 +25,7 @@ module Reek
|
|
28
25
|
# Returns +true+ if and only if the target source code contains smells.
|
29
26
|
#
|
30
27
|
def reek
|
31
|
-
ShouldReek.new
|
28
|
+
ShouldReek.new
|
32
29
|
end
|
33
30
|
end
|
34
31
|
end
|
data/lib/reek/version.rb
CHANGED
data/reek.gemspec
CHANGED
@@ -28,7 +28,7 @@ and reports any code smells it finds.
|
|
28
28
|
|
29
29
|
s.add_runtime_dependency(%q<ruby_parser>, ["~> 3.2"])
|
30
30
|
s.add_runtime_dependency(%q<sexp_processor>)
|
31
|
-
s.add_runtime_dependency(%q<ruby2ruby>, ["~> 2.0.
|
31
|
+
s.add_runtime_dependency(%q<ruby2ruby>, ["~> 2.0.7"])
|
32
32
|
|
33
33
|
s.add_development_dependency(%q<bundler>, ["~> 1.1"])
|
34
34
|
s.add_development_dependency(%q<rake>)
|
@@ -20,7 +20,6 @@ module SmellOfMatcher
|
|
20
20
|
detect_smells
|
21
21
|
|
22
22
|
return false if no_smells_found?
|
23
|
-
return false if wrong_smell_class_found?
|
24
23
|
return false if wrong_number_of_smells_found?
|
25
24
|
return false if wrong_smell_details_found?
|
26
25
|
|
@@ -48,25 +47,23 @@ module SmellOfMatcher
|
|
48
47
|
end
|
49
48
|
end
|
50
49
|
|
51
|
-
def wrong_smell_class_found?
|
52
|
-
@actual_smells.each do |smell|
|
53
|
-
if smell.smell_class != @klass::SMELL_CLASS ||
|
54
|
-
smell.subclass != @klass::SMELL_SUBCLASS
|
55
|
-
@reason = "Found #{smell.smell_class}/#{smell.subclass}"
|
56
|
-
return true
|
57
|
-
end
|
58
|
-
end
|
59
|
-
false
|
60
|
-
end
|
61
|
-
|
62
50
|
def wrong_number_of_smells_found?
|
63
|
-
|
64
|
-
|
65
|
-
|
51
|
+
return false if @expected_smells.empty?
|
52
|
+
|
53
|
+
if expected_number_of_smells != actual_number_of_smells
|
54
|
+
@reason = "expected #{expected_number_of_smells} smell(s), found #{actual_number_of_smells}"
|
66
55
|
true
|
67
56
|
end
|
68
57
|
end
|
69
58
|
|
59
|
+
def expected_number_of_smells
|
60
|
+
@expected_number_of_smells ||= @expected_smells.length
|
61
|
+
end
|
62
|
+
|
63
|
+
def actual_number_of_smells
|
64
|
+
@actual_number_of_smells ||= @actual_smells.length
|
65
|
+
end
|
66
|
+
|
70
67
|
def wrong_smell_details_found?
|
71
68
|
@expected_smells.zip(@actual_smells).each do |expected_smell, actual_smell|
|
72
69
|
expected_smell.each do |key, value|
|
@@ -9,7 +9,9 @@ describe QuietReport, " when empty" do
|
|
9
9
|
context 'empty source' do
|
10
10
|
it 'has an empty quiet_report' do
|
11
11
|
examiner = Examiner.new('')
|
12
|
-
QuietReport.new
|
12
|
+
qr = QuietReport.new
|
13
|
+
qr.add_examiner(examiner)
|
14
|
+
qr.gather_results.should == []
|
13
15
|
end
|
14
16
|
end
|
15
17
|
|
@@ -17,14 +19,16 @@ describe QuietReport, " when empty" do
|
|
17
19
|
before :each do
|
18
20
|
examiner = Examiner.new('def simple(a) a[3] end')
|
19
21
|
rpt = QuietReport.new
|
20
|
-
@
|
22
|
+
@result = rpt.add_examiner(examiner).gather_results.first
|
21
23
|
end
|
22
|
-
|
23
|
-
|
24
|
+
|
25
|
+
it 'has a header' do
|
26
|
+
@result.should match('string -- 2 warnings')
|
24
27
|
end
|
28
|
+
|
25
29
|
it 'should mention every smell name' do
|
26
|
-
@
|
27
|
-
@
|
30
|
+
@result.should match('[UncommunicativeParameterName]')
|
31
|
+
@result.should match('[Feature Envy]')
|
28
32
|
end
|
29
33
|
end
|
30
34
|
end
|
@@ -12,22 +12,209 @@ describe ControlParameter do
|
|
12
12
|
|
13
13
|
it_should_behave_like 'SmellDetector'
|
14
14
|
|
15
|
-
|
15
|
+
it 'should not report a ternary check on an ivar' do
|
16
|
+
src = 'def simple(arga) @ivar ? arga : 3 end'
|
17
|
+
src.should_not smell_of(ControlParameter)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should not report a ternary check on a lvar' do
|
21
|
+
src = 'def simple(arga) lvar = 27; lvar ? arga : @ivar end'
|
22
|
+
src.should_not smell_of(ControlParameter)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should not report when parameter is unused' do
|
26
|
+
src = 'def simple(arg) test = 1 end'
|
27
|
+
src.should_not smell_of(ControlParameter)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should not report when parameter is used inside conditional' do
|
31
|
+
src = 'def simple(arg) if true then puts arg end end'
|
32
|
+
src.should_not smell_of(ControlParameter)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should not report when used in first conditional but not second' do
|
36
|
+
src = <<EOS
|
37
|
+
def things(arg)
|
38
|
+
if arg
|
39
|
+
puts arg
|
40
|
+
end
|
41
|
+
if arg
|
42
|
+
puts 'a'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
EOS
|
46
|
+
src.should_not smell_of(ControlParameter)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should not report when used in second conditional but not first' do
|
50
|
+
src = <<EOS
|
51
|
+
def things(arg)
|
52
|
+
if arg
|
53
|
+
puts 'a'
|
54
|
+
end
|
55
|
+
if arg
|
56
|
+
puts arg
|
57
|
+
end
|
58
|
+
end
|
59
|
+
EOS
|
60
|
+
src.should_not smell_of(ControlParameter)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'should not report on complex non smelly method' do
|
64
|
+
src = <<EOS
|
65
|
+
def self.guess(arg)
|
66
|
+
case arg
|
67
|
+
when ""
|
68
|
+
t = self
|
69
|
+
when "a"
|
70
|
+
t = Switch::OptionalArgument
|
71
|
+
when "b"
|
72
|
+
t = Switch::PlacedArgument
|
73
|
+
else
|
74
|
+
t = Switch::RequiredArgument
|
75
|
+
end
|
76
|
+
self >= t or incompatible_argument_styles(arg, t)
|
77
|
+
t
|
78
|
+
end
|
79
|
+
EOS
|
80
|
+
src.should_not smell_of(ControlParameter)
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'parameter only used to determine code path' do
|
16
84
|
it 'should report a ternary check on a parameter' do
|
17
85
|
src = 'def simple(arga) arga ? @ivar : 3 end'
|
18
86
|
src.should smell_of(ControlParameter, ControlParameter::PARAMETER_KEY => 'arga')
|
19
87
|
end
|
20
|
-
|
21
|
-
|
88
|
+
|
89
|
+
it 'should spot a couple inside a block' do
|
90
|
+
src = 'def blocks(arg) @text.map { |blk| arg ? blk : "#{blk}" } end'
|
91
|
+
src.should smell_of(ControlParameter, ControlParameter::PARAMETER_KEY => 'arg')
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should report on an if statement modifier' do
|
95
|
+
src = 'def simple(arg) args = {}; args.merge(\'a\' => \'A\') if arg end'
|
96
|
+
src.should smell_of(ControlParameter, ControlParameter::PARAMETER_KEY => 'arg')
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'should report on an unless statement modifier' do
|
100
|
+
src = 'def simple(arg) args = {}; args.merge(\'a\' => \'A\') unless arg end'
|
101
|
+
src.should smell_of(ControlParameter, ControlParameter::PARAMETER_KEY => 'arg')
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should report on if control expression' do
|
105
|
+
src = 'def simple(arg) args = {}; if arg then args.merge(\'a\' => \'A\') end end'
|
106
|
+
src.should smell_of(ControlParameter, ControlParameter::PARAMETER_KEY => 'arg')
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should report on if control expression with &&' do
|
110
|
+
src = 'def simple(arg) if arg && true then puts "arg" end end'
|
111
|
+
src.should smell_of(ControlParameter, ControlParameter::PARAMETER_KEY => 'arg')
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'should report on if control expression with preceding &&' do
|
115
|
+
src = 'def simple(arg) if true && arg then puts "arg" end end'
|
116
|
+
src.should smell_of(ControlParameter, ControlParameter::PARAMETER_KEY => 'arg')
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should report on if control expression with two && conditions' do
|
120
|
+
src = 'def simple(a) ag = {}; if a && true && true then puts "2" end end'
|
121
|
+
src.should smell_of(ControlParameter, ControlParameter::PARAMETER_KEY => 'a')
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should report on if control expression with ||' do
|
125
|
+
src = 'def simple(arg) args = {}; if arg || true then puts "arg" end end'
|
126
|
+
src.should smell_of(ControlParameter, ControlParameter::PARAMETER_KEY => 'arg')
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should report on if control expression with or' do
|
130
|
+
src = 'def simple(arg) args = {}; if arg or true then puts "arg" end end'
|
131
|
+
src.should smell_of(ControlParameter, ControlParameter::PARAMETER_KEY => 'arg')
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should report on && notation' do
|
135
|
+
src = 'def simple(arg) args = {}; arg && args.merge(\'a\' => \'A\') end'
|
136
|
+
src.should smell_of(ControlParameter, ControlParameter::PARAMETER_KEY => 'arg')
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should report on || notation' do
|
140
|
+
src = 'def simple(arg) args = {}; arg || args.merge(\'a\' => \'A\') end'
|
141
|
+
src.should smell_of(ControlParameter, ControlParameter::PARAMETER_KEY => 'arg')
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'should report on case statement' do
|
145
|
+
src = 'def simple(arg) case arg when nil; nil when false; nil else nil end end'
|
146
|
+
src.should smell_of(ControlParameter, ControlParameter::PARAMETER_KEY => 'arg')
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'should report when the argument is a hash on which we access a key' do
|
150
|
+
src = 'def simple(arg) if arg[\'a\'] then puts \'a\' else puts \'b\' end end'
|
151
|
+
src.should smell_of(ControlParameter, ControlParameter::PARAMETER_KEY => 'arg')
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should report on nested if statements that are both control parameters' do
|
155
|
+
src = <<EOS
|
156
|
+
def nested(arg)
|
157
|
+
if arg
|
158
|
+
puts 'a'
|
159
|
+
puts 'b' if arg
|
160
|
+
end
|
161
|
+
end
|
162
|
+
EOS
|
163
|
+
src.should smell_of(ControlParameter, ControlParameter::PARAMETER_KEY => 'arg')
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'should report on nested if statements where the inner if is a control parameter' do
|
167
|
+
src = <<EOS
|
168
|
+
def nested(arg)
|
169
|
+
if true
|
170
|
+
puts 'a'
|
171
|
+
puts 'b' if arg
|
172
|
+
end
|
173
|
+
end
|
174
|
+
EOS
|
175
|
+
src.should smell_of(ControlParameter, ControlParameter::PARAMETER_KEY => 'arg')
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
context 'parameter used besides determining code path' do
|
180
|
+
it 'should not report on if conditional expression' do
|
181
|
+
src = 'def simple(arg) if arg then use(arg) else use(@other) end end'
|
22
182
|
src.should_not smell_of(ControlParameter)
|
23
183
|
end
|
24
|
-
|
25
|
-
|
184
|
+
|
185
|
+
it 'should not report on an if statement modifier' do
|
186
|
+
src = 'def simple(arg) args = {}; args.merge(\'a\' => arg) if arg end'
|
26
187
|
src.should_not smell_of(ControlParameter)
|
27
188
|
end
|
28
|
-
|
29
|
-
|
30
|
-
src
|
189
|
+
|
190
|
+
it 'should not report on an unless statement modifier' do
|
191
|
+
src = 'def simple(arg) args = {}; args.merge(\'a\' => arg) unless arg end'
|
192
|
+
src.should_not smell_of(ControlParameter)
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'should not report on if control expression' do
|
196
|
+
src = 'def simple(arg) args = {}; if arg then args.merge(\'a\' => arg) end end'
|
197
|
+
src.should_not smell_of(ControlParameter)
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'should not report on if control expression with &&' do
|
201
|
+
src = 'def simple(arg) if arg && true then puts arg end end'
|
202
|
+
src.should_not smell_of(ControlParameter)
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'should not report on && notation' do
|
206
|
+
src = 'def simple(arg) args = {}; arg && args.merge(\'a\' => arg) end'
|
207
|
+
src.should_not smell_of(ControlParameter)
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'should not report on || notation' do
|
211
|
+
src = 'def simple(arg) args = {}; arg || args.merge(\'a\' => arg) end'
|
212
|
+
src.should_not smell_of(ControlParameter)
|
213
|
+
end
|
214
|
+
|
215
|
+
it 'should not report when parameter is used outside conditional' do
|
216
|
+
src = 'def simple(arg) puts arg; if arg then @a = 1 end end'
|
217
|
+
src.should_not smell_of(ControlParameter)
|
31
218
|
end
|
32
219
|
end
|
33
220
|
|
@@ -42,7 +42,7 @@ EOS
|
|
42
42
|
it 'reports the number of occurrences' do
|
43
43
|
@smells[0].smell[DataClump::OCCURRENCES_KEY].should == 3
|
44
44
|
end
|
45
|
-
it 'reports all
|
45
|
+
it 'reports all methods' do
|
46
46
|
@smells[0].smell[DataClump::METHODS_KEY].should == ['first', 'second', 'third']
|
47
47
|
end
|
48
48
|
it 'reports the declaration line numbers' do
|
@@ -56,7 +56,7 @@ EOS
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
-
it 'reports 3 swapped pairs
|
59
|
+
it 'reports 3 swapped pairs' do
|
60
60
|
src = <<EOS
|
61
61
|
#{@context} Scrunch
|
62
62
|
def one(pa, pb) @field == :sym ? 0 : 3; end
|
@@ -68,7 +68,7 @@ EOS
|
|
68
68
|
DataClump::PARAMETERS_KEY => ['pa', 'pb']})
|
69
69
|
end
|
70
70
|
|
71
|
-
it 'reports 3 identical parameter sets
|
71
|
+
it 'reports 3 identical parameter sets' do
|
72
72
|
src = <<EOS
|
73
73
|
#{@context} Scrunch
|
74
74
|
def first(pa, pb, pc) @field == :sym ? 0 : 3; end
|
@@ -115,6 +115,31 @@ end
|
|
115
115
|
EOS
|
116
116
|
src.should smell_of(DataClump, DataClump::OCCURRENCES_KEY => 5)
|
117
117
|
end
|
118
|
+
|
119
|
+
it 'correctly checks number of occurences' do
|
120
|
+
src = <<-EOS
|
121
|
+
#{@context} Smelly
|
122
|
+
def fa(p1, p2, p3) end
|
123
|
+
def fb(p2, p3, p4) end
|
124
|
+
def fc(p3, p4, p5) end
|
125
|
+
def fd(p4, p5, p1) end
|
126
|
+
def fe(p5, p1, p2) end
|
127
|
+
end
|
128
|
+
EOS
|
129
|
+
src.should_not smell_of(DataClump)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'detects clumps smaller than the total number of arguments' do
|
133
|
+
src = <<-EOS
|
134
|
+
#{@context} Smelly
|
135
|
+
def fa(p1, p2, p3) end
|
136
|
+
def fb(p1, p3, p2) end
|
137
|
+
def fc(p4, p1, p2) end
|
138
|
+
end
|
139
|
+
EOS
|
140
|
+
src.should smell_of(DataClump,
|
141
|
+
{ DataClump::PARAMETERS_KEY => %w(p1 p2) })
|
142
|
+
end
|
118
143
|
end
|
119
144
|
|
120
145
|
describe DataClump do
|
@@ -23,19 +23,19 @@ describe UncommunicativeMethodName do
|
|
23
23
|
|
24
24
|
['x', 'x2', 'method2'].each do |method_name|
|
25
25
|
context 'with a bad name' do
|
26
|
-
before
|
27
|
-
src =
|
26
|
+
before do
|
27
|
+
src = "def #{method_name}; end"
|
28
28
|
ctx = CodeContext.new(nil, src.to_reek_source.syntax_tree)
|
29
|
-
|
30
|
-
@warning =
|
29
|
+
smells = @detector.examine_context(ctx)
|
30
|
+
@warning = smells[0]
|
31
31
|
end
|
32
32
|
|
33
33
|
it_should_behave_like 'common fields set correctly'
|
34
34
|
|
35
35
|
it 'reports the correct values' do
|
36
|
-
@
|
37
|
-
@
|
38
|
-
@
|
36
|
+
@warning.smell[UncommunicativeMethodName::METHOD_NAME_KEY].should == method_name
|
37
|
+
@warning.lines.should == [1]
|
38
|
+
@warning.context.should == method_name
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -0,0 +1,290 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'reek/source/sexp_extensions'
|
3
|
+
|
4
|
+
include Reek::Source
|
5
|
+
|
6
|
+
describe SexpExtensions::DefnNode do
|
7
|
+
context 'with no parameters' do
|
8
|
+
before :each do
|
9
|
+
@node = s(:defn, :hello, s(:args))
|
10
|
+
@node.extend(SexpExtensions::DefnNode)
|
11
|
+
end
|
12
|
+
it 'has no arg names' do
|
13
|
+
@node.arg_names.should == s()
|
14
|
+
end
|
15
|
+
it 'has no parameter names' do
|
16
|
+
@node.parameter_names.should == s()
|
17
|
+
end
|
18
|
+
it 'includes outer scope in its full name' do
|
19
|
+
@node.full_name('Fred').should == 'Fred#hello'
|
20
|
+
end
|
21
|
+
it 'includes no marker in its full name with empty outer scope' do
|
22
|
+
@node.full_name('').should == 'hello'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'with 1 parameter' do
|
27
|
+
before :each do
|
28
|
+
@node = s(:defn, :hello, s(:args, :param))
|
29
|
+
@node.extend(SexpExtensions::DefnNode)
|
30
|
+
end
|
31
|
+
it 'has 1 arg name' do
|
32
|
+
@node.arg_names.should == s(:param)
|
33
|
+
end
|
34
|
+
it 'has 1 parameter name' do
|
35
|
+
@node.parameter_names.should == s(:param)
|
36
|
+
end
|
37
|
+
it 'includes outer scope in its full name' do
|
38
|
+
@node.full_name('Fred').should == 'Fred#hello'
|
39
|
+
end
|
40
|
+
it 'includes no marker in its full name with empty outer scope' do
|
41
|
+
@node.full_name('').should == 'hello'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with a block' do
|
46
|
+
before :each do
|
47
|
+
@node = s(:defn, :hello, s(:args, :param, :"&blk"))
|
48
|
+
@node.extend(SexpExtensions::DefnNode)
|
49
|
+
end
|
50
|
+
it 'has 1 arg name' do
|
51
|
+
@node.arg_names.should == s(:param)
|
52
|
+
end
|
53
|
+
it 'has 2 parameter names' do
|
54
|
+
@node.parameter_names.should == s(:param, :"&blk")
|
55
|
+
end
|
56
|
+
it 'includes outer scope in its full name' do
|
57
|
+
@node.full_name('Fred').should == 'Fred#hello'
|
58
|
+
end
|
59
|
+
it 'includes no marker in its full name with empty outer scope' do
|
60
|
+
@node.full_name('').should == 'hello'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'with 1 defaulted parameter' do
|
65
|
+
before :each do
|
66
|
+
@node = s(:defn, :hello, s(:args, s(:lasgn, :param, s(:array))))
|
67
|
+
@node.extend(SexpExtensions::DefnNode)
|
68
|
+
end
|
69
|
+
it 'has 1 arg name' do
|
70
|
+
@node.arg_names.should == s(:param)
|
71
|
+
end
|
72
|
+
it 'has 1 parameter name' do
|
73
|
+
@node.parameter_names.should == s(:param)
|
74
|
+
end
|
75
|
+
it 'includes outer scope in its full name' do
|
76
|
+
@node.full_name('Fred').should == 'Fred#hello'
|
77
|
+
end
|
78
|
+
it 'includes no marker in its full name with empty outer scope' do
|
79
|
+
@node.full_name('').should == 'hello'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'with a body with 2 statements' do
|
84
|
+
before :each do
|
85
|
+
@node = s(:defn, :hello, s(:args), s(:first), s(:second))
|
86
|
+
@node.extend(SexpExtensions::DefnNode)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'has 2 body statements' do
|
90
|
+
@node.body.should == s(s(:first), s(:second))
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'has a body extended with SexpNode' do
|
94
|
+
b = @node.body
|
95
|
+
(class << b; self; end).ancestors.first.should == SexpNode
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe SexpExtensions::DefsNode do
|
101
|
+
context 'with no parameters' do
|
102
|
+
before :each do
|
103
|
+
@node = s(:defs, :obj, :hello, s(:args))
|
104
|
+
@node.extend(SexpExtensions::DefsNode)
|
105
|
+
end
|
106
|
+
it 'has no arg names' do
|
107
|
+
@node.arg_names.should == s()
|
108
|
+
end
|
109
|
+
it 'has no parameter names' do
|
110
|
+
@node.parameter_names.should == s()
|
111
|
+
end
|
112
|
+
it 'includes outer scope in its full name' do
|
113
|
+
@node.full_name('Fred').should == 'Fred#obj.hello'
|
114
|
+
end
|
115
|
+
it 'includes no marker in its full name with empty outer scope' do
|
116
|
+
@node.full_name('').should == 'obj.hello'
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'with 1 parameter' do
|
121
|
+
before :each do
|
122
|
+
@node = s(:defs, :obj, :hello, s(:args, :param))
|
123
|
+
@node.extend(SexpExtensions::DefsNode)
|
124
|
+
end
|
125
|
+
it 'has 1 arg name' do
|
126
|
+
@node.arg_names.should == s(:param)
|
127
|
+
end
|
128
|
+
it 'has 1 parameter name' do
|
129
|
+
@node.parameter_names.should == s(:param)
|
130
|
+
end
|
131
|
+
it 'includes outer scope in its full name' do
|
132
|
+
@node.full_name('Fred').should == 'Fred#obj.hello'
|
133
|
+
end
|
134
|
+
it 'includes no marker in its full name with empty outer scope' do
|
135
|
+
@node.full_name('').should == 'obj.hello'
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'with a block' do
|
140
|
+
before :each do
|
141
|
+
@node = s(:defs, :obj, :hello, s(:args, :param, :"&blk"))
|
142
|
+
@node.extend(SexpExtensions::DefsNode)
|
143
|
+
end
|
144
|
+
it 'has 1 arg name' do
|
145
|
+
@node.arg_names.should == s(:param)
|
146
|
+
end
|
147
|
+
it 'has 2 parameter names' do
|
148
|
+
@node.parameter_names.should == s(:param, :"&blk")
|
149
|
+
end
|
150
|
+
it 'includes outer scope in its full name' do
|
151
|
+
@node.full_name('Fred').should == 'Fred#obj.hello'
|
152
|
+
end
|
153
|
+
it 'includes no marker in its full name with empty outer scope' do
|
154
|
+
@node.full_name('').should == 'obj.hello'
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
context 'with 1 defaulted parameter' do
|
159
|
+
before :each do
|
160
|
+
@node = s(:defs, :obj, :hello, s(:args, s(:lasgn, :param, s(:array))))
|
161
|
+
@node.extend(SexpExtensions::DefsNode)
|
162
|
+
end
|
163
|
+
it 'has 1 arg name' do
|
164
|
+
@node.arg_names.should == s(:param)
|
165
|
+
end
|
166
|
+
it 'has 1 parameter name' do
|
167
|
+
@node.parameter_names.should == s(:param)
|
168
|
+
end
|
169
|
+
it 'includes outer scope in its full name' do
|
170
|
+
@node.full_name('Fred').should == 'Fred#obj.hello'
|
171
|
+
end
|
172
|
+
it 'includes no marker in its full name with empty outer scope' do
|
173
|
+
@node.full_name('').should == 'obj.hello'
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'with a body with 2 statements' do
|
178
|
+
before :each do
|
179
|
+
@node = s(:defs, s(:self), :hello, s(:args), s(:first), s(:second))
|
180
|
+
@node.extend(SexpExtensions::DefsNode)
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'has 2 body statements' do
|
184
|
+
@node.body.should == s(s(:first), s(:second))
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'has a body extended with SexpNode' do
|
188
|
+
b = @node.body
|
189
|
+
(class << b; self; end).ancestors.first.should == SexpNode
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
describe SexpExtensions::CallNode do
|
195
|
+
context 'with no parameters' do
|
196
|
+
before :each do
|
197
|
+
@node = s(:call, nil, :hello)
|
198
|
+
@node.extend(SexpExtensions::CallNode)
|
199
|
+
end
|
200
|
+
it 'has no parameter names' do
|
201
|
+
@node.parameter_names.should == nil
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
context 'with 1 literal parameter' do
|
206
|
+
before :each do
|
207
|
+
@node = s(:call, nil, :hello, s(:lit, :param))
|
208
|
+
@node.extend(SexpExtensions::CallNode)
|
209
|
+
end
|
210
|
+
it 'has 1 argument name' do
|
211
|
+
@node.arg_names.should == [:param]
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context 'with 2 literal parameters' do
|
216
|
+
before :each do
|
217
|
+
@node = s(:call, nil, :hello, s(:lit, :x), s(:lit, :y))
|
218
|
+
@node.extend(SexpExtensions::CallNode)
|
219
|
+
end
|
220
|
+
it 'has 2 argument names' do
|
221
|
+
@node.arg_names.should == [:x, :y]
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
describe SexpExtensions::IterNode do
|
227
|
+
context 'with no parameters' do
|
228
|
+
before :each do
|
229
|
+
@node = s(:iter, s(), s(:args), s())
|
230
|
+
@node.extend(SexpExtensions::IterNode)
|
231
|
+
end
|
232
|
+
it 'has no parameter names' do
|
233
|
+
@node.parameter_names.should == []
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
context 'with 1 parameter' do
|
238
|
+
before :each do
|
239
|
+
@node = s(:iter, s(), s(:args, :param), s())
|
240
|
+
@node.extend(SexpExtensions::IterNode)
|
241
|
+
end
|
242
|
+
it 'has 1 parameter name' do
|
243
|
+
@node.parameter_names.should == s(:param)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
context 'with 2 parameters' do
|
248
|
+
before :each do
|
249
|
+
@node = s(:iter, s(), s(:args, :x, :y), s())
|
250
|
+
@node.extend(SexpExtensions::IterNode)
|
251
|
+
end
|
252
|
+
it 'has 2 parameter names' do
|
253
|
+
@node.parameter_names.should == [:x, :y]
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
describe SexpExtensions::ModuleNode do
|
259
|
+
context 'with a simple name' do
|
260
|
+
subject do
|
261
|
+
mod = ast(:module, :Fred, nil)
|
262
|
+
mod
|
263
|
+
end
|
264
|
+
its(:name) { should == :Fred }
|
265
|
+
its(:simple_name) { should == :Fred }
|
266
|
+
its(:text_name) { should == 'Fred' }
|
267
|
+
it 'has a simple full_name' do
|
268
|
+
subject.full_name('').should == 'Fred'
|
269
|
+
end
|
270
|
+
it 'has a fq full_name' do
|
271
|
+
subject.full_name('Blimey::O::Reilly').should == 'Blimey::O::Reilly::Fred'
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
context 'with a scoped name' do
|
276
|
+
subject do
|
277
|
+
mod = ast(:module, s(:colon2, s(:const, :Foo), :Bar), nil)
|
278
|
+
mod
|
279
|
+
end
|
280
|
+
its(:name) { should == s(:colon2, s(:const, :Foo), :Bar) }
|
281
|
+
its(:simple_name) { should == :Bar }
|
282
|
+
its(:text_name) { should == 'Foo::Bar' }
|
283
|
+
it 'has a simple full_name' do
|
284
|
+
subject.full_name('').should == 'Foo::Bar'
|
285
|
+
end
|
286
|
+
it 'has a fq full_name' do
|
287
|
+
subject.full_name('Blimey::O::Reilly').should == 'Blimey::O::Reilly::Foo::Bar'
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|