hashie 2.1.2 → 3.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 +7 -0
- data/.travis.yml +3 -2
- data/CHANGELOG.md +11 -3
- data/Gemfile +1 -1
- data/README.md +72 -79
- data/UPGRADING.md +93 -0
- data/hashie.gemspec +8 -8
- data/lib/hashie.rb +18 -11
- data/lib/hashie/dash.rb +8 -9
- data/lib/hashie/extensions/coercion.rb +1 -1
- data/lib/hashie/extensions/dash/indifferent_access.rb +21 -0
- data/lib/hashie/extensions/deep_fetch.rb +1 -1
- data/lib/hashie/extensions/ignore_undeclared.rb +5 -1
- data/lib/hashie/extensions/key_conversion.rb +0 -82
- data/lib/hashie/extensions/pretty_inspect.rb +19 -0
- data/lib/hashie/extensions/stringify_keys.rb +44 -0
- data/lib/hashie/extensions/symbolize_keys.rb +44 -0
- data/lib/hashie/hash.rb +17 -5
- data/lib/hashie/mash.rb +24 -13
- data/lib/hashie/rash.rb +1 -1
- data/lib/hashie/trash.rb +9 -10
- data/lib/hashie/version.rb +1 -1
- data/spec/hashie/dash_spec.rb +69 -24
- data/spec/hashie/extensions/dash/indifferent_access_spec.rb +58 -0
- data/spec/hashie/extensions/deep_fetch_spec.rb +27 -0
- data/spec/hashie/extensions/ignore_undeclared_spec.rb +36 -13
- data/spec/hashie/extensions/indifferent_access_spec.rb +2 -2
- data/spec/hashie/hash_spec.rb +15 -23
- data/spec/hashie/mash_spec.rb +41 -29
- data/spec/hashie/trash_spec.rb +5 -2
- data/spec/spec_helper.rb +0 -1
- metadata +20 -28
- data/lib/hashie/hash_extensions.rb +0 -47
- data/spec/spec.opts +0 -3
data/lib/hashie.rb
CHANGED
@@ -1,17 +1,14 @@
|
|
1
1
|
module Hashie
|
2
|
-
autoload :Clash,
|
3
|
-
autoload :Dash,
|
4
|
-
autoload :Hash,
|
5
|
-
autoload :
|
6
|
-
autoload :
|
7
|
-
autoload :
|
8
|
-
autoload :Trash, 'hashie/trash'
|
9
|
-
autoload :Rash, 'hashie/rash'
|
2
|
+
autoload :Clash, 'hashie/clash'
|
3
|
+
autoload :Dash, 'hashie/dash'
|
4
|
+
autoload :Hash, 'hashie/hash'
|
5
|
+
autoload :Mash, 'hashie/mash'
|
6
|
+
autoload :Trash, 'hashie/trash'
|
7
|
+
autoload :Rash, 'hashie/rash'
|
10
8
|
|
11
9
|
module Extensions
|
12
10
|
autoload :Coercion, 'hashie/extensions/coercion'
|
13
11
|
autoload :DeepMerge, 'hashie/extensions/deep_merge'
|
14
|
-
autoload :KeyConversion, 'hashie/extensions/key_conversion'
|
15
12
|
autoload :IgnoreUndeclared, 'hashie/extensions/ignore_undeclared'
|
16
13
|
autoload :IndifferentAccess, 'hashie/extensions/indifferent_access'
|
17
14
|
autoload :MergeInitializer, 'hashie/extensions/merge_initializer'
|
@@ -19,8 +16,18 @@ module Hashie
|
|
19
16
|
autoload :MethodQuery, 'hashie/extensions/method_access'
|
20
17
|
autoload :MethodReader, 'hashie/extensions/method_access'
|
21
18
|
autoload :MethodWriter, 'hashie/extensions/method_access'
|
22
|
-
autoload :StringifyKeys, 'hashie/extensions/
|
23
|
-
autoload :SymbolizeKeys, 'hashie/extensions/
|
19
|
+
autoload :StringifyKeys, 'hashie/extensions/stringify_keys'
|
20
|
+
autoload :SymbolizeKeys, 'hashie/extensions/symbolize_keys'
|
24
21
|
autoload :DeepFetch, 'hashie/extensions/deep_fetch'
|
22
|
+
autoload :PrettyInspect, 'hashie/extensions/pretty_inspect'
|
23
|
+
autoload :KeyConversion, 'hashie/extensions/key_conversion'
|
24
|
+
|
25
|
+
module Mash
|
26
|
+
autoload :ActiveModel, 'hashie/extensions/mash/active_model'
|
27
|
+
end
|
28
|
+
|
29
|
+
module Dash
|
30
|
+
autoload :IndifferentAccess, 'hashie/extensions/dash/indifferent_access'
|
31
|
+
end
|
25
32
|
end
|
26
33
|
end
|
data/lib/hashie/dash.rb
CHANGED
@@ -13,7 +13,8 @@ module Hashie
|
|
13
13
|
# It is preferrable to a Struct because of the in-class
|
14
14
|
# API for defining properties as well as per-property defaults.
|
15
15
|
class Dash < Hash
|
16
|
-
include PrettyInspect
|
16
|
+
include Hashie::Extensions::PrettyInspect
|
17
|
+
|
17
18
|
alias_method :to_s, :inspect
|
18
19
|
|
19
20
|
# Defines a property on the Dash. Options are
|
@@ -28,8 +29,6 @@ module Hashie
|
|
28
29
|
# existing Dash.
|
29
30
|
#
|
30
31
|
def self.property(property_name, options = {})
|
31
|
-
property_name = property_name.to_sym
|
32
|
-
|
33
32
|
properties << property_name
|
34
33
|
|
35
34
|
if options.key?(:default)
|
@@ -39,9 +38,9 @@ module Hashie
|
|
39
38
|
end
|
40
39
|
|
41
40
|
unless instance_methods.map { |m| m.to_s }.include?("#{property_name}=")
|
42
|
-
define_method(property_name) { |&block| self.[](property_name
|
41
|
+
define_method(property_name) { |&block| self.[](property_name, &block) }
|
43
42
|
property_assignment = property_name.to_s.concat('=').to_sym
|
44
|
-
define_method(property_assignment) { |value| self.[]=(property_name
|
43
|
+
define_method(property_assignment) { |value| self.[]=(property_name, value) }
|
45
44
|
end
|
46
45
|
|
47
46
|
if defined? @subclasses
|
@@ -69,13 +68,13 @@ module Hashie
|
|
69
68
|
# Check to see if the specified property has already been
|
70
69
|
# defined.
|
71
70
|
def self.property?(name)
|
72
|
-
properties.include? name
|
71
|
+
properties.include? name
|
73
72
|
end
|
74
73
|
|
75
74
|
# Check to see if the specified property is
|
76
75
|
# required.
|
77
76
|
def self.required?(name)
|
78
|
-
required_properties.include? name
|
77
|
+
required_properties.include? name
|
79
78
|
end
|
80
79
|
|
81
80
|
# You may initialize a Dash with an attributes hash
|
@@ -103,7 +102,7 @@ module Hashie
|
|
103
102
|
# property's default value if it hasn't been set).
|
104
103
|
def [](property)
|
105
104
|
assert_property_exists! property
|
106
|
-
value = super(property
|
105
|
+
value = super(property)
|
107
106
|
# If the value is a lambda, proc, or whatever answers to call, eval the thing!
|
108
107
|
if value.is_a? Proc
|
109
108
|
self[property] = value.call # Set the result of the call as a value
|
@@ -118,7 +117,7 @@ module Hashie
|
|
118
117
|
def []=(property, value)
|
119
118
|
assert_property_required! property, value
|
120
119
|
assert_property_exists! property
|
121
|
-
super(property
|
120
|
+
super(property, value)
|
122
121
|
end
|
123
122
|
|
124
123
|
def merge(other_hash)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Hashie
|
2
|
+
module Extensions
|
3
|
+
module Dash
|
4
|
+
module IndifferentAccess
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
base.send :include, Hashie::Extensions::IndifferentAccess
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
# Check to see if the specified property has already been
|
12
|
+
# defined.
|
13
|
+
def property?(name)
|
14
|
+
name = name.to_s
|
15
|
+
!!properties.find { |property| property.to_s == name }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -18,7 +18,7 @@ module Hashie
|
|
18
18
|
begin
|
19
19
|
arg = Integer(arg) if obj.kind_of? Array
|
20
20
|
obj.fetch(arg)
|
21
|
-
rescue ArgumentError, IndexError => e
|
21
|
+
rescue ArgumentError, IndexError, NoMethodError => e
|
22
22
|
break block.call(arg) if block
|
23
23
|
raise UndefinedPathError, "Could not fetch path (#{args.join(' > ')}) at #{arg}", e.backtrace
|
24
24
|
end
|
@@ -5,7 +5,7 @@ module Hashie
|
|
5
5
|
# raising an error. This is useful when using a Trash to
|
6
6
|
# capture a subset of a larger hash.
|
7
7
|
#
|
8
|
-
# Note that attempting to retrieve an undeclared property
|
8
|
+
# Note that attempting to retrieve or set an undeclared property
|
9
9
|
# will still raise a NoMethodError, even if a value for
|
10
10
|
# that property was provided at initialization.
|
11
11
|
#
|
@@ -36,6 +36,10 @@ module Hashie
|
|
36
36
|
end
|
37
37
|
end if attributes
|
38
38
|
end
|
39
|
+
|
40
|
+
def property_exists?(property)
|
41
|
+
self.class.property?(property)
|
42
|
+
end
|
39
43
|
end
|
40
44
|
end
|
41
45
|
end
|
@@ -1,87 +1,5 @@
|
|
1
1
|
module Hashie
|
2
2
|
module Extensions
|
3
|
-
module StringifyKeys
|
4
|
-
# Convert all keys in the hash to strings.
|
5
|
-
#
|
6
|
-
# @example
|
7
|
-
# test = {:abc => 'def'}
|
8
|
-
# test.stringify_keys!
|
9
|
-
# test # => {'abc' => 'def'}
|
10
|
-
def stringify_keys!
|
11
|
-
keys.each do |k|
|
12
|
-
stringify_keys_recursively!(self[k])
|
13
|
-
self[k.to_s] = delete(k)
|
14
|
-
end
|
15
|
-
self
|
16
|
-
end
|
17
|
-
|
18
|
-
# Return a new hash with all keys converted
|
19
|
-
# to strings.
|
20
|
-
def stringify_keys
|
21
|
-
dup.stringify_keys!
|
22
|
-
end
|
23
|
-
|
24
|
-
protected
|
25
|
-
|
26
|
-
# Stringify all keys recursively within nested
|
27
|
-
# hashes and arrays.
|
28
|
-
def stringify_keys_recursively!(object)
|
29
|
-
if self.class === object
|
30
|
-
object.stringify_keys!
|
31
|
-
elsif ::Array === object
|
32
|
-
object.each do |i|
|
33
|
-
stringify_keys_recursively!(i)
|
34
|
-
end
|
35
|
-
object
|
36
|
-
elsif object.respond_to?(:stringify_keys!)
|
37
|
-
object.stringify_keys!
|
38
|
-
else
|
39
|
-
object
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
module SymbolizeKeys
|
45
|
-
# Convert all keys in the hash to symbols.
|
46
|
-
#
|
47
|
-
# @example
|
48
|
-
# test = {'abc' => 'def'}
|
49
|
-
# test.symbolize_keys!
|
50
|
-
# test # => {:abc => 'def'}
|
51
|
-
def symbolize_keys!
|
52
|
-
keys.each do |k|
|
53
|
-
symbolize_keys_recursively!(self[k])
|
54
|
-
self[k.to_sym] = delete(k)
|
55
|
-
end
|
56
|
-
self
|
57
|
-
end
|
58
|
-
|
59
|
-
# Return a new hash with all keys converted
|
60
|
-
# to symbols.
|
61
|
-
def symbolize_keys
|
62
|
-
dup.symbolize_keys!
|
63
|
-
end
|
64
|
-
|
65
|
-
protected
|
66
|
-
|
67
|
-
# Symbolize all keys recursively within nested
|
68
|
-
# hashes and arrays.
|
69
|
-
def symbolize_keys_recursively!(object)
|
70
|
-
if self.class === object
|
71
|
-
object.symbolize_keys!
|
72
|
-
elsif ::Array === object
|
73
|
-
object.each do |i|
|
74
|
-
symbolize_keys_recursively!(i)
|
75
|
-
end
|
76
|
-
object
|
77
|
-
elsif object.respond_to?(:symbolize_keys!)
|
78
|
-
object.symbolize_keys!
|
79
|
-
else
|
80
|
-
object
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
3
|
module KeyConversion
|
86
4
|
def self.included(base)
|
87
5
|
base.send :include, SymbolizeKeys
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Hashie
|
2
|
+
module Extensions
|
3
|
+
module PrettyInspect
|
4
|
+
def self.included(base)
|
5
|
+
base.send :alias_method, :hash_inspect, :inspect
|
6
|
+
base.send :alias_method, :inspect, :hashie_inspect
|
7
|
+
end
|
8
|
+
|
9
|
+
def hashie_inspect
|
10
|
+
ret = "#<#{self.class}"
|
11
|
+
keys.sort_by { |key| key.to_s }.each do |key|
|
12
|
+
ret << " #{key}=#{self[key].inspect}"
|
13
|
+
end
|
14
|
+
ret << '>'
|
15
|
+
ret
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Hashie
|
2
|
+
module Extensions
|
3
|
+
module StringifyKeys
|
4
|
+
# Convert all keys in the hash to strings.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# test = {:abc => 'def'}
|
8
|
+
# test.stringify_keys!
|
9
|
+
# test # => {'abc' => 'def'}
|
10
|
+
def stringify_keys!
|
11
|
+
keys.each do |k|
|
12
|
+
stringify_keys_recursively!(self[k])
|
13
|
+
self[k.to_s] = delete(k)
|
14
|
+
end
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
# Return a new hash with all keys converted
|
19
|
+
# to strings.
|
20
|
+
def stringify_keys
|
21
|
+
dup.stringify_keys!
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
# Stringify all keys recursively within nested
|
27
|
+
# hashes and arrays.
|
28
|
+
def stringify_keys_recursively!(object)
|
29
|
+
if self.class === object
|
30
|
+
object.stringify_keys!
|
31
|
+
elsif ::Array === object
|
32
|
+
object.each do |i|
|
33
|
+
stringify_keys_recursively!(i)
|
34
|
+
end
|
35
|
+
object
|
36
|
+
elsif object.respond_to?(:stringify_keys!)
|
37
|
+
object.stringify_keys!
|
38
|
+
else
|
39
|
+
object
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Hashie
|
2
|
+
module Extensions
|
3
|
+
module SymbolizeKeys
|
4
|
+
# Convert all keys in the hash to symbols.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# test = {'abc' => 'def'}
|
8
|
+
# test.symbolize_keys!
|
9
|
+
# test # => {:abc => 'def'}
|
10
|
+
def symbolize_keys!
|
11
|
+
keys.each do |k|
|
12
|
+
symbolize_keys_recursively!(self[k])
|
13
|
+
self[k.to_sym] = delete(k)
|
14
|
+
end
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
# Return a new hash with all keys converted
|
19
|
+
# to symbols.
|
20
|
+
def symbolize_keys
|
21
|
+
dup.symbolize_keys!
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
# Symbolize all keys recursively within nested
|
27
|
+
# hashes and arrays.
|
28
|
+
def symbolize_keys_recursively!(object)
|
29
|
+
if self.class === object
|
30
|
+
object.symbolize_keys!
|
31
|
+
elsif ::Array === object
|
32
|
+
object.each do |i|
|
33
|
+
symbolize_keys_recursively!(i)
|
34
|
+
end
|
35
|
+
object
|
36
|
+
elsif object.respond_to?(:symbolize_keys!)
|
37
|
+
object.symbolize_keys!
|
38
|
+
else
|
39
|
+
object
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/hashie/hash.rb
CHANGED
@@ -1,25 +1,37 @@
|
|
1
|
-
require 'hashie/
|
1
|
+
require 'hashie/extensions/stringify_keys'
|
2
|
+
require 'hashie/extensions/pretty_inspect'
|
2
3
|
|
3
4
|
module Hashie
|
4
5
|
# A Hashie Hash is simply a Hash that has convenience
|
5
6
|
# functions baked in such as stringify_keys that may
|
6
7
|
# not be available in all libraries.
|
7
8
|
class Hash < ::Hash
|
8
|
-
include
|
9
|
+
include Hashie::Extensions::PrettyInspect
|
10
|
+
include Hashie::Extensions::StringifyKeys
|
11
|
+
|
12
|
+
# Convert this hash into a Mash
|
13
|
+
def to_mash
|
14
|
+
::Hashie::Mash.new(self)
|
15
|
+
end
|
9
16
|
|
10
17
|
# Converts a mash back to a hash (with stringified or symbolized keys)
|
11
18
|
def to_hash(options = {})
|
12
19
|
out = {}
|
13
20
|
keys.each do |k|
|
14
|
-
assignment_key =
|
15
|
-
|
21
|
+
assignment_key = if options[:stringify_keys]
|
22
|
+
k.to_s
|
23
|
+
elsif options[:symbolize_keys]
|
24
|
+
k.to_s.to_sym
|
25
|
+
else
|
26
|
+
k
|
27
|
+
end
|
16
28
|
if self[k].is_a?(Array)
|
17
29
|
out[assignment_key] ||= []
|
18
30
|
self[k].each do |array_object|
|
19
31
|
out[assignment_key] << (Hash === array_object ? flexibly_convert_to_hash(array_object, options) : array_object)
|
20
32
|
end
|
21
33
|
else
|
22
|
-
out[assignment_key] =
|
34
|
+
out[assignment_key] = Hash === self[k] ? flexibly_convert_to_hash(self[k], options) : self[k]
|
23
35
|
end
|
24
36
|
end
|
25
37
|
out
|
data/lib/hashie/mash.rb
CHANGED
@@ -55,8 +55,10 @@ module Hashie
|
|
55
55
|
# mash.author # => <Mash>
|
56
56
|
#
|
57
57
|
class Mash < Hash
|
58
|
+
include Hashie::Extensions::PrettyInspect
|
59
|
+
|
58
60
|
ALLOWED_SUFFIXES = %w(? ! = _)
|
59
|
-
|
61
|
+
|
60
62
|
alias_method :to_s, :inspect
|
61
63
|
|
62
64
|
# If you pass in an existing hash, it will
|
@@ -185,11 +187,15 @@ module Hashie
|
|
185
187
|
self
|
186
188
|
end
|
187
189
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
190
|
+
def respond_to_missing?(method_name, *args)
|
191
|
+
return true if key?(method_name)
|
192
|
+
_, suffix = method_suffix(method_name)
|
193
|
+
case suffix
|
194
|
+
when '=', '?', '!', '_'
|
195
|
+
return true
|
196
|
+
else
|
197
|
+
super
|
198
|
+
end
|
193
199
|
end
|
194
200
|
|
195
201
|
def prefix_method?(method_name)
|
@@ -199,17 +205,16 @@ module Hashie
|
|
199
205
|
|
200
206
|
def method_missing(method_name, *args, &blk)
|
201
207
|
return self.[](method_name, &blk) if key?(method_name)
|
202
|
-
|
203
|
-
|
204
|
-
case match[2]
|
208
|
+
name, suffix = method_suffix(method_name)
|
209
|
+
case suffix
|
205
210
|
when '='
|
206
|
-
self[
|
211
|
+
self[name] = args.first
|
207
212
|
when '?'
|
208
|
-
!!self[
|
213
|
+
!!self[name]
|
209
214
|
when '!'
|
210
|
-
initializing_reader(
|
215
|
+
initializing_reader(name)
|
211
216
|
when '_'
|
212
|
-
underbang_reader(
|
217
|
+
underbang_reader(name)
|
213
218
|
else
|
214
219
|
default(method_name)
|
215
220
|
end
|
@@ -217,6 +222,12 @@ module Hashie
|
|
217
222
|
|
218
223
|
protected
|
219
224
|
|
225
|
+
def method_suffix(method_name)
|
226
|
+
suffixes_regex = ALLOWED_SUFFIXES.join
|
227
|
+
match = method_name.to_s.match(/(.*?)([#{suffixes_regex}]?)$/)
|
228
|
+
[match[1], match[2]]
|
229
|
+
end
|
230
|
+
|
220
231
|
def convert_key(key) #:nodoc:
|
221
232
|
key.to_s
|
222
233
|
end
|