recursive-open-struct 2.0.0 → 2.1.1

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.
@@ -1,111 +0,0 @@
1
- require_relative '../spec_helper'
2
- require 'recursive_open_struct'
3
-
4
- describe RecursiveOpenStruct do
5
-
6
- let(:hash) { {:foo => 'foo', 'bar' => :bar} }
7
- subject(:ros) { RecursiveOpenStruct.new(hash) }
8
-
9
- describe "OpenStruct 2.0+ methods" do
10
-
11
- context "Hash style setter" do
12
-
13
- it "method exists" do
14
- expect(ros.respond_to?('[]=')).to be_truthy
15
- end
16
-
17
- it "changes the value" do
18
- ros[:foo] = :foo
19
- ros.foo = :foo
20
- end
21
-
22
- end
23
-
24
- context "delete_field" do
25
-
26
- before(:each) { ros.delete_field :foo }
27
-
28
- it "removes the value" do
29
- expect(ros.foo).to be_nil
30
- expect(ros.to_h).to_not include(:foo)
31
- end
32
-
33
- it "removes the getter method" do
34
- is_expected.to_not respond_to :foo
35
- end
36
-
37
- it "removes the setter method" do
38
- expect(ros.respond_to? 'foo=').to be_falsey
39
- end
40
-
41
- it "works with indifferent access" do
42
- expect(ros.delete_field :bar).to eq :bar
43
- is_expected.to_not respond_to :bar
44
- is_expected.to_not respond_to 'bar='
45
- expect(ros.to_h).to be_empty
46
- end
47
-
48
- end
49
-
50
- context "eql?" do
51
- subject(:new_ros) { ros.dup }
52
-
53
- context "with identical ROS" do
54
- subject { ros }
55
- it { is_expected.to be_eql ros }
56
- end
57
-
58
- context "with similar ROS" do
59
- subject { RecursiveOpenStruct.new(hash) }
60
- it { is_expected.to be_eql ros }
61
- end
62
-
63
- context "with same Hash" do
64
- subject { RecursiveOpenStruct.new(hash, recurse_over_arrays: true) }
65
- it { is_expected.to be_eql ros }
66
- end
67
-
68
- context "with duplicated ROS" do
69
- subject { ros.dup }
70
-
71
- it "fails on different value" do
72
- subject.foo = 'bar'
73
- is_expected.not_to be_eql ros
74
- end
75
-
76
- it "fails on missing field" do
77
- subject.delete_field :bar
78
- is_expected.not_to be_eql ros
79
- end
80
-
81
- it "fails on added field" do
82
- subject.baz = :baz
83
- is_expected.not_to be_eql ros
84
- end
85
-
86
- end
87
-
88
- end
89
-
90
- context "hash" do
91
- it "calculates table hash" do
92
- expect(ros.hash).to eq(ros.instance_variable_get('@table').hash)
93
- end
94
-
95
- end
96
-
97
- context "each_pair" do
98
- it "iterates over hash keys, with keys as symbol" do
99
- ros_pairs = []
100
- ros.each_pair {|k,v| ros_pairs << [k,v]}
101
-
102
- hash_pairs = []
103
- {:foo => 'foo', :bar => :bar}.each_pair {|k,v| hash_pairs << [k,v]}
104
-
105
- expect(ros_pairs).to match (hash_pairs)
106
- end
107
- end
108
-
109
- end # describe OpenStruct 2.0+ methods
110
-
111
- end
@@ -1,49 +0,0 @@
1
- require_relative '../spec_helper'
2
- require 'recursive_open_struct'
3
-
4
- describe RecursiveOpenStruct do
5
- describe "OpenStruct 2.3.0+ methods" do
6
- describe "#dig" do
7
- # We only care when Ruby supports `#dig`.
8
- if OpenStruct.public_instance_methods.include? :dig
9
- context "recurse_over_arrays: false" do
10
- subject { RecursiveOpenStruct.new(a: { b: 2, c: ["doo", "bee", { inner: "one"}]}) }
11
-
12
- describe "OpenStruct-like behavior" do
13
- it { expect(subject.dig(:a, :b)).to eq 2 }
14
- it { expect(subject.dig(:a, :c, 0)).to eq "doo" }
15
- it { expect(subject.dig(:a, :c, 2, :inner)).to eq "one" }
16
- end
17
-
18
- describe "recursive behavior" do
19
- it {
20
- expect(subject.dig(:a)).to eq RecursiveOpenStruct.new(
21
- { b: 2, c: ["doo", "bee", { inner: "one"}]}
22
- )
23
- }
24
- it { expect(subject.dig(:a, :c, 2)).to eq({inner: "one"}) }
25
- end
26
- end
27
-
28
- context "recurse_over_arrays: true" do
29
- subject { RecursiveOpenStruct.new({a: { b: 2, c: ["doo", "bee", { inner: "one"}]}}, recurse_over_arrays: true) }
30
-
31
- describe "OpenStruct-like behavior" do
32
- it { expect(subject.dig(:a, :b)).to eq 2 }
33
- it { expect(subject.dig(:a, :c, 0)).to eq "doo" }
34
- it { expect(subject.dig(:a, :c, 2, :inner)).to eq "one" }
35
- end
36
-
37
- describe "recursive behavior" do
38
- it {
39
- expect(subject.dig(:a)).to eq RecursiveOpenStruct.new(
40
- { b: 2, c: ["doo", "bee", { inner: "one"}]}
41
- )
42
- }
43
- it { expect(subject.dig(:a, :c, 2)).to eq RecursiveOpenStruct.new(inner: "one") }
44
- end
45
- end
46
- end
47
- end # describe #dig
48
- end # describe OpenStruct 2.3+ methods
49
- end
@@ -1,14 +0,0 @@
1
- require_relative '../spec_helper'
2
- require 'recursive_open_struct'
3
-
4
- describe RecursiveOpenStruct do
5
- describe "subclassing RecursiveOpenStruct" do
6
- let(:subclass) { Class.new(RecursiveOpenStruct) }
7
-
8
- subject(:rossc) { subclass.new({ :one => [{:two => :three}] }, recurse_over_arrays: true) }
9
-
10
- specify "nested objects use the subclass of the parent" do
11
- expect(rossc.one.first.class).to eq subclass
12
- end
13
- end
14
- end
@@ -1,355 +0,0 @@
1
- require_relative '../spec_helper'
2
- require 'recursive_open_struct'
3
-
4
- describe RecursiveOpenStruct do
5
-
6
- describe "recursive behavior" do
7
- let(:h) { { :blah => { :another => 'value' } } }
8
- subject(:ros) { RecursiveOpenStruct.new(h) }
9
-
10
- it "can convert the entire hash tree back into a hash" do
11
- blank_obj = Object.new
12
- h = {:asdf => 'John Smith', :foo => [{:bar => blank_obj}, {:baz => nil}]}
13
- ros = RecursiveOpenStruct.new(h)
14
-
15
- expect(ros.to_h).to eq h
16
- expect(ros.to_hash).to eq h
17
- end
18
-
19
- it "returns accessed hashes as RecursiveOpenStructs instead of hashes" do
20
- expect(subject.blah.another).to eq 'value'
21
- end
22
-
23
- it "handles subscript notation the same way as dotted notation" do
24
- expect(subject.blah.another).to eq subject[:blah].another
25
- end
26
-
27
- it "uses #key_as_a_hash to return key as a Hash" do
28
- expect(subject.blah_as_a_hash).to eq({ :another => 'value' })
29
- end
30
-
31
- it "handles sub-element replacement with dotted notation before member setup" do
32
- expect(ros[:blah][:another]).to eql 'value'
33
- expect(ros.methods).not_to include(:blah)
34
-
35
- ros.blah = { changed: 'backing' }
36
-
37
- expect(ros.blah.changed).to eql 'backing'
38
- end
39
-
40
- it "handles being dump then loaded by Marshal" do
41
- foo_struct = [RecursiveOpenStruct.new]
42
- bar_struct = RecursiveOpenStruct.new(foo: foo_struct)
43
- serialized = Marshal.dump(bar_struct)
44
-
45
- expect(Marshal.load(serialized).foo).to eq(foo_struct)
46
- end
47
-
48
- describe "handling loops in the original Hashes" do
49
- let(:h1) { { :a => 'a'} }
50
- let(:h2) { { :a => 'b', :h1 => h1 } }
51
- before(:each) { h1[:h2] = h2 }
52
-
53
- subject { RecursiveOpenStruct.new(h2) }
54
-
55
- it { expect(subject.h1.a).to eq 'a' }
56
- it { expect(subject.h1.h2.a).to eq 'b' }
57
- it { expect(subject.h1.h2.h1.a).to eq 'a' }
58
- it { expect(subject.h1.h2.h1.h2.a).to eq 'b' }
59
- it { expect(subject.h1).to eq subject.h1.h2.h1 }
60
- it { expect(subject.h1).to_not eq subject.h1.h2 }
61
- end # describe handling loops in the origin Hashes
62
-
63
- it "can modify a key of a sub-element" do
64
- h = {
65
- :blah => {
66
- :blargh => 'Brad'
67
- }
68
- }
69
- ros = RecursiveOpenStruct.new(h)
70
- ros.blah.blargh = "Janet"
71
-
72
- expect(ros.blah.blargh).to eq "Janet"
73
- end
74
-
75
- describe 'subscript mutation notation' do
76
- it 'handles the basic case' do
77
- subject[:blah] = 12345
78
- expect(subject.blah).to eql 12345
79
- end
80
-
81
- it 'recurses properly' do
82
- subject[:blah][:another] = 'abc'
83
- expect(subject.blah.another).to eql 'abc'
84
- expect(subject.blah_as_a_hash).to eql({ :another => 'abc' })
85
- end
86
-
87
- let(:diff){ { :different => 'thing' } }
88
-
89
- it 'can replace the entire hash' do
90
- expect(subject.to_h).to eql(h)
91
- subject[:blah] = diff
92
- expect(subject.to_h).to eql({ :blah => diff })
93
- end
94
-
95
- it 'updates sub-element cache' do
96
- expect(subject.blah.different).to be_nil
97
- subject[:blah] = diff
98
- expect(subject.blah.different).to eql 'thing'
99
- expect(subject.blah_as_a_hash).to eql(diff)
100
- end
101
- end
102
-
103
- context "after a sub-element has been modified" do
104
- let(:hash) do
105
- { :blah => { :blargh => "Brad" }, :some_array => [ 1, 2, 3] }
106
- end
107
- let(:updated_hash) do
108
- { :blah => { :blargh => "Janet" }, :some_array => [ 1, 2, 3] }
109
- end
110
-
111
- subject { RecursiveOpenStruct.new(hash) }
112
-
113
- before(:each) { subject.blah.blargh = "Janet" }
114
-
115
- describe ".to_h" do
116
- it "returns a hash tree that contains those modifications" do
117
- expect(subject.to_h).to eq updated_hash
118
- end
119
-
120
- specify "modifying the returned hash tree does not modify the ROS" do
121
- subject.to_h[:blah][:blargh] = "Dr Scott"
122
-
123
- expect(subject.blah.blargh).to eq "Janet"
124
- end
125
- end
126
-
127
- it "does not mutate the original hash tree passed to the constructor" do
128
- expect(hash[:blah][:blargh]).to eq 'Brad'
129
- end
130
-
131
- it "limits the deep-copy to the initial hash tree" do
132
- subject.some_array[0] = 4
133
-
134
- expect(hash[:some_array][0]).to eq 4
135
- end
136
-
137
- describe "#dup" do
138
- let(:duped_subject) { subject.dup }
139
-
140
- it "preserves sub-element modifications" do
141
- expect(duped_subject.blah.blargh).to eq subject.blah.blargh
142
- end
143
-
144
- it "allows the copy's sub-elements to be modified independently from the original's" do
145
- expect(subject.blah.blargh).to eq "Janet"
146
-
147
- duped_subject.blah.blargh = "Dr. Scott"
148
-
149
- expect(subject.blah.blargh).to eq "Janet"
150
- expect(duped_subject.blah.blargh).to eq "Dr. Scott"
151
- end
152
- end
153
- end
154
-
155
- context "when memoizing and then modifying entire recursive structures" do
156
- subject do
157
- RecursiveOpenStruct.new(
158
- { :blah => original_blah }, :recurse_over_arrays => true)
159
- end
160
-
161
- before(:each) { subject.blah } # enforce memoization
162
-
163
- context "when modifying an entire Hash" do
164
- let(:original_blah) { { :a => 'A', :b => 'B' } }
165
- let(:new_blah) { { :something_new => "C" } }
166
-
167
- before(:each) { subject.blah = new_blah }
168
-
169
- it "returns the modified value instead of the memoized one" do
170
- expect(subject.blah.something_new).to eq "C"
171
- end
172
-
173
- specify "the old value no longer exists" do
174
- expect(subject.blah.a).to be_nil
175
- end
176
- end
177
-
178
- context "when modifying an entire Array" do
179
- let(:original_blah) { [1, 2, 3] }
180
-
181
- it "returns the modified value instead of the memoized one" do
182
- new_blah = [4, 5, 6]
183
- subject.blah = new_blah
184
- expect(subject.blah).to eq new_blah
185
- end
186
- end
187
- end
188
-
189
- describe 'recursing over arrays' do
190
- let(:blah_list) { [ { :foo => '1' }, { :foo => '2' }, 'baz' ] }
191
- let(:h) { { :blah => blah_list } }
192
-
193
- context "when dump and loaded by Marshal" do
194
- let(:test) { RecursiveOpenStruct.new(h, :recurse_over_arrays => true) }
195
- subject { Marshal.load(Marshal.dump(test))}
196
-
197
- it { expect(subject.blah.length).to eq 3 }
198
- it { expect(subject.blah[0].foo).to eq '1' }
199
- it { expect(subject.blah[1].foo).to eq '2' }
200
- it { expect(subject.blah_as_a_hash).to eq blah_list }
201
- it { expect(subject.blah[2]).to eq 'baz' }
202
- end
203
-
204
- context "when recursing over arrays is enabled" do
205
- subject { RecursiveOpenStruct.new(h, :recurse_over_arrays => true) }
206
-
207
- it { expect(subject.blah.length).to eq 3 }
208
- it { expect(subject.blah[0].foo).to eq '1' }
209
- it { expect(subject.blah[1].foo).to eq '2' }
210
- it { expect(subject.blah_as_a_hash).to eq blah_list }
211
- it { expect(subject.blah[2]).to eq 'baz' }
212
-
213
- context "when an inner value changes" do
214
- let(:updated_blah_list) { [ { :foo => '1' }, { :foo => 'Dr Scott' }, 'baz' ] }
215
- let(:updated_h) { { :blah => updated_blah_list } }
216
-
217
- before(:each) { subject.blah[1].foo = "Dr Scott" }
218
-
219
- it "Retains changes across Array lookups" do
220
- expect(subject.blah[1].foo).to eq "Dr Scott"
221
- end
222
-
223
- it "propagates the changes through to .to_h across Array lookups" do
224
- expect(subject.to_h).to eq({
225
- :blah => [ { :foo => '1' }, { :foo => "Dr Scott" }, 'baz' ]
226
- })
227
- end
228
-
229
- it "deep-copies hashes within Arrays" do
230
- subject.to_h[:blah][1][:foo] = "Rocky"
231
-
232
- expect(subject.blah[1].foo).to eq "Dr Scott"
233
- end
234
-
235
- it "does not mutate the input hash passed to the constructor" do
236
- expect(h[:blah][1][:foo]).to eq '2'
237
- end
238
-
239
- it "the deep copy recurses over Arrays as well" do
240
- expect(h[:blah][1][:foo]).to eq '2'
241
- end
242
-
243
- describe "#dup" do
244
- let(:duped_subject) { subject.dup }
245
-
246
- it "preserves sub-element modifications" do
247
- expect(duped_subject.blah[1].foo).to eq subject.blah[1].foo
248
- end
249
-
250
- it "allows the copy's sub-elements to be modified independently from the original's" do
251
- duped_subject.blah[1].foo = "Rocky"
252
-
253
- expect(duped_subject.blah[1].foo).to eq "Rocky"
254
- expect(subject.blah[1].foo).to eq "Dr Scott"
255
- end
256
- end
257
- end
258
-
259
- context "when array is nested deeper" do
260
- let(:deep_hash) { { :foo => { :blah => blah_list } } }
261
- subject { RecursiveOpenStruct.new(deep_hash, :recurse_over_arrays => true) }
262
-
263
- it { expect(subject.foo.blah.length).to eq 3 }
264
- it "Retains changes across Array lookups" do
265
- subject.foo.blah[1].foo = "Dr Scott"
266
- expect(subject.foo.blah[1].foo).to eq "Dr Scott"
267
- end
268
-
269
- end
270
-
271
- context "when array is in an array" do
272
- let(:haah) { { :blah => [ blah_list ] } }
273
- subject { RecursiveOpenStruct.new(haah, :recurse_over_arrays => true) }
274
-
275
- it { expect(subject.blah.length).to eq 1 }
276
- it { expect(subject.blah[0].length).to eq 3 }
277
- it "Retains changes across Array lookups" do
278
- subject.blah[0][1].foo = "Dr Scott"
279
-
280
- expect(subject.blah[0][1].foo).to eq "Dr Scott"
281
- end
282
-
283
- end
284
-
285
- end # when recursing over arrays is enabled
286
-
287
- context "when recursing over arrays is disabled" do
288
- subject { RecursiveOpenStruct.new(h) }
289
-
290
- it { expect(subject.blah.length).to eq 3 }
291
- it { expect(subject.blah[0]).to eq({ :foo => '1' }) }
292
- it { expect(subject.blah[0][:foo]).to eq '1' }
293
- end # when recursing over arrays is disabled
294
-
295
- describe 'modifying an array and recursing over it' do
296
- let(:h) { {} }
297
- subject { RecursiveOpenStruct.new(h, recurse_over_arrays: true) }
298
-
299
- context 'when adding an array with hashes into the tree' do
300
- before(:each) do
301
- subject.mystery = {}
302
- subject.mystery.science = [{ theatre: 9000 }]
303
- end
304
-
305
- it "ROS's it" do
306
- expect(subject.mystery.science[0].theatre).to eq 9000
307
- end
308
- end
309
-
310
- context 'when appending a hash to an array' do
311
- before(:each) do
312
- subject.mystery = {}
313
- subject.mystery.science = []
314
- subject.mystery.science << { theatre: 9000 }
315
- end
316
-
317
- it "ROS's it" do
318
- expect(subject.mystery.science[0].theatre).to eq 9000
319
- end
320
-
321
- specify "the changes show up in .to_h" do
322
- expect(subject.to_h).to eq({ mystery: { science: [{theatre: 9000}]}})
323
- end
324
- end
325
-
326
- context 'after appending a hash to an array' do
327
- before(:each) do
328
- subject.mystery = {}
329
- subject.mystery.science = []
330
- subject.mystery.science[0] = {}
331
- end
332
-
333
- it "can have new values be set" do
334
- expect do
335
- subject.mystery.science[0].theatre = 9000
336
- end.to_not raise_error
337
-
338
- expect(subject.mystery.science[0].theatre).to eq 9000
339
- end
340
- end
341
- end # modifying an array and then recursing
342
- end # recursing over arrays
343
-
344
- describe 'nested nil values' do
345
- let(:h) { { foo: { bar: nil }} }
346
- it 'returns nil' do
347
- expect(subject.foo.bar).to be_nil
348
- end
349
-
350
- it 'returns a hash with the key and a nil value' do
351
- expect(subject.to_hash).to eq({ foo: { bar: nil }})
352
- end
353
- end # nested nil values
354
- end # recursive behavior
355
- end
data/spec/spec_helper.rb DELETED
@@ -1,19 +0,0 @@
1
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
- $LOAD_PATH.unshift(File.dirname(__FILE__))
3
- require 'rspec'
4
- require 'pry'
5
-
6
- if ENV['COVERAGE'] == 'true'
7
- require 'simplecov'
8
- SimpleCov.start
9
- end
10
-
11
- # Requires supporting files with custom matchers and macros, etc,
12
- # in ./support/ and its subdirectories.
13
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
14
-
15
- RSpec.configure do |config|
16
- config.run_all_when_everything_filtered = true
17
- config.filter_run :focus
18
- # config.expect_with(:rspec) { |c| c.syntax = :should }
19
- end