hashie 3.4.2 → 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 +5 -5
- data/CHANGELOG.md +518 -122
- data/CONTRIBUTING.md +24 -7
- data/LICENSE +1 -1
- data/README.md +455 -48
- data/Rakefile +18 -1
- data/UPGRADING.md +157 -7
- data/hashie.gemspec +14 -7
- data/lib/hashie/array.rb +21 -0
- data/lib/hashie/clash.rb +24 -12
- data/lib/hashie/dash.rb +56 -31
- data/lib/hashie/extensions/active_support/core_ext/hash.rb +14 -0
- data/lib/hashie/extensions/array/pretty_inspect.rb +19 -0
- data/lib/hashie/extensions/coercion.rb +91 -52
- data/lib/hashie/extensions/dash/coercion.rb +25 -0
- data/lib/hashie/extensions/dash/indifferent_access.rb +30 -1
- data/lib/hashie/extensions/dash/predefined_values.rb +88 -0
- data/lib/hashie/extensions/dash/property_translation.rb +59 -30
- data/lib/hashie/extensions/deep_fetch.rb +5 -3
- data/lib/hashie/extensions/deep_find.rb +14 -5
- data/lib/hashie/extensions/deep_locate.rb +40 -21
- data/lib/hashie/extensions/deep_merge.rb +28 -10
- data/lib/hashie/extensions/ignore_undeclared.rb +6 -4
- data/lib/hashie/extensions/indifferent_access.rb +49 -8
- 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 +53 -0
- 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 +38 -0
- data/lib/hashie/extensions/method_access.rb +77 -19
- data/lib/hashie/extensions/parsers/yaml_erb_parser.rb +29 -5
- data/lib/hashie/extensions/ruby_version.rb +60 -0
- data/lib/hashie/extensions/ruby_version_check.rb +21 -0
- data/lib/hashie/extensions/strict_key_access.rb +77 -0
- data/lib/hashie/extensions/stringify_keys.rb +8 -5
- data/lib/hashie/extensions/symbolize_keys.rb +21 -7
- data/lib/hashie/hash.rb +18 -11
- data/lib/hashie/logger.rb +18 -0
- data/lib/hashie/mash.rb +196 -55
- data/lib/hashie/railtie.rb +21 -0
- data/lib/hashie/rash.rb +7 -7
- data/lib/hashie/utils.rb +44 -0
- data/lib/hashie/version.rb +1 -1
- data/lib/hashie.rb +34 -16
- metadata +30 -79
- data/spec/hashie/clash_spec.rb +0 -48
- data/spec/hashie/dash_spec.rb +0 -513
- data/spec/hashie/extensions/autoload_spec.rb +0 -24
- data/spec/hashie/extensions/coercion_spec.rb +0 -625
- 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 -45
- data/spec/hashie/extensions/deep_locate_spec.rb +0 -124
- data/spec/hashie/extensions/deep_merge_spec.rb +0 -45
- data/spec/hashie/extensions/ignore_undeclared_spec.rb +0 -46
- data/spec/hashie/extensions/indifferent_access_spec.rb +0 -219
- 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/safe_assignment_spec.rb +0 -23
- data/spec/hashie/extensions/merge_initializer_spec.rb +0 -23
- data/spec/hashie/extensions/method_access_spec.rb +0 -184
- data/spec/hashie/extensions/stringify_keys_spec.rb +0 -101
- data/spec/hashie/extensions/symbolize_keys_spec.rb +0 -106
- data/spec/hashie/hash_spec.rb +0 -84
- data/spec/hashie/mash_spec.rb +0 -683
- data/spec/hashie/parsers/yaml_erb_parser_spec.rb +0 -29
- data/spec/hashie/rash_spec.rb +0 -77
- data/spec/hashie/trash_spec.rb +0 -268
- data/spec/hashie/version_spec.rb +0 -7
- data/spec/spec_helper.rb +0 -15
- data/spec/support/module_context.rb +0 -11
- data/spec/support/ruby_version.rb +0 -10
@@ -0,0 +1,60 @@
|
|
1
|
+
# Copyright (c) Chad Fowler, Rich Kilmer, Jim Weirich and others.
|
2
|
+
# Portions copyright (c) Engine Yard and Andre Arko
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# 'Software'), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
module Hashie
|
16
|
+
module Extensions
|
17
|
+
class RubyVersion
|
18
|
+
include Comparable
|
19
|
+
|
20
|
+
attr_accessor :segments
|
21
|
+
|
22
|
+
def initialize(version)
|
23
|
+
@segments = split_to_segments(version)
|
24
|
+
end
|
25
|
+
|
26
|
+
def <=>(other)
|
27
|
+
lhsegments = segments
|
28
|
+
rhsegments = other.segments
|
29
|
+
|
30
|
+
lhsize = lhsegments.size
|
31
|
+
rhsize = rhsegments.size
|
32
|
+
limit = (lhsize > rhsize ? lhsize : rhsize) - 1
|
33
|
+
|
34
|
+
i = 0
|
35
|
+
|
36
|
+
while i <= limit
|
37
|
+
lhs = lhsegments[i] || 0
|
38
|
+
rhs = rhsegments[i] || 0
|
39
|
+
i += 1
|
40
|
+
|
41
|
+
next if lhs == rhs
|
42
|
+
return -1 if lhs.is_a?(String) && rhs.is_a?(Numeric)
|
43
|
+
return 1 if lhs.is_a?(Numeric) && rhs.is_a?(String)
|
44
|
+
|
45
|
+
return lhs <=> rhs
|
46
|
+
end
|
47
|
+
|
48
|
+
0
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def split_to_segments(version)
|
54
|
+
version.scan(/[0-9]+|[a-z]+/i).map do |segment|
|
55
|
+
/^\d+$/ =~ segment ? segment.to_i : segment
|
56
|
+
end.freeze
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'hashie/extensions/ruby_version'
|
2
|
+
|
3
|
+
module Hashie
|
4
|
+
module Extensions
|
5
|
+
module RubyVersionCheck
|
6
|
+
def self.included(base)
|
7
|
+
base.extend ClassMethods
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def with_minimum_ruby(version)
|
12
|
+
yield if with_minimum_ruby?(version)
|
13
|
+
end
|
14
|
+
|
15
|
+
def with_minimum_ruby?(version)
|
16
|
+
RubyVersion.new(RUBY_VERSION) >= RubyVersion.new(version)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Hashie
|
2
|
+
module Extensions
|
3
|
+
# SRP: This extension will fail an error whenever a key is accessed
|
4
|
+
# that does not exist in the hash.
|
5
|
+
#
|
6
|
+
# EXAMPLE:
|
7
|
+
#
|
8
|
+
# class StrictKeyAccessHash < Hash
|
9
|
+
# include Hashie::Extensions::StrictKeyAccess
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# >> hash = StrictKeyAccessHash[foo: "bar"]
|
13
|
+
# => {:foo=>"bar"}
|
14
|
+
# >> hash[:foo]
|
15
|
+
# => "bar"
|
16
|
+
# >> hash[:cow]
|
17
|
+
# KeyError: key not found: :cow
|
18
|
+
#
|
19
|
+
# NOTE: For googlers coming from Python to Ruby, this extension makes a Hash
|
20
|
+
# behave more like a "Dictionary".
|
21
|
+
#
|
22
|
+
module StrictKeyAccess
|
23
|
+
class DefaultError < StandardError
|
24
|
+
def initialize
|
25
|
+
super('Setting or using a default with Hashie::Extensions::StrictKeyAccess'\
|
26
|
+
' does not make sense'
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# NOTE: Defaults don't make any sense with a StrictKeyAccess.
|
32
|
+
# NOTE: When key lookup fails a KeyError is raised.
|
33
|
+
#
|
34
|
+
# Normal:
|
35
|
+
#
|
36
|
+
# >> a = Hash.new(123)
|
37
|
+
# => {}
|
38
|
+
# >> a["noes"]
|
39
|
+
# => 123
|
40
|
+
#
|
41
|
+
# With StrictKeyAccess:
|
42
|
+
#
|
43
|
+
# >> a = StrictKeyAccessHash.new(123)
|
44
|
+
# => {}
|
45
|
+
# >> a["noes"]
|
46
|
+
# KeyError: key not found: "noes"
|
47
|
+
#
|
48
|
+
def [](key)
|
49
|
+
fetch(key)
|
50
|
+
end
|
51
|
+
|
52
|
+
def default(_ = nil)
|
53
|
+
raise DefaultError
|
54
|
+
end
|
55
|
+
|
56
|
+
def default=(_)
|
57
|
+
raise DefaultError
|
58
|
+
end
|
59
|
+
|
60
|
+
def default_proc
|
61
|
+
raise DefaultError
|
62
|
+
end
|
63
|
+
|
64
|
+
def default_proc=(_)
|
65
|
+
raise DefaultError
|
66
|
+
end
|
67
|
+
|
68
|
+
def key(value)
|
69
|
+
super.tap do |result|
|
70
|
+
if result.nil? && (!key?(result) || self[result] != value)
|
71
|
+
raise KeyError, "key not found with value of #{value.inspect}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -15,7 +15,7 @@ module Hashie
|
|
15
15
|
# Return a new hash with all keys converted
|
16
16
|
# to strings.
|
17
17
|
def stringify_keys
|
18
|
-
|
18
|
+
StringifyKeys.stringify_keys(self)
|
19
19
|
end
|
20
20
|
|
21
21
|
module ClassMethods
|
@@ -25,7 +25,7 @@ module Hashie
|
|
25
25
|
def stringify_keys_recursively!(object)
|
26
26
|
case object
|
27
27
|
when self.class
|
28
|
-
|
28
|
+
stringify_keys!(object)
|
29
29
|
when ::Array
|
30
30
|
object.each do |i|
|
31
31
|
stringify_keys_recursively!(i)
|
@@ -43,7 +43,8 @@ module Hashie
|
|
43
43
|
# test.stringify_keys!
|
44
44
|
# test # => {'abc' => 'def'}
|
45
45
|
def stringify_keys!(hash)
|
46
|
-
hash.
|
46
|
+
hash.extend(Hashie::Extensions::StringifyKeys) unless hash.respond_to?(:stringify_keys!)
|
47
|
+
hash.keys.each do |k| # rubocop:disable Performance/HashEachMethods
|
47
48
|
stringify_keys_recursively!(hash[k])
|
48
49
|
hash[k.to_s] = hash.delete(k)
|
49
50
|
end
|
@@ -54,8 +55,10 @@ module Hashie
|
|
54
55
|
# to strings.
|
55
56
|
# @param [::Hash] hash
|
56
57
|
def stringify_keys(hash)
|
57
|
-
hash.dup
|
58
|
-
|
58
|
+
copy = hash.dup
|
59
|
+
copy.extend(Hashie::Extensions::StringifyKeys) unless copy.respond_to?(:stringify_keys!)
|
60
|
+
copy.tap do |new_hash|
|
61
|
+
stringify_keys!(new_hash)
|
59
62
|
end
|
60
63
|
end
|
61
64
|
end
|
@@ -15,7 +15,7 @@ module Hashie
|
|
15
15
|
# Return a new hash with all keys converted
|
16
16
|
# to symbols.
|
17
17
|
def symbolize_keys
|
18
|
-
|
18
|
+
SymbolizeKeys.symbolize_keys(self)
|
19
19
|
end
|
20
20
|
|
21
21
|
module ClassMethods
|
@@ -23,9 +23,9 @@ module Hashie
|
|
23
23
|
# hashes and arrays.
|
24
24
|
# @api private
|
25
25
|
def symbolize_keys_recursively!(object)
|
26
|
-
object.symbolize_keys! if object.respond_to? :symbolize_keys!
|
27
|
-
|
28
26
|
case object
|
27
|
+
when self.class
|
28
|
+
symbolize_keys!(object)
|
29
29
|
when ::Array
|
30
30
|
object.each do |i|
|
31
31
|
symbolize_keys_recursively!(i)
|
@@ -43,9 +43,10 @@ module Hashie
|
|
43
43
|
# Hashie.symbolize_keys! test
|
44
44
|
# test # => {:abc => 'def'}
|
45
45
|
def symbolize_keys!(hash)
|
46
|
-
hash.
|
46
|
+
hash.extend(Hashie::Extensions::SymbolizeKeys) unless hash.respond_to?(:symbolize_keys!)
|
47
|
+
hash.keys.each do |k| # rubocop:disable Performance/HashEachMethods
|
47
48
|
symbolize_keys_recursively!(hash[k])
|
48
|
-
hash[k
|
49
|
+
hash[convert_key(k)] = hash.delete(k)
|
49
50
|
end
|
50
51
|
hash
|
51
52
|
end
|
@@ -54,10 +55,23 @@ module Hashie
|
|
54
55
|
# to symbols.
|
55
56
|
# @param [::Hash] hash
|
56
57
|
def symbolize_keys(hash)
|
57
|
-
hash.dup
|
58
|
-
|
58
|
+
copy = hash.dup
|
59
|
+
copy.extend(Hashie::Extensions::SymbolizeKeys) unless copy.respond_to?(:symbolize_keys!)
|
60
|
+
copy.tap do |new_hash|
|
61
|
+
symbolize_keys!(new_hash)
|
59
62
|
end
|
60
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
|
61
75
|
end
|
62
76
|
|
63
77
|
class << self
|
data/lib/hashie/hash.rb
CHANGED
@@ -17,21 +17,22 @@ module Hashie
|
|
17
17
|
# Converts a mash back to a hash (with stringified or symbolized keys)
|
18
18
|
def to_hash(options = {})
|
19
19
|
out = {}
|
20
|
-
|
21
|
-
assignment_key =
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
20
|
+
each_key do |k|
|
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] << (
|
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,8 +45,14 @@ 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
|
-
if object.method(:to_hash).arity
|
55
|
+
if object.method(:to_hash).arity.zero?
|
49
56
|
object.to_hash
|
50
57
|
else
|
51
58
|
object.to_hash(options)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Hashie
|
4
|
+
# The logger that Hashie uses for reporting errors.
|
5
|
+
#
|
6
|
+
# @return [Logger]
|
7
|
+
def self.logger
|
8
|
+
@logger ||= Logger.new(STDOUT)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Sets the logger that Hashie uses for reporting errors.
|
12
|
+
#
|
13
|
+
# @param logger [Logger] The logger to set as Hashie's logger.
|
14
|
+
# @return [void]
|
15
|
+
def self.logger=(logger)
|
16
|
+
@logger = logger
|
17
|
+
end
|
18
|
+
end
|