hashie 3.6.0 → 5.0.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 +271 -207
- data/CONTRIBUTING.md +13 -6
- data/LICENSE +1 -1
- data/README.md +245 -54
- data/UPGRADING.md +121 -7
- data/hashie.gemspec +13 -7
- data/lib/hashie/dash.rb +18 -17
- data/lib/hashie/extensions/active_support/core_ext/hash.rb +14 -0
- data/lib/hashie/extensions/coercion.rb +23 -16
- data/lib/hashie/extensions/dash/indifferent_access.rb +29 -1
- data/lib/hashie/extensions/dash/predefined_values.rb +88 -0
- data/lib/hashie/extensions/dash/property_translation.rb +12 -4
- data/lib/hashie/extensions/deep_fetch.rb +4 -2
- data/lib/hashie/extensions/deep_find.rb +12 -3
- data/lib/hashie/extensions/deep_locate.rb +22 -7
- data/lib/hashie/extensions/deep_merge.rb +18 -1
- data/lib/hashie/extensions/ignore_undeclared.rb +4 -5
- data/lib/hashie/extensions/indifferent_access.rb +37 -6
- data/lib/hashie/extensions/key_conflict_warning.rb +55 -0
- data/lib/hashie/extensions/mash/define_accessors.rb +90 -0
- data/lib/hashie/extensions/mash/keep_original_keys.rb +2 -1
- data/lib/hashie/extensions/mash/permissive_respond_to.rb +61 -0
- data/lib/hashie/extensions/mash/safe_assignment.rb +3 -1
- data/lib/hashie/extensions/mash/symbolize_keys.rb +5 -5
- data/lib/hashie/extensions/method_access.rb +5 -2
- data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +26 -4
- data/lib/hashie/extensions/ruby_version_check.rb +5 -1
- data/lib/hashie/extensions/strict_key_access.rb +8 -4
- data/lib/hashie/extensions/symbolize_keys.rb +12 -1
- data/lib/hashie/hash.rb +16 -9
- data/lib/hashie/mash.rb +130 -64
- data/lib/hashie/railtie.rb +7 -0
- data/lib/hashie/rash.rb +1 -1
- data/lib/hashie/utils.rb +28 -0
- data/lib/hashie/version.rb +1 -1
- data/lib/hashie.rb +22 -19
- metadata +23 -133
- data/spec/hashie/array_spec.rb +0 -29
- data/spec/hashie/clash_spec.rb +0 -70
- data/spec/hashie/dash_spec.rb +0 -598
- data/spec/hashie/extensions/autoload_spec.rb +0 -24
- data/spec/hashie/extensions/coercion_spec.rb +0 -639
- data/spec/hashie/extensions/dash/coercion_spec.rb +0 -13
- data/spec/hashie/extensions/dash/indifferent_access_spec.rb +0 -84
- data/spec/hashie/extensions/deep_fetch_spec.rb +0 -97
- data/spec/hashie/extensions/deep_find_spec.rb +0 -138
- data/spec/hashie/extensions/deep_locate_spec.rb +0 -137
- data/spec/hashie/extensions/deep_merge_spec.rb +0 -70
- data/spec/hashie/extensions/ignore_undeclared_spec.rb +0 -47
- data/spec/hashie/extensions/indifferent_access_spec.rb +0 -295
- data/spec/hashie/extensions/indifferent_access_with_rails_hwia_spec.rb +0 -208
- data/spec/hashie/extensions/key_conversion_spec.rb +0 -12
- data/spec/hashie/extensions/mash/keep_original_keys_spec.rb +0 -46
- data/spec/hashie/extensions/mash/safe_assignment_spec.rb +0 -50
- data/spec/hashie/extensions/mash/symbolize_keys_spec.rb +0 -39
- data/spec/hashie/extensions/merge_initializer_spec.rb +0 -23
- data/spec/hashie/extensions/method_access_spec.rb +0 -226
- data/spec/hashie/extensions/strict_key_access_spec.rb +0 -110
- data/spec/hashie/extensions/stringify_keys_spec.rb +0 -124
- data/spec/hashie/extensions/symbolize_keys_spec.rb +0 -129
- data/spec/hashie/hash_spec.rb +0 -84
- data/spec/hashie/mash_spec.rb +0 -771
- data/spec/hashie/parsers/yaml_erb_parser_spec.rb +0 -46
- data/spec/hashie/rash_spec.rb +0 -83
- data/spec/hashie/trash_spec.rb +0 -328
- data/spec/hashie/utils_spec.rb +0 -25
- data/spec/hashie/version_spec.rb +0 -7
- data/spec/hashie_spec.rb +0 -13
- data/spec/integration/elasticsearch/integration_spec.rb +0 -40
- data/spec/integration/omniauth/app.rb +0 -11
- data/spec/integration/omniauth/integration_spec.rb +0 -38
- data/spec/integration/omniauth-oauth2/app.rb +0 -52
- data/spec/integration/omniauth-oauth2/integration_spec.rb +0 -26
- data/spec/integration/omniauth-oauth2/some_site.rb +0 -38
- data/spec/integration/rails/app.rb +0 -47
- data/spec/integration/rails/integration_spec.rb +0 -26
- data/spec/integration/rails-without-dependency/integration_spec.rb +0 -15
- data/spec/spec_helper.rb +0 -23
- data/spec/support/integration_specs.rb +0 -36
- data/spec/support/logger.rb +0 -24
- data/spec/support/module_context.rb +0 -11
- data/spec/support/ruby_version_check.rb +0 -6
@@ -3,7 +3,7 @@ module Hashie
|
|
3
3
|
module DeepMerge
|
4
4
|
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
5
5
|
def deep_merge(other_hash, &block)
|
6
|
-
copy =
|
6
|
+
copy = _deep_dup(self)
|
7
7
|
copy.extend(Hashie::Extensions::DeepMerge) unless copy.respond_to?(:deep_merge!)
|
8
8
|
copy.deep_merge!(other_hash, &block)
|
9
9
|
end
|
@@ -18,11 +18,28 @@ module Hashie
|
|
18
18
|
|
19
19
|
private
|
20
20
|
|
21
|
+
def _deep_dup(hash)
|
22
|
+
copy = hash.dup
|
23
|
+
|
24
|
+
copy.each do |key, value|
|
25
|
+
copy[key] =
|
26
|
+
if value.is_a?(::Hash)
|
27
|
+
_deep_dup(value)
|
28
|
+
else
|
29
|
+
Hashie::Utils.safe_dup(value)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
copy
|
34
|
+
end
|
35
|
+
|
21
36
|
def _recursive_merge(hash, other_hash, &block)
|
22
37
|
other_hash.each do |k, v|
|
23
38
|
hash[k] =
|
24
39
|
if hash.key?(k) && hash[k].is_a?(::Hash) && v.is_a?(::Hash)
|
25
40
|
_recursive_merge(hash[k], v, &block)
|
41
|
+
elsif v.is_a?(::Hash)
|
42
|
+
_recursive_merge({}, v, &block)
|
26
43
|
elsif hash.key?(k) && block_given?
|
27
44
|
yield(k, hash[k], v)
|
28
45
|
else
|
@@ -31,12 +31,11 @@ module Hashie
|
|
31
31
|
module IgnoreUndeclared
|
32
32
|
def initialize_attributes(attributes)
|
33
33
|
return unless attributes
|
34
|
+
|
34
35
|
klass = self.class
|
35
|
-
translations = klass.respond_to?(:translations) && klass.translations
|
36
|
-
|
37
|
-
|
38
|
-
self[att] = value
|
39
|
-
end
|
36
|
+
translations = klass.respond_to?(:translations) && klass.translations || []
|
37
|
+
|
38
|
+
super(attributes.select { |attr, _| klass.property?(attr) || translations.include?(attr) })
|
40
39
|
end
|
41
40
|
|
42
41
|
def property_exists?(property)
|
@@ -23,10 +23,15 @@ module Hashie
|
|
23
23
|
# h['baz'] # => 'blip'
|
24
24
|
#
|
25
25
|
module IndifferentAccess
|
26
|
+
include Hashie::Extensions::RubyVersionCheck
|
27
|
+
|
28
|
+
# @api private
|
29
|
+
def self.convert_key(key)
|
30
|
+
key.to_s
|
31
|
+
end
|
32
|
+
|
26
33
|
def self.included(base)
|
27
|
-
Hashie::Extensions::Dash::IndifferentAccess
|
28
|
-
base.extend(extension) if base <= Hashie::Dash && !base.singleton_class.included_modules.include?(extension)
|
29
|
-
end
|
34
|
+
Hashie::Extensions::Dash::IndifferentAccess.maybe_extend(base)
|
30
35
|
|
31
36
|
base.class_eval do
|
32
37
|
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
|
@@ -68,7 +73,7 @@ module Hashie
|
|
68
73
|
end
|
69
74
|
|
70
75
|
def convert_key(key)
|
71
|
-
key
|
76
|
+
IndifferentAccess.convert_key(key)
|
72
77
|
end
|
73
78
|
|
74
79
|
# Iterates through the keys and values, reconverting them to
|
@@ -76,7 +81,7 @@ module Hashie
|
|
76
81
|
# is injecting itself into member hashes.
|
77
82
|
def convert!
|
78
83
|
keys.each do |k| # rubocop:disable Performance/HashEachMethods
|
79
|
-
|
84
|
+
indifferent_writer k, regular_delete(k)
|
80
85
|
end
|
81
86
|
self
|
82
87
|
end
|
@@ -135,7 +140,7 @@ module Hashie
|
|
135
140
|
|
136
141
|
def merge(*args)
|
137
142
|
result = super
|
138
|
-
IndifferentAccess.inject!(result) if hash_lacking_indifference?(result)
|
143
|
+
return IndifferentAccess.inject!(result) if hash_lacking_indifference?(result)
|
139
144
|
result.convert!
|
140
145
|
end
|
141
146
|
|
@@ -143,6 +148,32 @@ module Hashie
|
|
143
148
|
super.convert!
|
144
149
|
end
|
145
150
|
|
151
|
+
def to_hash
|
152
|
+
{}.tap do |result|
|
153
|
+
each_pair { |key, value| result[key] = value }
|
154
|
+
|
155
|
+
if default_proc
|
156
|
+
result.default_proc = default_proc
|
157
|
+
else
|
158
|
+
result.default = default
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
with_minimum_ruby('2.5.0') do
|
164
|
+
def slice(*keys)
|
165
|
+
string_keys = keys.map { |key| convert_key(key) }
|
166
|
+
super(*string_keys)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
with_minimum_ruby('3.0.0') do
|
171
|
+
def except(*keys)
|
172
|
+
string_keys = keys.map { |key| convert_key(key) }
|
173
|
+
super(*string_keys)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
146
177
|
protected
|
147
178
|
|
148
179
|
def hash_lacking_indifference?(other)
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Hashie
|
2
|
+
module Extensions
|
3
|
+
module KeyConflictWarning
|
4
|
+
class CannotDisableMashWarnings < StandardError
|
5
|
+
def initialize
|
6
|
+
super(
|
7
|
+
'You cannot disable warnings on the base Mash class. ' \
|
8
|
+
'Please subclass the Mash and disable it in the subclass.'
|
9
|
+
)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Disable the logging of warnings based on keys conflicting keys/methods
|
14
|
+
#
|
15
|
+
# @api semipublic
|
16
|
+
# @return [void]
|
17
|
+
def disable_warnings(*method_keys)
|
18
|
+
raise CannotDisableMashWarnings if self == Hashie::Mash
|
19
|
+
if method_keys.any?
|
20
|
+
disabled_warnings.concat(method_keys).tap(&:flatten!).uniq!
|
21
|
+
else
|
22
|
+
disabled_warnings.clear
|
23
|
+
end
|
24
|
+
|
25
|
+
@disable_warnings = true
|
26
|
+
end
|
27
|
+
|
28
|
+
# Checks whether this class disables warnings for conflicting keys/methods
|
29
|
+
#
|
30
|
+
# @api semipublic
|
31
|
+
# @return [Boolean]
|
32
|
+
def disable_warnings?(method_key = nil)
|
33
|
+
return disabled_warnings.include?(method_key) if disabled_warnings.any? && method_key
|
34
|
+
@disable_warnings ||= false
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns an array of methods that this class disables warnings for.
|
38
|
+
#
|
39
|
+
# @api semipublic
|
40
|
+
# @return [Boolean]
|
41
|
+
def disabled_warnings
|
42
|
+
@_disabled_warnings ||= []
|
43
|
+
end
|
44
|
+
|
45
|
+
# Inheritance hook that sets class configuration when inherited.
|
46
|
+
#
|
47
|
+
# @api semipublic
|
48
|
+
# @return [void]
|
49
|
+
def inherited(subclass)
|
50
|
+
super
|
51
|
+
subclass.disable_warnings(disabled_warnings) if disable_warnings?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Hashie
|
2
|
+
module Extensions
|
3
|
+
module Mash
|
4
|
+
module DefineAccessors
|
5
|
+
def self.included(klass)
|
6
|
+
klass.class_eval do
|
7
|
+
mod = Ext.new
|
8
|
+
include mod
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.extended(obj)
|
13
|
+
included(obj.singleton_class)
|
14
|
+
end
|
15
|
+
|
16
|
+
class Ext < Module
|
17
|
+
def initialize
|
18
|
+
mod = self
|
19
|
+
define_method(:method_missing) do |method_name, *args, &block|
|
20
|
+
key, suffix = method_name_and_suffix(method_name)
|
21
|
+
case suffix
|
22
|
+
when '='.freeze
|
23
|
+
mod.define_writer(key, method_name)
|
24
|
+
when '?'.freeze
|
25
|
+
mod.define_predicate(key, method_name)
|
26
|
+
when '!'.freeze
|
27
|
+
mod.define_initializing_reader(key, method_name)
|
28
|
+
when '_'.freeze
|
29
|
+
mod.define_underbang_reader(key, method_name)
|
30
|
+
else
|
31
|
+
mod.define_reader(key, method_name)
|
32
|
+
end
|
33
|
+
send(method_name, *args, &block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def define_reader(key, method_name)
|
38
|
+
define_method(method_name) do |&block|
|
39
|
+
if key? method_name
|
40
|
+
self.[](method_name, &block)
|
41
|
+
else
|
42
|
+
self.[](key, &block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def define_writer(key, method_name)
|
48
|
+
define_method(method_name) do |value = nil|
|
49
|
+
if key? method_name
|
50
|
+
self.[](method_name, &proc)
|
51
|
+
else
|
52
|
+
assign_property(key, value)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def define_predicate(key, method_name)
|
58
|
+
define_method(method_name) do
|
59
|
+
if key? method_name
|
60
|
+
self.[](method_name, &proc)
|
61
|
+
else
|
62
|
+
!!self[key]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def define_initializing_reader(key, method_name)
|
68
|
+
define_method(method_name) do
|
69
|
+
if key? method_name
|
70
|
+
self.[](method_name, &proc)
|
71
|
+
else
|
72
|
+
initializing_reader(key)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def define_underbang_reader(key, method_name)
|
78
|
+
define_method(method_name) do
|
79
|
+
if key? method_name
|
80
|
+
self.[](key, &proc)
|
81
|
+
else
|
82
|
+
underbang_reader(key)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -15,7 +15,8 @@ module Hashie
|
|
15
15
|
# mash[:symbol_key] == mash['symbol_key'] #=> true
|
16
16
|
module KeepOriginalKeys
|
17
17
|
def self.included(descendant)
|
18
|
-
|
18
|
+
error_message = "#{descendant} is not a kind of Hashie::Mash"
|
19
|
+
raise ArgumentError, error_message unless descendant <= Hashie::Mash
|
19
20
|
end
|
20
21
|
|
21
22
|
private
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module Hashie
|
2
|
+
module Extensions
|
3
|
+
module Mash
|
4
|
+
# Allow a Mash to properly respond to everything
|
5
|
+
#
|
6
|
+
# By default, Mashes only say they respond to methods for keys that exist
|
7
|
+
# in their key set or any of the affix methods (e.g. setter, underbang,
|
8
|
+
# etc.). This causes issues when you try to use them within a
|
9
|
+
# SimpleDelegator or bind to a method for a key that is unset.
|
10
|
+
#
|
11
|
+
# This extension allows a Mash to properly respond to `respond_to?` and
|
12
|
+
# `method` for keys that have not yet been set. This enables full
|
13
|
+
# compatibility with SimpleDelegator and thunk-oriented programming.
|
14
|
+
#
|
15
|
+
# There is a trade-off with this extension: it will run slower than a
|
16
|
+
# regular Mash; insertions and initializations with keys run approximately
|
17
|
+
# 20% slower and cost approximately 19KB of memory per class that you
|
18
|
+
# make permissive.
|
19
|
+
#
|
20
|
+
# @api public
|
21
|
+
# @example Make a new, permissively responding Mash subclass
|
22
|
+
# class PermissiveMash < Hashie::Mash
|
23
|
+
# include Hashie::Extensions::Mash::PermissiveRespondTo
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# mash = PermissiveMash.new(a: 1)
|
27
|
+
# mash.respond_to? :b #=> true
|
28
|
+
module PermissiveRespondTo
|
29
|
+
# The Ruby hook for behavior when including the module
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
# @private
|
33
|
+
# @return void
|
34
|
+
def self.included(base)
|
35
|
+
base.instance_variable_set :@_method_cache, base.instance_methods
|
36
|
+
base.define_singleton_method(:method_cache) { @_method_cache }
|
37
|
+
end
|
38
|
+
|
39
|
+
# The Ruby hook for determining what messages a class might respond to
|
40
|
+
#
|
41
|
+
# @api private
|
42
|
+
# @private
|
43
|
+
def respond_to_missing?(_method_name, _include_private = false)
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# Override the Mash logging behavior to account for permissiveness
|
50
|
+
#
|
51
|
+
# @api private
|
52
|
+
# @private
|
53
|
+
def log_collision?(method_key)
|
54
|
+
self.class.method_cache.include?(method_key) &&
|
55
|
+
!self.class.disable_warnings?(method_key) &&
|
56
|
+
!(regular_key?(method_key) || regular_key?(method_key.to_s))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -3,7 +3,9 @@ module Hashie
|
|
3
3
|
module Mash
|
4
4
|
module SafeAssignment
|
5
5
|
def custom_writer(key, *args) #:nodoc:
|
6
|
-
|
6
|
+
if !key?(key) && respond_to?(key, true)
|
7
|
+
raise ArgumentError, "The property #{key} clashes with an existing method."
|
8
|
+
end
|
7
9
|
super
|
8
10
|
end
|
9
11
|
|
@@ -5,7 +5,7 @@ module Hashie
|
|
5
5
|
#
|
6
6
|
# @example
|
7
7
|
# class LazyResponse < Hashie::Mash
|
8
|
-
# include Hashie::Extensions::Mash::
|
8
|
+
# include Hashie::Extensions::Mash::SymbolizeKeys
|
9
9
|
# end
|
10
10
|
#
|
11
11
|
# response = LazyResponse.new("id" => 123, "name" => "Rey").to_h
|
@@ -24,13 +24,13 @@ module Hashie
|
|
24
24
|
|
25
25
|
private
|
26
26
|
|
27
|
-
# Converts a key to a symbol
|
27
|
+
# Converts a key to a symbol, if possible
|
28
28
|
#
|
29
29
|
# @api private
|
30
|
-
# @param [
|
31
|
-
# @return [
|
30
|
+
# @param [<K>] key the key to attempt convert to a symbol
|
31
|
+
# @return [Symbol, K]
|
32
32
|
def convert_key(key)
|
33
|
-
key.to_sym
|
33
|
+
key.respond_to?(:to_sym) ? key.to_sym : key
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
@@ -73,7 +73,9 @@ module Hashie
|
|
73
73
|
end
|
74
74
|
|
75
75
|
def method_missing(name, *args)
|
76
|
-
|
76
|
+
if args.size == 1 && name.to_s =~ /(.*)=$/
|
77
|
+
return self[convert_key(Regexp.last_match[1])] = args.first
|
78
|
+
end
|
77
79
|
|
78
80
|
super
|
79
81
|
end
|
@@ -231,7 +233,8 @@ module Hashie
|
|
231
233
|
# underscores.
|
232
234
|
module MethodAccessWithOverride
|
233
235
|
def self.included(base)
|
234
|
-
[MethodReader, MethodOverridingWriter,
|
236
|
+
[MethodReader, MethodOverridingWriter,
|
237
|
+
MethodQuery, MethodOverridingInitializer].each do |mod|
|
235
238
|
base.send :include, mod
|
236
239
|
end
|
237
240
|
end
|
@@ -6,19 +6,41 @@ module Hashie
|
|
6
6
|
module Extensions
|
7
7
|
module Parsers
|
8
8
|
class YamlErbParser
|
9
|
-
def initialize(file_path)
|
9
|
+
def initialize(file_path, options = {})
|
10
10
|
@content = File.read(file_path)
|
11
11
|
@file_path = file_path.is_a?(Pathname) ? file_path.to_s : file_path
|
12
|
+
@options = options
|
12
13
|
end
|
13
14
|
|
14
15
|
def perform
|
15
16
|
template = ERB.new(@content)
|
16
17
|
template.filename = @file_path
|
17
|
-
|
18
|
+
permitted_classes = @options.fetch(:permitted_classes) { [] }
|
19
|
+
permitted_symbols = @options.fetch(:permitted_symbols) { [] }
|
20
|
+
aliases = @options.fetch(:aliases) { true }
|
21
|
+
|
22
|
+
yaml_safe_load(template, permitted_classes, permitted_symbols, aliases)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.perform(file_path, options = {})
|
26
|
+
new(file_path, options).perform
|
18
27
|
end
|
19
28
|
|
20
|
-
|
21
|
-
|
29
|
+
private
|
30
|
+
|
31
|
+
if Gem::Version.new(Psych::VERSION) >= Gem::Version.new('3.1.0') # Ruby 2.6+
|
32
|
+
def yaml_safe_load(template, permitted_classes, permitted_symbols, aliases)
|
33
|
+
YAML.safe_load(
|
34
|
+
template.result,
|
35
|
+
permitted_classes: permitted_classes,
|
36
|
+
permitted_symbols: permitted_symbols,
|
37
|
+
aliases: aliases
|
38
|
+
)
|
39
|
+
end
|
40
|
+
else
|
41
|
+
def yaml_safe_load(template, permitted_classes, permitted_symbols, aliases)
|
42
|
+
YAML.safe_load(template.result, permitted_classes, permitted_symbols, aliases)
|
43
|
+
end
|
22
44
|
end
|
23
45
|
end
|
24
46
|
end
|
@@ -9,7 +9,11 @@ module Hashie
|
|
9
9
|
|
10
10
|
module ClassMethods
|
11
11
|
def with_minimum_ruby(version)
|
12
|
-
yield if
|
12
|
+
yield if with_minimum_ruby?(version)
|
13
|
+
end
|
14
|
+
|
15
|
+
def with_minimum_ruby?(version)
|
16
|
+
RubyVersion.new(RUBY_VERSION) >= RubyVersion.new(version)
|
13
17
|
end
|
14
18
|
end
|
15
19
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Hashie
|
2
2
|
module Extensions
|
3
|
-
# SRP: This extension will fail an error whenever a key is accessed
|
3
|
+
# SRP: This extension will fail an error whenever a key is accessed
|
4
|
+
# that does not exist in the hash.
|
4
5
|
#
|
5
6
|
# EXAMPLE:
|
6
7
|
#
|
@@ -15,12 +16,15 @@ module Hashie
|
|
15
16
|
# >> hash[:cow]
|
16
17
|
# KeyError: key not found: :cow
|
17
18
|
#
|
18
|
-
# NOTE: For googlers coming from Python to Ruby, this extension makes a Hash
|
19
|
+
# NOTE: For googlers coming from Python to Ruby, this extension makes a Hash
|
20
|
+
# behave more like a "Dictionary".
|
19
21
|
#
|
20
22
|
module StrictKeyAccess
|
21
23
|
class DefaultError < StandardError
|
22
|
-
def initialize
|
23
|
-
super
|
24
|
+
def initialize
|
25
|
+
super('Setting or using a default with Hashie::Extensions::StrictKeyAccess'\
|
26
|
+
' does not make sense'
|
27
|
+
)
|
24
28
|
end
|
25
29
|
end
|
26
30
|
|
@@ -46,7 +46,7 @@ module Hashie
|
|
46
46
|
hash.extend(Hashie::Extensions::SymbolizeKeys) unless hash.respond_to?(:symbolize_keys!)
|
47
47
|
hash.keys.each do |k| # rubocop:disable Performance/HashEachMethods
|
48
48
|
symbolize_keys_recursively!(hash[k])
|
49
|
-
hash[k
|
49
|
+
hash[convert_key(k)] = hash.delete(k)
|
50
50
|
end
|
51
51
|
hash
|
52
52
|
end
|
@@ -61,6 +61,17 @@ module Hashie
|
|
61
61
|
symbolize_keys!(new_hash)
|
62
62
|
end
|
63
63
|
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
# Converts a key to a symbol, if possible
|
68
|
+
#
|
69
|
+
# @api private
|
70
|
+
# @param [<K>] key the key to attempt convert to a symbol
|
71
|
+
# @return [Symbol, K]
|
72
|
+
def convert_key(key)
|
73
|
+
key.respond_to?(:to_sym) ? key.to_sym : key
|
74
|
+
end
|
64
75
|
end
|
65
76
|
|
66
77
|
class << self
|
data/lib/hashie/hash.rb
CHANGED
@@ -18,20 +18,21 @@ module Hashie
|
|
18
18
|
def to_hash(options = {})
|
19
19
|
out = {}
|
20
20
|
each_key do |k|
|
21
|
-
assignment_key =
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
assignment_key =
|
22
|
+
if options[:stringify_keys]
|
23
|
+
k.to_s
|
24
|
+
elsif options[:symbolize_keys] && k.respond_to?(:to_sym)
|
25
|
+
k.to_sym
|
26
|
+
else
|
27
|
+
k
|
28
|
+
end
|
28
29
|
if self[k].is_a?(Array)
|
29
30
|
out[assignment_key] ||= []
|
30
31
|
self[k].each do |array_object|
|
31
|
-
out[assignment_key] << (array_object
|
32
|
+
out[assignment_key] << maybe_convert_to_hash(array_object, options)
|
32
33
|
end
|
33
34
|
else
|
34
|
-
out[assignment_key] =
|
35
|
+
out[assignment_key] = maybe_convert_to_hash(self[k], options)
|
35
36
|
end
|
36
37
|
end
|
37
38
|
out
|
@@ -44,6 +45,12 @@ module Hashie
|
|
44
45
|
|
45
46
|
private
|
46
47
|
|
48
|
+
def maybe_convert_to_hash(object, options)
|
49
|
+
return object unless object.is_a?(Hash) || object.respond_to?(:to_hash)
|
50
|
+
|
51
|
+
flexibly_convert_to_hash(object, options)
|
52
|
+
end
|
53
|
+
|
47
54
|
def flexibly_convert_to_hash(object, options = {})
|
48
55
|
if object.method(:to_hash).arity.zero?
|
49
56
|
object.to_hash
|