deep_hash_transform 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 538a3d6cd8c8b0d3c8b7625395514c097f9a047b
4
+ data.tar.gz: 456d6517d42225594a5a928db69c37d643f548f2
5
+ SHA512:
6
+ metadata.gz: 2286c0194b9bb0a9699e5ea6d542bd64992c4aac32f404457cef1c03b40b22bd259f85320d24d3fab662ac83cf32d9be068a6f816dd4590b5784419a059145e2
7
+ data.tar.gz: ca69c276a74b53d8ce7caa67b652afb8cfc9af9a847a9630ba8b58a3fd92ab22f3734d17815f27ec01330824bd930fff2091ed217bf4b49412d2d8cfcf09d91b
@@ -0,0 +1,135 @@
1
+ # These features are available in Rails 4.0+
2
+ #
3
+ # Prefer Active Support's implementation when available.
4
+ #
5
+ # This allows libraries which support multiple Rails versions to depend on
6
+ # `deep_hash_transform` without worrying about implementation collision.
7
+ # This lib will step aside if it sees its work is done.
8
+ begin
9
+ require 'active_support/core_ext/hash/keys'
10
+ rescue LoadError
11
+ # No worries if Active Support isn't present. Can be used in isolation.
12
+ end
13
+
14
+ class Hash
15
+ # Returns a new hash with all keys converted using the block operation.
16
+ #
17
+ # hash = { name: 'Rob', age: '28' }
18
+ #
19
+ # hash.transform_keys{ |key| key.to_s.upcase }
20
+ # # => {"NAME"=>"Rob", "AGE"=>"28"}
21
+ def transform_keys
22
+ result = {}
23
+ each_key do |key|
24
+ result[yield(key)] = self[key]
25
+ end
26
+ result
27
+ end unless method_defined?(:transform_keys)
28
+
29
+ # Destructively convert all keys using the block operations.
30
+ # Same as transform_keys but modifies +self+.
31
+ def transform_keys!
32
+ keys.each do |key|
33
+ self[yield(key)] = delete(key)
34
+ end
35
+ self
36
+ end unless method_defined?(:transform_keys!)
37
+
38
+ # Returns a new hash with all keys converted to strings.
39
+ #
40
+ # hash = { name: 'Rob', age: '28' }
41
+ #
42
+ # hash.stringify_keys
43
+ # # => { "name" => "Rob", "age" => "28" }
44
+ def stringify_keys
45
+ transform_keys { |key| key.to_s }
46
+ end unless method_defined?(:stringify_keys)
47
+
48
+ # Destructively convert all keys to strings. Same as
49
+ # +stringify_keys+, but modifies +self+.
50
+ def stringify_keys!
51
+ transform_keys! { |key| key.to_s }
52
+ end unless method_defined?(:stringify_keys!)
53
+
54
+ # Returns a new hash with all keys converted to symbols, as long as
55
+ # they respond to +to_sym+.
56
+ #
57
+ # hash = { 'name' => 'Rob', 'age' => '28' }
58
+ #
59
+ # hash.symbolize_keys
60
+ # # => { name: "Rob", age: "28" }
61
+ def symbolize_keys
62
+ transform_keys { |key| key.to_sym rescue key }
63
+ end unless method_defined?(:symbolize_keys)
64
+
65
+ # Destructively convert all keys to symbols, as long as they respond
66
+ # to +to_sym+. Same as +symbolize_keys+, but modifies +self+.
67
+ def symbolize_keys!
68
+ transform_keys! { |key| key.to_sym rescue key }
69
+ end unless method_defined?(:symbolize_keys!)
70
+
71
+ # Returns a new hash with all keys converted by the block operation.
72
+ # This includes the keys from the root hash and from all
73
+ # nested hashes.
74
+ #
75
+ # hash = { person: { name: 'Rob', age: '28' } }
76
+ #
77
+ # hash.deep_transform_keys{ |key| key.to_s.upcase }
78
+ # # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}}
79
+ def deep_transform_keys(&block)
80
+ result = {}
81
+ each do |key, value|
82
+ result[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys(&block) : value
83
+ end
84
+ result
85
+ end unless method_defined?(:deep_transform_keys)
86
+
87
+ # Destructively convert all keys by using the block operation.
88
+ # This includes the keys from the root hash and from all
89
+ # nested hashes.
90
+ def deep_transform_keys!(&block)
91
+ keys.each do |key|
92
+ value = delete(key)
93
+ self[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys!(&block) : value
94
+ end
95
+ self
96
+ end unless method_defined?(:deep_transform_keys!)
97
+
98
+ # Returns a new hash with all keys converted to strings.
99
+ # This includes the keys from the root hash and from all
100
+ # nested hashes.
101
+ #
102
+ # hash = { person: { name: 'Rob', age: '28' } }
103
+ #
104
+ # hash.deep_stringify_keys
105
+ # # => {"person"=>{"name"=>"Rob", "age"=>"28"}}
106
+ def deep_stringify_keys
107
+ deep_transform_keys { |key| key.to_s }
108
+ end unless method_defined?(:deep_stringify_keys)
109
+
110
+ # Destructively convert all keys to strings.
111
+ # This includes the keys from the root hash and from all
112
+ # nested hashes.
113
+ def deep_stringify_keys!
114
+ deep_transform_keys! { |key| key.to_s }
115
+ end unless method_defined?(:deep_stringify_keys!)
116
+
117
+ # Returns a new hash with all keys converted to symbols, as long as
118
+ # they respond to +to_sym+. This includes the keys from the root hash
119
+ # and from all nested hashes.
120
+ #
121
+ # hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
122
+ #
123
+ # hash.deep_symbolize_keys
124
+ # # => {:person=>{:name=>"Rob", :age=>"28"}}
125
+ def deep_symbolize_keys
126
+ deep_transform_keys { |key| key.to_sym rescue key }
127
+ end unless method_defined?(:deep_symbolize_keys)
128
+
129
+ # Destructively convert all keys to symbols, as long as they respond
130
+ # to +to_sym+. This includes the keys from the root hash and from all
131
+ # nested hashes.
132
+ def deep_symbolize_keys!
133
+ deep_transform_keys! { |key| key.to_sym rescue key }
134
+ end unless method_defined?(:deep_symbolize_keys!)
135
+ end
@@ -0,0 +1,14 @@
1
+ STUBBED_ACTIVE_SUPPORT_HASH_KEYS_EXTENSIONS = true
2
+
3
+ class Hash
4
+ STUBS = [
5
+ :transform_keys, :transform_keys!,
6
+ :stringify_keys, :stringify_keys!,
7
+ :symbolize_keys, :symbolize_keys!,
8
+ :deep_transform_keys, :deep_transform_keys!,
9
+ :deep_stringify_keys, :deep_stringify_keys!,
10
+ :deep_symbolize_keys, :deep_symbolize_keys! ]
11
+
12
+ def rofl; :trololo end
13
+ STUBS.each { |stub| alias_method stub, :rofl }
14
+ end
@@ -0,0 +1,233 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require 'minitest/autorun'
4
+ $VERBOSE = true
5
+
6
+ require 'deep_hash_transform'
7
+
8
+ class TransformTest < Minitest::Test
9
+ def setup
10
+ @strings = { 'a' => 1, 'b' => 2 }
11
+ @nested_strings = { 'a' => { 'b' => { 'c' => 3 } } }
12
+ @symbols = { :a => 1, :b => 2 }
13
+ @nested_symbols = { :a => { :b => { :c => 3 } } }
14
+ @mixed = { :a => 1, 'b' => 2 }
15
+ @nested_mixed = { 'a' => { :b => { 'c' => 3 } } }
16
+ @fixnums = { 0 => 1, 1 => 2 }
17
+ @nested_fixnums = { 0 => { 1 => { 2 => 3} } }
18
+ @illegal_symbols = { [] => 3 }
19
+ @nested_illegal_symbols = { [] => { [] => 3} }
20
+ @upcase_strings = { 'A' => 1, 'B' => 2 }
21
+ @nested_upcase_strings = { 'A' => { 'B' => { 'C' => 3 } } }
22
+ end
23
+
24
+ def test_transform_keys
25
+ assert_equal @upcase_strings, @strings.transform_keys { |key| key.to_s.upcase }
26
+ assert_equal @upcase_strings, @symbols.transform_keys { |key| key.to_s.upcase }
27
+ assert_equal @upcase_strings, @mixed.transform_keys { |key| key.to_s.upcase }
28
+ end
29
+
30
+ def test_transform_keys_not_mutates
31
+ transformed_hash = @mixed.dup
32
+ transformed_hash.transform_keys { |key| key.to_s.upcase }
33
+ assert_equal @mixed, transformed_hash
34
+ end
35
+
36
+ def test_deep_transform_keys
37
+ assert_equal @nested_upcase_strings, @nested_symbols.deep_transform_keys { |key| key.to_s.upcase }
38
+ assert_equal @nested_upcase_strings, @nested_strings.deep_transform_keys { |key| key.to_s.upcase }
39
+ assert_equal @nested_upcase_strings, @nested_mixed.deep_transform_keys { |key| key.to_s.upcase }
40
+ end
41
+
42
+ def test_deep_transform_keys_not_mutates
43
+ transformed_hash = deep_dup(@nested_mixed)
44
+ transformed_hash.deep_transform_keys { |key| key.to_s.upcase }
45
+ assert_equal @nested_mixed, transformed_hash
46
+ end
47
+
48
+ def test_transform_keys!
49
+ assert_equal @upcase_strings, @symbols.dup.transform_keys! { |key| key.to_s.upcase }
50
+ assert_equal @upcase_strings, @strings.dup.transform_keys! { |key| key.to_s.upcase }
51
+ assert_equal @upcase_strings, @mixed.dup.transform_keys! { |key| key.to_s.upcase }
52
+ end
53
+
54
+ def test_transform_keys_with_bang_mutates
55
+ transformed_hash = @mixed.dup
56
+ transformed_hash.transform_keys! { |key| key.to_s.upcase }
57
+ assert_equal @upcase_strings, transformed_hash
58
+ assert_equal @mixed, { :a => 1, "b" => 2 }
59
+ end
60
+
61
+ def test_deep_transform_keys!
62
+ assert_equal @nested_upcase_strings, deep_dup(@nested_symbols).deep_transform_keys! { |key| key.to_s.upcase }
63
+ assert_equal @nested_upcase_strings, deep_dup(@nested_strings).deep_transform_keys! { |key| key.to_s.upcase }
64
+ assert_equal @nested_upcase_strings, deep_dup(@nested_mixed).deep_transform_keys! { |key| key.to_s.upcase }
65
+ end
66
+
67
+ def test_deep_transform_keys_with_bang_mutates
68
+ transformed_hash = deep_dup(@nested_mixed)
69
+ transformed_hash.deep_transform_keys! { |key| key.to_s.upcase }
70
+ assert_equal @nested_upcase_strings, transformed_hash
71
+ assert_equal @nested_mixed, { 'a' => { :b => { 'c' => 3 } } }
72
+ end
73
+
74
+ def test_symbolize_keys
75
+ assert_equal @symbols, @symbols.symbolize_keys
76
+ assert_equal @symbols, @strings.symbolize_keys
77
+ assert_equal @symbols, @mixed.symbolize_keys
78
+ end
79
+
80
+ def test_symbolize_keys_not_mutates
81
+ transformed_hash = @mixed.dup
82
+ transformed_hash.symbolize_keys
83
+ assert_equal @mixed, transformed_hash
84
+ end
85
+
86
+ def test_deep_symbolize_keys
87
+ assert_equal @nested_symbols, @nested_symbols.deep_symbolize_keys
88
+ assert_equal @nested_symbols, @nested_strings.deep_symbolize_keys
89
+ assert_equal @nested_symbols, @nested_mixed.deep_symbolize_keys
90
+ end
91
+
92
+ def test_deep_symbolize_keys_not_mutates
93
+ transformed_hash = deep_dup(@nested_mixed)
94
+ transformed_hash.deep_symbolize_keys
95
+ assert_equal @nested_mixed, transformed_hash
96
+ end
97
+
98
+ def test_symbolize_keys!
99
+ assert_equal @symbols, @symbols.dup.symbolize_keys!
100
+ assert_equal @symbols, @strings.dup.symbolize_keys!
101
+ assert_equal @symbols, @mixed.dup.symbolize_keys!
102
+ end
103
+
104
+ def test_symbolize_keys_with_bang_mutates
105
+ transformed_hash = @mixed.dup
106
+ transformed_hash.deep_symbolize_keys!
107
+ assert_equal @symbols, transformed_hash
108
+ assert_equal @mixed, { :a => 1, "b" => 2 }
109
+ end
110
+
111
+ def test_deep_symbolize_keys!
112
+ assert_equal @nested_symbols, deep_dup(@nested_symbols).deep_symbolize_keys!
113
+ assert_equal @nested_symbols, deep_dup(@nested_strings).deep_symbolize_keys!
114
+ assert_equal @nested_symbols, deep_dup(@nested_mixed).deep_symbolize_keys!
115
+ end
116
+
117
+ def test_deep_symbolize_keys_with_bang_mutates
118
+ transformed_hash = deep_dup(@nested_mixed)
119
+ transformed_hash.deep_symbolize_keys!
120
+ assert_equal @nested_symbols, transformed_hash
121
+ assert_equal @nested_mixed, { 'a' => { :b => { 'c' => 3 } } }
122
+ end
123
+
124
+ def test_symbolize_keys_preserves_keys_that_cant_be_symbolized
125
+ assert_equal @illegal_symbols, @illegal_symbols.symbolize_keys
126
+ assert_equal @illegal_symbols, @illegal_symbols.dup.symbolize_keys!
127
+ end
128
+
129
+ def test_deep_symbolize_keys_preserves_keys_that_cant_be_symbolized
130
+ assert_equal @nested_illegal_symbols, @nested_illegal_symbols.deep_symbolize_keys
131
+ assert_equal @nested_illegal_symbols, deep_dup(@nested_illegal_symbols).deep_symbolize_keys!
132
+ end
133
+
134
+ def test_symbolize_keys_preserves_fixnum_keys
135
+ assert_equal @fixnums, @fixnums.symbolize_keys
136
+ assert_equal @fixnums, @fixnums.dup.symbolize_keys!
137
+ end
138
+
139
+ def test_deep_symbolize_keys_preserves_fixnum_keys
140
+ assert_equal @nested_fixnums, @nested_fixnums.deep_symbolize_keys
141
+ assert_equal @nested_fixnums, deep_dup(@nested_fixnums).deep_symbolize_keys!
142
+ end
143
+
144
+ def test_stringify_keys
145
+ assert_equal @strings, @symbols.stringify_keys
146
+ assert_equal @strings, @strings.stringify_keys
147
+ assert_equal @strings, @mixed.stringify_keys
148
+ end
149
+
150
+ def test_stringify_keys_not_mutates
151
+ transformed_hash = @mixed.dup
152
+ transformed_hash.stringify_keys
153
+ assert_equal @mixed, transformed_hash
154
+ end
155
+
156
+ def test_deep_stringify_keys
157
+ assert_equal @nested_strings, @nested_symbols.deep_stringify_keys
158
+ assert_equal @nested_strings, @nested_strings.deep_stringify_keys
159
+ assert_equal @nested_strings, @nested_mixed.deep_stringify_keys
160
+ end
161
+
162
+ def test_deep_stringify_keys_not_mutates
163
+ transformed_hash = deep_dup(@nested_mixed)
164
+ transformed_hash.deep_stringify_keys
165
+ assert_equal @nested_mixed, transformed_hash
166
+ end
167
+
168
+ def test_stringify_keys!
169
+ assert_equal @strings, @symbols.dup.stringify_keys!
170
+ assert_equal @strings, @strings.dup.stringify_keys!
171
+ assert_equal @strings, @mixed.dup.stringify_keys!
172
+ end
173
+
174
+ def test_stringify_keys_with_bang_mutates
175
+ transformed_hash = @mixed.dup
176
+ transformed_hash.stringify_keys!
177
+ assert_equal @strings, transformed_hash
178
+ assert_equal @mixed, { :a => 1, "b" => 2 }
179
+ end
180
+
181
+ def test_deep_stringify_keys!
182
+ assert_equal @nested_strings, deep_dup(@nested_symbols).deep_stringify_keys!
183
+ assert_equal @nested_strings, deep_dup(@nested_strings).deep_stringify_keys!
184
+ assert_equal @nested_strings, deep_dup(@nested_mixed).deep_stringify_keys!
185
+ end
186
+
187
+ def test_deep_stringify_keys_with_bang_mutates
188
+ transformed_hash = deep_dup(@nested_mixed)
189
+ transformed_hash.deep_stringify_keys!
190
+ assert_equal @nested_strings, transformed_hash
191
+ assert_equal @nested_mixed, { 'a' => { :b => { 'c' => 3 } } }
192
+ end
193
+
194
+ private
195
+ def deep_dup(hash)
196
+ Marshal.load(Marshal.dump(hash))
197
+ end
198
+ end
199
+
200
+ # Put a fake Active Support implementation in the load path to verify that
201
+ # we defer to its Hash extensions when they're already defined.
202
+ class ForwardCompatibilityTest < Minitest::Test
203
+ def setup; expunge_loaded_features end
204
+ def teardown; expunge_loaded_features end
205
+
206
+ def test_check_for_active_support_implementation_before_providing_our_own
207
+ assert_equal [], $LOADED_FEATURES.grep(/hash\/keys/)
208
+
209
+ with_stubbed_active_support_in_load_path do
210
+ require 'deep_hash_transform'
211
+ end
212
+
213
+ assert defined?(::STUBBED_ACTIVE_SUPPORT_HASH_KEYS_EXTENSIONS)
214
+
215
+ Hash::STUBS.each do |stub|
216
+ assert_equal :trololo, Hash.new.send(stub)
217
+ end
218
+ end
219
+
220
+ private
221
+ def expunge_loaded_features
222
+ $LOADED_FEATURES.delete_if { |feature| feature =~ /deep_hash_transform/ }
223
+ end
224
+
225
+ def with_stubbed_active_support_in_load_path
226
+ $LOAD_PATH.unshift File.expand_path('../active_support_stub', __FILE__)
227
+ old_verbose, $VERBOSE = $VERBOSE, nil
228
+ yield
229
+ ensure
230
+ $VERBOSE = old_verbose
231
+ $LOAD_PATH.shift
232
+ end
233
+ end
metadata ADDED
@@ -0,0 +1,76 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: deep_hash_transform
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Rails Backport
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '10.1'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '10.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.1'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.1'
41
+ description:
42
+ email: support@basecamp.com
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - "./lib/deep_hash_transform.rb"
48
+ - "./test/active_support_stub/active_support/core_ext/hash/keys.rb"
49
+ - "./test/deep_hash_transform_test.rb"
50
+ homepage: https://github.com/basecamp/deep_hash_transform
51
+ licenses:
52
+ - MIT
53
+ metadata: {}
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 1.8.7
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubyforge_project:
70
+ rubygems_version: 2.2.0
71
+ signing_key:
72
+ specification_version: 4
73
+ summary: Re-key a nested Hash to all-Symbol or -String keys
74
+ test_files:
75
+ - "./test/active_support_stub/active_support/core_ext/hash/keys.rb"
76
+ - "./test/deep_hash_transform_test.rb"