right_support 2.8.37 → 2.8.38

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 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.