right_support 2.8.28 → 2.8.29

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d244fe9a56d4712f420a8e3aef63841427de950c
4
+ data.tar.gz: 9ea699ca1dd5bc23bb23c0085ed03d3ea1a23968
5
+ SHA512:
6
+ metadata.gz: 2fa6ca5181f6040eae44dec1fdb8bbb2980c9faa39b80de0cd2b87057078b4c6b1c0df3a54a1e0c6627d86ca0726a5023eec91a7ee697834666a12bd82dc36c2
7
+ data.tar.gz: d636fe0c0f2eec50ce62c1a91131631db306ce67777b2b2af825be726e19413439e42c87255a32fa26b7b2a54165e881098de0cbb73f3461025d105de1ffef2c
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.8.28
1
+ 2.8.29
@@ -25,7 +25,13 @@ module RightSupport::Data
25
25
  # various tools for manipulating hash-like classes.
26
26
  module HashTools
27
27
 
28
- HAS_JSON = require_succeeds?('json')
28
+ # require checks
29
+ HAS_EXTLIB = require_succeeds?('extlib')
30
+ HAS_JSON = require_succeeds?('json')
31
+
32
+ # exceptions
33
+ class NoExtlib < ::StandardError; end
34
+ class NoJson < ::StandardError; end
29
35
 
30
36
  # Determines if given object is hashable (i.e. object responds to hash methods).
31
37
  #
@@ -112,6 +118,8 @@ module RightSupport::Data
112
118
 
113
119
  # Creates a deep clone of the given hash.
114
120
  #
121
+ # @deprecated in favor of more robust deep_clone2
122
+ #
115
123
  # note that not all objects are clonable in Ruby even though all respond to clone
116
124
  # (which is completely counter-intuitive and contrary to all other managed languages).
117
125
  # Java, for example, has the built-in Cloneable marker interface which we will simulate
@@ -135,6 +143,9 @@ module RightSupport::Data
135
143
  result = original.clone
136
144
  result.each do |k, v|
137
145
  if hashable?(v)
146
+ # HACK: we should have passed &leaf_callback here but never did before
147
+ # so it is techincally a bug. we are not going to change it due to not
148
+ # wanting to break legacy code so use deep_clone2 instead.
138
149
  result[k] = deep_clone(v)
139
150
  elsif leaf_callback
140
151
  result[k] = leaf_callback.call(v)
@@ -147,6 +158,75 @@ module RightSupport::Data
147
158
  result
148
159
  end
149
160
 
161
+ # Deeply duplicates (clones) a hashable object containing other hashes or
162
+ # arrays of hashes but passing other types through.
163
+ #
164
+ # Optionally changes the target hashable type to 'normalize' to a specific
165
+ # hashable class (such as Mash).
166
+ #
167
+ # Optionally traverses arrays (default) in an attempt to deep-clone any
168
+ # sub-hashes instead of simply associating them.
169
+ #
170
+ # === Parameters
171
+ # @param [Object] any kind of object
172
+ # @param [Hash] options
173
+ # @option [Class] :class for cloned hashables or nil for same as source
174
+ #
175
+ # === Block
176
+ # @yieldparam [Object] value of leaf
177
+ # @yieldreturn [Object] cloned value of leaf or original value
178
+ #
179
+ # === Return
180
+ # @return [Object] depends on input type
181
+ def self.deep_clone2(any, options = {}, &leaf_callback)
182
+ if hashable?(any)
183
+ # clone to a new instance of hashable class with deep cloning.
184
+ any.inject((options[:class] || any.class).new) do |m, (k, v)|
185
+ m[k] = deep_clone2(v, options, &leaf_callback)
186
+ m
187
+ end
188
+ elsif any.kind_of?(::Array)
189
+ # traverse arrays
190
+ any.map { |e| deep_clone2(e, options, &leaf_callback) }
191
+ elsif leaf_callback
192
+ leaf_callback.call(any)
193
+ elsif any.respond_to?(:duplicable?)
194
+ # see #deep_clone for remarks
195
+ any.duplicable? ? any.clone : any
196
+ else
197
+ any # whatever
198
+ end
199
+ end
200
+
201
+ # Deeply mashes and duplicates (clones) a hashable using deep_clone2 after
202
+ # checking that extlib is available.
203
+ #
204
+ # The advantage of Mash over Hash is, of course, to be able to use either
205
+ # a String or Symbol as a key for the same value.
206
+ #
207
+ # Note that Mash.new(my_mash) will convert child hashes to mashes but not
208
+ # with the guarantee of cloning and detaching the deep mash. In other words.
209
+ # if any part of the hash is already a mash then it is not cloned by
210
+ # invoking Mash.new()
211
+ #
212
+ # === Parameters
213
+ # @param [Object] any kind of object
214
+ #
215
+ # === Block
216
+ # @yieldparam [Object] value of leaf
217
+ # @yieldreturn [Object] cloned value of leaf or original value
218
+ #
219
+ # === Return
220
+ # @return [Object] depends on input type
221
+ def self.deep_mash(any, &leaf_callback)
222
+ if HAS_EXTLIB
223
+ options = { :class => ::Mash }
224
+ deep_clone2(any, options, &leaf_callback)
225
+ else
226
+ raise NoExtlib, "extlib is unavailable"
227
+ end
228
+ end
229
+
150
230
  # Performs a deep merge (but not a deep clone) of one hash into another.
151
231
  #
152
232
  # === Parameters
@@ -327,8 +407,6 @@ module RightSupport::Data
327
407
  end
328
408
  end
329
409
 
330
- class NoJson < Exception; end
331
-
332
410
  # Generates JSON from the given hash (of hashes) that is sorted by key at
333
411
  # all levels. Does not handle case of hash to array of hashes, etc.
334
412
  #
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: right_support 2.8.28 ruby lib
5
+ # stub: right_support 2.8.29 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "right_support"
9
- s.version = "2.8.28"
9
+ s.version = "2.8.29"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["Tony Spataro", "Sergey Sergyenko", "Ryan Williamson", "Lee Kirchhoff", "Alexey Karpik", "Scott Messier"]
14
- s.date = "2014-08-15"
14
+ s.date = "2014-08-26"
15
15
  s.description = "A toolkit of useful, reusable foundation code created by RightScale."
16
16
  s.email = "support@rightscale.com"
17
17
  s.extra_rdoc_files = [
@@ -175,20 +175,75 @@ describe RightSupport::Data::HashTools do
175
175
  data[:tree][:branch][:a].duplicable?.should be_true
176
176
  data[:tree][:branch][:b].duplicable?.should be_true
177
177
  end
178
- deep_check_object_id(actual, data)
178
+ deep_check_object_id(data, actual)
179
179
  end
180
180
  end
181
181
 
182
182
  it 'should deep clone leaves using callback when given' do
183
- initial = { :x => 1, :y => { :a => [1, 2, 3], :b => [4, 5, 6] } }
184
- actual = subject.deep_clone(initial) { |value| value.kind_of?(Array) ? value.clone : value }
183
+ initial = { :x => 'a', :y => { :a => ['b', 'c'], :b => ['d', ['e', 'f']] } }
184
+ actual = subject.deep_clone(initial) { |value| value.clone }
185
185
  actual.should == initial
186
186
  deep_check_object_id(actual, initial) do |a, b|
187
- if a.kind_of?(Array)
188
- a.object_id.should_not == b.object_id
189
- else
190
- a.object_id.should == b.object_id
187
+ a.object_id.should_not == b.object_id
188
+ end
189
+ end
190
+ end
191
+
192
+ # also tests deep_clone2
193
+ context '#deep_mash' do
194
+ def deep_check_object_id(a, b, &leaf_callback)
195
+ a.object_id.should_not == b.object_id
196
+ if subject.hashable?(a)
197
+ b.class.should == ::Mash
198
+ a.each do |k, v|
199
+ other = b[k]
200
+ if subject.hashable?(v)
201
+ deep_check_object_id(v, other)
202
+ elsif v.kind_of?(::Array)
203
+ v.object_id.should_not == other.object_id
204
+ other.class.should == ::Array
205
+ v.size.should == other.size
206
+ v.each_with_index do |e, idx|
207
+ deep_check_object_id(e, other[idx])
208
+ end
209
+ elsif leaf_callback
210
+ leaf_callback.call(v, other)
211
+ elsif v.respond_to?(:duplicable?) && v.duplicable?
212
+ v.object_id.should_not == other.object_id
213
+ else
214
+ v.object_id.should == other.object_id
215
+ end
216
+ end
217
+ end
218
+ end
219
+
220
+ {
221
+ :empty => {},
222
+ :shallow => { :x => 1, :y => 2 },
223
+ :deep => { :x => 1, :y => { :a => 'A' }, :z => { :b => 'B', :c => { :foo => :bar } } },
224
+ :arrayed => [ { :x => 1 }, { :y => { :a => 'A' } }, :z => { :b => 'B', :c => { :foo => :bar } } ],
225
+ :duplicable => {
226
+ :tree => {
227
+ :branch => {
228
+ :a => ::RightSupport::Data::HashToolsSpec::DuplicableValue.new(1),
229
+ :b => ::RightSupport::Data::HashToolsSpec::DuplicableValue.new('hi there') } } }
230
+ }.each do |kind, data|
231
+ it "should deep mash values in #{kind} hashes" do
232
+ actual = subject.deep_mash(data)
233
+ if :duplicable == kind
234
+ # verify that leaves are duplicable
235
+ data[:tree][:branch][:a].duplicable?.should be_true
236
+ data[:tree][:branch][:b].duplicable?.should be_true
191
237
  end
238
+ deep_check_object_id(data, actual)
239
+ end
240
+ end
241
+
242
+ it 'should deep clone leaves using callback when given' do
243
+ initial = { :x => 'a', :y => { :a => ['b', 'c'], :b => ['d', ['e', 'f']] } }
244
+ actual = subject.deep_mash(initial) { |value| value.clone }
245
+ deep_check_object_id(initial, actual) do |a, b|
246
+ a.object_id.should_not == b.object_id
192
247
  end
193
248
  end
194
249
  end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: right_support
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.28
5
- prerelease:
4
+ version: 2.8.29
6
5
  platform: ruby
7
6
  authors:
8
7
  - Tony Spataro
@@ -14,7 +13,7 @@ authors:
14
13
  autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
- date: 2014-08-15 00:00:00.000000000 Z
16
+ date: 2014-09-15 00:00:00.000000000 Z
18
17
  dependencies: []
19
18
  description: A toolkit of useful, reusable foundation code created by RightScale.
20
19
  email: support@rightscale.com
@@ -24,7 +23,7 @@ extra_rdoc_files:
24
23
  - LICENSE
25
24
  - README.rdoc
26
25
  files:
27
- - .rspec
26
+ - ".rspec"
28
27
  - CHANGELOG.rdoc
29
28
  - Gemfile
30
29
  - Gemfile.lock
@@ -146,29 +145,25 @@ files:
146
145
  homepage: https://github.com/rightscale/right_support
147
146
  licenses:
148
147
  - MIT
148
+ metadata: {}
149
149
  post_install_message:
150
150
  rdoc_options: []
151
151
  require_paths:
152
152
  - lib
153
153
  required_ruby_version: !ruby/object:Gem::Requirement
154
- none: false
155
154
  requirements:
156
- - - ! '>='
155
+ - - ">="
157
156
  - !ruby/object:Gem::Version
158
157
  version: '0'
159
- segments:
160
- - 0
161
- hash: 1570969451733484161
162
158
  required_rubygems_version: !ruby/object:Gem::Requirement
163
- none: false
164
159
  requirements:
165
- - - ! '>='
160
+ - - ">="
166
161
  - !ruby/object:Gem::Version
167
162
  version: '0'
168
163
  requirements: []
169
164
  rubyforge_project:
170
- rubygems_version: 1.8.26
165
+ rubygems_version: 2.2.2
171
166
  signing_key:
172
- specification_version: 3
167
+ specification_version: 4
173
168
  summary: Reusable foundation code.
174
169
  test_files: []