-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathdeep_symbolizable.rb
68 lines (57 loc) · 2.05 KB
/
deep_symbolizable.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# Forked from https://gist.github.com/morhekil/3706140
# Symbolizes all of hash's keys and subkeys.
# Also allows for custom pre-processing of keys (e.g. downcasing, etc)
# if the block is given:
#
# somehash.deep_symbolize { |key| key.downcase }
#
# Usage: either include it into global Hash class to make it available to
# to all hashes, or extend only your own hash objects with this
# module.
# E.g.:
# 1) class Hash; include DeepSymbolizable; end
# 2) myhash.extend DeepSymbolizable
module DeepSymbolizable
class Hash
include DeepSymbolizable
end
def deep_symbolize(&block)
method = self.class.to_s.downcase.to_sym
syms = DeepSymbolizable::Symbolizers
syms.respond_to?(method) ? syms.send(method, self, &block) : self
end
module Symbolizers
extend self
# the primary method - symbolizes keys of the given hash,
# preprocessing them with a block if one was given, and recursively
# going into all nested enumerables
def hash(hash, &block)
hash.inject({}) do |result, (key, value)|
# Recursively deep-symbolize subhashes
value = _recurse_(value, &block)
# Pre-process the key with a block if it was given
key = yield key if block_given?
# Symbolize the key string if it responds to to_sym
sym_key = key.to_sym rescue key
# write it back into the result and return the updated hash
result[sym_key] = value
result
end
end
# walking over arrays and symbolizing all nested elements
def array(ary, &block)
ary.map { |v| _recurse_(v, &block) }
end
# handling recursion - any Enumerable elements (except String)
# is being extended with the module, and then symbolized
def _recurse_(value, &block)
if value.is_a?(Enumerable) && !value.is_a?(String)
# support for a use case without extended core Hash
value.extend DeepSymbolizable unless value.class.include?(DeepSymbolizable)
value = value.deep_symbolize(&block)
end
value
end
end
end
class Hash; include DeepSymbolizable; end