hashie 5.2.0 → 6.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 +19 -0
- data/CONTRIBUTING.md +2 -0
- data/README.md +60 -10
- data/Rakefile +15 -0
- data/UPGRADING.md +100 -6
- data/lib/hashie/clash.rb +3 -2
- data/lib/hashie/dash.rb +25 -25
- data/lib/hashie/extensions/block_access.rb +5 -5
- data/lib/hashie/extensions/dash/coercion.rb +4 -4
- data/lib/hashie/extensions/dash/indifferent_access.rb +5 -5
- data/lib/hashie/extensions/dash/lazy.rb +10 -10
- data/lib/hashie/extensions/dash/predefined_values.rb +12 -16
- data/lib/hashie/extensions/dash/property_translation.rb +22 -14
- data/lib/hashie/extensions/deep_find.rb +4 -4
- data/lib/hashie/extensions/deep_grep.rb +15 -15
- data/lib/hashie/extensions/deep_locate.rb +3 -3
- data/lib/hashie/extensions/deep_merge.rb +16 -14
- data/lib/hashie/extensions/deep_merge_initializer.rb +3 -3
- data/lib/hashie/extensions/indifferent_access.rb +6 -6
- data/lib/hashie/extensions/mash/define_accessors.rb +3 -1
- data/lib/hashie/extensions/mash/keep_original_keys.rb +2 -2
- data/lib/hashie/extensions/mash/permissive_respond_to.rb +1 -1
- data/lib/hashie/extensions/mash/required_keys.rb +2 -2
- data/lib/hashie/extensions/mash/strict_key_access.rb +2 -2
- data/lib/hashie/extensions/method_access.rb +15 -15
- data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +1 -1
- data/lib/hashie/extensions/parsers/yaml_parser.rb +2 -2
- data/lib/hashie/extensions/persistable.rb +4 -4
- data/lib/hashie/extensions/ruby_version.rb +2 -2
- data/lib/hashie/extensions/stringify_keys.rb +4 -3
- data/lib/hashie/extensions/symbolize_keys.rb +4 -3
- data/lib/hashie/hash.rb +5 -5
- data/lib/hashie/mash.rb +20 -16
- data/lib/hashie/rash.rb +2 -2
- data/lib/hashie/utils.rb +3 -2
- data/lib/hashie/version.rb +1 -1
- metadata +3 -3
|
@@ -10,7 +10,7 @@ module Hashie
|
|
|
10
10
|
# include Hashie::Extensions::Dash::Coercion
|
|
11
11
|
# property :count, coerce: Integer
|
|
12
12
|
# end
|
|
13
|
-
# klass.new(count: '3')
|
|
13
|
+
# klass.new(count: '3')[:count] # => 3
|
|
14
14
|
module Coercion
|
|
15
15
|
# Extends a Dash with the ability to define coercion for properties.
|
|
16
16
|
#
|
|
@@ -19,7 +19,7 @@ module Hashie
|
|
|
19
19
|
# include Hashie::Extensions::Dash::Coercion
|
|
20
20
|
# property :count, coerce: Integer
|
|
21
21
|
# end
|
|
22
|
-
# klass.new(count: '3')
|
|
22
|
+
# klass.new(count: '3')[:count] # => 3
|
|
23
23
|
def self.included(base)
|
|
24
24
|
base.send :include, Hashie::Extensions::Coercion
|
|
25
25
|
base.extend ClassMethods
|
|
@@ -32,7 +32,7 @@ module Hashie
|
|
|
32
32
|
# include Hashie::Extensions::Dash::Coercion
|
|
33
33
|
# property :count, coerce: Integer
|
|
34
34
|
# end
|
|
35
|
-
# klass.new(count: '3')
|
|
35
|
+
# klass.new(count: '3')[:count] # => 3
|
|
36
36
|
module ClassMethods
|
|
37
37
|
# Defines a property on the Dash. Options are the standard
|
|
38
38
|
# `Hashie::Dash#property` options plus:
|
|
@@ -44,7 +44,7 @@ module Hashie
|
|
|
44
44
|
# include Hashie::Extensions::Dash::Coercion
|
|
45
45
|
# property :count, coerce: Integer
|
|
46
46
|
# end
|
|
47
|
-
# klass.new(count: '3')
|
|
47
|
+
# klass.new(count: '3')[:count] # => 3
|
|
48
48
|
def property(property_name, options = {})
|
|
49
49
|
super
|
|
50
50
|
coerce_key property_name, options[:coerce] if options[:coerce]
|
|
@@ -29,16 +29,16 @@ module Hashie
|
|
|
29
29
|
# klass.property?('name') # => true
|
|
30
30
|
# klass.singleton_class.included_modules.include?(Hashie::Extensions::Dash::IndifferentAccess::ClassMethods) # => true
|
|
31
31
|
def self.maybe_extend(base)
|
|
32
|
-
return unless
|
|
32
|
+
return unless _requires_class_methods?(base)
|
|
33
33
|
|
|
34
34
|
base.extend(ClassMethods)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
def self.
|
|
37
|
+
def self._requires_class_methods?(klass)
|
|
38
38
|
klass <= Hashie::Dash &&
|
|
39
39
|
!klass.singleton_class.included_modules.include?(ClassMethods)
|
|
40
40
|
end
|
|
41
|
-
private_class_method :
|
|
41
|
+
private_class_method :_requires_class_methods?
|
|
42
42
|
|
|
43
43
|
# @example Include defaults under string keys in the returned hash
|
|
44
44
|
# klass = Class.new(Hashie::Dash) do
|
|
@@ -82,7 +82,7 @@ module Hashie
|
|
|
82
82
|
# klass.property?('name') # => true
|
|
83
83
|
# klass.property?(:missing) # => false
|
|
84
84
|
def property?(name)
|
|
85
|
-
targets = if
|
|
85
|
+
targets = if _translation_for?(name)
|
|
86
86
|
Array(translations.find { |key, _| key.to_s == name.to_s }.last)
|
|
87
87
|
else
|
|
88
88
|
[name]
|
|
@@ -132,7 +132,7 @@ module Hashie
|
|
|
132
132
|
|
|
133
133
|
private
|
|
134
134
|
|
|
135
|
-
def
|
|
135
|
+
def _translation_for?(name)
|
|
136
136
|
included_modules.include?(Hashie::Extensions::Dash::PropertyTranslation) &&
|
|
137
137
|
translation_exists?(name)
|
|
138
138
|
end
|
|
@@ -43,11 +43,11 @@ module Hashie
|
|
|
43
43
|
def [](property, &block)
|
|
44
44
|
return super unless @lazy_loader
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
canonical_property =
|
|
48
|
-
|
|
46
|
+
_assert_property_exists!(property)
|
|
47
|
+
canonical_property = _lazy_property(property)
|
|
48
|
+
_load_property(canonical_property) unless key?(property)
|
|
49
49
|
value = super
|
|
50
|
-
|
|
50
|
+
_assert_property_required!(canonical_property, value)
|
|
51
51
|
value
|
|
52
52
|
end
|
|
53
53
|
|
|
@@ -111,7 +111,7 @@ module Hashie
|
|
|
111
111
|
@lazy_attributes = attributes || {}
|
|
112
112
|
end
|
|
113
113
|
|
|
114
|
-
def
|
|
114
|
+
def _assert_required_attributes_set!
|
|
115
115
|
super unless @lazy_loader
|
|
116
116
|
end
|
|
117
117
|
|
|
@@ -120,13 +120,13 @@ module Hashie
|
|
|
120
120
|
@lazy_loading = []
|
|
121
121
|
end
|
|
122
122
|
|
|
123
|
-
def
|
|
123
|
+
def _lazy_property(property)
|
|
124
124
|
return property if self.class.properties.include?(property)
|
|
125
125
|
|
|
126
126
|
self.class.properties.find { |key| key.to_s == property.to_s } || property
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
def
|
|
129
|
+
def _lazy_attribute_key(property)
|
|
130
130
|
return property if @lazy_attributes.key?(property)
|
|
131
131
|
return unless respond_to?(:convert_key)
|
|
132
132
|
|
|
@@ -134,7 +134,7 @@ module Hashie
|
|
|
134
134
|
converted if @lazy_attributes.key?(converted)
|
|
135
135
|
end
|
|
136
136
|
|
|
137
|
-
def
|
|
137
|
+
def _load_property(property)
|
|
138
138
|
raise ArgumentError, "circular lazy loading for property `#{property}`" if @lazy_loading.include?(property)
|
|
139
139
|
|
|
140
140
|
@lazy_loading << property
|
|
@@ -144,12 +144,12 @@ module Hashie
|
|
|
144
144
|
else
|
|
145
145
|
property
|
|
146
146
|
end
|
|
147
|
-
attribute =
|
|
147
|
+
attribute = _lazy_attribute_key(property)
|
|
148
148
|
if attribute
|
|
149
149
|
source = property
|
|
150
150
|
value = @lazy_attributes[attribute]
|
|
151
151
|
else
|
|
152
|
-
attribute =
|
|
152
|
+
attribute = _lazy_attribute_key(source)
|
|
153
153
|
value = attribute ? @lazy_attributes[attribute] : @lazy_loader.call(source)
|
|
154
154
|
end
|
|
155
155
|
if value.nil?
|
|
@@ -72,23 +72,23 @@ module Hashie
|
|
|
72
72
|
|
|
73
73
|
return unless (predefined_values = options[:values])
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
_assert_predefined_values!(predefined_values)
|
|
76
|
+
_set_predefined_values(property_name, predefined_values)
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
private
|
|
80
80
|
|
|
81
|
-
def
|
|
82
|
-
return if
|
|
81
|
+
def _assert_predefined_values!(predefined_values)
|
|
82
|
+
return if _supported_type?(predefined_values)
|
|
83
83
|
|
|
84
84
|
raise ArgumentError, %(`values` accepts an `Array` or a `Range`)
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
-
def
|
|
87
|
+
def _supported_type?(predefined_values)
|
|
88
88
|
[::Array, ::Range].any? { |klass| predefined_values.is_a?(klass) }
|
|
89
89
|
end
|
|
90
90
|
|
|
91
|
-
def
|
|
91
|
+
def _set_predefined_values(property_name, predefined_values)
|
|
92
92
|
@values_for_properties[property_name] = predefined_values
|
|
93
93
|
end
|
|
94
94
|
end
|
|
@@ -112,21 +112,21 @@ module Hashie
|
|
|
112
112
|
def initialize(*)
|
|
113
113
|
super
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
_assert_property_values!
|
|
116
116
|
end
|
|
117
117
|
|
|
118
118
|
private
|
|
119
119
|
|
|
120
|
-
def
|
|
120
|
+
def _assert_property_values!
|
|
121
121
|
self.class.values_for_properties.each_key do |property|
|
|
122
|
-
value =
|
|
122
|
+
value = self[property]
|
|
123
123
|
|
|
124
|
-
allowed_values = values_for_properties
|
|
125
|
-
|
|
124
|
+
allowed_values = self.class.values_for_properties[property]
|
|
125
|
+
_fail_property_value_error!(property, value, allowed_values) if value && !allowed_values.include?(value)
|
|
126
126
|
end
|
|
127
127
|
end
|
|
128
128
|
|
|
129
|
-
def
|
|
129
|
+
def _fail_property_value_error!(property, value, allowed_values)
|
|
130
130
|
expected_values = if allowed_values.is_a?(::Range)
|
|
131
131
|
"a value in `#{allowed_values}`"
|
|
132
132
|
else
|
|
@@ -137,10 +137,6 @@ module Hashie
|
|
|
137
137
|
"value `#{value.inspect}` is not allowed for `#{property}`; " \
|
|
138
138
|
"expected #{expected_values}"
|
|
139
139
|
end
|
|
140
|
-
|
|
141
|
-
def values_for_properties(property)
|
|
142
|
-
self.class.values_for_properties[property]
|
|
143
|
-
end
|
|
144
140
|
end
|
|
145
141
|
end
|
|
146
142
|
end
|
|
@@ -127,10 +127,10 @@ module Hashie
|
|
|
127
127
|
transformer = options[:transform_with]
|
|
128
128
|
|
|
129
129
|
if from
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
elsif
|
|
130
|
+
_fail_self_transformation_error!(property_name) if property_name.to_s == from.to_s
|
|
131
|
+
_define_translation(from, property_name, converter || transformer)
|
|
132
|
+
_define_writer_for_source_property(from)
|
|
133
|
+
elsif _valid_transformer?(transformer)
|
|
134
134
|
transforms[property_name] = transformer
|
|
135
135
|
end
|
|
136
136
|
end
|
|
@@ -204,24 +204,25 @@ module Hashie
|
|
|
204
204
|
|
|
205
205
|
private
|
|
206
206
|
|
|
207
|
-
def
|
|
207
|
+
def _define_translation(from, property_name, translator)
|
|
208
208
|
translations_hash[from][property_name] = translator
|
|
209
209
|
end
|
|
210
210
|
|
|
211
|
-
def
|
|
211
|
+
def _define_writer_for_source_property(property)
|
|
212
|
+
setter = :"#{property}="
|
|
213
|
+
return if method_defined?(setter) || private_method_defined?(setter)
|
|
214
|
+
|
|
212
215
|
define_method "#{property}=" do |val|
|
|
213
|
-
|
|
214
|
-
self[name] = with.respond_to?(:call) ? with.call(val) : val
|
|
215
|
-
end
|
|
216
|
+
_write_translated_property(property, val)
|
|
216
217
|
end
|
|
217
218
|
end
|
|
218
219
|
|
|
219
|
-
def
|
|
220
|
+
def _fail_self_transformation_error!(property_name)
|
|
220
221
|
raise ArgumentError,
|
|
221
222
|
"property name `#{property_name}` and :from option must not be the same"
|
|
222
223
|
end
|
|
223
224
|
|
|
224
|
-
def
|
|
225
|
+
def _valid_transformer?(transformer)
|
|
225
226
|
transformer.respond_to? :call
|
|
226
227
|
end
|
|
227
228
|
end
|
|
@@ -249,7 +250,7 @@ module Hashie
|
|
|
249
250
|
# dash.name # => 'Ada'
|
|
250
251
|
def []=(property, value)
|
|
251
252
|
if self.class.translation_exists? property
|
|
252
|
-
|
|
253
|
+
_write_translated_property(property, value)
|
|
253
254
|
|
|
254
255
|
if self.class.transformation_exists? property
|
|
255
256
|
super(property, self.class.transformed_property(property, value))
|
|
@@ -298,13 +299,20 @@ module Hashie
|
|
|
298
299
|
# dash.property_exists?(:name) # => true
|
|
299
300
|
# expect { dash.property_exists?(:missing) }.to raise_error(NoMethodError)
|
|
300
301
|
def property_exists?(property)
|
|
301
|
-
|
|
302
|
+
_fail_no_property_error!(property) unless self.class.property?(property)
|
|
302
303
|
true
|
|
303
304
|
end
|
|
304
305
|
|
|
305
306
|
private
|
|
306
307
|
|
|
307
|
-
def
|
|
308
|
+
def _write_translated_property(property, value)
|
|
309
|
+
source = _translations.key?(property) ? property : _translations.keys.find { |key| key.to_s == property.to_s }
|
|
310
|
+
_translations[source].each do |name, with|
|
|
311
|
+
self[name] = with.respond_to?(:call) ? with.call(value) : value
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def _translations
|
|
308
316
|
self.class.translations_hash
|
|
309
317
|
end
|
|
310
318
|
end
|
|
@@ -57,18 +57,18 @@ module Hashie
|
|
|
57
57
|
# ]
|
|
58
58
|
# my_hash.deep_find_all(:address) # => ['123 Street', '234 Street']
|
|
59
59
|
#
|
|
60
|
-
# @example Collect all values, or
|
|
60
|
+
# @example Collect all values, or an empty array if absent
|
|
61
61
|
# hash = { users: [{ name: 'Ada' }, { name: 'Grace' }] }.extend(Hashie::Extensions::DeepFind)
|
|
62
62
|
# hash.deep_find_all(:name) # => ['Ada', 'Grace']
|
|
63
|
-
# hash.deep_find_all(:email) # =>
|
|
63
|
+
# hash.deep_find_all(:email) # => []
|
|
64
64
|
def deep_find_all(key)
|
|
65
|
-
|
|
66
|
-
matches.empty? ? nil : matches
|
|
65
|
+
_deep_find_all(key)
|
|
67
66
|
end
|
|
68
67
|
|
|
69
68
|
# @example Select every nested value
|
|
70
69
|
# hash = { users: [{ name: 'Ada' }, { name: 'Grace' }] }.extend(Hashie::Extensions::DeepFind)
|
|
71
70
|
# hash.deep_select(:name) # => ['Ada', 'Grace']
|
|
71
|
+
# hash.deep_select(:email) # => []
|
|
72
72
|
alias deep_select deep_find_all
|
|
73
73
|
|
|
74
74
|
private
|
|
@@ -23,47 +23,47 @@ module Hashie
|
|
|
23
23
|
def self.deep_grep(pattern, object)
|
|
24
24
|
raise ArgumentError, 'pattern must be a Regexp' unless pattern.is_a?(Regexp)
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
_search(pattern, object, [], {}.compare_by_identity)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def self.
|
|
29
|
+
def self._search(pattern, object, results, ancestors)
|
|
30
30
|
return results if ancestors.key?(object) ||
|
|
31
31
|
!(object.is_a?(::Hash) || object.is_a?(::Array))
|
|
32
32
|
|
|
33
33
|
ancestors[object] = true
|
|
34
34
|
if object.is_a?(::Hash)
|
|
35
|
-
|
|
35
|
+
_search_hash(pattern, object, results, ancestors)
|
|
36
36
|
else
|
|
37
|
-
|
|
37
|
+
_search_array(pattern, object, results, ancestors)
|
|
38
38
|
end
|
|
39
39
|
ancestors.delete(object)
|
|
40
40
|
results
|
|
41
41
|
end
|
|
42
|
-
private_class_method :
|
|
42
|
+
private_class_method :_search
|
|
43
43
|
|
|
44
|
-
def self.
|
|
45
|
-
results << object if object.any? { |key, value| !
|
|
44
|
+
def self._search_hash(pattern, object, results, ancestors)
|
|
45
|
+
results << object if object.any? { |key, value| !_matches?(pattern, key) && _matches?(pattern, value) }
|
|
46
46
|
object.each do |key, value|
|
|
47
|
-
if
|
|
47
|
+
if _matches?(pattern, key)
|
|
48
48
|
results << { key => value }
|
|
49
49
|
else
|
|
50
|
-
|
|
50
|
+
_search(pattern, value, results, ancestors)
|
|
51
51
|
end
|
|
52
52
|
end
|
|
53
53
|
end
|
|
54
|
-
private_class_method :
|
|
54
|
+
private_class_method :_search_hash
|
|
55
55
|
|
|
56
|
-
def self.
|
|
56
|
+
def self._search_array(pattern, object, results, ancestors)
|
|
57
57
|
object.each do |value|
|
|
58
|
-
|
|
58
|
+
_matches?(pattern, value) ? results << value : _search(pattern, value, results, ancestors)
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
|
-
private_class_method :
|
|
61
|
+
private_class_method :_search_array
|
|
62
62
|
|
|
63
|
-
def self.
|
|
63
|
+
def self._matches?(pattern, value)
|
|
64
64
|
(value.is_a?(String) || value.is_a?(Symbol)) && pattern.match?(value.to_s)
|
|
65
65
|
end
|
|
66
|
-
private_class_method :
|
|
66
|
+
private_class_method :_matches?
|
|
67
67
|
end
|
|
68
68
|
end
|
|
69
69
|
end
|
|
@@ -56,7 +56,7 @@ module Hashie
|
|
|
56
56
|
|
|
57
57
|
def self._construct_key_comparator(search_key, object)
|
|
58
58
|
if (object.respond_to?(:indifferent_access?) && object.indifferent_access?) ||
|
|
59
|
-
|
|
59
|
+
_activesupport_indifferent?(object)
|
|
60
60
|
search_key = search_key.to_s
|
|
61
61
|
end
|
|
62
62
|
|
|
@@ -90,11 +90,11 @@ module Hashie
|
|
|
90
90
|
end
|
|
91
91
|
private_class_method :_match_comparator?
|
|
92
92
|
|
|
93
|
-
def self.
|
|
93
|
+
def self._activesupport_indifferent?(object)
|
|
94
94
|
defined?(::ActiveSupport::HashWithIndifferentAccess) &&
|
|
95
95
|
object.is_a?(::ActiveSupport::HashWithIndifferentAccess)
|
|
96
96
|
end
|
|
97
|
-
private_class_method :
|
|
97
|
+
private_class_method :_activesupport_indifferent?
|
|
98
98
|
end
|
|
99
99
|
end
|
|
100
100
|
end
|
|
@@ -34,19 +34,21 @@ module Hashie
|
|
|
34
34
|
|
|
35
35
|
private
|
|
36
36
|
|
|
37
|
-
def _deep_dup(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
37
|
+
def _deep_dup(value, incoming: false)
|
|
38
|
+
case value
|
|
39
|
+
when ::Hash
|
|
40
|
+
copy = incoming ? value.dup.clear : value.dup
|
|
41
|
+
value.each do |key, child|
|
|
42
|
+
copy[key] = _deep_dup(child, incoming: incoming)
|
|
43
|
+
end
|
|
44
|
+
copy
|
|
45
|
+
when ::Array
|
|
46
|
+
value.dup.map! { |child| _deep_dup(child, incoming: incoming) }
|
|
47
|
+
when ::String
|
|
48
|
+
value.dup
|
|
49
|
+
else
|
|
50
|
+
value
|
|
47
51
|
end
|
|
48
|
-
|
|
49
|
-
copy
|
|
50
52
|
end
|
|
51
53
|
|
|
52
54
|
def _recursive_merge(hash, other_hash, &block)
|
|
@@ -55,11 +57,11 @@ module Hashie
|
|
|
55
57
|
if hash.key?(k) && hash[k].is_a?(::Hash) && v.is_a?(::Hash)
|
|
56
58
|
_recursive_merge(hash[k], v, &block)
|
|
57
59
|
elsif v.is_a?(::Hash)
|
|
58
|
-
_recursive_merge(
|
|
60
|
+
_recursive_merge(v.dup.clear, v, &block)
|
|
59
61
|
elsif hash.key?(k) && block_given?
|
|
60
62
|
yield(k, hash[k], v)
|
|
61
63
|
else
|
|
62
|
-
|
|
64
|
+
_deep_dup(v, incoming: true)
|
|
63
65
|
end
|
|
64
66
|
end
|
|
65
67
|
hash
|
|
@@ -21,18 +21,18 @@ module Hashie
|
|
|
21
21
|
def initialize(hash = {}, default = nil, &block)
|
|
22
22
|
default.nil? ? super(&block) : super(default)
|
|
23
23
|
hash.each_pair do |key, value|
|
|
24
|
-
self[key] =
|
|
24
|
+
self[key] = _deep_merge_initializer_value(value, default, &block)
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
private
|
|
29
29
|
|
|
30
|
-
def
|
|
30
|
+
def _deep_merge_initializer_value(value, default, &block)
|
|
31
31
|
case value
|
|
32
32
|
when ::Hash
|
|
33
33
|
self.class.new(value, default, &block)
|
|
34
34
|
when ::Array
|
|
35
|
-
value.map { |item|
|
|
35
|
+
value.map { |item| _deep_merge_initializer_value(item, default, &block) }
|
|
36
36
|
else
|
|
37
37
|
value
|
|
38
38
|
end
|
|
@@ -115,7 +115,7 @@ module Hashie
|
|
|
115
115
|
# value = hash.indifferent_value([{ name: 'Ada' }])
|
|
116
116
|
# value.first['name'] # => 'Ada'
|
|
117
117
|
def indifferent_value(value)
|
|
118
|
-
if
|
|
118
|
+
if _hash_lacking_indifference?(value)
|
|
119
119
|
IndifferentAccess.inject!(value)
|
|
120
120
|
elsif value.is_a?(::Array)
|
|
121
121
|
value.replace(value.map { |e| indifferent_value(e) })
|
|
@@ -140,7 +140,7 @@ module Hashie
|
|
|
140
140
|
# hash.indifferent_update(user: { name: 'Ada' })
|
|
141
141
|
# hash['user']['name'] # => 'Ada'
|
|
142
142
|
def indifferent_update(other_hash)
|
|
143
|
-
return regular_update(other_hash) if
|
|
143
|
+
return regular_update(other_hash) if _hash_with_indifference?(other_hash)
|
|
144
144
|
|
|
145
145
|
other_hash.each_pair do |k, v|
|
|
146
146
|
self[k] = v
|
|
@@ -211,7 +211,7 @@ module Hashie
|
|
|
211
211
|
# hash.key?(:age) # => false
|
|
212
212
|
def merge(*args)
|
|
213
213
|
result = super
|
|
214
|
-
return IndifferentAccess.inject!(result) if
|
|
214
|
+
return IndifferentAccess.inject!(result) if _hash_lacking_indifference?(result)
|
|
215
215
|
|
|
216
216
|
result.convert!
|
|
217
217
|
end
|
|
@@ -260,15 +260,15 @@ module Hashie
|
|
|
260
260
|
super(*string_keys)
|
|
261
261
|
end
|
|
262
262
|
|
|
263
|
-
|
|
263
|
+
private
|
|
264
264
|
|
|
265
|
-
def
|
|
265
|
+
def _hash_lacking_indifference?(other)
|
|
266
266
|
other.is_a?(::Hash) &&
|
|
267
267
|
!(other.respond_to?(:indifferent_access?) &&
|
|
268
268
|
other.indifferent_access?)
|
|
269
269
|
end
|
|
270
270
|
|
|
271
|
-
def
|
|
271
|
+
def _hash_with_indifference?(other)
|
|
272
272
|
other.is_a?(::Hash) &&
|
|
273
273
|
other.respond_to?(:indifferent_access?) &&
|
|
274
274
|
other.indifferent_access?
|
|
@@ -47,7 +47,9 @@ module Hashie
|
|
|
47
47
|
def initialize
|
|
48
48
|
mod = self
|
|
49
49
|
define_method(:method_missing) do |method_name, *args, &block|
|
|
50
|
-
|
|
50
|
+
return super(method_name, *args, &block) if singleton_class.private_method_defined?(method_name) || singleton_class.protected_method_defined?(method_name)
|
|
51
|
+
|
|
52
|
+
key, suffix = _method_name_and_suffix(method_name)
|
|
51
53
|
case suffix
|
|
52
54
|
when '='
|
|
53
55
|
mod.define_writer(key, method_name)
|
|
@@ -35,7 +35,7 @@ module Hashie
|
|
|
35
35
|
def convert_key(key)
|
|
36
36
|
return key if regular_key?(key)
|
|
37
37
|
|
|
38
|
-
converted_key =
|
|
38
|
+
converted_key = _convert(key)
|
|
39
39
|
converted_key && regular_key?(converted_key) ? converted_key : key
|
|
40
40
|
end
|
|
41
41
|
|
|
@@ -44,7 +44,7 @@ module Hashie
|
|
|
44
44
|
#
|
|
45
45
|
# @param [Object, String, Symbol] key the key to convert.
|
|
46
46
|
# @return [Object, String, Symbol] the converted key.
|
|
47
|
-
def
|
|
47
|
+
def _convert(key)
|
|
48
48
|
case key
|
|
49
49
|
when Symbol then key.name
|
|
50
50
|
when String then key.to_sym
|
|
@@ -52,7 +52,7 @@ module Hashie
|
|
|
52
52
|
#
|
|
53
53
|
# @api private
|
|
54
54
|
# @private
|
|
55
|
-
def
|
|
55
|
+
def _log_collision?(method_key)
|
|
56
56
|
self.class.method_cache.include?(method_key) &&
|
|
57
57
|
!self.class.disable_warnings?(method_key) &&
|
|
58
58
|
!(regular_key?(method_key) || regular_key?(method_key.to_s))
|
|
@@ -93,12 +93,12 @@ module Hashie
|
|
|
93
93
|
# klass.new(name: 'Ada', age: 37).age # => 37
|
|
94
94
|
def initialize(*args, &block)
|
|
95
95
|
super
|
|
96
|
-
|
|
96
|
+
_assert_required_keys_set!
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
private
|
|
100
100
|
|
|
101
|
-
def
|
|
101
|
+
def _assert_required_keys_set!
|
|
102
102
|
missing_keys = self.class.required_keys.select { |key| self[key].nil? }
|
|
103
103
|
return if missing_keys.empty?
|
|
104
104
|
|
|
@@ -44,7 +44,7 @@ module Hashie
|
|
|
44
44
|
def method_missing(method_name, *args, &blk)
|
|
45
45
|
return super if key?(method_name)
|
|
46
46
|
|
|
47
|
-
name, suffix =
|
|
47
|
+
name, suffix = _method_name_and_suffix(method_name)
|
|
48
48
|
raise KeyError, "key not found: `#{name}`" if !key?(name) && !suffix
|
|
49
49
|
|
|
50
50
|
super
|
|
@@ -54,7 +54,7 @@ module Hashie
|
|
|
54
54
|
def respond_to_missing?(method_name, *args)
|
|
55
55
|
return true if key?(method_name)
|
|
56
56
|
|
|
57
|
-
_, suffix =
|
|
57
|
+
_, suffix = _method_name_and_suffix(method_name)
|
|
58
58
|
return false unless suffix
|
|
59
59
|
|
|
60
60
|
super
|