hashie 4.1.0 → 5.2.0
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 +4 -4
- data/CHANGELOG.md +138 -53
- data/CONTRIBUTING.md +38 -1
- data/LICENSE +1 -1
- data/README.md +920 -205
- data/Rakefile +32 -1
- data/UPGRADING.md +56 -0
- data/hashie.gemspec +10 -5
- data/lib/hashie/array.rb +15 -12
- data/lib/hashie/clash.rb +59 -4
- data/lib/hashie/dash.rb +160 -32
- data/lib/hashie/extensions/active_support/core_ext/hash.rb +38 -0
- data/lib/hashie/extensions/array/pretty_inspect.rb +20 -0
- data/lib/hashie/extensions/block_access.rb +71 -0
- data/lib/hashie/extensions/coercion.rb +180 -26
- data/lib/hashie/extensions/dash/coercion.rb +34 -3
- data/lib/hashie/extensions/dash/indifferent_access.rb +90 -3
- data/lib/hashie/extensions/dash/lazy.rb +170 -0
- data/lib/hashie/extensions/dash/predefined_values.rb +148 -0
- data/lib/hashie/extensions/dash/property_translation.rb +138 -15
- data/lib/hashie/extensions/deep_fetch.rb +21 -9
- data/lib/hashie/extensions/deep_find.rb +20 -0
- data/lib/hashie/extensions/deep_grep.rb +69 -0
- data/lib/hashie/extensions/deep_locate.rb +16 -29
- data/lib/hashie/extensions/deep_merge.rb +16 -0
- data/lib/hashie/extensions/deep_merge_initializer.rb +42 -0
- data/lib/hashie/extensions/ignore_undeclared.rb +24 -7
- data/lib/hashie/extensions/indifferent_access.rb +124 -5
- data/lib/hashie/extensions/kernel_coercion.rb +58 -0
- data/lib/hashie/extensions/key_conflict_warning.rb +39 -4
- data/lib/hashie/extensions/key_conversion.rb +9 -0
- data/lib/hashie/extensions/mash/define_accessors.rb +71 -8
- data/lib/hashie/extensions/mash/keep_original_keys.rb +13 -9
- data/lib/hashie/extensions/mash/permissive_respond_to.rb +2 -0
- data/lib/hashie/extensions/mash/required_keys.rb +111 -0
- data/lib/hashie/extensions/mash/safe_assignment.rb +22 -4
- data/lib/hashie/extensions/mash/strict_key_access.rb +65 -0
- data/lib/hashie/extensions/mash/symbolize_keys.rb +11 -7
- data/lib/hashie/extensions/mash/transform_keys.rb +86 -0
- data/lib/hashie/extensions/mash/underscore_keys.rb +32 -0
- data/lib/hashie/extensions/merge_initializer.rb +9 -0
- data/lib/hashie/extensions/method_access.rb +94 -8
- data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +28 -35
- data/lib/hashie/extensions/parsers/yaml_parser.rb +81 -0
- data/lib/hashie/extensions/persistable.rb +137 -0
- data/lib/hashie/extensions/pretty_inspect.rb +14 -0
- data/lib/hashie/extensions/ruby_version.rb +18 -1
- data/lib/hashie/extensions/ruby_version_check.rb +17 -0
- data/lib/hashie/extensions/strict_key_access.rb +59 -5
- data/lib/hashie/extensions/stringify_keys.rb +72 -17
- data/lib/hashie/extensions/symbolize_keys.rb +84 -17
- data/lib/hashie/hash.rb +18 -2
- data/lib/hashie/logger.rb +18 -1
- data/lib/hashie/mash.rb +314 -82
- data/lib/hashie/railtie.rb +27 -1
- data/lib/hashie/rash.rb +64 -4
- data/lib/hashie/trash.rb +8 -0
- data/lib/hashie/utils.rb +17 -6
- data/lib/hashie/version.rb +3 -1
- data/lib/hashie.rb +46 -0
- metadata +22 -9
|
@@ -1,31 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Hashie
|
|
2
4
|
module Extensions
|
|
5
|
+
# Extends a Hash with the ability to convert its keys to symbols.
|
|
6
|
+
# Keys that do not respond to #to_sym are preserved.
|
|
7
|
+
#
|
|
8
|
+
# @example Extend a pre-existing Hash object
|
|
9
|
+
# hash = { 'test' => 'value' }
|
|
10
|
+
# hash.extend(Hashie::Extensions::SymbolizeKeys)
|
|
11
|
+
# hash.symbolize_keys!
|
|
12
|
+
# hash # => { test: 'value' }
|
|
13
|
+
#
|
|
14
|
+
# @example Create a Hash class with this capability
|
|
15
|
+
# class SymbolizableHash < Hash
|
|
16
|
+
# include Hashie::Extensions::SymbolizeKeys
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# hash = SymbolizableHash.new
|
|
20
|
+
# hash['test'] = 'value'
|
|
21
|
+
# hash.symbolize_keys!
|
|
22
|
+
# hash # => { test: 'value' }
|
|
23
|
+
#
|
|
24
|
+
# @example Use the module function to symbolize keys in a hash
|
|
25
|
+
# hash = { 'test' => 'value', 123 => 'number' }
|
|
26
|
+
# Hashie::Extensions::SymbolizeKeys.symbolize_keys!(hash)
|
|
27
|
+
# hash # => { test: 'value', 123 => 'number' }
|
|
3
28
|
module SymbolizeKeys
|
|
4
|
-
#
|
|
29
|
+
# Converts keys in the hash and nested hashes and arrays to symbols.
|
|
5
30
|
#
|
|
6
|
-
# @example
|
|
7
|
-
# test = {'abc' => 'def'}
|
|
31
|
+
# @example Convert keys in place
|
|
32
|
+
# test = { 'abc' => [{ 'def' => 'value' }] }
|
|
33
|
+
# test.extend(Hashie::Extensions::SymbolizeKeys)
|
|
8
34
|
# test.symbolize_keys!
|
|
9
|
-
# test # => {:
|
|
35
|
+
# test # => { abc: [{ def: 'value' }] }
|
|
36
|
+
#
|
|
37
|
+
# @api public
|
|
38
|
+
# @return [Hash] the receiver with its keys symbolized where possible
|
|
10
39
|
def symbolize_keys!
|
|
11
40
|
SymbolizeKeys.symbolize_keys!(self)
|
|
12
41
|
self
|
|
13
42
|
end
|
|
14
43
|
|
|
15
|
-
#
|
|
16
|
-
#
|
|
44
|
+
# Returns a shallow copy with keys recursively converted to symbols.
|
|
45
|
+
# Nested hashes and arrays are shared with the original and are modified.
|
|
46
|
+
#
|
|
47
|
+
# @example Copy a flat hash without modifying the original
|
|
48
|
+
# test = { 'abc' => 'def' }
|
|
49
|
+
# test.extend(Hashie::Extensions::SymbolizeKeys)
|
|
50
|
+
# test.symbolize_keys # => { abc: 'def' }
|
|
51
|
+
# test # => { 'abc' => 'def' }
|
|
52
|
+
#
|
|
53
|
+
# @example Nested values are shared, not deep copied
|
|
54
|
+
# test = { 'abc' => [{ 'def' => 'value' }] }
|
|
55
|
+
# test.extend(Hashie::Extensions::SymbolizeKeys)
|
|
56
|
+
# test.symbolize_keys # => { abc: [{ def: 'value' }] }
|
|
57
|
+
# test # => { 'abc' => [{ def: 'value' }] }
|
|
58
|
+
#
|
|
59
|
+
# @api public
|
|
60
|
+
# @return [Hash] a shallow copy with symbolized keys
|
|
17
61
|
def symbolize_keys
|
|
18
62
|
SymbolizeKeys.symbolize_keys(self)
|
|
19
63
|
end
|
|
20
64
|
|
|
65
|
+
# @example Add recursive conversion functions to an object
|
|
66
|
+
# converter = Object.new.extend(Hashie::Extensions::SymbolizeKeys::ClassMethods)
|
|
67
|
+
# converter.symbolize_keys('user' => { 'name' => 'Ada' }) # => { user: { name: 'Ada' } }
|
|
21
68
|
module ClassMethods
|
|
22
69
|
# Symbolize all keys recursively within nested
|
|
23
70
|
# hashes and arrays.
|
|
24
71
|
# @api private
|
|
25
72
|
def symbolize_keys_recursively!(object)
|
|
26
73
|
case object
|
|
27
|
-
when self.class
|
|
28
|
-
symbolize_keys!(object)
|
|
29
74
|
when ::Array
|
|
30
75
|
object.each do |i|
|
|
31
76
|
symbolize_keys_recursively!(i)
|
|
@@ -35,25 +80,36 @@ module Hashie
|
|
|
35
80
|
end
|
|
36
81
|
end
|
|
37
82
|
|
|
38
|
-
#
|
|
83
|
+
# Converts keys in a hash recursively to symbols, in place.
|
|
39
84
|
#
|
|
85
|
+
# @example Convert keys through Hashie's module function
|
|
86
|
+
# test = { 'abc' => 'def' }
|
|
87
|
+
# Hashie.symbolize_keys!(test)
|
|
88
|
+
# test # => { abc: 'def' }
|
|
89
|
+
#
|
|
90
|
+
# @api public
|
|
40
91
|
# @param [Hash] hash
|
|
41
|
-
# @
|
|
42
|
-
# test = {'abc' => 'def'}
|
|
43
|
-
# Hashie.symbolize_keys! test
|
|
44
|
-
# test # => {:abc => 'def'}
|
|
92
|
+
# @return [Hash] the passed hash with symbolized keys
|
|
45
93
|
def symbolize_keys!(hash)
|
|
46
94
|
hash.extend(Hashie::Extensions::SymbolizeKeys) unless hash.respond_to?(:symbolize_keys!)
|
|
47
95
|
hash.keys.each do |k| # rubocop:disable Performance/HashEachMethods
|
|
48
96
|
symbolize_keys_recursively!(hash[k])
|
|
49
|
-
hash[k
|
|
97
|
+
hash[convert_key(k)] = hash.delete(k)
|
|
50
98
|
end
|
|
51
99
|
hash
|
|
52
100
|
end
|
|
53
101
|
|
|
54
|
-
#
|
|
55
|
-
#
|
|
56
|
-
#
|
|
102
|
+
# Returns a shallow copy of a hash with recursively symbolized keys.
|
|
103
|
+
# Nested hashes and arrays are shared with the original and are modified.
|
|
104
|
+
#
|
|
105
|
+
# @example Copy keys through Hashie's module function
|
|
106
|
+
# test = { 'abc' => 'def' }
|
|
107
|
+
# Hashie.symbolize_keys(test) # => { abc: 'def' }
|
|
108
|
+
# test # => { 'abc' => 'def' }
|
|
109
|
+
#
|
|
110
|
+
# @api public
|
|
111
|
+
# @param [Hash] hash
|
|
112
|
+
# @return [Hash] a shallow copy with symbolized keys
|
|
57
113
|
def symbolize_keys(hash)
|
|
58
114
|
copy = hash.dup
|
|
59
115
|
copy.extend(Hashie::Extensions::SymbolizeKeys) unless copy.respond_to?(:symbolize_keys!)
|
|
@@ -61,6 +117,17 @@ module Hashie
|
|
|
61
117
|
symbolize_keys!(new_hash)
|
|
62
118
|
end
|
|
63
119
|
end
|
|
120
|
+
|
|
121
|
+
private
|
|
122
|
+
|
|
123
|
+
# Converts a key to a symbol, if possible
|
|
124
|
+
#
|
|
125
|
+
# @api private
|
|
126
|
+
# @param [<K>] key the key to attempt convert to a symbol
|
|
127
|
+
# @return [Symbol, K]
|
|
128
|
+
def convert_key(key)
|
|
129
|
+
key.respond_to?(:to_sym) ? key.to_sym : key
|
|
130
|
+
end
|
|
64
131
|
end
|
|
65
132
|
|
|
66
133
|
class << self
|
data/lib/hashie/hash.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'hashie/extensions/stringify_keys'
|
|
2
4
|
require 'hashie/extensions/pretty_inspect'
|
|
3
5
|
|
|
@@ -5,24 +7,34 @@ module Hashie
|
|
|
5
7
|
# A Hashie Hash is simply a Hash that has convenience
|
|
6
8
|
# functions baked in such as stringify_keys that may
|
|
7
9
|
# not be available in all libraries.
|
|
10
|
+
#
|
|
11
|
+
# @example Convert keys using the built-in extensions
|
|
12
|
+
# Hashie::Hash[name: 'Ada'].stringify_keys # => { 'name' => 'Ada' }
|
|
8
13
|
class Hash < ::Hash
|
|
9
14
|
include Hashie::Extensions::PrettyInspect
|
|
10
15
|
include Hashie::Extensions::StringifyKeys
|
|
11
16
|
|
|
12
17
|
# Convert this hash into a Mash
|
|
18
|
+
#
|
|
19
|
+
# @example Read converted data through methods
|
|
20
|
+
# Hashie::Hash[name: 'Ada'].to_mash.name # => 'Ada'
|
|
13
21
|
def to_mash
|
|
14
22
|
::Hashie::Mash.new(self)
|
|
15
23
|
end
|
|
16
24
|
|
|
17
25
|
# Converts a mash back to a hash (with stringified or symbolized keys)
|
|
26
|
+
#
|
|
27
|
+
# @example Recursively convert nested hashes and their keys
|
|
28
|
+
# hash = Hashie::Hash[user: Hashie::Hash[name: 'Ada']]
|
|
29
|
+
# hash.to_hash(stringify_keys: true) # => { 'user' => { 'name' => 'Ada' } }
|
|
18
30
|
def to_hash(options = {})
|
|
19
31
|
out = {}
|
|
20
32
|
each_key do |k|
|
|
21
33
|
assignment_key =
|
|
22
34
|
if options[:stringify_keys]
|
|
23
35
|
k.to_s
|
|
24
|
-
elsif options[:symbolize_keys]
|
|
25
|
-
k.
|
|
36
|
+
elsif options[:symbolize_keys] && k.respond_to?(:to_sym)
|
|
37
|
+
k.to_sym
|
|
26
38
|
else
|
|
27
39
|
k
|
|
28
40
|
end
|
|
@@ -39,6 +51,10 @@ module Hashie
|
|
|
39
51
|
end
|
|
40
52
|
|
|
41
53
|
# The C generator for the json gem doesn't like mashies
|
|
54
|
+
#
|
|
55
|
+
# @example Serialize as an ordinary JSON object
|
|
56
|
+
# require 'json'
|
|
57
|
+
# JSON.parse(Hashie::Hash[name: 'Ada'].to_json) # => { 'name' => 'Ada' }
|
|
42
58
|
def to_json(*args)
|
|
43
59
|
to_hash.to_json(*args)
|
|
44
60
|
end
|
data/lib/hashie/logger.rb
CHANGED
|
@@ -1,17 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'logger'
|
|
2
4
|
|
|
3
5
|
module Hashie
|
|
4
6
|
# The logger that Hashie uses for reporting errors.
|
|
5
7
|
#
|
|
6
8
|
# @return [Logger]
|
|
9
|
+
#
|
|
10
|
+
# @example Obtain the logger used for warnings
|
|
11
|
+
# Hashie.logger.respond_to?(:warn) # => true
|
|
7
12
|
def self.logger
|
|
8
|
-
@logger ||= Logger.new(
|
|
13
|
+
@logger ||= Logger.new($stdout)
|
|
9
14
|
end
|
|
10
15
|
|
|
11
16
|
# Sets the logger that Hashie uses for reporting errors.
|
|
12
17
|
#
|
|
13
18
|
# @param logger [Logger] The logger to set as Hashie's logger.
|
|
14
19
|
# @return [void]
|
|
20
|
+
#
|
|
21
|
+
# @example Temporarily capture warnings
|
|
22
|
+
# require 'stringio'
|
|
23
|
+
# original = Hashie.logger
|
|
24
|
+
# begin
|
|
25
|
+
# output = StringIO.new
|
|
26
|
+
# Hashie.logger = Logger.new(output)
|
|
27
|
+
# Hashie.logger.warn('example warning')
|
|
28
|
+
# output.string.include?('example warning') # => true
|
|
29
|
+
# ensure
|
|
30
|
+
# Hashie.logger = original
|
|
31
|
+
# end
|
|
15
32
|
def self.logger=(logger)
|
|
16
33
|
@logger = logger
|
|
17
34
|
end
|