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
data/CHANGELOG.textile
CHANGED
data/README.textile
CHANGED
@@ -1,15 +1,23 @@
|
|
1
|
+
|
1
2
|
h2. Gorillib: infochimps' lightweight subset of ruby convenience methods
|
2
3
|
|
3
|
-
|
4
|
-
* No dependencies unless audaciously advertised.
|
5
|
-
* Compatibile with active_record and extlib
|
4
|
+
We love the conveniences provided by active_support and extlib, we just don't love them at the same time and on top of each other. active_support is slow to load, has many dependencies, and is all intertwingled. We had too many collisions between active_support 2.x and 3.x and extlib.
|
6
5
|
|
6
|
+
What gorillib gives you is clarity over what features are brought in. If you want to *just* get <code>Object#blank?</code>, just <code>require 'gorillib/object/blank'</code>. No dependencies, no codependents.
|
7
7
|
|
8
|
-
|
8
|
+
* No creep: include only what you need
|
9
|
+
* No dependencies unless audaciously advertised.
|
10
|
+
* Upwards compatible with active_record and extlib
|
11
|
+
- the active_support components have significantly more robust internationalization, and some functions have rich option sets in active_support vs. basic functionality in gorillib. So the rule is if you were happy with gorillib you'll be happy with active_support, but not vice-versa.
|
9
12
|
|
10
|
-
|
13
|
+
h3. require 'gorillib/receiver'
|
11
14
|
|
15
|
+
Gorillib has at least one powerful addition to the canon: the receiver mixin.
|
12
16
|
|
17
|
+
* lightweight
|
18
|
+
* gives you weak type safety but doesn't jack around with setters/getters.
|
19
|
+
* object/hash semantics
|
20
|
+
|
13
21
|
h3. require 'gorillib'
|
14
22
|
|
15
23
|
* require 'gorrillib/base'
|
@@ -19,28 +27,30 @@ h3. require 'gorillib/base'
|
|
19
27
|
requires the following libraries:
|
20
28
|
|
21
29
|
* gorillib/object/blank
|
22
|
-
* gorillib/array/extract_options
|
23
30
|
* gorillib/hash/reverse_merge
|
24
31
|
* gorillib/hash/compact
|
25
|
-
* gorillib/array/
|
32
|
+
* gorillib/array/compact_blank
|
33
|
+
* gorillib/object/try
|
26
34
|
|
27
35
|
h3. require 'gorillib/some'
|
28
36
|
|
29
37
|
requires @gorillib/base@ and the following additional libraries:
|
30
38
|
|
39
|
+
* gorillib/logger/log.rb
|
31
40
|
* set
|
32
41
|
* time
|
33
42
|
* date
|
43
|
+
* gorillib/array/extract_options
|
34
44
|
* gorillib/enumerable/sum
|
35
45
|
* gorillib/datetime/flat
|
36
|
-
* gorillib/datetime/
|
46
|
+
* gorillib/datetime/parse
|
37
47
|
* gorillib/hash/zip
|
38
48
|
* gorillib/hash/slice
|
39
49
|
* gorillib/hash/keys
|
40
|
-
* gorillib/metaprogramming/singleton_class
|
41
|
-
* gorillib/metaprogramming/remove_method
|
42
50
|
* gorillib/metaprogramming/class_attribute
|
43
51
|
* gorillib/metaprogramming/cattr_accessor
|
52
|
+
* gorillib/metaprogramming/singleton_class
|
53
|
+
* gorillib/metaprogramming/remove_method
|
44
54
|
|
45
55
|
---------------------------------------------------------------------------
|
46
56
|
|
@@ -51,13 +61,15 @@ h3. gorillib/array
|
|
51
61
|
- Hash extractable_options? (helper method)
|
52
62
|
* *gorrillib/array/compact_blank*
|
53
63
|
- Array compact_blank, compact_blank!
|
64
|
+
* *gorrillib/array/deep_compact*
|
65
|
+
- Array deep_compact, deep_compact!
|
54
66
|
|
55
67
|
h3. gorillib/datetime
|
56
68
|
|
57
69
|
* *gorillib/datetime/flat*
|
58
70
|
- Date, Time to_flat
|
59
71
|
* *gorillib/datetime/parse*
|
60
|
-
-
|
72
|
+
- Time parse_safely
|
61
73
|
|
62
74
|
h3. gorillib/enumerable
|
63
75
|
|
@@ -68,6 +80,8 @@ h3. gorillib/hash
|
|
68
80
|
|
69
81
|
* *gorillib/hash/compact*
|
70
82
|
- Hash compact, compact!, compact_blank, compact_blank!
|
83
|
+
* *gorrilib/hash/deep_compact*
|
84
|
+
- Hash deep_compact, deep_compact!
|
71
85
|
* *gorrilib/hash/deep_merge*
|
72
86
|
- Hash deep_merge, deep_merge!
|
73
87
|
* *gorillib/hash/keys*
|
@@ -102,10 +116,19 @@ h3. gorillib/metaprogramming
|
|
102
116
|
* *gorillib/metaprogramming/delegation*
|
103
117
|
- Module# delegate
|
104
118
|
|
119
|
+
h3. gorillib/numeric
|
120
|
+
|
121
|
+
* *gorillib/numeric/clamp*
|
122
|
+
- Numeric clamp -- coerce a number to lie within a certain min/max
|
123
|
+
|
105
124
|
h3. gorillib/object
|
106
125
|
|
107
126
|
* *gorillib/object/blank*
|
108
127
|
- Object blank?, present? (and specialized for all other classes)
|
128
|
+
* *gorillib/object/try*
|
129
|
+
- Object try
|
130
|
+
* *gorillib/object/try_dup*
|
131
|
+
- Object try_dup
|
109
132
|
|
110
133
|
h3. gorillib/string
|
111
134
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/gorillib.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{gorillib}
|
8
|
-
s.version = "0.0
|
8
|
+
s.version = "0.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Infochimps"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-06-07}
|
13
13
|
s.description = %q{Gorillib: infochimps lightweight subset of ruby convenience methods}
|
14
14
|
s.email = %q{coders@infochimps.org}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -32,17 +32,29 @@ Gem::Specification.new do |s|
|
|
32
32
|
"lib/gorillib/array/deep_compact.rb",
|
33
33
|
"lib/gorillib/array/extract_options.rb",
|
34
34
|
"lib/gorillib/base.rb",
|
35
|
-
"lib/gorillib/datetime/#flat.rb#",
|
36
35
|
"lib/gorillib/datetime/flat.rb",
|
37
36
|
"lib/gorillib/datetime/parse.rb",
|
38
37
|
"lib/gorillib/enumerable/sum.rb",
|
39
38
|
"lib/gorillib/hash/compact.rb",
|
40
39
|
"lib/gorillib/hash/deep_compact.rb",
|
40
|
+
"lib/gorillib/hash/deep_dup.rb",
|
41
41
|
"lib/gorillib/hash/deep_merge.rb",
|
42
|
+
"lib/gorillib/hash/indifferent_access.rb",
|
42
43
|
"lib/gorillib/hash/keys.rb",
|
43
44
|
"lib/gorillib/hash/reverse_merge.rb",
|
44
45
|
"lib/gorillib/hash/slice.rb",
|
46
|
+
"lib/gorillib/hash/tree_merge.rb",
|
45
47
|
"lib/gorillib/hash/zip.rb",
|
48
|
+
"lib/gorillib/hashlike.rb",
|
49
|
+
"lib/gorillib/hashlike/compact.rb",
|
50
|
+
"lib/gorillib/hashlike/deep_compact.rb",
|
51
|
+
"lib/gorillib/hashlike/deep_dup.rb",
|
52
|
+
"lib/gorillib/hashlike/deep_merge.rb",
|
53
|
+
"lib/gorillib/hashlike/hashlike_via_accessors.rb",
|
54
|
+
"lib/gorillib/hashlike/keys.rb",
|
55
|
+
"lib/gorillib/hashlike/reverse_merge.rb",
|
56
|
+
"lib/gorillib/hashlike/slice.rb",
|
57
|
+
"lib/gorillib/hashlike/tree_merge.rb",
|
46
58
|
"lib/gorillib/logger/log.rb",
|
47
59
|
"lib/gorillib/metaprogramming/aliasing.rb",
|
48
60
|
"lib/gorillib/metaprogramming/cattr_accessor.rb",
|
@@ -55,11 +67,21 @@ Gem::Specification.new do |s|
|
|
55
67
|
"lib/gorillib/object/blank.rb",
|
56
68
|
"lib/gorillib/object/try.rb",
|
57
69
|
"lib/gorillib/object/try_dup.rb",
|
70
|
+
"lib/gorillib/receiver.rb",
|
71
|
+
"lib/gorillib/receiver/active_model_shim.rb",
|
72
|
+
"lib/gorillib/receiver/acts_as_hash.rb",
|
73
|
+
"lib/gorillib/receiver/acts_as_loadable.rb",
|
74
|
+
"lib/gorillib/receiver/tree_diff.rb",
|
75
|
+
"lib/gorillib/receiver/validations.rb",
|
58
76
|
"lib/gorillib/some.rb",
|
59
77
|
"lib/gorillib/string/constantize.rb",
|
60
78
|
"lib/gorillib/string/human.rb",
|
61
79
|
"lib/gorillib/string/inflections.rb",
|
62
80
|
"lib/gorillib/string/truncate.rb",
|
81
|
+
"lib/gorillib/struct/acts_as_hash.rb",
|
82
|
+
"lib/gorillib/struct/hashlike_iteration.rb",
|
83
|
+
"notes/fancy_hashes_and_receivers.textile",
|
84
|
+
"notes/hash_rdocs.textile",
|
63
85
|
"spec/array/compact_blank_spec.rb",
|
64
86
|
"spec/array/extract_options_spec.rb",
|
65
87
|
"spec/datetime/flat_spec.rb",
|
@@ -68,10 +90,16 @@ Gem::Specification.new do |s|
|
|
68
90
|
"spec/hash/compact_spec.rb",
|
69
91
|
"spec/hash/deep_compact_spec.rb",
|
70
92
|
"spec/hash/deep_merge_spec.rb",
|
93
|
+
"spec/hash/indifferent_access_spec.rb",
|
71
94
|
"spec/hash/keys_spec.rb",
|
72
95
|
"spec/hash/reverse_merge_spec.rb",
|
73
96
|
"spec/hash/slice_spec.rb",
|
74
97
|
"spec/hash/zip_spec.rb",
|
98
|
+
"spec/hashlike/behave_same_as_hash_spec.rb",
|
99
|
+
"spec/hashlike/hashlike_behavior_spec.rb",
|
100
|
+
"spec/hashlike/hashlike_via_accessors_fuzzing_spec.rb",
|
101
|
+
"spec/hashlike/hashlike_via_accessors_spec.rb",
|
102
|
+
"spec/hashlike_spec.rb",
|
75
103
|
"spec/logger/log_spec.rb",
|
76
104
|
"spec/metaprogramming/aliasing_spec.rb",
|
77
105
|
"spec/metaprogramming/cattr_accessor_spec.rb",
|
@@ -83,13 +111,25 @@ Gem::Specification.new do |s|
|
|
83
111
|
"spec/object/blank_spec.rb",
|
84
112
|
"spec/object/try_dup_spec.rb",
|
85
113
|
"spec/object/try_spec.rb",
|
114
|
+
"spec/receiver/acts_as_hash_spec.rb",
|
115
|
+
"spec/receiver_spec.rb",
|
86
116
|
"spec/spec_helper.rb",
|
87
117
|
"spec/string/constantize_spec.rb",
|
88
118
|
"spec/string/human_spec.rb",
|
89
119
|
"spec/string/inflections_spec.rb",
|
90
120
|
"spec/string/inflector_test_cases.rb",
|
91
121
|
"spec/string/truncate_spec.rb",
|
92
|
-
"spec/
|
122
|
+
"spec/struct/acts_as_hash_fuzz_spec.rb",
|
123
|
+
"spec/struct/acts_as_hash_spec.rb",
|
124
|
+
"spec/support/hashlike_fuzzing_helper.rb",
|
125
|
+
"spec/support/hashlike_helper.rb",
|
126
|
+
"spec/support/hashlike_struct_helper.rb",
|
127
|
+
"spec/support/hashlike_via_delegation.rb",
|
128
|
+
"spec/support/kcode_test_helper.rb",
|
129
|
+
"spec/support/matchers/be_array_eql.rb",
|
130
|
+
"spec/support/matchers/be_hash_eql.rb",
|
131
|
+
"spec/support/matchers/enumerate_method.rb",
|
132
|
+
"spec/support/matchers/evaluate_to_true.rb"
|
93
133
|
]
|
94
134
|
s.homepage = %q{http://infochimps.com/labs}
|
95
135
|
s.licenses = ["MIT"]
|
@@ -105,10 +145,16 @@ Gem::Specification.new do |s|
|
|
105
145
|
"spec/hash/compact_spec.rb",
|
106
146
|
"spec/hash/deep_compact_spec.rb",
|
107
147
|
"spec/hash/deep_merge_spec.rb",
|
148
|
+
"spec/hash/indifferent_access_spec.rb",
|
108
149
|
"spec/hash/keys_spec.rb",
|
109
150
|
"spec/hash/reverse_merge_spec.rb",
|
110
151
|
"spec/hash/slice_spec.rb",
|
111
152
|
"spec/hash/zip_spec.rb",
|
153
|
+
"spec/hashlike/behave_same_as_hash_spec.rb",
|
154
|
+
"spec/hashlike/hashlike_behavior_spec.rb",
|
155
|
+
"spec/hashlike/hashlike_via_accessors_fuzzing_spec.rb",
|
156
|
+
"spec/hashlike/hashlike_via_accessors_spec.rb",
|
157
|
+
"spec/hashlike_spec.rb",
|
112
158
|
"spec/logger/log_spec.rb",
|
113
159
|
"spec/metaprogramming/aliasing_spec.rb",
|
114
160
|
"spec/metaprogramming/cattr_accessor_spec.rb",
|
@@ -120,13 +166,25 @@ Gem::Specification.new do |s|
|
|
120
166
|
"spec/object/blank_spec.rb",
|
121
167
|
"spec/object/try_dup_spec.rb",
|
122
168
|
"spec/object/try_spec.rb",
|
169
|
+
"spec/receiver/acts_as_hash_spec.rb",
|
170
|
+
"spec/receiver_spec.rb",
|
123
171
|
"spec/spec_helper.rb",
|
124
172
|
"spec/string/constantize_spec.rb",
|
125
173
|
"spec/string/human_spec.rb",
|
126
174
|
"spec/string/inflections_spec.rb",
|
127
175
|
"spec/string/inflector_test_cases.rb",
|
128
176
|
"spec/string/truncate_spec.rb",
|
129
|
-
"spec/
|
177
|
+
"spec/struct/acts_as_hash_fuzz_spec.rb",
|
178
|
+
"spec/struct/acts_as_hash_spec.rb",
|
179
|
+
"spec/support/hashlike_fuzzing_helper.rb",
|
180
|
+
"spec/support/hashlike_helper.rb",
|
181
|
+
"spec/support/hashlike_struct_helper.rb",
|
182
|
+
"spec/support/hashlike_via_delegation.rb",
|
183
|
+
"spec/support/kcode_test_helper.rb",
|
184
|
+
"spec/support/matchers/be_array_eql.rb",
|
185
|
+
"spec/support/matchers/be_hash_eql.rb",
|
186
|
+
"spec/support/matchers/enumerate_method.rb",
|
187
|
+
"spec/support/matchers/evaluate_to_true.rb"
|
130
188
|
]
|
131
189
|
|
132
190
|
if s.respond_to? :specification_version then
|
@@ -25,7 +25,7 @@ unless Enumerable.method_defined?(:sum)
|
|
25
25
|
else
|
26
26
|
inject { |sum, element| sum + element } || identity
|
27
27
|
end
|
28
|
-
end
|
28
|
+
end unless method_defined?(:sum)
|
29
29
|
end
|
30
30
|
|
31
31
|
class Range #:nodoc:
|
@@ -35,6 +35,6 @@ unless Enumerable.method_defined?(:sum)
|
|
35
35
|
return super if block_given? || !(first.instance_of?(Integer) && last.instance_of?(Integer))
|
36
36
|
actual_last = exclude_end? ? (last - 1) : last
|
37
37
|
(actual_last - first + 1) * (actual_last + first) / 2
|
38
|
-
end
|
38
|
+
end unless method_defined?(:sum)
|
39
39
|
end
|
40
40
|
end
|
@@ -1,31 +1,4 @@
|
|
1
|
-
require 'gorillib/
|
2
|
-
|
1
|
+
require 'gorillib/hashlike/compact'
|
3
2
|
class Hash
|
4
|
-
|
5
|
-
# remove all key-value pairs where the value is nil
|
6
|
-
#
|
7
|
-
def compact
|
8
|
-
reject{|key,val| val.nil? }
|
9
|
-
end unless method_defined?(:compact)
|
10
|
-
|
11
|
-
#
|
12
|
-
# Replace the hash with its compacted self
|
13
|
-
#
|
14
|
-
def compact!
|
15
|
-
replace(compact)
|
16
|
-
end unless method_defined?(:compact!)
|
17
|
-
|
18
|
-
#
|
19
|
-
# remove all key-value pairs where the value is blank
|
20
|
-
#
|
21
|
-
def compact_blank
|
22
|
-
reject{|key,val| val.blank? }
|
23
|
-
end unless method_defined?(:compact_blank)
|
24
|
-
|
25
|
-
#
|
26
|
-
# Replace the hash with its compact_blank'ed self
|
27
|
-
#
|
28
|
-
def compact_blank!
|
29
|
-
replace(compact_blank)
|
30
|
-
end unless method_defined?(:compact_blank!)
|
3
|
+
include Gorillib::Hashlike::Compact
|
31
4
|
end
|
@@ -1,14 +1,4 @@
|
|
1
|
-
require 'gorillib/
|
2
|
-
|
3
|
-
#
|
4
|
-
# deep_compact! removes all keys with 'blank?' values in the hash, in place, recursively
|
5
|
-
#
|
1
|
+
require 'gorillib/hashlike/deep_compact'
|
6
2
|
class Hash
|
7
|
-
|
8
|
-
self.each do |key, val|
|
9
|
-
val.deep_compact! if val.respond_to?(:deep_compact!)
|
10
|
-
self.delete(key) if val.blank?
|
11
|
-
end
|
12
|
-
self
|
13
|
-
end
|
3
|
+
include Gorillib::Hashlike::DeepCompact
|
14
4
|
end
|
@@ -1,16 +1,4 @@
|
|
1
|
+
require 'gorillib/hashlike/deep_merge'
|
1
2
|
class Hash
|
2
|
-
|
3
|
-
def deep_merge(other_hash)
|
4
|
-
dup.deep_merge!(other_hash)
|
5
|
-
end unless method_defined?(:deep_merge)
|
6
|
-
|
7
|
-
# Returns a new hash with +self+ and +other_hash+ merged recursively.
|
8
|
-
# Modifies the receiver in place.
|
9
|
-
def deep_merge!(other_hash)
|
10
|
-
other_hash.each_pair do |k,v|
|
11
|
-
tv = self[k]
|
12
|
-
self[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_merge(v) : v
|
13
|
-
end
|
14
|
-
self
|
15
|
-
end unless method_defined?(:deep_merge!)
|
3
|
+
include Gorillib::Hashlike::DeepMerge
|
16
4
|
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
require 'gorillib/hash/keys'
|
2
|
+
|
3
|
+
# This class has dubious semantics and we only have it so that
|
4
|
+
# people can write <tt>params[:key]</tt> instead of <tt>params['key']</tt>
|
5
|
+
# and they get the same value for both keys.
|
6
|
+
|
7
|
+
module Gorillib
|
8
|
+
class HashWithIndifferentAccess < Hash
|
9
|
+
def extractable_options?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
|
13
|
+
def with_indifferent_access
|
14
|
+
dup
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(constructor = {})
|
18
|
+
if constructor.is_a?(Hash)
|
19
|
+
super()
|
20
|
+
update(constructor)
|
21
|
+
else
|
22
|
+
super(constructor)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def default(key = nil)
|
27
|
+
if include?(converted = convert_key(key))
|
28
|
+
self[converted]
|
29
|
+
else
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.new_from_hash_copying_default(hash)
|
35
|
+
new(hash).tap do |new_hash|
|
36
|
+
new_hash.default = hash.default
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
alias_method(:regular_writer, :[]=) unless method_defined?(:regular_writer)
|
41
|
+
alias_method :regular_update, :update unless method_defined?(:regular_update)
|
42
|
+
|
43
|
+
# Assigns a new value to the hash:
|
44
|
+
#
|
45
|
+
# hash = HashWithIndifferentAccess.new
|
46
|
+
# hash[:key] = "value"
|
47
|
+
#
|
48
|
+
def []=(key, value)
|
49
|
+
regular_writer(convert_key(key), convert_value(value))
|
50
|
+
end
|
51
|
+
|
52
|
+
alias_method :store, :[]=
|
53
|
+
|
54
|
+
# Updates the instantized hash with values from the second:
|
55
|
+
#
|
56
|
+
# hash_1 = HashWithIndifferentAccess.new
|
57
|
+
# hash_1[:key] = "value"
|
58
|
+
#
|
59
|
+
# hash_2 = HashWithIndifferentAccess.new
|
60
|
+
# hash_2[:key] = "New Value!"
|
61
|
+
#
|
62
|
+
# hash_1.update(hash_2) # => {"key"=>"New Value!"}
|
63
|
+
#
|
64
|
+
def update(other_hash)
|
65
|
+
raise TypeError, "can't convert #{other_hash.nil? ? 'nil' : other_hash.class} into Hash" unless other_hash.respond_to?(:each_pair)
|
66
|
+
if other_hash.is_a? HashWithIndifferentAccess
|
67
|
+
super(other_hash)
|
68
|
+
else
|
69
|
+
other_hash.each_pair{|key, value| regular_writer(convert_key(key), convert_value(value)) }
|
70
|
+
self
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
alias_method :merge!, :update
|
75
|
+
|
76
|
+
# Checks the hash for a key matching the argument passed in:
|
77
|
+
#
|
78
|
+
# hash = HashWithIndifferentAccess.new
|
79
|
+
# hash["key"] = "value"
|
80
|
+
# hash.key? :key # => true
|
81
|
+
# hash.key? "key" # => true
|
82
|
+
#
|
83
|
+
def key?(key)
|
84
|
+
super(convert_key(key))
|
85
|
+
end
|
86
|
+
|
87
|
+
alias_method :include?, :key?
|
88
|
+
alias_method :has_key?, :key?
|
89
|
+
alias_method :member?, :key?
|
90
|
+
|
91
|
+
# Fetches the value for the specified key, same as doing hash[key]
|
92
|
+
def fetch(key, *extras)
|
93
|
+
super(convert_key(key), *extras)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Returns an array of the values at the specified indices:
|
97
|
+
#
|
98
|
+
# hash = HashWithIndifferentAccess.new
|
99
|
+
# hash[:a] = "x"
|
100
|
+
# hash[:b] = "y"
|
101
|
+
# hash.values_at("a", "b") # => ["x", "y"]
|
102
|
+
#
|
103
|
+
def values_at(*indices)
|
104
|
+
indices.collect {|key| self[convert_key(key)]}
|
105
|
+
end
|
106
|
+
|
107
|
+
# Returns an exact copy of the hash.
|
108
|
+
def dup
|
109
|
+
self.class.new(self).tap do |new_hash|
|
110
|
+
new_hash.default = default
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
|
115
|
+
# Does not overwrite the existing hash.
|
116
|
+
def merge(hash)
|
117
|
+
self.dup.update(hash)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
|
121
|
+
# This overloaded definition prevents returning a regular hash, if reverse_merge is called on a <tt>HashWithDifferentAccess</tt>.
|
122
|
+
def reverse_merge(other_hash)
|
123
|
+
super self.class.new_from_hash_copying_default(other_hash)
|
124
|
+
end
|
125
|
+
|
126
|
+
def reverse_merge!(other_hash)
|
127
|
+
replace(reverse_merge( other_hash ))
|
128
|
+
end
|
129
|
+
|
130
|
+
# Removes a specified key from the hash.
|
131
|
+
def delete(key)
|
132
|
+
super(convert_key(key))
|
133
|
+
end
|
134
|
+
|
135
|
+
def stringify_keys!; self end
|
136
|
+
def stringify_keys; dup end
|
137
|
+
undef_method :symbolize_keys! if method_defined?(:symbolize_keys!)
|
138
|
+
def symbolize_keys; to_hash.symbolize_keys end
|
139
|
+
def to_options!; self end
|
140
|
+
|
141
|
+
# Convert to a Hash with String keys.
|
142
|
+
def to_hash
|
143
|
+
Hash.new(default).merge!(self)
|
144
|
+
end
|
145
|
+
|
146
|
+
def assoc key
|
147
|
+
key = convert_key(key)
|
148
|
+
return unless has_key?(key)
|
149
|
+
[key, self[key]]
|
150
|
+
end
|
151
|
+
|
152
|
+
def rassoc val
|
153
|
+
key = key(val) or return
|
154
|
+
[key, self[key]]
|
155
|
+
end
|
156
|
+
|
157
|
+
protected
|
158
|
+
def convert_key(key)
|
159
|
+
key.kind_of?(Symbol) ? key.to_s : key
|
160
|
+
end
|
161
|
+
|
162
|
+
def convert_value(value)
|
163
|
+
if value.is_a? Hash
|
164
|
+
value.nested_under_indifferent_access
|
165
|
+
elsif value.is_a?(Array)
|
166
|
+
value.dup.replace(value.map{|e| convert_value(e) })
|
167
|
+
else
|
168
|
+
value
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
module Gorillib
|
176
|
+
class HashWithIndifferentSymbolKeys < Gorillib::HashWithIndifferentAccess
|
177
|
+
|
178
|
+
def convert_key key
|
179
|
+
return key if key.is_a?(Fixnum)
|
180
|
+
key.respond_to?(:to_sym) ? key.to_sym : key
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class Hash
|
186
|
+
|
187
|
+
# Returns an +ActiveSupport::HashWithIndifferentAccess+ out of its receiver:
|
188
|
+
#
|
189
|
+
# {:a => 1}.with_indifferent_access["a"] # => 1
|
190
|
+
#
|
191
|
+
def with_indifferent_access
|
192
|
+
Gorillib::HashWithIndifferentAccess.new_from_hash_copying_default(self)
|
193
|
+
end
|
194
|
+
|
195
|
+
# Called when object is nested under an object that receives
|
196
|
+
# #with_indifferent_access. This method with be called on the current object
|
197
|
+
# by the enclosing object and is aliased to #with_indifferent_access by
|
198
|
+
# default. Subclasses of Hash may overwrite this method to return +self+ if
|
199
|
+
# converting to an +ActiveSupport::HashWithIndifferentAccess+ would not be
|
200
|
+
# desirable.
|
201
|
+
#
|
202
|
+
# b = {:b => 1}
|
203
|
+
# {:a => b}.with_indifferent_access["a"] # calls b.nested_under_indifferent_access
|
204
|
+
#
|
205
|
+
alias nested_under_indifferent_access with_indifferent_access
|
206
|
+
end
|
207
|
+
|