right_support 2.8.37 → 2.8.38

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: 695bd84c95a2c978873deaf2b85ac85e9f72a10c
4
- data.tar.gz: 855562b8a7497925dfdc17951e852e8263724227
3
+ metadata.gz: e0cb72f5d96896f6a249867296e5a6ee14021caa
4
+ data.tar.gz: 930f29d6b579d374ddadf6636c3687aeb12f394e
5
5
  SHA512:
6
- metadata.gz: acfa03c38cb1e5dd0edba374ffe3a3000b411415743d0a60a6f60866cd3515bd8445df5145995ec709117b4f8f083785298530209b2e5ddde7ec360cc5b2b2eb
7
- data.tar.gz: 304ca6549fcbcdb76a4a7a53a71f18d90ddbe12d6600523a47523fde823bfb6c2d0a5474c74953ee84d2c0e9488f12fc46abba133b61484ad9e150fff04e68c6
6
+ metadata.gz: 9bc745e71199150c1c3097efe6ba4ec77549e6c5d34ae7fdd899710f5122adde38e77b01a56f4e826e8e49a297eed2534fc1be78cf72ffb924e79beb6335b064
7
+ data.tar.gz: e823929462c375b3bb12f51c91fd39780de10eec2194232d32c5ea649166709f523bc2cad31f4030d588a9f95eebd38ba84d969c6f4aa9a195f223d188fbac28
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.8.37
1
+ 2.8.38
@@ -138,6 +138,13 @@ module RightSupport::Data
138
138
  # === Return
139
139
  # @return [Hash] deep cloned hash
140
140
  def self.deep_clone(original, &leaf_callback)
141
+ # note that .clone preserves .frozen? state so this legacy method will
142
+ # attempt to modify a still-frozen hash/array and raise an exception.
143
+ # see deep_clone2 which clones by creating a new instance of the object
144
+ # class and produce an unfrozen clone of the hash/array.
145
+ # as a side note, calling .dup does not preserve .frozen? state but is has
146
+ # its own side effects, which is why we have more specific logic like
147
+ # leaf_callback and .duplicable?
141
148
  result = original.clone
142
149
  result.each do |k, v|
143
150
  if hashable?(v)
@@ -196,8 +203,36 @@ module RightSupport::Data
196
203
  end
197
204
  end
198
205
 
199
- # Deeply mashes and duplicates (clones) a hashable using deep_clone2 after
200
- # checking that extlib is available.
206
+ # Deeply freezes the given hash/array and all of their non-hierarchical
207
+ # elements in a hierarchichal data structure such that an attempt to modify
208
+ # any part of it will raise an exception.
209
+ #
210
+ # === Parameters
211
+ # @param [Object] any kind of object
212
+ #
213
+ # === Return
214
+ # @return [Object] deeply frozen object
215
+ def self.deep_freeze!(any)
216
+ if hashable?(any)
217
+ # clone to a new instance of hashable class with deep cloning.
218
+ any.each do |k, v|
219
+ # notes:
220
+ # a) either key or value of a hash could be a complex type.
221
+ # b) Hash freezes simple type keys upon insertion out of necessity to
222
+ # avoid spontaneous rehashing. Hash will not freeze complex types
223
+ # used as keys so we will (re)freeze all keys for safety.
224
+ deep_freeze!(k)
225
+ deep_freeze!(v)
226
+ end
227
+ elsif any.kind_of?(::Array)
228
+ # traverse arrays
229
+ any.each { |e| deep_freeze!(e) }
230
+ end
231
+ any.freeze
232
+ end
233
+
234
+ # Deeply mashes and duplicates (clones) a hashable using deep_clone2 and our
235
+ # own version of Mash.
201
236
  #
202
237
  # The advantage of Mash over Hash is, of course, to be able to use either
203
238
  # a String or Symbol as a key for the same value.
@@ -221,7 +256,39 @@ module RightSupport::Data
221
256
  deep_clone2(any, options, &leaf_callback)
222
257
  end
223
258
 
224
- # Performs a deep merge (but not a deep clone) of one hash into another.
259
+ # Performs a deep clone and merge of one hash into another, similar in
260
+ # behavior to Hash#merge
261
+ #
262
+ # === Parameters
263
+ # @param [Hash] target hash containing original data to be replaced in the
264
+ # resulting hash
265
+ # @param [Hash] source hash containing data to recursively assign or nil or
266
+ # empty
267
+ #
268
+ # === Return
269
+ # @return [Hash] to_hash result of merge
270
+ def self.deep_merge(target, source)
271
+ # merge or replace any values that appear in source.
272
+ result = target.class.new
273
+ (source || {}).each do |k, v|
274
+ if hashable?(target[k]) && hashable?(v)
275
+ result[k] = deep_merge(target[k], v)
276
+ else
277
+ result[k] = v
278
+ end
279
+ end
280
+
281
+ # deep clone any target-only value.
282
+ target.each do |k, v|
283
+ unless result.has_key?(k)
284
+ result[k] = deep_clone2(v)
285
+ end
286
+ end
287
+ result
288
+ end
289
+
290
+ # Performs a deep merge (but not a deep clone) of one hash into another,
291
+ # similar in behavior to Hash#merge!
225
292
  #
226
293
  # === Parameters
227
294
  # @param [Hash] target hash to contain original and merged data
@@ -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.37 ruby lib
5
+ # stub: right_support 2.8.38 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "right_support"
9
- s.version = "2.8.37"
9
+ s.version = "2.8.38"
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-11-26"
14
+ s.date = "2014-12-05"
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 = [
@@ -148,7 +148,7 @@ Gem::Specification.new do |s|
148
148
  ]
149
149
  s.homepage = "https://github.com/rightscale/right_support"
150
150
  s.licenses = ["MIT"]
151
- s.rubygems_version = "2.2.0"
151
+ s.rubygems_version = "2.2.2"
152
152
  s.summary = "Reusable foundation code."
153
153
 
154
154
  if s.respond_to? :specification_version then
@@ -257,6 +257,72 @@ describe RightSupport::Data::HashTools do
257
257
  end
258
258
  end
259
259
 
260
+ context '#deep_freeze!' do
261
+ it "should deep freeze hashes and arrays" do
262
+ original = {
263
+ 'a' => ' s ',
264
+ 'b' => {
265
+ 'h' => ' s2 ',
266
+ 'a' => [ 1, { :nested => ' s3 ' } ]
267
+ }
268
+ }
269
+ original.each do |k, v|
270
+ # note that Hash freezes keys upon insertion out of necessity to avoid
271
+ # spontaneous rehashing.
272
+ k.should be_frozen
273
+ v.should_not be_frozen
274
+ end
275
+ original['b']['a'][1][:nested].should_not be_frozen
276
+ subject.deep_freeze!(original)
277
+ original.each do |k, v|
278
+ k.should be_frozen
279
+ v.should be_frozen
280
+ end
281
+ original['b']['a'][1][:nested].should be_frozen
282
+ end
283
+ end
284
+
285
+ context '#deep_merge' do
286
+ {
287
+ :identical => {
288
+ :left => { :one => 1 },
289
+ :right => { :one => 1 },
290
+ :expected => { :one => 1 } },
291
+ :disjoint => {
292
+ :left => { :one => 1 },
293
+ :right => { :two => 1 },
294
+ :expected => { :one => 1, :two => 1 } },
295
+ :value_diff => {
296
+ :left => { :one => 1 },
297
+ :right => { :one => 2 },
298
+ :expected => { :one => 2 } },
299
+ :recursive_disjoint => {
300
+ :left => { :one => { :a => 1, :b => 2 }, :two => 3 },
301
+ :right => { :one => { :a => 1 }, :two => 3 },
302
+ :expected => { :one => { :a => 1, :b => 2 }, :two => 3 } },
303
+ :recursive_value_diff => {
304
+ :left => { :one => { :a => 1, :b => 2 }, :two => 3 },
305
+ :right => { :one => { :a => 1, :b => 3 }, :two => 3 },
306
+ :expected => { :one => { :a => 1, :b => 3 }, :two => 3 } },
307
+ :recursive_disjoint_and_value_diff => {
308
+ :left => { :one => { :a => 1, :b => 2, :c => 3 }, :two => 3, :three => 4 },
309
+ :right => { :one => { :a => 1, :b => 3, :d => 4 }, :two => 5, :four => 6 },
310
+ :expected => { :one => { :a => 1, :b => 3, :c => 3 , :d => 4 }, :two => 5, :three => 4, :four => 6 } }
311
+ }.each do |kind, data|
312
+ it "should deep merge #{kind} hashes" do
313
+ left_same_as_expected = data[:left] == data[:expected]
314
+ actual = subject.deep_merge(data[:left], data[:right])
315
+ actual.should == data[:expected]
316
+
317
+ # original should be unmodified.
318
+ actual.object_id.should_not == data[:left].object_id
319
+ unless left_same_as_expected
320
+ data[:left].should_not == data[:expected]
321
+ end
322
+ end
323
+ end
324
+ end
325
+
260
326
  context '#deep_merge!' do
261
327
  {
262
328
  :identical => {
@@ -287,6 +353,7 @@ describe RightSupport::Data::HashTools do
287
353
  it "should deep merge #{kind} hashes" do
288
354
  actual = subject.deep_merge!(data[:left], data[:right])
289
355
  actual.should == data[:expected]
356
+ actual.object_id.should == data[:left].object_id # original returned modified
290
357
  end
291
358
  end
292
359
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: right_support
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.37
4
+ version: 2.8.38
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tony Spataro
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2014-11-26 00:00:00.000000000 Z
16
+ date: 2014-12-05 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: rake
@@ -239,7 +239,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
239
239
  version: '0'
240
240
  requirements: []
241
241
  rubyforge_project:
242
- rubygems_version: 2.2.0
242
+ rubygems_version: 2.2.2
243
243
  signing_key:
244
244
  specification_version: 4
245
245
  summary: Reusable foundation code.