fancy-open-struct 0.3.0 → 0.4.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/.travis.yml +0 -1
- data/CHANGELOG +4 -0
- data/lib/fancy-open-struct.rb +56 -33
- data/lib/fancy-open-struct/version.rb +1 -1
- data/spec/fancy_open_struct_spec.rb +45 -0
- metadata +1 -1
data/.travis.yml
CHANGED
data/CHANGELOG
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
0.4.0
|
2
|
+
- Changed ostruct methods (new_ostruct_member, recurse_over_array) so that they are private
|
3
|
+
- Overhauled the caching sub-system and how values are set and retrieved to fix a bug with values not updating
|
4
|
+
|
1
5
|
0.3.0
|
2
6
|
- Deprecated the display_recursive_open_hash alias for debug_inspect
|
3
7
|
- Removed some unnecessary code from the to_h method
|
data/lib/fancy-open-struct.rb
CHANGED
@@ -22,43 +22,14 @@ class FancyOpenStruct < OpenStruct
|
|
22
22
|
@sub_elements = {}
|
23
23
|
end
|
24
24
|
|
25
|
-
def new_ostruct_member(name)
|
26
|
-
name = name.to_sym
|
27
|
-
unless self.respond_to?(name)
|
28
|
-
define_singleton_method name do
|
29
|
-
v = @table[name]
|
30
|
-
if v.is_a?(Hash)
|
31
|
-
@sub_elements[name] ||= self.class.new(v, :recurse_over_arrays => @recurse_over_arrays)
|
32
|
-
elsif v.is_a?(Array) and @recurse_over_arrays
|
33
|
-
@sub_elements[name] ||= recurse_over_array v
|
34
|
-
else
|
35
|
-
v
|
36
|
-
end
|
37
|
-
end
|
38
|
-
define_singleton_method("#{name}=") { |x| modifiable[name] = x }
|
39
|
-
define_singleton_method("#{name}_as_a_hash") { @table[name] }
|
40
|
-
end
|
41
|
-
name
|
42
|
-
end
|
43
|
-
|
44
|
-
def recurse_over_array(array)
|
45
|
-
array.map do |a|
|
46
|
-
if a.is_a? Hash
|
47
|
-
self.class.new(a, :recurse_over_arrays => true)
|
48
|
-
elsif a.is_a? Array
|
49
|
-
recurse_over_array a
|
50
|
-
else
|
51
|
-
a
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
25
|
def to_h
|
57
26
|
@table.dup.update(@sub_elements) do |k, oldval, newval|
|
58
27
|
if newval.kind_of?(self.class)
|
59
28
|
newval.to_h
|
60
29
|
elsif newval.kind_of?(Array)
|
61
30
|
newval.map { |a| a.kind_of?(self.class) ? a.to_h : a }
|
31
|
+
else
|
32
|
+
newval
|
62
33
|
end
|
63
34
|
end
|
64
35
|
end
|
@@ -73,17 +44,66 @@ class FancyOpenStruct < OpenStruct
|
|
73
44
|
|
74
45
|
# Hash getter method which translates the key to a Symbol
|
75
46
|
def [](key)
|
76
|
-
|
47
|
+
key = key.to_sym unless key.kind_of? Symbol
|
48
|
+
@table[key]
|
77
49
|
end
|
78
50
|
|
79
51
|
# Hash setter method which translates the key to a Symbol and also creates
|
80
52
|
# a getter method (OpenStruct member) for accessing the key/value later via dot syntax
|
81
53
|
def []=(key, value)
|
82
|
-
|
54
|
+
key = key.to_sym unless key.kind_of? Symbol
|
55
|
+
modifiable[new_ostruct_member(key)] = value
|
56
|
+
build_sub_elements_key_cache(key)
|
83
57
|
end
|
84
58
|
|
85
59
|
private
|
86
60
|
|
61
|
+
def new_ostruct_member(name)
|
62
|
+
name = name.to_sym
|
63
|
+
unless self.respond_to?(name)
|
64
|
+
define_singleton_method name do
|
65
|
+
value = @table[name]
|
66
|
+
if value.is_a?(Hash)
|
67
|
+
@sub_elements[name] ||= self.class.new(value, :recurse_over_arrays => @recurse_over_arrays)
|
68
|
+
elsif value.is_a?(Array) and @recurse_over_arrays
|
69
|
+
@sub_elements[name] ||= recurse_over_array value
|
70
|
+
else
|
71
|
+
value
|
72
|
+
end
|
73
|
+
end
|
74
|
+
define_singleton_method("#{name}=") do |x|
|
75
|
+
modifiable[name] = x
|
76
|
+
build_sub_elements_key_cache(name)
|
77
|
+
end
|
78
|
+
define_singleton_method("#{name}_as_a_hash") { @table[name] }
|
79
|
+
end
|
80
|
+
name
|
81
|
+
end
|
82
|
+
|
83
|
+
def build_sub_elements_key_cache(name)
|
84
|
+
value = @table[name]
|
85
|
+
if value.is_a?(Hash)
|
86
|
+
@sub_elements[name] = self.class.new(value, :recurse_over_arrays => @recurse_over_arrays)
|
87
|
+
elsif value.is_a?(Array) and @recurse_over_arrays
|
88
|
+
@sub_elements[name] = recurse_over_array value
|
89
|
+
else
|
90
|
+
@sub_elements[name] = value
|
91
|
+
end
|
92
|
+
@sub_elements[name]
|
93
|
+
end
|
94
|
+
|
95
|
+
def recurse_over_array(array)
|
96
|
+
array.map do |a|
|
97
|
+
if a.is_a? Hash
|
98
|
+
self.class.new(a, :recurse_over_arrays => true)
|
99
|
+
elsif a.is_a? Array
|
100
|
+
recurse_over_array a
|
101
|
+
else
|
102
|
+
a
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
87
107
|
# Dynamically handle any attempts to get or set values via dot syntax
|
88
108
|
# if the OpenStruct member methods haven't already been created
|
89
109
|
def method_missing(mid, *args) # :nodoc:
|
@@ -93,10 +113,13 @@ class FancyOpenStruct < OpenStruct
|
|
93
113
|
raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1) if len != 1
|
94
114
|
# Set up an instance method to point to the key/value in the table and set the value
|
95
115
|
modifiable[new_ostruct_member(mname.to_sym)] = args[0]
|
116
|
+
build_sub_elements_key_cache(mname.to_sym)
|
117
|
+
@table[mname.to_sym]
|
96
118
|
elsif @table.has_key?(mid)
|
97
119
|
# The table has apparently been modified externally, so we need to set up
|
98
120
|
# an instance method to point to the key/value in the table.
|
99
121
|
new_ostruct_member(mname.to_sym)
|
122
|
+
build_sub_elements_key_cache(mname.to_sym)
|
100
123
|
self.send(mid)
|
101
124
|
else
|
102
125
|
nil
|
@@ -127,6 +127,18 @@ describe FancyOpenStruct do
|
|
127
127
|
fos.to_h.should == {:blah => "John Smith"}
|
128
128
|
fos[:blah].should == "John Smith"
|
129
129
|
end
|
130
|
+
|
131
|
+
it 'lets you access keys via strings or symbols' do
|
132
|
+
h = {'blah' => 'John Smith'}
|
133
|
+
fos = FancyOpenStruct.new(h)
|
134
|
+
fos.to_h.should == {:blah => "John Smith"}
|
135
|
+
fos['blah'].should == "John Smith"
|
136
|
+
fos['foo'] = 'bar'
|
137
|
+
fos.foo.should == 'bar'
|
138
|
+
fos[:foo].should == 'bar'
|
139
|
+
fos['foo'].should == 'bar'
|
140
|
+
fos.to_h.should == {:blah => "John Smith", :foo => 'bar'}
|
141
|
+
end
|
130
142
|
end
|
131
143
|
end
|
132
144
|
|
@@ -216,6 +228,32 @@ describe FancyOpenStruct do
|
|
216
228
|
subject.foo.blah[1].foo.should == "Dr Scott"
|
217
229
|
end
|
218
230
|
|
231
|
+
it 'recurses and updates both shallow and deep values if they are changed' do
|
232
|
+
fos = FancyOpenStruct.new({}, :recurse_over_arrays => true)
|
233
|
+
deep_array_hash = [
|
234
|
+
{
|
235
|
+
:foo =>
|
236
|
+
{:bar => :baz}
|
237
|
+
},
|
238
|
+
{
|
239
|
+
:qux => [
|
240
|
+
{:zap => :zam}, {:zip => :boop}
|
241
|
+
]
|
242
|
+
}
|
243
|
+
]
|
244
|
+
fos.bar = deep_array_hash
|
245
|
+
fos.bar[0].foo.bar.should == :baz
|
246
|
+
fos.bar[1].qux[0].zap.should == :zam
|
247
|
+
fos.bar[1].qux[0].zap = :changed1
|
248
|
+
fos.bar[1].qux[0].zap.should == :changed1
|
249
|
+
fos.bar[1].qux[1].zip.should == :boop
|
250
|
+
fos.bar[1].qux[1].zip = :changed2
|
251
|
+
fos.bar[1].qux[1].zip.should == :changed2
|
252
|
+
fos.bar = {:qux_new => [{:zap => :zam}, {:zip => :boop}]}
|
253
|
+
fos.bar.qux.should be_nil
|
254
|
+
fos.bar.qux_new[0].zap.should == :zam
|
255
|
+
fos.bar.qux_new[1].zip.should == :boop
|
256
|
+
end
|
219
257
|
end
|
220
258
|
|
221
259
|
context "when array is in an array" do
|
@@ -285,6 +323,13 @@ describe FancyOpenStruct do
|
|
285
323
|
fossc.one.first.class.should == FancyOpenStructSubClass
|
286
324
|
end
|
287
325
|
|
326
|
+
it 'returns nil for missing keys' do
|
327
|
+
fos = FancyOpenStruct.new {}
|
328
|
+
fos.foo.should be_nil
|
329
|
+
fos['bar'].should be_nil
|
330
|
+
fos[:baz].should be_nil
|
331
|
+
end
|
332
|
+
|
288
333
|
describe 'method aliases' do
|
289
334
|
it 'responds to #to_hash' do
|
290
335
|
FancyOpenStruct.new.respond_to?(:to_hash).should be_true
|