fancy-open-struct 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,4 +8,3 @@ rvm:
8
8
 
9
9
  # Rubies 1.9.x
10
10
  - 1.9.3
11
- - jruby-19mode # JRuby in 1.9 mode
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
@@ -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
- @table[key.to_sym]
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
- modifiable[new_ostruct_member(key.to_sym)] = value
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
@@ -1,5 +1,5 @@
1
1
  require 'ostruct'
2
2
 
3
3
  class FancyOpenStruct < OpenStruct
4
- VERSION = "0.3.0"
4
+ VERSION = "0.4.0"
5
5
  end
@@ -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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fancy-open-struct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: