recursive-open-struct 0.4.1 → 0.4.2
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/lib/recursive_open_struct.rb +13 -4
- data/spec/recursive_open_struct_spec.rb +80 -47
- metadata +2 -2
@@ -1,15 +1,24 @@
|
|
1
1
|
require 'ostruct'
|
2
2
|
|
3
3
|
class RecursiveOpenStruct < OpenStruct
|
4
|
-
VERSION = "0.4.
|
4
|
+
VERSION = "0.4.2"
|
5
5
|
|
6
6
|
def initialize(h=nil, args={})
|
7
7
|
@recurse_over_arrays = args.fetch(:recurse_over_arrays,false)
|
8
8
|
super(h)
|
9
|
+
@sub_elements = {}
|
9
10
|
end
|
10
11
|
|
11
12
|
def to_h
|
12
|
-
@table.dup
|
13
|
+
@table.dup.update(@sub_elements) do |k, oldval, newval|
|
14
|
+
if newval.kind_of?(self.class)
|
15
|
+
newval.to_h
|
16
|
+
elsif newval.kind_of?(Array)
|
17
|
+
newval.map { |a| a.kind_of?(self.class) ? a.to_h : a }
|
18
|
+
else
|
19
|
+
raise "Cached value of unsupported type: #{newval.inspect}"
|
20
|
+
end
|
21
|
+
end
|
13
22
|
end
|
14
23
|
|
15
24
|
def new_ostruct_member(name)
|
@@ -19,9 +28,9 @@ class RecursiveOpenStruct < OpenStruct
|
|
19
28
|
define_method(name) do
|
20
29
|
v = @table[name]
|
21
30
|
if v.is_a?(Hash)
|
22
|
-
RecursiveOpenStruct.new(v)
|
31
|
+
@sub_elements[name] ||= RecursiveOpenStruct.new(v)
|
23
32
|
elsif v.is_a?(Array) and @recurse_over_arrays
|
24
|
-
v.map { |a| (a.is_a? Hash) ? RecursiveOpenStruct.new(a, :recurse_over_arrays => true) : a }
|
33
|
+
@sub_elements[name] ||= v.map { |a| (a.is_a? Hash) ? RecursiveOpenStruct.new(a, :recurse_over_arrays => true) : a }
|
25
34
|
else
|
26
35
|
v
|
27
36
|
end
|
@@ -17,12 +17,6 @@ describe RecursiveOpenStruct do
|
|
17
17
|
ros.asdf.should == "John Smith"
|
18
18
|
end
|
19
19
|
|
20
|
-
it "can be converted back to a hash" do
|
21
|
-
h = { :asdf => 'John Smith' }
|
22
|
-
ros = RecursiveOpenStruct.new(h)
|
23
|
-
ros.to_h.should == h
|
24
|
-
end
|
25
|
-
|
26
20
|
it "can modify an existing key" do
|
27
21
|
h = { :blah => 'John Smith' }
|
28
22
|
ros = RecursiveOpenStruct.new(h)
|
@@ -31,81 +25,120 @@ describe RecursiveOpenStruct do
|
|
31
25
|
end
|
32
26
|
|
33
27
|
describe "handling of arbitrary attributes" do
|
28
|
+
subject { RecursiveOpenStruct.new }
|
34
29
|
before(:each) do
|
35
|
-
|
36
|
-
@ros.blah = "John Smith"
|
30
|
+
subject.blah = "John Smith"
|
37
31
|
end
|
38
32
|
|
39
33
|
describe "#respond?" do
|
40
|
-
it {
|
41
|
-
it {
|
42
|
-
it {
|
43
|
-
it {
|
34
|
+
it { subject.should respond_to :blah }
|
35
|
+
it { subject.should respond_to :blah= }
|
36
|
+
it { subject.should_not respond_to :asdf }
|
37
|
+
it { subject.should_not respond_to :asdf= }
|
44
38
|
end # describe #respond?
|
45
39
|
|
46
40
|
describe "#methods" do
|
47
|
-
it {
|
48
|
-
it {
|
49
|
-
it {
|
50
|
-
it {
|
41
|
+
it { subject.methods.map(&:to_sym).should include :blah }
|
42
|
+
it { subject.methods.map(&:to_sym).should include :blah= }
|
43
|
+
it { subject.methods.map(&:to_sym).should_not include :asdf }
|
44
|
+
it { subject.methods.map(&:to_sym).should_not include :asdf= }
|
51
45
|
end # describe #methods
|
52
46
|
end # describe handling of arbitrary attributes
|
53
47
|
end # describe behavior it inherits from OpenStruct
|
54
48
|
|
55
|
-
describe "
|
56
|
-
|
57
|
-
h = { :
|
58
|
-
|
49
|
+
describe "improvements on OpenStruct" do
|
50
|
+
it "can be converted back to a hash" do
|
51
|
+
h = { :asdf => 'John Smith' }
|
52
|
+
ros = RecursiveOpenStruct.new(h)
|
53
|
+
ros.to_h.should == h
|
59
54
|
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "recursive behavior" do
|
58
|
+
let(:h) { { :blah => { :another => 'value' } } }
|
59
|
+
subject { RecursiveOpenStruct.new(h) }
|
60
60
|
|
61
61
|
it "returns accessed hashes as RecursiveOpenStructs instead of hashes" do
|
62
|
-
|
62
|
+
subject.blah.another.should == 'value'
|
63
63
|
end
|
64
64
|
|
65
65
|
it "uses #key_as_a_hash to return key as a Hash" do
|
66
|
-
|
66
|
+
subject.blah_as_a_hash.should == { :another => 'value' }
|
67
67
|
end
|
68
68
|
|
69
69
|
describe "handling loops in the origin Hashes" do
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
70
|
+
let(:h1) { { :a => 'a'} }
|
71
|
+
let(:h2) { { :a => 'b', :h1 => h1 } }
|
72
|
+
before(:each) { h1[:h2] = h2 }
|
73
|
+
|
74
|
+
subject { RecursiveOpenStruct.new(h2) }
|
75
|
+
|
76
|
+
it { subject.h1.a.should == 'a' }
|
77
|
+
it { subject.h1.h2.a.should == 'b' }
|
78
|
+
it { subject.h1.h2.h1.a.should == 'a' }
|
79
|
+
it { subject.h1.h2.h1.h2.a.should == 'b' }
|
80
|
+
it { subject.h1.should == subject.h1.h2.h1 }
|
81
|
+
it { subject.h1.should_not == subject.h1.h2 }
|
82
|
+
end # describe handling loops in the origin Hashes
|
83
|
+
|
84
|
+
it "can modify a key of a sub-element" do
|
85
|
+
h = {
|
86
|
+
:blah => {
|
87
|
+
:blargh => 'Brad'
|
88
|
+
}
|
89
|
+
}
|
90
|
+
ros = RecursiveOpenStruct.new(h)
|
91
|
+
ros.blah.blargh = "Janet"
|
92
|
+
ros.blah.blargh.should == "Janet"
|
93
|
+
end
|
94
|
+
|
95
|
+
context "after a sub-element has been modified" do
|
96
|
+
let(:hash) do
|
97
|
+
{
|
98
|
+
:blah => {
|
99
|
+
:blargh => 'Brad'
|
100
|
+
}
|
101
|
+
}
|
102
|
+
end
|
103
|
+
subject { RecursiveOpenStruct.new(hash) }
|
104
|
+
before(:each) { subject.blah.blargh = "Janet" }
|
105
|
+
it "returns a hash that contains those modifications" do
|
106
|
+
subject.to_h.should == { :blah => { :blargh => "Janet" } }
|
75
107
|
end
|
108
|
+
end
|
76
109
|
|
77
|
-
it { @ros.h1.a.should == 'a' }
|
78
|
-
it { @ros.h1.h2.a.should == 'b' }
|
79
|
-
it { @ros.h1.h2.h1.a.should == 'a' }
|
80
|
-
it { @ros.h1.h2.h1.h2.a.should == 'b' }
|
81
|
-
it { @ros.h1.should == @ros.h1.h2.h1 }
|
82
|
-
it { @ros.h1.should_not == @ros.h1.h2 }
|
83
|
-
end # describe handling loops in the origin Hashes
|
84
110
|
|
85
111
|
describe 'recursing over arrays' do
|
86
112
|
let(:blah_list) { [ { :foo => '1' }, { :foo => '2' }, 'baz' ] }
|
87
113
|
let(:h) { { :blah => blah_list } }
|
88
114
|
|
89
115
|
context "when recursing over arrays is enabled" do
|
90
|
-
|
91
|
-
|
116
|
+
subject { RecursiveOpenStruct.new(h, :recurse_over_arrays => true) }
|
117
|
+
|
118
|
+
it { subject.blah.length.should == 3 }
|
119
|
+
it { subject.blah[0].foo.should == '1' }
|
120
|
+
it { subject.blah[1].foo.should == '2' }
|
121
|
+
it { subject.blah_as_a_hash.should == blah_list }
|
122
|
+
it { subject.blah[2].should == 'baz' }
|
123
|
+
it "Retains changes across Array lookups" do
|
124
|
+
subject.blah[1].foo = "Dr Scott"
|
125
|
+
subject.blah[1].foo.should == "Dr Scott"
|
126
|
+
end
|
127
|
+
it "propagates the changes through to .to_h across Array lookups" do
|
128
|
+
subject.blah[1].foo = "Dr Scott"
|
129
|
+
subject.to_h.should == {
|
130
|
+
:blah => [ { :foo => '1' }, { :foo => "Dr Scott" }, 'baz' ]
|
131
|
+
}
|
92
132
|
end
|
93
133
|
|
94
|
-
it { @ros.blah.length.should == 3 }
|
95
|
-
it { @ros.blah[0].foo.should == '1' }
|
96
|
-
it { @ros.blah[1].foo.should == '2' }
|
97
|
-
it { @ros.blah_as_a_hash.should == blah_list }
|
98
|
-
it { @ros.blah[2].should == 'baz' }
|
99
134
|
end # when recursing over arrays is enabled
|
100
135
|
|
101
136
|
context "when recursing over arrays is disabled" do
|
102
|
-
|
103
|
-
@ros = RecursiveOpenStruct.new(h)
|
104
|
-
end
|
137
|
+
subject { RecursiveOpenStruct.new(h) }
|
105
138
|
|
106
|
-
it {
|
107
|
-
it {
|
108
|
-
it {
|
139
|
+
it { subject.blah.length.should == 3 }
|
140
|
+
it { subject.blah[0].should == { :foo => '1' } }
|
141
|
+
it { subject.blah[0][:foo].should == '1' }
|
109
142
|
end # when recursing over arrays is disabled
|
110
143
|
|
111
144
|
end # recursing over arrays
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: recursive-open-struct
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-05-
|
12
|
+
date: 2013-05-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|