reek 0.3.1 → 1.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/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
|