hashie 3.4.2 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|