reek 0.3.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +20 -0
- data/README.txt +4 -80
- data/Rakefile +15 -4
- data/bin/reek +10 -16
- data/config/defaults.reek +53 -0
- data/lib/reek.rb +1 -21
- data/lib/reek/block_context.rb +37 -0
- data/lib/reek/class_context.rb +73 -0
- data/lib/reek/code_context.rb +47 -0
- data/lib/reek/code_parser.rb +204 -0
- data/lib/reek/exceptions.reek +13 -0
- data/lib/reek/if_context.rb +25 -0
- data/lib/reek/method_context.rb +85 -0
- data/lib/reek/module_context.rb +34 -0
- data/lib/reek/name.rb +42 -0
- data/lib/reek/object_refs.rb +3 -6
- data/lib/reek/options.rb +60 -40
- data/lib/reek/rake_task.rb +20 -29
- data/lib/reek/report.rb +16 -27
- data/lib/reek/sexp_formatter.rb +52 -0
- data/lib/reek/singleton_method_context.rb +27 -0
- data/lib/reek/smell_warning.rb +49 -0
- data/lib/reek/smells/control_couple.rb +21 -13
- data/lib/reek/smells/duplication.rb +23 -27
- data/lib/reek/smells/feature_envy.rb +18 -25
- data/lib/reek/smells/large_class.rb +32 -17
- data/lib/reek/smells/long_method.rb +24 -16
- data/lib/reek/smells/long_parameter_list.rb +25 -18
- data/lib/reek/smells/long_yield_list.rb +7 -9
- data/lib/reek/smells/nested_iterators.rb +13 -9
- data/lib/reek/smells/smell_detector.rb +66 -0
- data/lib/reek/smells/smells.rb +71 -10
- data/lib/reek/smells/uncommunicative_name.rb +49 -41
- data/lib/reek/smells/utility_function.rb +18 -18
- data/lib/reek/source.rb +116 -0
- data/lib/reek/spec.rb +146 -0
- data/lib/reek/stop_context.rb +62 -0
- data/lib/reek/yield_call_context.rb +14 -0
- data/reek.gemspec +42 -0
- data/spec/integration/reek_source_spec.rb +20 -0
- data/spec/{script_spec.rb → integration/script_spec.rb} +11 -24
- data/spec/reek/class_context_spec.rb +198 -0
- data/spec/reek/code_context_spec.rb +92 -0
- data/spec/reek/code_parser_spec.rb +44 -0
- data/spec/reek/config_spec.rb +42 -0
- data/spec/reek/if_context_spec.rb +17 -0
- data/spec/reek/method_context_spec.rb +52 -0
- data/spec/reek/module_context_spec.rb +38 -0
- data/spec/reek/options_spec.rb +2 -28
- data/spec/reek/report_spec.rb +6 -40
- data/spec/reek/sexp_formatter_spec.rb +31 -0
- data/spec/reek/singleton_method_context_spec.rb +17 -0
- data/spec/reek/smells/control_couple_spec.rb +10 -18
- data/spec/reek/smells/duplication_spec.rb +53 -32
- data/spec/reek/smells/feature_envy_spec.rb +87 -49
- data/spec/reek/smells/large_class_spec.rb +45 -4
- data/spec/reek/smells/long_method_spec.rb +25 -41
- data/spec/reek/smells/long_parameter_list_spec.rb +30 -76
- data/spec/reek/smells/nested_iterators_spec.rb +19 -29
- data/spec/reek/smells/smell_spec.rb +9 -18
- data/spec/reek/smells/uncommunicative_name_spec.rb +88 -53
- data/spec/reek/smells/utility_function_spec.rb +45 -44
- data/spec/samples/inline_spec.rb +40 -0
- data/spec/samples/optparse_spec.rb +100 -0
- data/spec/samples/redcloth_spec.rb +93 -0
- data/spec/spec_helper.rb +3 -1
- data/tasks/reek.rake +1 -10
- data/tasks/rspec.rake +16 -35
- metadata +43 -46
- data/lib/reek/checker.rb +0 -66
- data/lib/reek/class_checker.rb +0 -25
- data/lib/reek/file_checker.rb +0 -20
- data/lib/reek/method_checker.rb +0 -198
- data/lib/reek/printer.rb +0 -154
- data/lib/reek/smells/smell.rb +0 -56
- data/lib/reek/version.rb +0 -9
- data/setup.rb +0 -1585
- data/spec/integration_spec.rb +0 -30
- data/spec/reek/class_checker_spec.rb +0 -48
- data/spec/reek/method_checker_spec.rb +0 -67
- data/spec/reek/printer_spec.rb +0 -30
- data/spec/reek_source_spec.rb +0 -12
- data/spec/samples/inline.reek +0 -27
- data/spec/samples/optparse.reek +0 -79
- data/spec/samples/optparse/date.rb +0 -17
- data/spec/samples/optparse/shellwords.rb +0 -6
- data/spec/samples/optparse/time.rb +0 -10
- data/spec/samples/optparse/uri.rb +0 -6
- data/spec/samples/optparse/version.rb +0 -70
- data/spec/samples/redcloth.reek +0 -65
- data/tasks/samples.rake +0 -17
- data/website/index.html +0 -71
- data/website/index.txt +0 -40
- data/website/javascripts/rounded_corners_lite.inc.js +0 -285
- data/website/stylesheets/screen.css +0 -138
- data/website/template.rhtml +0 -48
@@ -1,13 +1,11 @@
|
|
1
|
-
require
|
2
|
-
|
3
|
-
require 'reek/version'
|
1
|
+
require 'reek'
|
4
2
|
|
5
3
|
describe 'version number' do
|
6
4
|
it 'should report the correct value' do
|
7
5
|
actual = `ruby -Ilib bin/reek --version`.split
|
8
6
|
$?.exitstatus.should == 0
|
9
7
|
actual[0].should == 'reek'
|
10
|
-
actual[1].should == Reek::VERSION
|
8
|
+
actual[1].should == Reek::VERSION
|
11
9
|
end
|
12
10
|
end
|
13
11
|
|
@@ -17,51 +15,40 @@ describe 'exit status', 'when reek is used incorrectly' do
|
|
17
15
|
$?.exitstatus.should == 1
|
18
16
|
end
|
19
17
|
|
20
|
-
it 'should
|
21
|
-
`ruby -Ilib bin/reek nosuchfile.rb
|
22
|
-
$?.exitstatus.should ==
|
18
|
+
it 'should complain about missing file' do
|
19
|
+
`ruby -Ilib bin/reek nosuchfile.rb`
|
20
|
+
$?.exitstatus.should == 1
|
23
21
|
end
|
24
22
|
|
25
23
|
it 'should return non-zero status on missing argument' do
|
26
|
-
`ruby -Ilib bin/reek -
|
24
|
+
`ruby -Ilib bin/reek -f 2>/dev/null`
|
27
25
|
$?.exitstatus.should == 1
|
28
26
|
end
|
29
|
-
|
30
|
-
it 'should not complain when no source given' do
|
31
|
-
`ruby -Ilib bin/reek 2>/dev/null`
|
32
|
-
$?.exitstatus.should == 0
|
33
|
-
end
|
34
27
|
end
|
35
28
|
|
36
29
|
describe 'exit status', 'when reek is used correctly' do
|
37
30
|
it 'should return non-zero status when smells are reported' do
|
38
|
-
`
|
31
|
+
`echo "def x() 3; end" | ruby -Ilib bin/reek`
|
39
32
|
$?.exitstatus.should == 2
|
40
33
|
end
|
41
34
|
|
42
35
|
it 'should return zero status with no smells' do
|
43
|
-
`
|
36
|
+
`echo "def simple() @fred = 3 end" | ruby -Ilib bin/reek`
|
44
37
|
$?.exitstatus.should == 0
|
45
38
|
end
|
46
39
|
end
|
47
40
|
|
48
|
-
describe 'report format', 'with no sources' do
|
49
|
-
it 'should output nothing' do
|
50
|
-
`ruby -Ilib bin/reek`.should be_empty
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
41
|
describe 'report format', 'with one source' do
|
55
42
|
it 'should output nothing with empty source' do
|
56
|
-
`ruby -Ilib bin/reek
|
43
|
+
`echo "" | ruby -Ilib bin/reek`.should be_empty
|
57
44
|
end
|
58
45
|
|
59
46
|
it 'should output nothing when no smells' do
|
60
|
-
`
|
47
|
+
`echo "def simple() @fred = 3; end" | ruby -Ilib bin/reek`.should be_empty
|
61
48
|
end
|
62
49
|
|
63
50
|
it 'should not adorn the list of warnings' do
|
64
|
-
report = `
|
51
|
+
report = `echo "class Turn; def y() @x = 3; end end" | ruby -Ilib bin/reek`
|
65
52
|
report.split(/\n/).length.should == 2
|
66
53
|
report.should_not match(/\n\n/)
|
67
54
|
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
require 'reek/class_context'
|
4
|
+
require 'reek/stop_context'
|
5
|
+
require 'reek/smells/feature_envy'
|
6
|
+
|
7
|
+
include Reek
|
8
|
+
include Reek::Smells
|
9
|
+
|
10
|
+
describe ClassContext do
|
11
|
+
it 'should report Long Parameter List' do
|
12
|
+
ruby = 'class Inner; def simple(arga, argb, argc, argd) f(3);true end end'
|
13
|
+
ruby.should reek_of(:LongParameterList, /Inner/, /simple/, /4 parameters/)
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should report two different methods' do
|
17
|
+
src = <<EOEX
|
18
|
+
class Fred
|
19
|
+
def simple(arga, argb, argc, argd) f(3);true end
|
20
|
+
def simply(arga, argb, argc, argd) f(3);false end
|
21
|
+
end
|
22
|
+
EOEX
|
23
|
+
src.should reek_of(:LongParameterList, /Fred/, /simple/)
|
24
|
+
src.should reek_of(:LongParameterList, /Fred/, /simply/)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should report many different methods' do
|
28
|
+
src = <<EOEX
|
29
|
+
class Fred
|
30
|
+
def textile_bq(tag, atts, cite, content) f(3);end
|
31
|
+
def textile_p(tag, atts, cite, content) f(3);end
|
32
|
+
def textile_fn_(tag, num, atts, cite, content) f(3);end
|
33
|
+
def textile_popup_help(name, windowW, windowH) f(3);end
|
34
|
+
end
|
35
|
+
EOEX
|
36
|
+
src.should reek_of(:LongParameterList, /Fred/, /textile_bq/)
|
37
|
+
src.should reek_of(:LongParameterList, /Fred/, /textile_fn_/)
|
38
|
+
src.should reek_of(:LongParameterList, /Fred/, /textile_p/)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe Class do
|
43
|
+
|
44
|
+
module Insert
|
45
|
+
def meth_a() end
|
46
|
+
private
|
47
|
+
def meth_b() end
|
48
|
+
protected
|
49
|
+
def meth_c() end
|
50
|
+
end
|
51
|
+
|
52
|
+
class Parent
|
53
|
+
def meth1() end
|
54
|
+
private
|
55
|
+
def meth2() end
|
56
|
+
protected
|
57
|
+
def meth3() end
|
58
|
+
end
|
59
|
+
|
60
|
+
class FullChild < Parent
|
61
|
+
include Insert
|
62
|
+
def meth7() end
|
63
|
+
private
|
64
|
+
def meth8() end
|
65
|
+
protected
|
66
|
+
def meth6() end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe 'with no superclass or modules' do
|
70
|
+
it 'should report correct number of methods' do
|
71
|
+
Parent.non_inherited_methods.length.should == 3
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe 'with superclass and modules' do
|
76
|
+
it 'should report correct number of methods' do
|
77
|
+
FullChild.non_inherited_methods.length.should == 3
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe ClassContext, 'overridden methods' do
|
83
|
+
class Above
|
84
|
+
def above() end
|
85
|
+
def both() end
|
86
|
+
end
|
87
|
+
|
88
|
+
class Below < Above
|
89
|
+
def both() end
|
90
|
+
def below() end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe 'of loaded class' do
|
94
|
+
before :each do
|
95
|
+
@ctx = ClassContext.create(StopContext.new, [0, :Below])
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should recognise non-overridden method' do
|
99
|
+
@ctx.is_overriding_method?('below').should == false
|
100
|
+
@ctx.is_overriding_method?('above').should == false
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should recognise overridden method' do
|
104
|
+
@ctx.is_overriding_method?('both').should == true
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should recognise methods in current codebase' do
|
108
|
+
ctx = ClassContext.create(StopContext.new, [0, :FeatureEnvy])
|
109
|
+
ctx.is_overriding_method?('examine_context').should == true
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe 'of non-loaded class' do
|
114
|
+
before :each do
|
115
|
+
@ctx = ClassContext.create(StopContext.new, [0, :Missing])
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should recognise non-overridden method' do
|
119
|
+
@ctx.is_overriding_method?('below').should == false
|
120
|
+
@ctx.is_overriding_method?('above').should == false
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should recognise overridden method' do
|
124
|
+
@ctx.is_overriding_method?('both').should == false
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe 'Integration defect:' do
|
130
|
+
it 'should not report UtilityFunction for FeatureEnvy#examine_context' do
|
131
|
+
kelement = ClassContext.create(StopContext.new, [0, :FeatureEnvy, s(:const, :SmellDetector)])
|
132
|
+
meth = Name.new(:examine_context)
|
133
|
+
kelement.is_overriding_method?(meth).should == true
|
134
|
+
melement = MethodContext.new(kelement, [0, :examine_context])
|
135
|
+
melement.is_overriding_method?(meth).should == true
|
136
|
+
melement.depends_on_instance?.should == true
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
describe CodeContext, 'find class' do
|
141
|
+
module Mod1
|
142
|
+
class Klass1
|
143
|
+
module Mod2
|
144
|
+
class Klass2
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
before :each do
|
151
|
+
@stop = StopContext.new
|
152
|
+
@mod1 = ModuleContext.create(@stop, [0, :Mod1])
|
153
|
+
@klass1 = ClassContext.create(@mod1, [0, :Klass1])
|
154
|
+
@mod2 = ModuleContext.create(@klass1, [0, :Mod2])
|
155
|
+
@klass2 = ClassContext.create(@mod2, [0, :Klass2])
|
156
|
+
end
|
157
|
+
|
158
|
+
describe StopContext do
|
159
|
+
it 'should not find unqualified class' do
|
160
|
+
@stop.find_module('Klass2').should == nil
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'should find unqualified module' do
|
164
|
+
@stop.find_module('Mod1').name.should == 'Mod1'
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe ModuleContext do
|
169
|
+
it 'should find local name' do
|
170
|
+
@mod1.find_module('Klass1').name.should == 'Mod1::Klass1'
|
171
|
+
@mod2.find_module('Klass2').name.should == 'Mod1::Klass1::Mod2::Klass2'
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'should not find deeper class' do
|
175
|
+
@mod1.find_module('Klass2').should == nil
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'should find own Module' do
|
179
|
+
@mod1.myself.name.should == 'Mod1'
|
180
|
+
@mod2.myself.name.should == 'Mod1::Klass1::Mod2'
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe ClassContext do
|
185
|
+
it 'should find local module' do
|
186
|
+
@klass1.find_module('Mod2').name.should == 'Mod1::Klass1::Mod2'
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'should not find deeper module' do
|
190
|
+
@klass1.find_module('Klass2').should == nil
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'should find own Class' do
|
194
|
+
@klass1.myself.name.should == 'Mod1::Klass1'
|
195
|
+
@klass2.myself.name.should == 'Mod1::Klass1::Mod2::Klass2'
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
require 'reek/block_context'
|
4
|
+
require 'reek/if_context'
|
5
|
+
require 'reek/class_context'
|
6
|
+
require 'reek/module_context'
|
7
|
+
require 'reek/method_context'
|
8
|
+
require 'reek/stop_context'
|
9
|
+
|
10
|
+
include Reek
|
11
|
+
|
12
|
+
describe CodeContext, 'to_s' do
|
13
|
+
|
14
|
+
it "should report full context" do
|
15
|
+
element = StopContext.new
|
16
|
+
element = ModuleContext.new(element, [0, :mod])
|
17
|
+
element = ClassContext.new(element, [0, :klass])
|
18
|
+
element = MethodContext.new(element, [0, :bad])
|
19
|
+
element = BlockContext.new(element, nil)
|
20
|
+
element.to_s.should match(/bad/)
|
21
|
+
element.to_s.should match(/klass/)
|
22
|
+
element.to_s.should match(/mod/)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should report method name via if context" do
|
26
|
+
element1 = StopContext.new
|
27
|
+
element2 = MethodContext.new(element1, [0, :bad])
|
28
|
+
element3 = IfContext.new(element2, [0,1])
|
29
|
+
BlockContext.new(element3, nil).to_s.should match(/bad/)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should report method name via nested blocks" do
|
33
|
+
element1 = StopContext.new
|
34
|
+
element2 = MethodContext.new(element1, [0, :bad])
|
35
|
+
element3 = BlockContext.new(element2, nil)
|
36
|
+
BlockContext.new(element3, nil).to_s.should match(/bad/)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe CodeContext, 'instance variables' do
|
41
|
+
it 'should pass instance variables down to the first class' do
|
42
|
+
element = StopContext.new
|
43
|
+
element = ModuleContext.new(element, [0, :mod])
|
44
|
+
class_element = ClassContext.new(element, [0, :klass])
|
45
|
+
element = MethodContext.new(class_element, [0, :bad])
|
46
|
+
element = BlockContext.new(element, nil)
|
47
|
+
element.record_instance_variable(:fred)
|
48
|
+
class_element.variable_names.should == [Name.new(:fred)]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe CodeContext, 'generics' do
|
53
|
+
it 'should pass unknown method calls down the stack' do
|
54
|
+
stop = StopContext.new
|
55
|
+
def stop.bananas(arg1, arg2) arg1 + arg2 + 43 end
|
56
|
+
element = ModuleContext.new(stop, [0, :mod])
|
57
|
+
class_element = ClassContext.new(element, [0, :klass])
|
58
|
+
element = MethodContext.new(class_element, [0, :bad])
|
59
|
+
element = BlockContext.new(element, nil)
|
60
|
+
element.bananas(17, -5).should == 55
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe CodeContext do
|
65
|
+
it 'should recognise itself in a collection of names' do
|
66
|
+
element = StopContext.new
|
67
|
+
element = ModuleContext.new(element, [0, :mod])
|
68
|
+
element.matches?(['banana', 'mod']).should == true
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should recognise itself in a collection of REs' do
|
72
|
+
element = StopContext.new
|
73
|
+
element = ModuleContext.new(element, [0, :mod])
|
74
|
+
element.matches?([/banana/, /mod/]).should == true
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should recognise its fq name in a collection of names' do
|
78
|
+
element = StopContext.new
|
79
|
+
element = ModuleContext.new(element, [0, :mod])
|
80
|
+
element = ClassContext.create(element, [0, :klass])
|
81
|
+
element.matches?(['banana', 'mod']).should == true
|
82
|
+
element.matches?(['banana', 'mod::klass']).should == true
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should recognise its fq name in a collection of names' do
|
86
|
+
element = StopContext.new
|
87
|
+
element = ModuleContext.new(element, [0, :mod])
|
88
|
+
element = ClassContext.create(element, [0, :klass])
|
89
|
+
element.matches?([/banana/, /mod/]).should == true
|
90
|
+
element.matches?([/banana/, /mod::klass/]).should == true
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
require 'reek/code_parser'
|
4
|
+
require 'reek/report'
|
5
|
+
|
6
|
+
include Reek
|
7
|
+
|
8
|
+
describe CodeParser, "with no method definitions" do
|
9
|
+
it 'should report no problems for empty source code' do
|
10
|
+
''.should_not reek
|
11
|
+
end
|
12
|
+
it 'should report no problems for empty class' do
|
13
|
+
'class Fred; end'.should_not reek
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe CodeParser, 'with a global method definition' do
|
18
|
+
it 'should report no problems for simple method' do
|
19
|
+
'def Outermost::fred() true; end'.should_not reek
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe CodeParser, 'when given a C extension' do
|
24
|
+
before(:each) do
|
25
|
+
@cchk = CodeParser.new(Report.new, SmellConfig.new.smell_listeners)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should ignore :cfunc' do
|
29
|
+
@cchk.check_object(Enumerable)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe CodeParser, 'when a yield is the receiver' do
|
34
|
+
it 'should report no problems' do
|
35
|
+
source = 'def values(*args)
|
36
|
+
@to_sql += case
|
37
|
+
when block_given? then " #{yield.to_sql}"
|
38
|
+
else " values (#{args.to_sql})"
|
39
|
+
end
|
40
|
+
self
|
41
|
+
end'
|
42
|
+
source.should_not reek
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
require 'reek/smells/smells'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
include Reek
|
7
|
+
|
8
|
+
describe 'Config' do
|
9
|
+
before :each do
|
10
|
+
@first = {
|
11
|
+
'one' => {'two' => 3, 'three' => 4},
|
12
|
+
'two' => {'four' => true}
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should deep merge Hashes' do
|
17
|
+
other = Hash.new {|hash,key| hash[key] = {} }
|
18
|
+
other['one']['gunk'] = 45
|
19
|
+
other['two']['four'] = false
|
20
|
+
@first.value_merge!(other).to_yaml
|
21
|
+
@first['two']['four'].should == false
|
22
|
+
@first['one'].keys.length.should == 3
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should deep copy Hashes' do
|
26
|
+
second = @first.deep_copy
|
27
|
+
second['two'].object_id.should_not be_eql(@first['two'].object_id)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should merge array values' do
|
31
|
+
@first['three'] = [1,2,3]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe Config, 'merging arrays' do
|
36
|
+
it 'should merge array values' do
|
37
|
+
first = {'key' => {'one' => [1,2,3]}}
|
38
|
+
second = {'key' => {'one' => [4,5]}}
|
39
|
+
first.value_merge!(second)
|
40
|
+
first['key']['one'].should == [1,2,3,4,5]
|
41
|
+
end
|
42
|
+
end
|