gorillib 0.0.8 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.textile +6 -0
- data/README.textile +34 -11
- data/VERSION +1 -1
- data/gorillib.gemspec +63 -5
- data/lib/gorillib/enumerable/sum.rb +2 -2
- data/lib/gorillib/hash/compact.rb +2 -29
- data/lib/gorillib/hash/deep_compact.rb +2 -12
- data/lib/gorillib/hash/deep_dup.rb +4 -0
- data/lib/gorillib/hash/deep_merge.rb +2 -14
- data/lib/gorillib/hash/indifferent_access.rb +207 -0
- data/lib/gorillib/hash/keys.rb +2 -40
- data/lib/gorillib/hash/reverse_merge.rb +2 -24
- data/lib/gorillib/hash/slice.rb +2 -51
- data/lib/gorillib/hash/tree_merge.rb +4 -0
- data/lib/gorillib/hashlike.rb +824 -0
- data/lib/gorillib/hashlike/compact.rb +60 -0
- data/lib/gorillib/hashlike/deep_compact.rb +18 -0
- data/lib/gorillib/hashlike/deep_dup.rb +15 -0
- data/lib/gorillib/hashlike/deep_merge.rb +20 -0
- data/lib/gorillib/hashlike/hashlike_via_accessors.rb +169 -0
- data/lib/gorillib/hashlike/keys.rb +59 -0
- data/lib/gorillib/hashlike/reverse_merge.rb +31 -0
- data/lib/gorillib/hashlike/slice.rb +67 -0
- data/lib/gorillib/hashlike/tree_merge.rb +76 -0
- data/lib/gorillib/metaprogramming/mattr_accessor.rb +1 -1
- data/lib/gorillib/receiver.rb +315 -0
- data/lib/gorillib/receiver/active_model_shim.rb +19 -0
- data/lib/gorillib/receiver/acts_as_hash.rb +191 -0
- data/lib/gorillib/receiver/acts_as_loadable.rb +42 -0
- data/lib/gorillib/receiver/tree_diff.rb +74 -0
- data/lib/gorillib/receiver/validations.rb +30 -0
- data/lib/gorillib/struct/acts_as_hash.rb +108 -0
- data/lib/gorillib/struct/hashlike_iteration.rb +0 -0
- data/notes/fancy_hashes_and_receivers.textile +120 -0
- data/notes/hash_rdocs.textile +97 -0
- data/spec/hash/deep_merge_spec.rb +0 -2
- data/spec/hash/indifferent_access_spec.rb +391 -0
- data/spec/hash/slice_spec.rb +35 -12
- data/spec/hashlike/behave_same_as_hash_spec.rb +105 -0
- data/spec/hashlike/hashlike_behavior_spec.rb +824 -0
- data/spec/hashlike/hashlike_via_accessors_fuzzing_spec.rb +37 -0
- data/spec/hashlike/hashlike_via_accessors_spec.rb +262 -0
- data/spec/hashlike_spec.rb +302 -0
- data/spec/metaprogramming/aliasing_spec.rb +3 -0
- data/spec/metaprogramming/cattr_accessor_spec.rb +2 -0
- data/spec/metaprogramming/class_attribute_spec.rb +2 -0
- data/spec/metaprogramming/delegation_spec.rb +2 -0
- data/spec/metaprogramming/mattr_accessor_spec.rb +2 -0
- data/spec/metaprogramming/singleton_class_spec.rb +3 -0
- data/spec/receiver/acts_as_hash_spec.rb +286 -0
- data/spec/receiver_spec.rb +478 -0
- data/spec/spec_helper.rb +11 -6
- data/spec/string/truncate_spec.rb +1 -0
- data/spec/struct/acts_as_hash_fuzz_spec.rb +67 -0
- data/spec/struct/acts_as_hash_spec.rb +426 -0
- data/spec/support/hashlike_fuzzing_helper.rb +127 -0
- data/spec/support/hashlike_helper.rb +75 -0
- data/spec/support/hashlike_struct_helper.rb +37 -0
- data/spec/support/hashlike_via_delegation.rb +30 -0
- data/spec/support/matchers/be_array_eql.rb +12 -0
- data/spec/support/matchers/be_hash_eql.rb +14 -0
- data/spec/support/matchers/enumerate_method.rb +10 -0
- data/spec/support/matchers/evaluate_to_true.rb +5 -0
- metadata +62 -4
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'gorillib/object/blank'
|
2
|
+
module Gorillib
|
3
|
+
module Hashlike
|
4
|
+
module Compact
|
5
|
+
|
6
|
+
# returns a compact!ed copy (contains no key/value pairs having nil? values)
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# hsh = { :a => 100, :b => nil, :c => false, :d => "" }
|
10
|
+
# hsh.compact # => { :a => 100, :c => false, :d => "" }
|
11
|
+
# hsh # => { :a => 100, :b => nil, :c => false, :d => "" }
|
12
|
+
#
|
13
|
+
# @return [Hashlike]
|
14
|
+
#
|
15
|
+
def compact
|
16
|
+
reject{|key,val| val.nil? }
|
17
|
+
end
|
18
|
+
|
19
|
+
# Removes all key/value pairs having nil? values
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
# hsh = { :a => 100, :b => nil, :c => false, :d => "" }
|
23
|
+
# hsh.compact # => { :a => 100, :c => false, :d => "" }
|
24
|
+
# hsh # => { :a => 100, :c => false, :d => "" }
|
25
|
+
#
|
26
|
+
# @return [Hashlike]
|
27
|
+
#
|
28
|
+
def compact!
|
29
|
+
delete_if{|key,val| val.nil? }
|
30
|
+
end
|
31
|
+
|
32
|
+
# returns a compact!ed copy (contains no key/value pairs having blank? values)
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# hsh = { :a => 100, :b => nil, :c => false, :d => "" }
|
36
|
+
# hsh.compact # => { :a => 100 }
|
37
|
+
# hsh # => { :a => 100, :b => nil, :c => false, :d => "" }
|
38
|
+
#
|
39
|
+
# @return [Hashlike]
|
40
|
+
#
|
41
|
+
def compact_blank
|
42
|
+
reject{|key,val| val.blank? }
|
43
|
+
end
|
44
|
+
|
45
|
+
# Removes all key/value pairs having blank? values
|
46
|
+
#
|
47
|
+
# @example
|
48
|
+
# hsh = { :a => 100, :b => nil, :c => false, :d => "" }
|
49
|
+
# hsh.compact # => { :a => 100 }
|
50
|
+
# hsh # => { :a => 100 }
|
51
|
+
#
|
52
|
+
# @return [Hashlike]
|
53
|
+
#
|
54
|
+
def compact_blank!
|
55
|
+
delete_if{|key,val| val.blank? }
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'gorillib/object/blank'
|
2
|
+
module Gorillib
|
3
|
+
module Hashlike
|
4
|
+
module DeepCompact
|
5
|
+
|
6
|
+
#
|
7
|
+
# deep_compact! removes all keys with 'blank?' values in the hash, in place, recursively
|
8
|
+
#
|
9
|
+
def deep_compact!
|
10
|
+
self.each do |key, val|
|
11
|
+
val.deep_compact! if val.respond_to?(:deep_compact!)
|
12
|
+
self.delete(key) if val.blank?
|
13
|
+
end
|
14
|
+
self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Gorillib
|
2
|
+
module Hashlike
|
3
|
+
module DeepDup
|
4
|
+
# Returns a deep copy of hash.
|
5
|
+
def deep_dup
|
6
|
+
duplicate = self.dup
|
7
|
+
duplicate.each_pair do |k,v|
|
8
|
+
tv = duplicate[k]
|
9
|
+
duplicate[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_dup : v
|
10
|
+
end
|
11
|
+
duplicate
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Gorillib
|
2
|
+
module Hashlike
|
3
|
+
module DeepMerge
|
4
|
+
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
5
|
+
def deep_merge(other_hash)
|
6
|
+
dup.deep_merge!(other_hash)
|
7
|
+
end unless method_defined?(:deep_merge)
|
8
|
+
|
9
|
+
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
10
|
+
# Modifies the receiver in place.
|
11
|
+
def deep_merge!(other_hash)
|
12
|
+
other_hash.each_pair do |k,v|
|
13
|
+
tv = self[k]
|
14
|
+
self[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_merge(v) : v
|
15
|
+
end
|
16
|
+
self
|
17
|
+
end unless method_defined?(:deep_merge!)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require 'enumerator'
|
2
|
+
module Gorillib
|
3
|
+
module Hashlike
|
4
|
+
#
|
5
|
+
# Makes a Receiver thingie behave mostly like a hash.
|
6
|
+
#
|
7
|
+
# By default, the hashlike methods iterate over the receiver attributes:
|
8
|
+
# instance #keys delegates to self.class.keys which calls
|
9
|
+
# receiver_attr_names. If you want to filter our add to the keys list, you
|
10
|
+
# can just override the class-level keys method (and call super, or not):
|
11
|
+
#
|
12
|
+
# def self.keys
|
13
|
+
# super + [:firstname, :lastname] - [:fullname]
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# in addition to the below, by including Enumerable, this also adds
|
17
|
+
#
|
18
|
+
# :each_cons, :each_entry, :each_slice, :each_with_index, :each_with_object,
|
19
|
+
# :map, :collect, :collect_concat, :entries, :to_a, :flat_map, :inject, :reduce,
|
20
|
+
# :group_by, :chunk, :cycle, :partition, :reverse_each, :slice_before, :drop,
|
21
|
+
# :drop_while, :take, :take_while, :detect, :find, :find_all, :find_index, :grep,
|
22
|
+
# :all?, :any?, :none?, :one?, :first, :count, :zip :max, :max_by, :min, :min_by,
|
23
|
+
# :minmax, :minmax_by, :sort, :sort_by
|
24
|
+
#
|
25
|
+
# As opposed to hash, does *not* define
|
26
|
+
#
|
27
|
+
# default, default=, default_proc, default_proc=, shift, flatten, compare_by_identity
|
28
|
+
# compare_by_identity? rehash
|
29
|
+
#
|
30
|
+
module HashlikeViaAccessors
|
31
|
+
|
32
|
+
# Hashlike#[]
|
33
|
+
#
|
34
|
+
# Element Reference -- Retrieves the value stored for +key+.
|
35
|
+
#
|
36
|
+
# In a normal hash, a default value can be set; none is provided here.
|
37
|
+
#
|
38
|
+
# Delegates to self.send(key)
|
39
|
+
#
|
40
|
+
# @example
|
41
|
+
# hsh = { :a => 100, :b => 200 }
|
42
|
+
# hsh[:a] # => 100
|
43
|
+
# hsh[:c] # => nil
|
44
|
+
#
|
45
|
+
# @param key [Object] key to retrieve
|
46
|
+
# @return [Object] the value stored for key, nil if missing
|
47
|
+
#
|
48
|
+
def [](key)
|
49
|
+
key = convert_key(key)
|
50
|
+
self.send(key)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Hashlike#[]=
|
54
|
+
# Hashlike#store
|
55
|
+
#
|
56
|
+
# Element Assignment -- Associates the value given by +val+ with the key
|
57
|
+
# given by +key+.
|
58
|
+
#
|
59
|
+
# key should not have its value changed while it is in use as a key. In a
|
60
|
+
# normal hash, a String passed as a key will be duplicated and frozen. No such
|
61
|
+
# guarantee is provided here
|
62
|
+
#
|
63
|
+
# Delegates to self.send("key=", val)
|
64
|
+
#
|
65
|
+
# @example
|
66
|
+
# hsh = { :a => 100, :b => 200 }
|
67
|
+
# hsh[:a] = 9
|
68
|
+
# hsh[:c] = 4
|
69
|
+
# hsh # => { :a => 9, :b => 200, :c => 4 }
|
70
|
+
#
|
71
|
+
# hsh[key] = val -> val
|
72
|
+
# hsh.store(key, val) -> val
|
73
|
+
#
|
74
|
+
# @param key [Object] key to associate
|
75
|
+
# @param val [Object] value to associate it with
|
76
|
+
# @return [Object]
|
77
|
+
#
|
78
|
+
def []=(key, val)
|
79
|
+
key = convert_key(key)
|
80
|
+
self.send("#{key}=", val)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Hashlike#delete
|
84
|
+
#
|
85
|
+
# Deletes and returns the value from +hsh+ whose key is equal to +key+. If the
|
86
|
+
# optional code block is given and the key is not found, pass in the key and
|
87
|
+
# return the result of +block+.
|
88
|
+
#
|
89
|
+
# In a normal hash, a default value can be set; none is provided here.
|
90
|
+
#
|
91
|
+
# @example
|
92
|
+
# hsh = { :a => 100, :b => 200 }
|
93
|
+
# hsh.delete(:a) # => 100
|
94
|
+
# hsh.delete(:z) # => nil
|
95
|
+
# hsh.delete(:z){|el| "#{el} not found" } # => "z not found"
|
96
|
+
#
|
97
|
+
# @overload hsh.delete(key) -> val
|
98
|
+
# @param key [Object] key to remove
|
99
|
+
# @return [Object, Nil] the removed object, nil if missing
|
100
|
+
#
|
101
|
+
# @overload hsh.delete(key){|key| block } -> val
|
102
|
+
# @param key [Object] key to remove
|
103
|
+
# @yield [Object] called (with key) if key is missing
|
104
|
+
# @yieldparam key
|
105
|
+
# @return [Object, Nil] the removed object, or if missing, the return value
|
106
|
+
# of the block
|
107
|
+
#
|
108
|
+
def delete(key, &block)
|
109
|
+
key = convert_key(key)
|
110
|
+
if has_key?(key)
|
111
|
+
val = self[key]
|
112
|
+
self.send(:remove_instance_variable, "@#{key}")
|
113
|
+
val
|
114
|
+
elsif block_given?
|
115
|
+
block.call(key)
|
116
|
+
else
|
117
|
+
nil
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# # Hashlike#==
|
122
|
+
# #
|
123
|
+
# # Equality -- Two hashes are equal if they contain the same number of keys,
|
124
|
+
# # and the value corresponding to each key in the first hash is equal (using
|
125
|
+
# # <tt>==</tt>) to the value for the same key in the second. If +obj+ is not a
|
126
|
+
# # Hashlike, attempt to convert it using +to_hash+ and return <tt>obj ==
|
127
|
+
# # hsh</tt>.
|
128
|
+
# #
|
129
|
+
# # Does not take a default value comparion into account.
|
130
|
+
# #
|
131
|
+
# # @example
|
132
|
+
# # h1 = { :a => 1, :c => 2 }
|
133
|
+
# # h2 = { 7 => 35, :c => 2, :a => 1 }
|
134
|
+
# # h3 = { :a => 1, :c => 2, 7 => 35 }
|
135
|
+
# # h4 = { :a => 1, :d => 2, :f => 35 }
|
136
|
+
# # h1 == h2 # => false
|
137
|
+
# # h2 == h3 # => true
|
138
|
+
# # h3 == h4 # => false
|
139
|
+
# #
|
140
|
+
# def ==(other_hash)
|
141
|
+
# (length == other_hash.length) &&
|
142
|
+
# all?{|k,v| v == other_hash[k] }
|
143
|
+
# end
|
144
|
+
|
145
|
+
# Hashlike#keys
|
146
|
+
#
|
147
|
+
# Returns a new array populated with the keys from this hashlike.
|
148
|
+
#
|
149
|
+
# @see Hashlike#values.
|
150
|
+
#
|
151
|
+
# @example
|
152
|
+
# hsh = { :a => 100, :b => 200, :c => 300, :d => 400 }
|
153
|
+
# hsh.keys # => [:a, :b, :c, :d]
|
154
|
+
#
|
155
|
+
# @return [Array] list of keys
|
156
|
+
#
|
157
|
+
def keys
|
158
|
+
instance_variables.map{|s| convert_key(s[1..-1]) }
|
159
|
+
end
|
160
|
+
|
161
|
+
protected
|
162
|
+
def convert_key(key)
|
163
|
+
raise ArgumentError, "Keys for #{self.class} must be symbols, strings or respond to #to_sym" unless key.respond_to?(:to_sym)
|
164
|
+
key.to_sym
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Gorillib
|
2
|
+
module Hashlike
|
3
|
+
module Keys
|
4
|
+
# Return a new hash with all keys converted to strings.
|
5
|
+
def stringify_keys
|
6
|
+
dup.stringify_keys!
|
7
|
+
end unless method_defined?(:stringify_keys)
|
8
|
+
|
9
|
+
# Destructively convert all keys to strings.
|
10
|
+
def stringify_keys!
|
11
|
+
keys.each do |key|
|
12
|
+
self[key.to_s] = delete(key)
|
13
|
+
end
|
14
|
+
self
|
15
|
+
end unless method_defined?(:stringify_keys!)
|
16
|
+
|
17
|
+
# Return a new hash with all keys converted to symbols, as long as
|
18
|
+
# they respond to +to_sym+.
|
19
|
+
def symbolize_keys
|
20
|
+
dup.symbolize_keys!
|
21
|
+
end unless method_defined?(:symbolize_keys)
|
22
|
+
|
23
|
+
# Destructively convert all keys to symbols, as long as they respond
|
24
|
+
# to +to_sym+.
|
25
|
+
def symbolize_keys!
|
26
|
+
keys.each do |key|
|
27
|
+
self[(key.to_sym rescue key) || key] = delete(key)
|
28
|
+
end
|
29
|
+
self
|
30
|
+
end unless method_defined?(:symbolize_keys!)
|
31
|
+
|
32
|
+
# Validate all keys in a hash match *valid keys, raising ArgumentError on a mismatch.
|
33
|
+
# Note that keys are NOT treated indifferently, meaning if you use strings for keys but assert symbols
|
34
|
+
# as keys, this will fail.
|
35
|
+
#
|
36
|
+
# ==== Examples
|
37
|
+
# { :name => "Rob", :years => "28" }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key(s): years"
|
38
|
+
# { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key(s): name, age"
|
39
|
+
# { :name => "Rob", :age => "28" }.assert_valid_keys(:name, :age) # => passes, raises nothing
|
40
|
+
def assert_valid_keys(*valid_keys)
|
41
|
+
unknown_keys = keys - [valid_keys].flatten
|
42
|
+
raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
|
43
|
+
end unless method_defined?(:assert_valid_keys)
|
44
|
+
end
|
45
|
+
# # @return [Hash] the object as a Hash with symbolized keys.
|
46
|
+
# def symbolize_keys() to_hash ; end
|
47
|
+
# # @return [Hash] the object as a Hash with string keys.
|
48
|
+
# def stringify_keys() to_hash.stringify_keys ; end
|
49
|
+
#
|
50
|
+
# # Used to provide the same interface as Hash.
|
51
|
+
# # @return This object unchanged.
|
52
|
+
# def symbolize_keys!; self end
|
53
|
+
#
|
54
|
+
# # Used to provide the same interface as Hash.
|
55
|
+
# # @return This object unchanged.
|
56
|
+
# def stringify_keys!; self end
|
57
|
+
#
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Gorillib
|
2
|
+
module Hashlike
|
3
|
+
module ReverseMerge
|
4
|
+
# Allows for reverse merging two hashes where the keys in the calling hash take precedence over those
|
5
|
+
# in the <tt>other_hash</tt>. This is particularly useful for initializing an option hash with default values:
|
6
|
+
#
|
7
|
+
# def setup(options = {})
|
8
|
+
# options.reverse_merge! :size => 25, :velocity => 10
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# Using <tt>merge</tt>, the above example would look as follows:
|
12
|
+
#
|
13
|
+
# def setup(options = {})
|
14
|
+
# { :size => 25, :velocity => 10 }.merge(options)
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# The default <tt>:size</tt> and <tt>:velocity</tt> are only set if the +options+ hash passed in doesn't already
|
18
|
+
# have the respective key.
|
19
|
+
def reverse_merge(other_hash)
|
20
|
+
other_hash.merge(self)
|
21
|
+
end unless method_defined?(:reverse_merge)
|
22
|
+
|
23
|
+
# Performs the opposite of <tt>merge</tt>, with the keys and values from the first hash taking precedence over the second.
|
24
|
+
# Modifies the receiver in place.
|
25
|
+
def reverse_merge!(other_hash)
|
26
|
+
merge!( other_hash ){|k,o,n| o }
|
27
|
+
end unless method_defined?(:reverse_merge!)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Gorillib
|
2
|
+
module Hashlike
|
3
|
+
module Slice
|
4
|
+
# Slice a hash to include only the given allowed_keys. This is useful for
|
5
|
+
# limiting an options hash to valid keys before passing to a method:
|
6
|
+
#
|
7
|
+
# def search(criteria = {})
|
8
|
+
# assert_valid_keys(:mass, :velocity, :time)
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# search(options.slice(:mass, :velocity, :time))
|
12
|
+
#
|
13
|
+
# If you have an array of keys you want to limit to, you should splat them:
|
14
|
+
#
|
15
|
+
# valid_keys = [:mass, :velocity, :time]
|
16
|
+
# search(options.slice(*valid_keys))
|
17
|
+
def slice(*allowed_keys)
|
18
|
+
allowed_keys = allowed_keys.map!{|key| convert_key(key) } if respond_to?(:convert_key)
|
19
|
+
hash = self.class.new
|
20
|
+
allowed_keys.each{|k| hash[k] = self[k] if has_key?(k) }
|
21
|
+
hash
|
22
|
+
end unless method_defined?(:slice)
|
23
|
+
|
24
|
+
# Replaces the hash with only the given allowed_keys.
|
25
|
+
# Returns a hash containing the removed key/value pairs
|
26
|
+
# @example
|
27
|
+
# hsh = {:a => 1, :b => 2, :c => 3, :d => 4}
|
28
|
+
# hsh.slice!(:a, :b)
|
29
|
+
# # => {:c => 3, :d =>4}
|
30
|
+
# hsh
|
31
|
+
# # => {:a => 1, :b => 2}
|
32
|
+
def slice!(*allowed_keys)
|
33
|
+
allowed_keys = allowed_keys.map!{|key| convert_key(key) } if respond_to?(:convert_key)
|
34
|
+
omit = slice(*self.keys - allowed_keys)
|
35
|
+
hash = slice(*allowed_keys)
|
36
|
+
replace(hash)
|
37
|
+
omit
|
38
|
+
end unless method_defined?(:slice!)
|
39
|
+
|
40
|
+
# This also works, and doesn't require #replace method, but is uglier and
|
41
|
+
# wasn't written by Railsians. I'm not sure that slice! is interesting if
|
42
|
+
# you're a duck-typed Hash but not is_a?(Hash), so we'll just leave it at the
|
43
|
+
# active_record implementation.
|
44
|
+
#
|
45
|
+
# def slice!(*allowed_keys)
|
46
|
+
# allowed_keys = allowed_keys.map!{|key| convert_key(key) } if respond_to?(:convert_key)
|
47
|
+
# omit_keys = self.keys - allowed_keys
|
48
|
+
# omit = slice(*omit_keys)
|
49
|
+
# omit_keys.each{|k| delete(k) }
|
50
|
+
# omit
|
51
|
+
# end
|
52
|
+
|
53
|
+
# Removes the given allowed_keys from the hash
|
54
|
+
# Returns a hash containing the removed key/value pairs
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
# hsh = {:a => 1, :b => 2, :c => 3, :d => 4}
|
58
|
+
# hsh.extract!(:a, :b)
|
59
|
+
# # => {:a => 1, :b => 2}
|
60
|
+
# hsh
|
61
|
+
# # => {:c => 3, :d =>4}
|
62
|
+
def extract!(*allowed_keys)
|
63
|
+
slice!(*self.keys - allowed_keys)
|
64
|
+
end unless method_defined?(:extract!)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|