hashie 2.0.5 → 2.1.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/.rubocop.yml +36 -0
- data/.travis.yml +13 -6
- data/CHANGELOG.md +40 -21
- data/CONTRIBUTING.md +110 -19
- data/Gemfile +9 -0
- data/LICENSE +1 -1
- data/README.md +347 -0
- data/Rakefile +4 -2
- data/hashie.gemspec +4 -7
- data/lib/hashie.rb +3 -0
- data/lib/hashie/clash.rb +19 -19
- data/lib/hashie/dash.rb +47 -39
- data/lib/hashie/extensions/coercion.rb +10 -6
- data/lib/hashie/extensions/deep_fetch.rb +29 -0
- data/lib/hashie/extensions/deep_merge.rb +15 -6
- data/lib/hashie/extensions/ignore_undeclared.rb +41 -0
- data/lib/hashie/extensions/indifferent_access.rb +37 -10
- data/lib/hashie/extensions/key_conversion.rb +3 -3
- data/lib/hashie/extensions/method_access.rb +9 -9
- data/lib/hashie/hash.rb +7 -7
- data/lib/hashie/hash_extensions.rb +5 -7
- data/lib/hashie/mash.rb +38 -31
- data/lib/hashie/rash.rb +119 -0
- data/lib/hashie/trash.rb +31 -22
- data/lib/hashie/version.rb +1 -1
- data/spec/hashie/clash_spec.rb +43 -45
- data/spec/hashie/dash_spec.rb +115 -53
- data/spec/hashie/extensions/coercion_spec.rb +42 -37
- data/spec/hashie/extensions/deep_fetch_spec.rb +70 -0
- data/spec/hashie/extensions/deep_merge_spec.rb +11 -9
- data/spec/hashie/extensions/ignore_undeclared_spec.rb +23 -0
- data/spec/hashie/extensions/indifferent_access_spec.rb +117 -64
- data/spec/hashie/extensions/key_conversion_spec.rb +28 -27
- data/spec/hashie/extensions/merge_initializer_spec.rb +13 -10
- data/spec/hashie/extensions/method_access_spec.rb +49 -40
- data/spec/hashie/hash_spec.rb +25 -13
- data/spec/hashie/mash_spec.rb +243 -187
- data/spec/hashie/rash_spec.rb +44 -0
- data/spec/hashie/trash_spec.rb +81 -43
- data/spec/hashie/version_spec.rb +7 -0
- data/spec/spec_helper.rb +0 -4
- metadata +27 -78
- data/.document +0 -5
- data/README.markdown +0 -236
- data/lib/hashie/extensions/structure.rb +0 -47
data/Rakefile
CHANGED
@@ -6,8 +6,10 @@ Bundler::GemHelper.install_tasks
|
|
6
6
|
|
7
7
|
require 'rspec/core/rake_task'
|
8
8
|
RSpec::Core::RakeTask.new do |spec|
|
9
|
-
# spec.libs << 'lib' << 'spec'
|
10
9
|
spec.pattern = 'spec/**/*_spec.rb'
|
11
10
|
end
|
12
11
|
|
13
|
-
|
12
|
+
require 'rubocop/rake_task'
|
13
|
+
Rubocop::RakeTask.new(:rubocop)
|
14
|
+
|
15
|
+
task default: [:rubocop, :spec]
|
data/hashie.gemspec
CHANGED
@@ -3,8 +3,8 @@ require File.expand_path('../lib/hashie/version', __FILE__)
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
4
|
gem.authors = ["Michael Bleigh", "Jerry Cheung"]
|
5
5
|
gem.email = ["michael@intridea.com", "jollyjerry@gmail.com"]
|
6
|
-
gem.description = %q{Hashie is a
|
7
|
-
gem.summary = %q{Your friendly neighborhood hash
|
6
|
+
gem.description = %q{Hashie is a collection of classes and mixins that make hashes more powerful.}
|
7
|
+
gem.summary = %q{Your friendly neighborhood hash library.}
|
8
8
|
gem.homepage = 'https://github.com/intridea/hashie'
|
9
9
|
|
10
10
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
@@ -15,9 +15,6 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.version = Hashie::VERSION
|
16
16
|
gem.license = "MIT"
|
17
17
|
|
18
|
-
gem.add_development_dependency 'rake'
|
19
|
-
gem.add_development_dependency 'rspec'
|
20
|
-
gem.add_development_dependency 'guard'
|
21
|
-
gem.add_development_dependency 'guard-rspec'
|
22
|
-
gem.add_development_dependency 'growl'
|
18
|
+
gem.add_development_dependency 'rake'
|
19
|
+
gem.add_development_dependency 'rspec'
|
23
20
|
end
|
data/lib/hashie.rb
CHANGED
@@ -6,11 +6,13 @@ module Hashie
|
|
6
6
|
autoload :Mash, 'hashie/mash'
|
7
7
|
autoload :PrettyInspect, 'hashie/hash_extensions'
|
8
8
|
autoload :Trash, 'hashie/trash'
|
9
|
+
autoload :Rash, 'hashie/rash'
|
9
10
|
|
10
11
|
module Extensions
|
11
12
|
autoload :Coercion, 'hashie/extensions/coercion'
|
12
13
|
autoload :DeepMerge, 'hashie/extensions/deep_merge'
|
13
14
|
autoload :KeyConversion, 'hashie/extensions/key_conversion'
|
15
|
+
autoload :IgnoreUndeclared, 'hashie/extensions/ignore_undeclared'
|
14
16
|
autoload :IndifferentAccess, 'hashie/extensions/indifferent_access'
|
15
17
|
autoload :MergeInitializer, 'hashie/extensions/merge_initializer'
|
16
18
|
autoload :MethodAccess, 'hashie/extensions/method_access'
|
@@ -19,5 +21,6 @@ module Hashie
|
|
19
21
|
autoload :MethodWriter, 'hashie/extensions/method_access'
|
20
22
|
autoload :StringifyKeys, 'hashie/extensions/key_conversion'
|
21
23
|
autoload :SymbolizeKeys, 'hashie/extensions/key_conversion'
|
24
|
+
autoload :DeepFetch, 'hashie/extensions/deep_fetch'
|
22
25
|
end
|
23
26
|
end
|
data/lib/hashie/clash.rb
CHANGED
@@ -3,10 +3,10 @@ require 'hashie/hash'
|
|
3
3
|
module Hashie
|
4
4
|
#
|
5
5
|
# A Clash is a "Chainable Lazy Hash". Inspired by libraries such as Arel,
|
6
|
-
# a Clash allows you to chain together method arguments to build a
|
6
|
+
# a Clash allows you to chain together method arguments to build a
|
7
7
|
# hash, something that's especially useful if you're doing something
|
8
8
|
# like constructing a complex options hash. Here's a basic example:
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# c = Hashie::Clash.new.conditions(:foo => 'bar').order(:created_at)
|
11
11
|
# c # => {:conditions => {:foo => 'bar'}, :order => :created_at}
|
12
12
|
#
|
@@ -15,7 +15,7 @@ module Hashie
|
|
15
15
|
# back out again with the _end! method. Example:
|
16
16
|
#
|
17
17
|
# c = Hashie::Clash.new.conditions!.foo('bar').baz(123)._end!.order(:created_at)
|
18
|
-
# c # => {:
|
18
|
+
# c # => { conditions: { foo: 'bar', baz: 123 }, order: :created_at}
|
19
19
|
#
|
20
20
|
# Because the primary functionality of Clash is to build options objects,
|
21
21
|
# all keys are converted to symbols since many libraries expect symbols explicitly
|
@@ -25,7 +25,7 @@ module Hashie
|
|
25
25
|
class ChainError < ::StandardError; end
|
26
26
|
# The parent Clash if this Clash was created via chaining.
|
27
27
|
attr_reader :_parent
|
28
|
-
|
28
|
+
|
29
29
|
# Initialize a new clash by passing in a Hash to
|
30
30
|
# convert and, optionally, the parent to which this
|
31
31
|
# Clash is chained.
|
@@ -35,7 +35,7 @@ module Hashie
|
|
35
35
|
self[k.to_sym] = v
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
# Jump back up a level if you are using bang method
|
40
40
|
# chaining. For example:
|
41
41
|
#
|
@@ -43,44 +43,44 @@ module Hashie
|
|
43
43
|
# c.baz!.foo(123) # => c[:baz]
|
44
44
|
# c.baz!._end! # => c
|
45
45
|
def _end!
|
46
|
-
|
46
|
+
_parent
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
def id(*args) #:nodoc:
|
50
50
|
method_missing(:id, *args)
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
def merge_store(key, *args) #:nodoc:
|
54
54
|
case args.length
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
55
|
+
when 1
|
56
|
+
val = args.first
|
57
|
+
val = self[key].merge(val) if self[key].is_a?(::Hash) && val.is_a?(::Hash)
|
58
|
+
else
|
59
|
+
val = args
|
60
60
|
end
|
61
61
|
|
62
62
|
self[key.to_sym] = val
|
63
63
|
self
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
def method_missing(name, *args) #:nodoc:
|
67
67
|
name = name.to_s
|
68
68
|
if name.match(/!$/) && args.empty?
|
69
69
|
key = name[0...-1].to_sym
|
70
|
-
|
70
|
+
|
71
71
|
if self[key].nil?
|
72
72
|
self[key] = Clash.new({}, self)
|
73
73
|
elsif self[key].is_a?(::Hash) && !self[key].is_a?(Clash)
|
74
74
|
self[key] = Clash.new(self[key], self)
|
75
75
|
else
|
76
|
-
|
76
|
+
fail ChainError, 'Tried to chain into a non-hash key.'
|
77
77
|
end
|
78
|
-
|
78
|
+
|
79
79
|
self[key]
|
80
80
|
elsif args.any?
|
81
81
|
key = name.to_sym
|
82
|
-
|
82
|
+
merge_store(key, *args)
|
83
83
|
end
|
84
84
|
end
|
85
85
|
end
|
86
|
-
end
|
86
|
+
end
|
data/lib/hashie/dash.rb
CHANGED
@@ -30,24 +30,18 @@ module Hashie
|
|
30
30
|
def self.property(property_name, options = {})
|
31
31
|
property_name = property_name.to_sym
|
32
32
|
|
33
|
-
|
33
|
+
properties << property_name
|
34
34
|
|
35
|
-
if options.
|
36
|
-
|
37
|
-
elsif
|
38
|
-
|
35
|
+
if options.key?(:default)
|
36
|
+
defaults[property_name] = options[:default]
|
37
|
+
elsif defaults.key?(property_name)
|
38
|
+
defaults.delete property_name
|
39
39
|
end
|
40
40
|
|
41
41
|
unless instance_methods.map { |m| m.to_s }.include?("#{property_name}=")
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
-
def #{property_name}=(value)
|
48
|
-
self.[]=(#{property_name.to_s.inspect}, value)
|
49
|
-
end
|
50
|
-
ACCESSORS
|
42
|
+
define_method(property_name) { |&block| self.[](property_name.to_s, &block) }
|
43
|
+
property_assignment = property_name.to_s.concat('=').to_sym
|
44
|
+
define_method(property_assignment) { |value| self.[]=(property_name.to_s, value) }
|
51
45
|
end
|
52
46
|
|
53
47
|
if defined? @subclasses
|
@@ -67,9 +61,9 @@ module Hashie
|
|
67
61
|
def self.inherited(klass)
|
68
62
|
super
|
69
63
|
(@subclasses ||= Set.new) << klass
|
70
|
-
klass.instance_variable_set('@properties',
|
71
|
-
klass.instance_variable_set('@defaults',
|
72
|
-
klass.instance_variable_set('@required_properties',
|
64
|
+
klass.instance_variable_set('@properties', properties.dup)
|
65
|
+
klass.instance_variable_set('@defaults', defaults.dup)
|
66
|
+
klass.instance_variable_set('@required_properties', required_properties.dup)
|
73
67
|
end
|
74
68
|
|
75
69
|
# Check to see if the specified property has already been
|
@@ -127,6 +121,21 @@ module Hashie
|
|
127
121
|
super(property.to_s, value)
|
128
122
|
end
|
129
123
|
|
124
|
+
def merge(other_hash)
|
125
|
+
new_dash = dup
|
126
|
+
other_hash.each do |k, v|
|
127
|
+
new_dash[k] = block_given? ? yield(k, self[k], v) : v
|
128
|
+
end
|
129
|
+
new_dash
|
130
|
+
end
|
131
|
+
|
132
|
+
def merge!(other_hash)
|
133
|
+
other_hash.each do |k, v|
|
134
|
+
self[k] = block_given? ? yield(k, self[k], v) : v
|
135
|
+
end
|
136
|
+
self
|
137
|
+
end
|
138
|
+
|
130
139
|
def replace(other_hash)
|
131
140
|
other_hash = self.class.defaults.merge(other_hash)
|
132
141
|
(keys - other_hash.keys).each { |key| delete(key) }
|
@@ -136,35 +145,34 @@ module Hashie
|
|
136
145
|
|
137
146
|
private
|
138
147
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
148
|
+
def initialize_attributes(attributes)
|
149
|
+
attributes.each_pair do |att, value|
|
150
|
+
self[att] = value
|
151
|
+
end if attributes
|
152
|
+
end
|
144
153
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
end
|
154
|
+
def assert_property_exists!(property)
|
155
|
+
unless self.class.property?(property)
|
156
|
+
fail NoMethodError, "The property '#{property}' is not defined for this Dash."
|
149
157
|
end
|
158
|
+
end
|
150
159
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
end
|
160
|
+
def assert_required_properties_set!
|
161
|
+
self.class.required_properties.each do |required_property|
|
162
|
+
assert_property_set!(required_property)
|
155
163
|
end
|
164
|
+
end
|
156
165
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
end
|
166
|
+
def assert_property_set!(property)
|
167
|
+
if send(property).nil?
|
168
|
+
fail ArgumentError, "The property '#{property}' is required for this Dash."
|
161
169
|
end
|
170
|
+
end
|
162
171
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
end
|
172
|
+
def assert_property_required!(property, value)
|
173
|
+
if self.class.required?(property) && value.nil?
|
174
|
+
fail ArgumentError, "The property '#{property}' is required for this Dash."
|
167
175
|
end
|
168
|
-
|
176
|
+
end
|
169
177
|
end
|
170
178
|
end
|
@@ -2,7 +2,7 @@ module Hashie
|
|
2
2
|
module Extensions
|
3
3
|
module Coercion
|
4
4
|
def self.included(base)
|
5
|
-
base.
|
5
|
+
base.extend ClassMethods
|
6
6
|
base.send :include, InstanceMethods
|
7
7
|
end
|
8
8
|
|
@@ -21,7 +21,7 @@ module Hashie
|
|
21
21
|
super(key, value)
|
22
22
|
end
|
23
23
|
|
24
|
-
def custom_writer(key, value)
|
24
|
+
def custom_writer(key, value, convert = true)
|
25
25
|
self[key] = value
|
26
26
|
end
|
27
27
|
|
@@ -53,7 +53,7 @@ module Hashie
|
|
53
53
|
attrs.each { |key| @key_coercions[key] = into }
|
54
54
|
end
|
55
55
|
|
56
|
-
|
56
|
+
alias_method :coerce_keys, :coerce_key
|
57
57
|
|
58
58
|
# Returns a hash of any existing key coercions.
|
59
59
|
def key_coercions
|
@@ -87,7 +87,7 @@ module Hashie
|
|
87
87
|
# end
|
88
88
|
# end
|
89
89
|
def coerce_value(from, into, options = {})
|
90
|
-
options = {:
|
90
|
+
options = { strict: true }.merge(options)
|
91
91
|
|
92
92
|
if options[:strict]
|
93
93
|
(@strict_value_coercions ||= {})[from] = into
|
@@ -100,9 +100,13 @@ module Hashie
|
|
100
100
|
end
|
101
101
|
|
102
102
|
# Return all value coercions that have the :strict rule as true.
|
103
|
-
def strict_value_coercions
|
103
|
+
def strict_value_coercions
|
104
|
+
@strict_value_coercions || {}
|
105
|
+
end
|
104
106
|
# Return all value coercions that have the :strict rule as false.
|
105
|
-
def lenient_value_coercions
|
107
|
+
def lenient_value_coercions
|
108
|
+
@value_coercions || {}
|
109
|
+
end
|
106
110
|
|
107
111
|
# Fetch the value coercion, if any, for the specified object.
|
108
112
|
def value_coercion(value)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Hashie
|
2
|
+
module Extensions
|
3
|
+
# Searches a deeply nested datastructure for a key path, and returns the associated value.
|
4
|
+
#
|
5
|
+
# options = { user: { location: { address: '123 Street' } } }
|
6
|
+
# options.deep_fetch :user, :location, :address #=> '123 Street'
|
7
|
+
#
|
8
|
+
# If a block is provided its value will be returned if the key does not exist.
|
9
|
+
#
|
10
|
+
# options.deep_fetch(:user, :non_existent_key) { 'a value' } #=> 'a value'
|
11
|
+
#
|
12
|
+
# This is particularly useful for fetching values from deeply nested api responses or params hashes.
|
13
|
+
module DeepFetch
|
14
|
+
class UndefinedPathError < StandardError; end
|
15
|
+
|
16
|
+
def deep_fetch(*args, &block)
|
17
|
+
args.reduce(self) do |obj, arg|
|
18
|
+
begin
|
19
|
+
arg = Integer(arg) if obj.kind_of? Array
|
20
|
+
obj.fetch(arg)
|
21
|
+
rescue ArgumentError, IndexError => e
|
22
|
+
break block.call(arg) if block
|
23
|
+
raise UndefinedPathError, "Could not fetch path (#{args.join(' > ')}) at #{arg}", e.backtrace
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -3,19 +3,28 @@ 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)
|
6
|
-
(
|
7
|
-
h.deep_merge!(other_hash)
|
6
|
+
dup.deep_merge!(other_hash)
|
8
7
|
end
|
9
8
|
|
10
9
|
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
11
10
|
# Modifies the receiver in place.
|
12
11
|
def deep_merge!(other_hash)
|
13
|
-
other_hash
|
14
|
-
(class << (tv = self[k]); self; end).send :include, Hashie::Extensions::DeepMerge
|
15
|
-
self[k] = tv.is_a?(::Hash) && v.is_a?(::Hash) ? tv.deep_merge(v) : v
|
16
|
-
end
|
12
|
+
_recursive_merge(self, other_hash)
|
17
13
|
self
|
18
14
|
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def _recursive_merge(hash, other_hash)
|
19
|
+
if other_hash.is_a?(::Hash) && hash.is_a?(::Hash)
|
20
|
+
other_hash.each do |k, v|
|
21
|
+
hash[k] = hash.key?(k) ? _recursive_merge(hash[k], v) : v
|
22
|
+
end
|
23
|
+
hash
|
24
|
+
else
|
25
|
+
other_hash
|
26
|
+
end
|
27
|
+
end
|
19
28
|
end
|
20
29
|
end
|
21
30
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Hashie
|
2
|
+
module Extensions
|
3
|
+
# IgnoreUndeclared is a simple mixin that silently ignores
|
4
|
+
# undeclared properties on initialization instead of
|
5
|
+
# raising an error. This is useful when using a Trash to
|
6
|
+
# capture a subset of a larger hash.
|
7
|
+
#
|
8
|
+
# Note that attempting to retrieve an undeclared property
|
9
|
+
# will still raise a NoMethodError, even if a value for
|
10
|
+
# that property was provided at initialization.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# class Person < Trash
|
14
|
+
# include Hashie::Extensions::IgnoreUndeclared
|
15
|
+
#
|
16
|
+
# property :first_name
|
17
|
+
# property :last_name
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# user_data = {
|
21
|
+
# :first_name => 'Freddy',
|
22
|
+
# :last_name => 'Nostrils',
|
23
|
+
# :email => 'freddy@example.com'
|
24
|
+
# }
|
25
|
+
#
|
26
|
+
# p = Person.new(user_data) # 'email' is silently ignored
|
27
|
+
#
|
28
|
+
# p.first_name # => 'Freddy'
|
29
|
+
# p.last_name # => 'Nostrils'
|
30
|
+
# p.email # => NoMethodError
|
31
|
+
module IgnoreUndeclared
|
32
|
+
def initialize_attributes(attributes)
|
33
|
+
attributes.each_pair do |att, value|
|
34
|
+
if self.class.property?(att) || (self.class.respond_to?(:translations) && self.class.translations.include?(att.to_sym))
|
35
|
+
self[att] = value
|
36
|
+
end
|
37
|
+
end if attributes
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -27,6 +27,7 @@ module Hashie
|
|
27
27
|
base.class_eval do
|
28
28
|
alias_method :regular_writer, :[]=
|
29
29
|
alias_method :[]=, :indifferent_writer
|
30
|
+
alias_method :store, :indifferent_writer
|
30
31
|
%w(default update replace fetch delete key? values_at).each do |m|
|
31
32
|
alias_method "regular_#{m}", m
|
32
33
|
alias_method m, "indifferent_#{m}"
|
@@ -35,6 +36,16 @@ module Hashie
|
|
35
36
|
%w(include? member? has_key?).each do |key_alias|
|
36
37
|
alias_method key_alias, :indifferent_key?
|
37
38
|
end
|
39
|
+
|
40
|
+
class << self
|
41
|
+
def [](*)
|
42
|
+
super.convert!
|
43
|
+
end
|
44
|
+
|
45
|
+
def try_convert(*)
|
46
|
+
(hash = super) && self[hash]
|
47
|
+
end
|
48
|
+
end
|
38
49
|
end
|
39
50
|
end
|
40
51
|
|
@@ -61,7 +72,7 @@ module Hashie
|
|
61
72
|
# is injecting itself into member hashes.
|
62
73
|
def convert!
|
63
74
|
keys.each do |k|
|
64
|
-
regular_writer convert_key(k), convert_value(
|
75
|
+
regular_writer convert_key(k), convert_value(regular_delete(k))
|
65
76
|
end
|
66
77
|
self
|
67
78
|
end
|
@@ -75,7 +86,7 @@ module Hashie
|
|
75
86
|
value
|
76
87
|
end
|
77
88
|
end
|
78
|
-
|
89
|
+
|
79
90
|
def indifferent_default(key = nil)
|
80
91
|
return self[convert_key(key)] if key?(key)
|
81
92
|
regular_default(key)
|
@@ -83,18 +94,34 @@ module Hashie
|
|
83
94
|
|
84
95
|
def indifferent_update(other_hash)
|
85
96
|
return regular_update(other_hash) if hash_with_indifference?(other_hash)
|
86
|
-
other_hash.each_pair do |k,v|
|
97
|
+
other_hash.each_pair do |k, v|
|
87
98
|
self[k] = v
|
88
99
|
end
|
89
100
|
end
|
90
|
-
|
91
|
-
def indifferent_writer(key, value); regular_writer convert_key(key), convert_value(value) end
|
92
|
-
def indifferent_fetch(key, *args); regular_fetch convert_key(key), *args end
|
93
|
-
def indifferent_delete(key); regular_delete convert_key(key) end
|
94
|
-
def indifferent_key?(key); regular_key? convert_key(key) end
|
95
|
-
def indifferent_values_at(*indices); indices.map{|i| self[i] } end
|
96
101
|
|
97
|
-
def
|
102
|
+
def indifferent_writer(key, value)
|
103
|
+
regular_writer convert_key(key), convert_value(value)
|
104
|
+
end
|
105
|
+
|
106
|
+
def indifferent_fetch(key, *args)
|
107
|
+
regular_fetch convert_key(key), *args
|
108
|
+
end
|
109
|
+
|
110
|
+
def indifferent_delete(key)
|
111
|
+
regular_delete convert_key(key)
|
112
|
+
end
|
113
|
+
|
114
|
+
def indifferent_key?(key)
|
115
|
+
regular_key? convert_key(key)
|
116
|
+
end
|
117
|
+
|
118
|
+
def indifferent_values_at(*indices)
|
119
|
+
indices.map { |i| self[i] }
|
120
|
+
end
|
121
|
+
|
122
|
+
def indifferent_access?
|
123
|
+
true
|
124
|
+
end
|
98
125
|
|
99
126
|
def indifferent_replace(other_hash)
|
100
127
|
(keys - other_hash.keys).each { |key| delete(key) }
|