recursive-open-struct 0.6.5 → 1.0.0

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
  SHA1:
3
- metadata.gz: 16edd384bbe19b6efc58d29e12740a3756f6e51a
4
- data.tar.gz: 97ad4a2805226395ef2df02f61f5482b37bc047f
3
+ metadata.gz: 2d1f3fe927a4c1021ecddcde1416e8f6135043c0
4
+ data.tar.gz: e9ef12ce07604f331d0ccf2d807575c1a41f078b
5
5
  SHA512:
6
- metadata.gz: 731c64834e1e18e6bcb2cd43fb112b6e87ebbabc6d63e31ce8cafaeb377e56f8601f2b9dcc4f02ecc2282f9a11c4176bb3dcd4f592e4126dad5ec6f9f4caf249
7
- data.tar.gz: 173c905112efdc0d907af7de0730af75dd27fc733bd90a591bcb626048d5bb978c001d6e695b618db7204e214f17129ead2953c4fb573572da9ecd87ccd0280b
6
+ metadata.gz: f430a2b3b7a980715c81d850b93e41259b5a3abaffb8101bd04a96cc55ad599862a1405314886753d9122fd8f045e0b4517622a8d9125478148da891f2e312e4
7
+ data.tar.gz: 00ef1d3a89aa84d70499a3cc888e8a69f5f2cc921e8e07512b0290af4786c9d80b3a6a0029f6d79f7b65a2f10efa6438d2ae88d9792288c188be8c2da5b55052
@@ -1,8 +1,12 @@
1
1
  ---
2
2
  language: ruby
3
3
  rvm:
4
- - 1.9.3
5
4
  - 2.0.0
6
- - 2.1.0
7
- - 2.2
5
+ - 2.1.7
6
+ - 2.2.3
7
+ - 2.3.0
8
+ - ruby-head
8
9
  - jruby-19mode
10
+ - jruby-9.0.0.0
11
+ - jruby-head
12
+ sudo: false
@@ -1,3 +1,19 @@
1
+ 1.0.0 / 2015-12-11
2
+ ==================
3
+
4
+ * API-Breaking Change: Frederico Aloi: Change `to_h` to always return symbol
5
+ keys. This is more consistent with OpenStruct.
6
+ * API-Breaking Change: No longer officially supporting Ruby 1.9.3.
7
+ * NEW/FIX: Kris Dekeyser: Ensure that ROS continues to work with the new
8
+ version of OpenStruct included in dev versions of Ruby 2.2.x and Ruby 2.3. It
9
+ now implements lazy attribute creation, which broke ROS.
10
+ * NEW: Added `preserve_original_keys` option to revert to the 0.x behavior. Set
11
+ it to true if you want methods like `to_h` to return strings and perhaps
12
+ other non-symbols.
13
+ * NEW: Ensuring support for Ruby 2.0.0+ including the upcoming 2.3 release and
14
+ JRuby 9000.
15
+ * FIX: Peter Yeremenko: Fix a mistake in one of the examples in the README
16
+
1
17
  0.6.5 / 2015-06-30
2
18
  ==================
3
19
 
data/README.md CHANGED
@@ -5,23 +5,34 @@ RecursiveOpenStructs.
5
5
 
6
6
  It allows for hashes within hashes to be called in a chain of methods:
7
7
 
8
- ros = RecursiveOpenStruct.new( { :fooa => { :foob => 'fooc' } } )
8
+ ros = RecursiveOpenStruct.new( { fooa: { foob: 'fooc' } } )
9
9
 
10
10
  ros.fooa.foob # => 'fooc'
11
11
 
12
12
  Also, if needed, nested hashes can still be accessed as hashes:
13
13
 
14
- ros.fooa_as_a_hash # { :foob => 'fooc' }
14
+ ros.fooa_as_a_hash # { foob: 'fooc' }
15
15
 
16
16
  RecursiveOpenStruct can also optionally recurse across arrays, although you
17
17
  have to explicitly enable it:
18
18
 
19
- h = { :somearr => [ { :name => 'a'}, { :name => 'b' } ] }
19
+ h = { :somearr => [ { name: 'a'}, { name: 'b' } ] }
20
+ ros = RecursiveOpenStruct.new(h, recurse_over_arrays: true )
20
21
 
21
- ros = RecursiveOpenStruct.new(h, :recurse_over_arrays => true )
22
+ ros.somearr[0].name # => 'a'
23
+ ros.somearr[1].name # => 'b'
22
24
 
23
- ros.somarr[0].name # => 'a'
24
- ros.somarr[1].name # => 'b'
25
+ Also, by default it will turn all hash keys into symbols internally:
26
+
27
+ h = { 'fear' => 'is', 'the' => 'mindkiller' } }
28
+ ros = RecursiveOpenStruct.new(h)
29
+ ros.to_h # => { fear: 'is', the: 'mindkiller' }
30
+
31
+ You can preserve the original keys by enabling `:preserve_original_keys`:
32
+
33
+ h = { 'fear' => 'is', 'the' => 'mindkiller' } }
34
+ ros = RecursiveOpenStruct.new(h, preserve_original_keys: true)
35
+ ros.to_h # => { 'fear' => 'is', 'the' => 'mindkiller' }
25
36
 
26
37
  ## Installation
27
38
 
@@ -12,10 +12,13 @@ class RecursiveOpenStruct < OpenStruct
12
12
  def initialize(hash=nil, args={})
13
13
  hash ||= {}
14
14
  @recurse_over_arrays = args.fetch(:recurse_over_arrays, false)
15
- @deep_dup = DeepDup.new(recurse_over_arrays: @recurse_over_arrays)
15
+ @preserve_original_keys = args.fetch(:preserve_original_keys, false)
16
+ @deep_dup = DeepDup.new(
17
+ recurse_over_arrays: @recurse_over_arrays,
18
+ preserve_original_keys: @preserve_original_keys
19
+ )
16
20
 
17
21
  @table = args.fetch(:mutate_input_hash, false) ? hash : @deep_dup.call(hash)
18
- @table && @table.each_key { |k| new_ostruct_member(k) }
19
22
 
20
23
  @sub_elements = {}
21
24
  end
@@ -39,17 +42,46 @@ class RecursiveOpenStruct < OpenStruct
39
42
  send name
40
43
  end
41
44
 
45
+ # Makes sure ROS responds as expected on #respond_to? and #method requests
46
+ def respond_to_missing?(mid, include_private = false)
47
+ mname = _get_key_from_table_(mid.to_s.chomp('=').chomp('_as_a_hash'))
48
+ @table.key?(mname) || super
49
+ end
50
+
51
+ # Adapted implementation of method_missing to accomodate the differences between ROS and OS.
52
+ def method_missing(mid, *args)
53
+ len = args.length
54
+ if mid =~ /^(.*)=$/
55
+ if len != 1
56
+ raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1)
57
+ end
58
+ modifiable[new_ostruct_member($1.to_sym)] = args[0]
59
+ elsif len == 0
60
+ key = mid
61
+ key = $1 if key =~ /^(.*)_as_a_hash$/
62
+ if @table.key?(_get_key_from_table_(key))
63
+ new_ostruct_member(key)
64
+ send(mid)
65
+ end
66
+ else
67
+ err = NoMethodError.new "undefined method `#{mid}' for #{self}", mid, args
68
+ err.set_backtrace caller(1)
69
+ raise err
70
+ end
71
+ end
72
+
42
73
  def new_ostruct_member(name)
43
74
  key_name = _get_key_from_table_ name
44
- unless self.respond_to?(name)
75
+ unless self.methods.include?(name.to_sym)
45
76
  class << self; self; end.class_eval do
46
77
  define_method(name) do
47
78
  v = @table[key_name]
48
79
  if v.is_a?(Hash)
49
80
  @sub_elements[key_name] ||= self.class.new(
50
81
  v,
51
- :recurse_over_arrays => @recurse_over_arrays,
52
- :mutate_input_hash => true
82
+ recurse_over_arrays: @recurse_over_arrays,
83
+ preserve_original_keys: @preserve_original_keys,
84
+ mutate_input_hash: true
53
85
  )
54
86
  elsif v.is_a?(Array) and @recurse_over_arrays
55
87
  @sub_elements[key_name] ||= recurse_over_array(v)
@@ -68,22 +100,9 @@ class RecursiveOpenStruct < OpenStruct
68
100
  key_name
69
101
  end
70
102
 
71
- # TODO: Make me private if/when we do an API-breaking change release
72
- def recurse_over_array(array)
73
- array.map do |a|
74
- if a.is_a? Hash
75
- self.class.new(a, :recurse_over_arrays => true, :mutate_input_hash => true)
76
- elsif a.is_a? Array
77
- recurse_over_array a
78
- else
79
- a
80
- end
81
- end
82
- end
83
-
84
103
  def delete_field(name)
85
104
  sym = _get_key_from_table_(name)
86
- singleton_class.__send__(:remove_method, sym, "#{sym}=")
105
+ singleton_class.__send__(:remove_method, sym, "#{sym}=") rescue NoMethodError # ignore if methods not yet generated.
87
106
  @sub_elements.delete sym
88
107
  @table.delete sym
89
108
  end
@@ -95,4 +114,17 @@ class RecursiveOpenStruct < OpenStruct
95
114
  return name.to_sym if @table.has_key?(name.to_sym)
96
115
  name
97
116
  end
117
+
118
+ def recurse_over_array(array)
119
+ array.map do |a|
120
+ if a.is_a? Hash
121
+ self.class.new(a, :recurse_over_arrays => true, :mutate_input_hash => true)
122
+ elsif a.is_a? Array
123
+ recurse_over_array a
124
+ else
125
+ a
126
+ end
127
+ end
128
+ end
129
+
98
130
  end
@@ -1,6 +1,7 @@
1
1
  class RecursiveOpenStruct::DeepDup
2
2
  def initialize(opts={})
3
3
  @recurse_over_arrays = opts.fetch(:recurse_over_arrays, false)
4
+ @preserve_original_keys = opts.fetch(:preserve_original_keys, false)
4
5
  end
5
6
 
6
7
  def call(obj)
@@ -12,7 +13,7 @@ class RecursiveOpenStruct::DeepDup
12
13
  def deep_dup(obj, visited=[])
13
14
  if obj.is_a?(Hash)
14
15
  obj.each_with_object({}) do |(key, value), h|
15
- h[key] = value_or_deep_dup(value, visited)
16
+ h[@preserve_original_keys ? key : key.to_sym] = value_or_deep_dup(value, visited)
16
17
  end
17
18
  elsif obj.is_a?(Array) && @recurse_over_arrays
18
19
  obj.each_with_object([]) do |value, arr|
@@ -3,5 +3,5 @@
3
3
  require 'ostruct'
4
4
 
5
5
  class RecursiveOpenStruct < OpenStruct
6
- VERSION = "0.6.5"
6
+ VERSION = "1.0.0"
7
7
  end
@@ -9,9 +9,10 @@ describe RecursiveOpenStruct do
9
9
 
10
10
  describe 'indifferent access' do
11
11
  let(:hash) { {:foo => value, 'bar' => symbol} }
12
- subject(:hash_ros) { RecursiveOpenStruct.new(hash) }
13
- context 'setting value with method' do
12
+ let(:hash_ros_opts) { {} }
13
+ subject(:hash_ros) { RecursiveOpenStruct.new(hash, hash_ros_opts) }
14
14
 
15
+ context 'setting value with method' do
15
16
  before(:each) do
16
17
  subject.foo = value
17
18
  end
@@ -23,7 +24,6 @@ describe RecursiveOpenStruct do
23
24
  end
24
25
 
25
26
  context 'setting value with symbol' do
26
-
27
27
  before(:each) do
28
28
  subject[:foo] = value
29
29
  end
@@ -35,7 +35,6 @@ describe RecursiveOpenStruct do
35
35
  end
36
36
 
37
37
  context 'setting value with string' do
38
-
39
38
  before(:each) do
40
39
  subject['foo'] = value
41
40
  end
@@ -47,9 +46,7 @@ describe RecursiveOpenStruct do
47
46
  end
48
47
 
49
48
  context 'overwriting values' do
50
-
51
49
  context 'set with method' do
52
-
53
50
  before(:each) do
54
51
  subject.foo = value
55
52
  end
@@ -63,11 +60,9 @@ describe RecursiveOpenStruct do
63
60
  subject['foo'] = new_value
64
61
  expect(subject.foo).to be new_value
65
62
  end
66
-
67
63
  end
68
64
 
69
65
  context 'set with symbol' do
70
-
71
66
  before(:each) do
72
67
  subject[:foo] = value
73
68
  end
@@ -81,11 +76,9 @@ describe RecursiveOpenStruct do
81
76
  subject['foo'] = new_value
82
77
  expect(subject[:foo]).to be new_value
83
78
  end
84
-
85
79
  end
86
80
 
87
81
  context 'set with string' do
88
-
89
82
  before(:each) do
90
83
  subject['foo'] = value
91
84
  end
@@ -99,11 +92,9 @@ describe RecursiveOpenStruct do
99
92
  subject[:foo] = new_value
100
93
  expect(subject['foo']).to be new_value
101
94
  end
102
-
103
95
  end
104
96
 
105
97
  context 'set with hash' do
106
-
107
98
  it('overrides with method') do
108
99
  hash_ros.foo = new_value
109
100
  expect(hash_ros[:foo]).to be new_value
@@ -121,27 +112,52 @@ describe RecursiveOpenStruct do
121
112
  hash_ros['foo'] = new_value
122
113
  expect(hash_ros[:foo]).to be new_value
123
114
  end
115
+ end
124
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
125
138
  end
126
139
 
127
- context 'keeps original keys' do
128
- subject(:recursive) { RecursiveOpenStruct.new(recursive_hash, recurse_over_arrays: true) }
129
- let(:recursive_hash) { {:foo => [ {'bar' => [ { 'foo' => :bar} ] } ] } }
130
- let(:modified_hash) { {:foo => [ {'bar' => [ { 'foo' => :foo} ] } ] } }
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} ] } ] } }
131
145
 
132
- it 'after initialization' do
133
- expect(hash_ros.to_h).to eq hash
134
- end
146
+ let(:hash_ros_opts) { { preserve_original_keys: true }}
135
147
 
136
- it 'in recursive hashes' do
137
- expect(recursive.to_h).to eq recursive_hash
138
- end
148
+ specify 'after initialization' do
149
+ expect(hash_ros.to_h).to eq hash
150
+ end
139
151
 
140
- it 'after resetting value' do
141
- recursive.foo.first[:bar].first[:foo] = :foo
142
- expect(recursive.to_h).to eq modified_hash
143
- end
152
+ specify 'in recursive hashes' do
153
+ expect(recursive.to_h).to eq recursive_hash
154
+ end
144
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
145
161
  end
146
162
 
147
163
  end
@@ -95,8 +95,8 @@ describe RecursiveOpenStruct do
95
95
  end
96
96
 
97
97
  context "each_pair" do
98
- it "iterates over hash keys" do
99
- expect(ros.each_pair).to match hash.each_pair
98
+ it "iterates over hash keys, with keys as symbol" do
99
+ expect(ros.each_pair).to match ({:foo => 'foo', :bar => :bar}.each_pair)
100
100
  end
101
101
  end
102
102
 
metadata CHANGED
@@ -1,97 +1,97 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: recursive-open-struct
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.5
4
+ version: 1.0.0
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: 2015-07-01 00:00:00.000000000 Z
11
+ date: 2015-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: pry
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
33
  version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - '>='
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rdoc
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - "~>"
74
74
  - !ruby/object:Gem::Version
75
75
  version: '3.2'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '3.2'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: simplecov
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - '>='
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - '>='
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
97
  description: |
@@ -113,10 +113,10 @@ extra_rdoc_files:
113
113
  - LICENSE.txt
114
114
  - README.md
115
115
  files:
116
- - .document
117
- - .gitignore
118
- - .rspec
119
- - .travis.yml
116
+ - ".document"
117
+ - ".gitignore"
118
+ - ".rspec"
119
+ - ".travis.yml"
120
120
  - CHANGELOG.md
121
121
  - Gemfile
122
122
  - LICENSE.txt
@@ -146,17 +146,17 @@ require_paths:
146
146
  - lib
147
147
  required_ruby_version: !ruby/object:Gem::Requirement
148
148
  requirements:
149
- - - '>='
149
+ - - ">="
150
150
  - !ruby/object:Gem::Version
151
151
  version: '0'
152
152
  required_rubygems_version: !ruby/object:Gem::Requirement
153
153
  requirements:
154
- - - '>='
154
+ - - ">="
155
155
  - !ruby/object:Gem::Version
156
156
  version: '0'
157
157
  requirements: []
158
158
  rubyforge_project:
159
- rubygems_version: 2.0.14
159
+ rubygems_version: 2.4.5.1
160
160
  signing_key:
161
161
  specification_version: 4
162
162
  summary: OpenStruct subclass that returns nested hash attributes as RecursiveOpenStructs