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.
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
@@ -1,2 +0,0 @@
1
- source 'https://rubygems.org'
2
- gemspec
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