recursive-open-struct 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aef116134efc7102292ad51046c306be7e93621f688e02255996ca218ed578b1
4
- data.tar.gz: 722c1e817dbdd25d4a48deb5923ce6f83de55211dd86c00a5c292f91e86bc74b
3
+ metadata.gz: f4474b5a862c6ea4da4f2c930664880ca70a01f75c077a2e9952fd80ed2d26da
4
+ data.tar.gz: dcea4c80ebe98a5f91f9ea40b2b7e82cc219b259eae83b62a00329f8075cc85a
5
5
  SHA512:
6
- metadata.gz: fde1398adbd2795f9f108859d1d6c963a89048275be0fbf5e5cb1f92abb404ed8a55d4e97a8e2ba0d6367d3a255ecfdfe3dcfacc74d1b9bdd0d0c4e035acbe09
7
- data.tar.gz: 82d16703403627ea358097b26d47334a984107c68a9c5360ac617169c4b9602292a7d7df77a96971ac3369fcca11256457518a61ce9895b7fcf9b58ab924c50b
6
+ metadata.gz: e8698402e67013a209a3434235e26201550c2249db8ae82480ec2208bdd0c83fb6524be046ecb4af3ed8cfe09adebd513a383d56b8b40d91f2c973fcd1f18196
7
+ data.tar.gz: a15827f31947ca85607086b9cda61ab18b4421bb310dd3034ca4dd39ef43ecf5215d599103cb897152924d6faa1ae94e0bc800cf197c5e96ab50fc794c547a2c
@@ -3,6 +3,7 @@ Recursive-open-struct was written by these fine people:
3
3
  * Ben Langfeld <ben@langfeld.me>
4
4
  * Beni Cherniavsky-Paskin <cben@redhat.com>
5
5
  * Cédric Felizard <cedric@felizard.fr>
6
+ * David Feldman <dbfeldman@gmail.com>
6
7
  * Edward Betts <edward@4angle.com>
7
8
  * Ewoud Kohl van Wijngaarden <ewoud@kohlvanwijngaarden.nl>
8
9
  * Federico Aloi <federico.aloi@gmail.com>
@@ -1,3 +1,12 @@
1
+ 1.1.2 / 2020/06/20
2
+ ==================
3
+
4
+ * FIX [#58](https://github.com/aetherknight/recursive-open-struct/pull/58):
5
+ David Feldman: Fix `[]=` so that it properly updates sub-elements
6
+ * [#58](https://github.com/aetherknight/recursive-open-struct/pull/58):
7
+ David Feldman: Make the default options configurable at the class level to
8
+ simplify adding additional options in subclasses
9
+
1
10
  1.1.1 / 2020/03/10
2
11
  ==================
3
12
 
@@ -3,7 +3,6 @@ require 'recursive_open_struct/version'
3
3
 
4
4
  require 'recursive_open_struct/debug_inspect'
5
5
  require 'recursive_open_struct/deep_dup'
6
- require 'recursive_open_struct/ruby_19_backport'
7
6
  require 'recursive_open_struct/dig'
8
7
 
9
8
  # TODO: When we care less about Rubies before 2.4.0, match OpenStruct's method
@@ -14,23 +13,28 @@ require 'recursive_open_struct/dig'
14
13
  # `#to_h`.
15
14
 
16
15
  class RecursiveOpenStruct < OpenStruct
17
- include Ruby19Backport if RUBY_VERSION =~ /\A1.9/
18
16
  include Dig if OpenStruct.public_instance_methods.include? :dig
19
17
 
20
18
  # TODO: deprecated, possibly remove or make optional an runtime so that it
21
19
  # doesn't normally pollute the public method namespace
22
20
  include DebugInspect
23
21
 
24
- def initialize(hash=nil, args={})
22
+ def self.default_options
23
+ {
24
+ mutate_input_hash: false,
25
+ recurse_over_arrays: false,
26
+ preserve_original_keys: false
27
+ }
28
+ end
29
+
30
+ def initialize(hash=nil, passed_options={})
25
31
  hash ||= {}
26
- @recurse_over_arrays = args.fetch(:recurse_over_arrays, false)
27
- @preserve_original_keys = args.fetch(:preserve_original_keys, false)
28
- @deep_dup = DeepDup.new(
29
- recurse_over_arrays: @recurse_over_arrays,
30
- preserve_original_keys: @preserve_original_keys
31
- )
32
32
 
33
- @table = args.fetch(:mutate_input_hash, false) ? hash : @deep_dup.call(hash)
33
+ @options = self.class.default_options.merge!(passed_options).freeze
34
+
35
+ @deep_dup = DeepDup.new(@options)
36
+
37
+ @table = @options[:mutate_input_hash] ? hash : @deep_dup.call(hash)
34
38
 
35
39
  @sub_elements = {}
36
40
  end
@@ -56,13 +60,8 @@ class RecursiveOpenStruct < OpenStruct
56
60
  key_name = _get_key_from_table_(name)
57
61
  v = @table[key_name]
58
62
  if v.is_a?(Hash)
59
- @sub_elements[key_name] ||= self.class.new(
60
- v,
61
- recurse_over_arrays: @recurse_over_arrays,
62
- preserve_original_keys: @preserve_original_keys,
63
- mutate_input_hash: true
64
- )
65
- elsif v.is_a?(Array) and @recurse_over_arrays
63
+ @sub_elements[key_name] ||= _create_sub_element_(v, mutate_input_hash: true)
64
+ elsif v.is_a?(Array) and @options[:recurse_over_arrays]
66
65
  @sub_elements[key_name] ||= recurse_over_array(v)
67
66
  @sub_elements[key_name] = recurse_over_array(@sub_elements[key_name])
68
67
  else
@@ -70,6 +69,13 @@ class RecursiveOpenStruct < OpenStruct
70
69
  end
71
70
  end
72
71
 
72
+ def []=(name, value)
73
+ key_name = _get_key_from_table_(name)
74
+ tbl = modifiable? # Ensure we are modifiable
75
+ @sub_elements.delete(key_name)
76
+ tbl[key_name] = value
77
+ end
78
+
73
79
  # Makes sure ROS responds as expected on #respond_to? and #method requests
74
80
  def respond_to_missing?(mid, include_private = false)
75
81
  mname = _get_key_from_table_(mid.to_s.chomp('=').chomp('_as_a_hash'))
@@ -95,13 +101,16 @@ class RecursiveOpenStruct < OpenStruct
95
101
  if len != 1
96
102
  raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
97
103
  end
98
- modifiable?[new_ostruct_member!($1.to_sym)] = args[0]
104
+ # self[$1.to_sym] = args[0]
105
+ # modifiable?[new_ostruct_member!($1.to_sym)] = args[0]
106
+ new_ostruct_member!($1.to_sym)
107
+ public_send(mid, args[0])
99
108
  elsif len == 0
100
109
  key = mid
101
110
  key = $1 if key =~ /^(.*)_as_a_hash$/
102
111
  if @table.key?(_get_key_from_table_(key))
103
112
  new_ostruct_member!(key)
104
- send(mid)
113
+ public_send(mid)
105
114
  end
106
115
  else
107
116
  err = NoMethodError.new "undefined method `#{mid}' for #{self}", mid, args
@@ -120,8 +129,7 @@ class RecursiveOpenStruct < OpenStruct
120
129
  self[key_name]
121
130
  end
122
131
  define_method("#{name}=") do |x|
123
- @sub_elements.delete(key_name)
124
- modifiable?[key_name] = x
132
+ self[key_name] = x
125
133
  end
126
134
  define_method("#{name}_as_a_hash") { @table[key_name] }
127
135
  end
@@ -141,8 +149,8 @@ class RecursiveOpenStruct < OpenStruct
141
149
  def delete_field(name)
142
150
  sym = _get_key_from_table_(name)
143
151
  singleton_class.__send__(:remove_method, sym, "#{sym}=") rescue NoMethodError # ignore if methods not yet generated.
144
- @sub_elements.delete sym
145
- @table.delete sym
152
+ @sub_elements.delete(sym)
153
+ @table.delete(sym)
146
154
  end
147
155
 
148
156
  private
@@ -153,11 +161,14 @@ class RecursiveOpenStruct < OpenStruct
153
161
  name
154
162
  end
155
163
 
164
+ def _create_sub_element_(hash, **overrides)
165
+ self.class.new(hash, @options.merge(overrides))
166
+ end
167
+
156
168
  def recurse_over_array(array)
157
169
  array.each_with_index do |a, i|
158
170
  if a.is_a? Hash
159
- array[i] = self.class.new(a, :recurse_over_arrays => true,
160
- :mutate_input_hash => true, :preserve_original_keys => @preserve_original_keys)
171
+ array[i] = _create_sub_element_(a, mutate_input_hash: true, recurse_over_arrays: true)
161
172
  elsif a.is_a? Array
162
173
  array[i] = recurse_over_array a
163
174
  end
@@ -3,5 +3,5 @@
3
3
  require 'ostruct'
4
4
 
5
5
  class RecursiveOpenStruct < OpenStruct
6
- VERSION = "1.1.1"
6
+ VERSION = "1.1.2"
7
7
  end
@@ -28,6 +28,15 @@ describe RecursiveOpenStruct do
28
28
  expect(subject.blah_as_a_hash).to eq({ :another => 'value' })
29
29
  end
30
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
+
31
40
  describe "handling loops in the original Hashes" do
32
41
  let(:h1) { { :a => 'a'} }
33
42
  let(:h2) { { :a => 'b', :h1 => h1 } }
@@ -55,6 +64,34 @@ describe RecursiveOpenStruct do
55
64
  expect(ros.blah.blargh).to eq "Janet"
56
65
  end
57
66
 
67
+ describe 'subscript mutation notation' do
68
+ it 'handles the basic case' do
69
+ subject[:blah] = 12345
70
+ expect(subject.blah).to eql 12345
71
+ end
72
+
73
+ it 'recurses properly' do
74
+ subject[:blah][:another] = 'abc'
75
+ expect(subject.blah.another).to eql 'abc'
76
+ expect(subject.blah_as_a_hash).to eql({ :another => 'abc' })
77
+ end
78
+
79
+ let(:diff){ { :different => 'thing' } }
80
+
81
+ it 'can replace the entire hash' do
82
+ expect(subject.to_h).to eql(h)
83
+ subject[:blah] = diff
84
+ expect(subject.to_h).to eql({ :blah => diff })
85
+ end
86
+
87
+ it 'updates sub-element cache' do
88
+ expect(subject.blah.different).to be_nil
89
+ subject[:blah] = diff
90
+ expect(subject.blah.different).to eql 'thing'
91
+ expect(subject.blah_as_a_hash).to eql(diff)
92
+ end
93
+ end
94
+
58
95
  context "after a sub-element has been modified" do
59
96
  let(:hash) do
60
97
  { :blah => { :blargh => "Brad" }, :some_array => [ 1, 2, 3] }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: recursive-open-struct
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - William (B.J.) Snow Orvis
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-11 00:00:00.000000000 Z
11
+ date: 2020-06-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -129,7 +129,6 @@ files:
129
129
  - lib/recursive_open_struct/debug_inspect.rb
130
130
  - lib/recursive_open_struct/deep_dup.rb
131
131
  - lib/recursive_open_struct/dig.rb
132
- - lib/recursive_open_struct/ruby_19_backport.rb
133
132
  - lib/recursive_open_struct/version.rb
134
133
  - recursive-open-struct.gemspec
135
134
  - spec/recursive_open_struct/debug_inspect_spec.rb
@@ -1,27 +0,0 @@
1
- module RecursiveOpenStruct::Ruby19Backport
2
- # Apply fix if necessary:
3
- # https://github.com/ruby/ruby/commit/2d952c6d16ffe06a28bb1007e2cd1410c3db2d58
4
- def initialize_copy(orig)
5
- super
6
- @table.each_key{|key| new_ostruct_member(key)}
7
- end
8
-
9
- def []=(name, value)
10
- modifiable[new_ostruct_member(name)] = value
11
- end
12
-
13
- def eql?(other)
14
- return false unless other.kind_of?(OpenStruct)
15
- @table.eql?(other.table)
16
- end
17
-
18
- def hash
19
- @table.hash
20
- end
21
-
22
- def each_pair
23
- return to_enum(:each_pair) { @table.size } unless block_given?
24
- @table.each_pair{|p| yield p}
25
- end
26
- end
27
-