recursive-open-struct 2.0.0 → 2.1.1
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 +4 -1
- data/CHANGELOG.md +24 -0
- data/lib/recursive-open-struct.rb +2 -0
- data/lib/recursive_open_struct/debug_inspect.rb +37 -29
- data/lib/recursive_open_struct/deep_dup.rb +32 -25
- data/lib/recursive_open_struct/dig.rb +8 -4
- data/lib/recursive_open_struct/version.rb +3 -1
- data/lib/recursive_open_struct.rb +34 -18
- metadata +57 -40
- data/.document +0 -5
- data/.github/workflows/ruby.yml +0 -38
- data/.gitignore +0 -52
- data/.rspec +0 -1
- data/.travis.yml +0 -34
- data/CONTRIBUTING.md +0 -51
- data/Gemfile +0 -2
- data/Rakefile +0 -60
- data/recursive-open-struct.gemspec +0 -46
- data/spec/recursive_open_struct/debug_inspect_spec.rb +0 -70
- data/spec/recursive_open_struct/indifferent_access_spec.rb +0 -190
- data/spec/recursive_open_struct/open_struct_behavior_spec.rb +0 -148
- data/spec/recursive_open_struct/ostruct_2_0_0_spec.rb +0 -111
- data/spec/recursive_open_struct/ostruct_2_3_0_spec.rb +0 -49
- data/spec/recursive_open_struct/recursion_and_subclassing_spec.rb +0 -14
- data/spec/recursive_open_struct/recursion_spec.rb +0 -355
- data/spec/spec_helper.rb +0 -19
data/.travis.yml
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
language: ruby
|
|
3
|
-
rvm:
|
|
4
|
-
# No longer supported (but test anyways)
|
|
5
|
-
- 2.0.0
|
|
6
|
-
- 2.1.10
|
|
7
|
-
- 2.2.10
|
|
8
|
-
- jruby-19mode
|
|
9
|
-
- 2.3.8
|
|
10
|
-
- 2.4.10
|
|
11
|
-
# Current stable supported by Travis
|
|
12
|
-
- 2.5.8
|
|
13
|
-
- 2.6.6
|
|
14
|
-
- 2.7.2
|
|
15
|
-
- 3.0.0
|
|
16
|
-
- jruby-9.1.9.0
|
|
17
|
-
# Future
|
|
18
|
-
- ruby-head
|
|
19
|
-
- jruby-head
|
|
20
|
-
- truffleruby-head
|
|
21
|
-
sudo: false
|
|
22
|
-
matrix:
|
|
23
|
-
allow_failures:
|
|
24
|
-
# No longer supported
|
|
25
|
-
- rvm: 2.0.0
|
|
26
|
-
- rvm: 2.1.10
|
|
27
|
-
- rvm: 2.2.10
|
|
28
|
-
- rvm: 2.3.8
|
|
29
|
-
- rvm: 2.4.10
|
|
30
|
-
- rvm: jruby-19mode
|
|
31
|
-
# Future
|
|
32
|
-
- rvm: ruby-head
|
|
33
|
-
- rvm: jruby-head
|
|
34
|
-
- rvm: truffleruby-head
|
data/CONTRIBUTING.md
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
# Contributing to recursive-open-struct
|
|
2
|
-
|
|
3
|
-
Thanks for wanting to contribute a bug or code to recursive-open-struct!
|
|
4
|
-
|
|
5
|
-
To help you out with understanding the direction and philosophy of this project
|
|
6
|
-
with regards to to new features/how it should behave (and whether to file a bug
|
|
7
|
-
report), please review the following contribution guidelines.
|
|
8
|
-
|
|
9
|
-
## ROS Feature Philosophy
|
|
10
|
-
|
|
11
|
-
Recursive-open-struct tries to be a minimal extension to the Ruby stdlib's
|
|
12
|
-
`ostruct`/OpenStruct that allows for a nested set of Hashes (and Arrays) to
|
|
13
|
-
initialize similarly structured OpenStruct-like objects. This has the benefit
|
|
14
|
-
of creating arbitrary objects whose values can be accessed with accessor
|
|
15
|
-
methods, similar to JavaScript Objects' dot-notation.
|
|
16
|
-
|
|
17
|
-
To phrase it another way, RecursiveOpenStruct tries to behave as closely as
|
|
18
|
-
possible to OpenStruct, except for the recursive functionality that it adds.
|
|
19
|
-
|
|
20
|
-
If Recursive-open-struct were to add additional features (particularly methods)
|
|
21
|
-
that are not implemented by OpenStruct, then those method names would not be
|
|
22
|
-
available for use for accessing fields with the dot-notation that OpenStruct
|
|
23
|
-
and RecursiveOpenStruct provide.
|
|
24
|
-
|
|
25
|
-
For example, OpenStruct is not (at the time this is written) a
|
|
26
|
-
subclass/specialization of Hash, so several methods implemented by Hash do not
|
|
27
|
-
work with OpenStruct (and thus Recursive OpenStruct), such as `#fetch`.
|
|
28
|
-
|
|
29
|
-
If you want to add features into RecursiveOpenStruct that would "pollute" the
|
|
30
|
-
method namespace more than OpenStruct already does, consider creating your own
|
|
31
|
-
subclass instead of submitting a code change to RecursiveOpenStruct itself.
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
## Filing/Fixing Bugs and Requesting/Proposing New Features
|
|
35
|
-
|
|
36
|
-
For simple bug fixes, feel free to provide a pull request. This includes bugs
|
|
37
|
-
in stated features of RecursiveOpenStruct, as well as features added to
|
|
38
|
-
OpenStruct in a newer version of Ruby that RecursiveOpenStruct needs custom
|
|
39
|
-
support to handle.
|
|
40
|
-
|
|
41
|
-
For anything else (new features, bugs that you want to report, and bugs that
|
|
42
|
-
are difficult to fix), I recommend opening an issue first to discuss the
|
|
43
|
-
feature or bug. I am fairly cautious about adding new features that might cause
|
|
44
|
-
RecursiveOpenStruct's API to deviate radically from OpenStruct's (since it
|
|
45
|
-
might introduce new reserved method names), and it is useful to discuss the
|
|
46
|
-
best way to solve a problem when there are tradeoffs or imperfect solutions.
|
|
47
|
-
|
|
48
|
-
When contributing code that changes behavior or fixes bugs, please include unit
|
|
49
|
-
tests to cover the new behavior or to provide regression testing for bugs.
|
|
50
|
-
Also, treat the unit tests as documentation --- make sure they are clean,
|
|
51
|
-
clear, and concise, and well organized.
|
data/Gemfile
DELETED
data/Rakefile
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
|
|
3
|
-
require 'rubygems'
|
|
4
|
-
require 'bundler/gem_tasks'
|
|
5
|
-
|
|
6
|
-
require 'rspec/core/rake_task'
|
|
7
|
-
RSpec::Core::RakeTask.new(:spec) do |spec|
|
|
8
|
-
spec.pattern = FileList['spec/**/*_spec.rb']
|
|
9
|
-
end
|
|
10
|
-
namespace :spec do
|
|
11
|
-
if RUBY_VERSION =~ /^1\.8/
|
|
12
|
-
desc "Rspec code coverage (1.8.7)"
|
|
13
|
-
RSpec::Core::RakeTask.new(:coverage) do |spec|
|
|
14
|
-
spec.pattern = 'spec/**/*_spec.rb'
|
|
15
|
-
spec.rcov = true
|
|
16
|
-
end
|
|
17
|
-
else
|
|
18
|
-
desc "Rspec code coverage (1.9+)"
|
|
19
|
-
task :coverage do
|
|
20
|
-
ENV['COVERAGE'] = 'true'
|
|
21
|
-
Rake::Task["spec"].execute
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
require 'rdoc/task'
|
|
27
|
-
Rake::RDocTask.new do |rdoc|
|
|
28
|
-
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
|
29
|
-
|
|
30
|
-
rdoc.rdoc_dir = 'rdoc'
|
|
31
|
-
rdoc.title = "recursive-open-struct #{version}"
|
|
32
|
-
rdoc.rdoc_files.include('README*')
|
|
33
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
task :default => :spec
|
|
37
|
-
|
|
38
|
-
task :fix_permissions do
|
|
39
|
-
File.umask 0022
|
|
40
|
-
filelist = `git ls-files`.split("\n")
|
|
41
|
-
FileUtils.chmod 0644, filelist, :verbose => true
|
|
42
|
-
FileUtils.chmod 0755, ['lib','spec'], :verbose => true
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
desc "Update the AUTHORS.txt file"
|
|
46
|
-
task :update_authors do
|
|
47
|
-
authors = `git log --format="%aN <%aE>"|sort -f|uniq`
|
|
48
|
-
File.open('AUTHORS.txt', 'w') do |f|
|
|
49
|
-
f.write("Recursive-open-struct was written by these fine people:\n\n")
|
|
50
|
-
f.write(authors.split("\n").map { |a| "* #{a}" }.join( "\n" ))
|
|
51
|
-
f.write("\n")
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
task :build => [:update_authors, :fix_permissions]
|
|
56
|
-
|
|
57
|
-
desc "Run an interactive pry shell with ros required"
|
|
58
|
-
task :pry do
|
|
59
|
-
sh "pry -I lib -r recursive-open-struct"
|
|
60
|
-
end
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
|
-
|
|
3
|
-
require './lib/recursive_open_struct/version'
|
|
4
|
-
|
|
5
|
-
Gem::Specification.new do |s|
|
|
6
|
-
s.name = "recursive-open-struct"
|
|
7
|
-
s.version = RecursiveOpenStruct::VERSION
|
|
8
|
-
s.authors = ["William (B.J.) Snow Orvis"]
|
|
9
|
-
s.email = "aetherknight@gmail.com"
|
|
10
|
-
s.date = Time.now.utc.strftime("%Y-%m-%d")
|
|
11
|
-
s.homepage = "https://github.com/aetherknight/recursive-open-struct"
|
|
12
|
-
s.licenses = ["MIT"]
|
|
13
|
-
|
|
14
|
-
s.summary = "OpenStruct subclass that returns nested hash attributes as RecursiveOpenStructs"
|
|
15
|
-
s.description = <<-QUOTE .gsub(/^ /,'')
|
|
16
|
-
RecursiveOpenStruct is a subclass of OpenStruct. It differs from
|
|
17
|
-
OpenStruct in that it allows nested hashes to be treated in a recursive
|
|
18
|
-
fashion. For example:
|
|
19
|
-
|
|
20
|
-
ros = RecursiveOpenStruct.new({ :a => { :b => 'c' } })
|
|
21
|
-
ros.a.b # 'c'
|
|
22
|
-
|
|
23
|
-
Also, nested hashes can still be accessed as hashes:
|
|
24
|
-
|
|
25
|
-
ros.a_as_a_hash # { :b => 'c' }
|
|
26
|
-
QUOTE
|
|
27
|
-
|
|
28
|
-
s.files = `git ls-files`.split("\n")
|
|
29
|
-
s.test_files = `git ls-files spec`.split("\n")
|
|
30
|
-
s.require_paths = ["lib"]
|
|
31
|
-
s.extra_rdoc_files = [
|
|
32
|
-
"CHANGELOG.md",
|
|
33
|
-
"LICENSE.txt",
|
|
34
|
-
"README.md"
|
|
35
|
-
]
|
|
36
|
-
|
|
37
|
-
s.add_development_dependency('bundler', [">= 0"])
|
|
38
|
-
s.add_development_dependency('pry', [">= 0"])
|
|
39
|
-
s.add_development_dependency('rake', [">= 0"])
|
|
40
|
-
s.add_development_dependency('rdoc', [">= 0"])
|
|
41
|
-
s.add_development_dependency('rspec', "~> 3.2")
|
|
42
|
-
s.add_development_dependency('simplecov', [">= 0"])
|
|
43
|
-
|
|
44
|
-
s.add_dependency('ostruct')
|
|
45
|
-
end
|
|
46
|
-
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
require_relative '../spec_helper'
|
|
2
|
-
require 'recursive_open_struct'
|
|
3
|
-
|
|
4
|
-
describe RecursiveOpenStruct do
|
|
5
|
-
describe "#debug_inspect" do
|
|
6
|
-
before(:each) do
|
|
7
|
-
h1 = { :a => 'a'}
|
|
8
|
-
h2 = { :a => 'b', :h1 => h1 }
|
|
9
|
-
h1[:h2] = h2
|
|
10
|
-
@ros = RecursiveOpenStruct.new(h2)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
it "should have a simple way of display" do
|
|
14
|
-
@output = <<-QUOTE
|
|
15
|
-
a = "b"
|
|
16
|
-
h1.
|
|
17
|
-
a = "a"
|
|
18
|
-
h2.
|
|
19
|
-
a = "b"
|
|
20
|
-
h1.
|
|
21
|
-
a = "a"
|
|
22
|
-
h2.
|
|
23
|
-
a = "b"
|
|
24
|
-
h1.
|
|
25
|
-
a = "a"
|
|
26
|
-
h2.
|
|
27
|
-
a = "b"
|
|
28
|
-
h1.
|
|
29
|
-
a = "a"
|
|
30
|
-
h2.
|
|
31
|
-
a = "b"
|
|
32
|
-
h1.
|
|
33
|
-
a = "a"
|
|
34
|
-
h2.
|
|
35
|
-
a = "b"
|
|
36
|
-
h1.
|
|
37
|
-
a = "a"
|
|
38
|
-
h2.
|
|
39
|
-
(recursion limit reached)
|
|
40
|
-
QUOTE
|
|
41
|
-
@io = StringIO.new
|
|
42
|
-
@ros.debug_inspect(@io)
|
|
43
|
-
expect(@io.string).to match /^a = "b"$/
|
|
44
|
-
expect(@io.string).to match /^h1\.$/
|
|
45
|
-
expect(@io.string).to match /^ a = "a"$/
|
|
46
|
-
expect(@io.string).to match /^ h2\.$/
|
|
47
|
-
expect(@io.string).to match /^ a = "b"$/
|
|
48
|
-
expect(@io.string).to match /^ h1\.$/
|
|
49
|
-
expect(@io.string).to match /^ a = "a"$/
|
|
50
|
-
expect(@io.string).to match /^ h2\.$/
|
|
51
|
-
expect(@io.string).to match /^ a = "b"$/
|
|
52
|
-
expect(@io.string).to match /^ h1\.$/
|
|
53
|
-
expect(@io.string).to match /^ a = "a"$/
|
|
54
|
-
expect(@io.string).to match /^ h2\.$/
|
|
55
|
-
expect(@io.string).to match /^ a = "b"$/
|
|
56
|
-
expect(@io.string).to match /^ h1\.$/
|
|
57
|
-
expect(@io.string).to match /^ a = "a"$/
|
|
58
|
-
expect(@io.string).to match /^ h2\.$/
|
|
59
|
-
expect(@io.string).to match /^ a = "b"$/
|
|
60
|
-
expect(@io.string).to match /^ h1\.$/
|
|
61
|
-
expect(@io.string).to match /^ a = "a"$/
|
|
62
|
-
expect(@io.string).to match /^ h2\.$/
|
|
63
|
-
expect(@io.string).to match /^ a = "b"$/
|
|
64
|
-
expect(@io.string).to match /^ h1\.$/
|
|
65
|
-
expect(@io.string).to match /^ a = "a"$/
|
|
66
|
-
expect(@io.string).to match /^ h2\.$/
|
|
67
|
-
expect(@io.string).to match /^ \(recursion limit reached\)$/
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
end
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
require_relative '../spec_helper'
|
|
2
|
-
require 'recursive_open_struct'
|
|
3
|
-
|
|
4
|
-
describe RecursiveOpenStruct do
|
|
5
|
-
let(:value) { 'foo' }
|
|
6
|
-
let(:symbol) { :bar }
|
|
7
|
-
let(:new_value) { 'bar' }
|
|
8
|
-
let(:new_symbol) { :foo }
|
|
9
|
-
|
|
10
|
-
describe 'indifferent access' do
|
|
11
|
-
let(:hash) { {:foo => value, 'bar' => symbol} }
|
|
12
|
-
let(:hash_ros_opts) { {} }
|
|
13
|
-
subject(:hash_ros) { RecursiveOpenStruct.new(hash, hash_ros_opts) }
|
|
14
|
-
|
|
15
|
-
context 'setting value with method' do
|
|
16
|
-
before(:each) do
|
|
17
|
-
subject.foo = value
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
it('allows getting with method') { expect(subject.foo).to be value }
|
|
21
|
-
it('allows getting with symbol') { expect(subject[:foo]).to be value }
|
|
22
|
-
it('allows getting with string') { expect(subject['foo']).to be value }
|
|
23
|
-
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
context 'setting value with symbol' do
|
|
27
|
-
before(:each) do
|
|
28
|
-
subject[:foo] = value
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
it('allows getting with method') { expect(subject.foo).to be value }
|
|
32
|
-
it('allows getting with symbol') { expect(subject[:foo]).to be value }
|
|
33
|
-
it('allows getting with string') { expect(subject['foo']).to be value }
|
|
34
|
-
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
context 'setting value with string' do
|
|
38
|
-
before(:each) do
|
|
39
|
-
subject['foo'] = value
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
it('allows getting with method') { expect(subject.foo).to be value }
|
|
43
|
-
it('allows getting with symbol') { expect(subject[:foo]).to be value }
|
|
44
|
-
it('allows getting with string') { expect(subject['foo']).to be value }
|
|
45
|
-
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
context 'overwriting values' do
|
|
49
|
-
context 'set with method' do
|
|
50
|
-
before(:each) do
|
|
51
|
-
subject.foo = value
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
it('overrides with symbol') do
|
|
55
|
-
subject[:foo] = new_value
|
|
56
|
-
expect(subject.foo).to be new_value
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
it('overrides with string') do
|
|
60
|
-
subject['foo'] = new_value
|
|
61
|
-
expect(subject.foo).to be new_value
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
context 'set with symbol' do
|
|
66
|
-
before(:each) do
|
|
67
|
-
subject[:foo] = value
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
it('overrides with method') do
|
|
71
|
-
subject.foo = new_value
|
|
72
|
-
expect(subject[:foo]).to be new_value
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
it('overrides with string') do
|
|
76
|
-
subject['foo'] = new_value
|
|
77
|
-
expect(subject[:foo]).to be new_value
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
context 'set with string' do
|
|
82
|
-
before(:each) do
|
|
83
|
-
subject['foo'] = value
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
it('overrides with method') do
|
|
87
|
-
subject.foo = new_value
|
|
88
|
-
expect(subject['foo']).to be new_value
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
it('overrides with symbol') do
|
|
92
|
-
subject[:foo] = new_value
|
|
93
|
-
expect(subject['foo']).to be new_value
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
context 'set with hash' do
|
|
98
|
-
it('overrides with method') do
|
|
99
|
-
hash_ros.foo = new_value
|
|
100
|
-
expect(hash_ros[:foo]).to be new_value
|
|
101
|
-
|
|
102
|
-
hash_ros.bar = new_symbol
|
|
103
|
-
expect(hash_ros['bar']).to be new_symbol
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
it('overrides with symbol') do
|
|
107
|
-
hash_ros[:bar] = new_symbol
|
|
108
|
-
expect(hash_ros['bar']).to be new_symbol
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
it('overrides with string') do
|
|
112
|
-
hash_ros['foo'] = new_value
|
|
113
|
-
expect(hash_ros[:foo]).to be new_value
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
context 'when preserve_original_keys is not enabled' do
|
|
118
|
-
context 'transforms original keys to symbols' do
|
|
119
|
-
subject(:recursive) { RecursiveOpenStruct.new(recursive_hash, recurse_over_arrays: true) }
|
|
120
|
-
let(:recursive_hash) { {:foo => [ {'bar' => [ { 'foo' => :bar} ] } ] } }
|
|
121
|
-
let(:symbolized_recursive_hash) { {:foo => [ {:bar => [ { :foo => :bar} ] } ] } }
|
|
122
|
-
let(:symbolized_modified_hash) { {:foo => [ {:bar => [ { :foo => :foo} ] } ] } }
|
|
123
|
-
let(:symbolized_hash) { Hash[hash.map{|(k,v)| [k.to_sym,v]}] }
|
|
124
|
-
|
|
125
|
-
specify 'after initialization' do
|
|
126
|
-
expect(hash_ros.to_h).to eq symbolized_hash
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
specify 'in recursive hashes' do
|
|
130
|
-
expect(recursive.to_h).to eq symbolized_recursive_hash
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
specify 'after resetting value' do
|
|
134
|
-
recursive.foo.first[:bar].first[:foo] = :foo
|
|
135
|
-
expect(recursive.to_h).to eq symbolized_modified_hash
|
|
136
|
-
end
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
|
|
140
|
-
context 'when preserve_original_keys is enabled' do
|
|
141
|
-
context 'preserves the original keys' do
|
|
142
|
-
subject(:recursive) { RecursiveOpenStruct.new(recursive_hash, recurse_over_arrays: true, preserve_original_keys: true) }
|
|
143
|
-
let(:recursive_hash) { {:foo => [ {'bar' => [ { 'foo' => :bar} ] } ] } }
|
|
144
|
-
let(:modified_hash) { {:foo => [ {'bar' => [ { 'foo' => :foo} ] } ] } }
|
|
145
|
-
|
|
146
|
-
let(:hash_ros_opts) { { preserve_original_keys: true }}
|
|
147
|
-
|
|
148
|
-
specify 'after initialization' do
|
|
149
|
-
expect(hash_ros.to_h).to eq hash
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
specify 'in recursive hashes' do
|
|
153
|
-
expect(recursive.to_h).to eq recursive_hash
|
|
154
|
-
end
|
|
155
|
-
|
|
156
|
-
specify 'after resetting value' do
|
|
157
|
-
recursive.foo.first[:bar].first[:foo] = :foo
|
|
158
|
-
expect(recursive.to_h).to eq modified_hash
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
context 'when undefined method' do
|
|
164
|
-
context 'when raise_on_missing is enabled' do
|
|
165
|
-
subject(:recursive) { RecursiveOpenStruct.new(recursive_hash, raise_on_missing: true) }
|
|
166
|
-
let(:recursive_hash) { {:foo => [ {'bar' => [ { 'foo' => :bar} ] } ] } }
|
|
167
|
-
|
|
168
|
-
specify 'raises NoMethodError' do
|
|
169
|
-
expect {
|
|
170
|
-
recursive.undefined_method
|
|
171
|
-
}.to raise_error(NoMethodError)
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
context 'when raise_on_missing is disabled' do
|
|
176
|
-
context 'preserves the original keys' do
|
|
177
|
-
subject(:recursive) { RecursiveOpenStruct.new(recursive_hash) }
|
|
178
|
-
let(:recursive_hash) { {:foo => [ {'bar' => [ { 'foo' => :bar} ] } ] } }
|
|
179
|
-
|
|
180
|
-
specify 'returns nil' do
|
|
181
|
-
expect(recursive.undefined_method).to be_nil
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
|
-
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
end
|
|
190
|
-
end
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
require_relative '../spec_helper'
|
|
2
|
-
require 'recursive_open_struct'
|
|
3
|
-
|
|
4
|
-
describe RecursiveOpenStruct do
|
|
5
|
-
let(:hash) { {} }
|
|
6
|
-
subject(:ros) { RecursiveOpenStruct.new(hash) }
|
|
7
|
-
|
|
8
|
-
describe "behavior it inherits from OpenStruct" do
|
|
9
|
-
context 'when not initialized from anything' do
|
|
10
|
-
subject(:ros) { RecursiveOpenStruct.new }
|
|
11
|
-
it "can represent arbitrary data objects" do
|
|
12
|
-
ros.blah = "John Smith"
|
|
13
|
-
expect(ros.blah).to eq "John Smith"
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
it 'returns nil for missing attributes' do
|
|
17
|
-
expect(ros.foo).to be_nil
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
context 'when initialized with nil' do
|
|
22
|
-
let(:hash) { nil }
|
|
23
|
-
it 'returns nil for missing attributes' do
|
|
24
|
-
expect(ros.foo).to be_nil
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
context 'when initialized with an empty hash' do
|
|
29
|
-
it 'returns nil for missing attributes' do
|
|
30
|
-
expect(ros.foo).to be_nil
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
context "when initialized from a hash" do
|
|
35
|
-
let(:hash) { { :asdf => 'John Smith' } }
|
|
36
|
-
|
|
37
|
-
context 'that contains symbol keys' do
|
|
38
|
-
it "turns those symbol keys into method names" do
|
|
39
|
-
expect(ros.asdf).to eq "John Smith"
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
it "can modify an existing key" do
|
|
44
|
-
ros.asdf = "George Washington"
|
|
45
|
-
expect(ros.asdf).to eq "George Washington"
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
context 'that contains string keys' do
|
|
49
|
-
let(:hash) { { 'asdf' => 'John Smith' } }
|
|
50
|
-
it "turns those string keys into method names" do
|
|
51
|
-
expect(ros.asdf).to eq "John Smith"
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
context 'that contains keys that mirror existing private methods' do
|
|
56
|
-
let(:hash) { { test: :foo, rand: 'not a number' } }
|
|
57
|
-
|
|
58
|
-
# https://github.com/aetherknight/recursive-open-struct/issues/42
|
|
59
|
-
it 'handles subscript notation without calling the method name first (#42)' do
|
|
60
|
-
expect(ros['test']).to eq :foo
|
|
61
|
-
expect(ros['rand']).to eq 'not a number'
|
|
62
|
-
|
|
63
|
-
expect(ros.test).to eq :foo
|
|
64
|
-
expect(ros.rand).to eq 'not a number'
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
context 'that contains keys that mirror existing public methods inherited from Object' do
|
|
70
|
-
let(:hash) { { method: :something } }
|
|
71
|
-
it 'handles subscript notation without calling the existing methods' do
|
|
72
|
-
expect(ros[:method]).to eq :something
|
|
73
|
-
expect(ros['method']).to eq :something
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
if [/\A([0-9]+)\.([0-9]+)\.([0-9]+)\z/.match(RUBY_VERSION)].tap { |l| m = l[0] ; l[0] = (m[1].to_i >= 2 && m[2].to_i >= 4) }.first
|
|
78
|
-
context 'when Ruby 2.4.0 or newer' do
|
|
79
|
-
specify 'new_ostruct_member! is private' do
|
|
80
|
-
expect {
|
|
81
|
-
ros.new_ostruct_member!(:bonsoir)
|
|
82
|
-
}.to raise_error(NoMethodError)
|
|
83
|
-
# OpenStruct.new().new_ostruct_member!(:foo)
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
describe "handling of arbitrary attributes" do
|
|
92
|
-
subject { RecursiveOpenStruct.new }
|
|
93
|
-
before(:each) do
|
|
94
|
-
subject.blah = "John Smith"
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
describe "#respond?" do
|
|
98
|
-
it { expect(subject).to respond_to :blah }
|
|
99
|
-
it { expect(subject).to respond_to :blah= }
|
|
100
|
-
it { expect(subject).to_not respond_to :asdf }
|
|
101
|
-
it { expect(subject).to_not respond_to :asdf= }
|
|
102
|
-
end # describe #respond?
|
|
103
|
-
|
|
104
|
-
describe "#methods" do
|
|
105
|
-
it { expect(subject.methods.map(&:to_sym)).to include :blah }
|
|
106
|
-
it { expect(subject.methods.map(&:to_sym)).to include :blah= }
|
|
107
|
-
it { expect(subject.methods.map(&:to_sym)).to_not include :asdf }
|
|
108
|
-
it { expect(subject.methods.map(&:to_sym)).to_not include :asdf= }
|
|
109
|
-
end # describe #methods
|
|
110
|
-
end # describe handling of arbitrary attributes
|
|
111
|
-
|
|
112
|
-
describe "handling of freezing" do
|
|
113
|
-
let(:hash) { { :asdf => 'John Smith' } }
|
|
114
|
-
|
|
115
|
-
before do
|
|
116
|
-
ros.freeze
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
it "can read existing keys" do
|
|
120
|
-
expect(ros.asdf).to eq 'John Smith'
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
it "cannot write new keys" do
|
|
124
|
-
expect { ros.new_key = 'new_value' }.to raise_error FrozenError
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
it "cannot write existing keys" do
|
|
128
|
-
expect { ros.asdf = 'new_value' }.to raise_error FrozenError
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
context "with recursive structure" do
|
|
132
|
-
let(:hash) { { :key => { :subkey => 42 } } }
|
|
133
|
-
|
|
134
|
-
it "can read existing sub-elements" do
|
|
135
|
-
expect(ros.key.subkey).to eq 42
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
it "can write new sub-elements" do
|
|
139
|
-
expect { ros.key.new_subkey = 43 }.not_to raise_error
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
it "can write existing sub-elements" do
|
|
143
|
-
expect { ros.key.subkey = 43 }.not_to raise_error
|
|
144
|
-
end
|
|
145
|
-
end
|
|
146
|
-
end
|
|
147
|
-
end # describe behavior it inherits from OpenStruct
|
|
148
|
-
end
|