right_support 2.8.28 → 2.8.29

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 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: []