recursive-open-struct 1.1.1 → 1.1.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.
- checksums.yaml +4 -4
- data/AUTHORS.txt +1 -0
- data/CHANGELOG.md +9 -0
- data/lib/recursive_open_struct.rb +36 -25
- data/lib/recursive_open_struct/version.rb +1 -1
- data/spec/recursive_open_struct/recursion_spec.rb +37 -0
- metadata +2 -3
- data/lib/recursive_open_struct/ruby_19_backport.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f4474b5a862c6ea4da4f2c930664880ca70a01f75c077a2e9952fd80ed2d26da
|
4
|
+
data.tar.gz: dcea4c80ebe98a5f91f9ea40b2b7e82cc219b259eae83b62a00329f8075cc85a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e8698402e67013a209a3434235e26201550c2249db8ae82480ec2208bdd0c83fb6524be046ecb4af3ed8cfe09adebd513a383d56b8b40d91f2c973fcd1f18196
|
7
|
+
data.tar.gz: a15827f31947ca85607086b9cda61ab18b4421bb310dd3034ca4dd39ef43ecf5215d599103cb897152924d6faa1ae94e0bc800cf197c5e96ab50fc794c547a2c
|
data/AUTHORS.txt
CHANGED
@@ -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>
|
data/CHANGELOG.md
CHANGED
@@ -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
|
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
|
-
@
|
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] ||=
|
60
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
145
|
-
@table.delete
|
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] =
|
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
|
@@ -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.
|
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-
|
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
|
-
|