hash_extend 0.0.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +265 -2
- data/lib/hash_extend/version.rb +1 -1
- data/lib/hash_extend.rb +102 -7
- metadata +21 -41
data/README.md
CHANGED
@@ -1,2 +1,265 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# HashExtend
|
2
|
+
|
3
|
+
Extend ruby Hash. No override.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'hash_extend'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install hash_extend
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
### stealth_delete
|
22
|
+
|
23
|
+
Delete key(s) passed by, but return the hash instead of the deleted value
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
stealth_delete! *keys
|
27
|
+
stealth_delete *keys
|
28
|
+
```
|
29
|
+
|
30
|
+
Demo
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
{:one=>1, :two=>2, :three=>3}.stealth_delete :one
|
34
|
+
#=> {:two=>2, :three=>3}
|
35
|
+
|
36
|
+
{:one=>1, :two=>2, :three=>3}.stealth_delete :one, :three
|
37
|
+
#=> {:two=>2}
|
38
|
+
|
39
|
+
{:one=>1, :two=>2, :three=>3}.stealth_delete :four
|
40
|
+
#=> {:one=>1, :two=>2, :three=>3}
|
41
|
+
|
42
|
+
{:one=>1, :two=>2, :three=>3}.stealth_delete :one, :four
|
43
|
+
#=> {:two=>2, :three=>3}
|
44
|
+
```
|
45
|
+
|
46
|
+
Code
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
def stealth_delete! *keys
|
50
|
+
keys.each do |key|
|
51
|
+
delete key
|
52
|
+
end
|
53
|
+
return self
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
|
58
|
+
### map_values
|
59
|
+
|
60
|
+
Update values through block
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
map_values!
|
64
|
+
map_values
|
65
|
+
```
|
66
|
+
|
67
|
+
Demo
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
# square values
|
71
|
+
{:one=>1, :two=>2, :three=>3}.map_values{ |value| value ** 2 }
|
72
|
+
#=> {:one=>1, :two=>4, :three=>9}
|
73
|
+
```
|
74
|
+
|
75
|
+
Code
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
def map_values!
|
79
|
+
self.each do |key, value|
|
80
|
+
self[key] = yield value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
```
|
84
|
+
|
85
|
+
|
86
|
+
### map_keys
|
87
|
+
|
88
|
+
Update keys through block
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
map_keys!
|
92
|
+
map_keys
|
93
|
+
```
|
94
|
+
|
95
|
+
Demo
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
{"one"=>1, "two"=>2, "three"=>3}.map_keys(&:to_sym)
|
99
|
+
#=> {:one=>1, :two=>2, :three=>3}
|
100
|
+
```
|
101
|
+
|
102
|
+
Code
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
def map_keys
|
106
|
+
self.inject({}) do |hash, (key, value)|
|
107
|
+
hash[yield key] = value; hash
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def map_keys! &block
|
112
|
+
to_map = self.dup
|
113
|
+
self.clear.merge! to_map.map_keys &block
|
114
|
+
end
|
115
|
+
```
|
116
|
+
|
117
|
+
Perfomances : Generaly, use the "!" is faster than the "no self modification" methods. Cause the last one used to "dup" the object. As we can't modify keys hash during iteration, here it's the reverse.
|
118
|
+
|
119
|
+
|
120
|
+
### delete_many
|
121
|
+
|
122
|
+
Delete severals keys in one
|
123
|
+
|
124
|
+
Demo
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
h = Hash[:one, 1, :two, 2, :three, 3] #=> {:one=>1, :two=>2, :three=>3}
|
128
|
+
h.delete_many(:un, :trois) #=> [1, 3]
|
129
|
+
h #=> {:two=>2}
|
130
|
+
|
131
|
+
h.delete_many(:six) #=> [nil]
|
132
|
+
```
|
133
|
+
|
134
|
+
Code
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
def delete_many *keys
|
138
|
+
keys.map{ |key| self.delete(key) }
|
139
|
+
end
|
140
|
+
```
|
141
|
+
|
142
|
+
|
143
|
+
### insert
|
144
|
+
|
145
|
+
Insert a value through descendance of keys (hash in hash)
|
146
|
+
|
147
|
+
Demo
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
h = Hash.new #=> {}
|
151
|
+
h.insert(12, :calendar, :gregorian, :months)
|
152
|
+
#=> {:calendar => {:gregorian => {:months => 12}}}
|
153
|
+
|
154
|
+
h.insert(13, :calendar, :lunar, :months)
|
155
|
+
#=> {:calendar => {:gregorian => {:months => 12}, :lunar => {:months => 13}}}
|
156
|
+
```
|
157
|
+
|
158
|
+
Code
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
def insert value, *keys
|
162
|
+
if keys.size > 1
|
163
|
+
shifted = keys.shift
|
164
|
+
|
165
|
+
self[shifted] ||= Hash.new
|
166
|
+
self[shifted] = self[shifted].insert value, *keys
|
167
|
+
else
|
168
|
+
self[keys.first] = value
|
169
|
+
end
|
170
|
+
|
171
|
+
self
|
172
|
+
end
|
173
|
+
```
|
174
|
+
|
175
|
+
|
176
|
+
### compact
|
177
|
+
|
178
|
+
Allow to compact hash just like arrays. Well, you can check nil, or black, or whatever you want on keys OR values
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
compact! options = Hash.new
|
182
|
+
compact options = Hash.new
|
183
|
+
```
|
184
|
+
|
185
|
+
Arguments : ':compare' must be in %w{key value}, default is :value
|
186
|
+
Arguments : ':with' is recommended in %w{blank? empty?}, default is :nil?
|
187
|
+
|
188
|
+
Demo
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
{:un=>1, :deux=>2, :trois=>3, :quatre=>nil, :cinq=>[]}.compact!
|
192
|
+
#=> {:cinq=>[], :un=>1, :deux=>2, :trois=>3}
|
193
|
+
|
194
|
+
{:un=>1, :deux=>2, :trois=>3, :quatre=>nil, :cinq=>[]}.compact!(:with=>:blank?)
|
195
|
+
#=> {:un=>1, :deux=>2, :trois=>3}
|
196
|
+
|
197
|
+
# for the perverts ones
|
198
|
+
{:un=>1, :deux=>2, :trois=>3, :quatre=>nil, :cinq=>[]}.compact!(:with=>"is_a?(Fixnum)")
|
199
|
+
#=> {:quatre=>nil, :cinq=>[]}
|
200
|
+
|
201
|
+
# And for the ones who REALLY care about memory
|
202
|
+
{:un=>1, "deux"=>2, "trois"=>3, "quatre"=>nil, :cinq=>[]}.compact!(:compare => :key, :with=>"is_a?(String)")
|
203
|
+
#=> {:un=>1, :cinq=>[]}
|
204
|
+
```
|
205
|
+
|
206
|
+
Code
|
207
|
+
|
208
|
+
```ruby
|
209
|
+
def compact! options = Hash.new
|
210
|
+
compare = options.delete(:compare) || :value
|
211
|
+
raise ArgumentError, ":compare option must be in %w{key value}" unless [:key, :value].include? compare.to_sym
|
212
|
+
|
213
|
+
if (with = options.delete :with)
|
214
|
+
self.each do |key, value|
|
215
|
+
self.delete(key) if eval "#{ compare }.#{ with }"
|
216
|
+
end
|
217
|
+
|
218
|
+
else
|
219
|
+
self.each do |key, value|
|
220
|
+
self.delete(key) if eval "#{ compare }.nil?"
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
self
|
225
|
+
end
|
226
|
+
```
|
227
|
+
|
228
|
+
|
229
|
+
### select_by
|
230
|
+
|
231
|
+
Select into hash from a collection of keys. Usefull to select correct params after a form.
|
232
|
+
|
233
|
+
```ruby
|
234
|
+
select_by! *collection
|
235
|
+
select_by *collection
|
236
|
+
```
|
237
|
+
|
238
|
+
Demo
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
{:one=>1, :two=>2, :three=>3, :four=>4}.select_by :one, :three
|
242
|
+
#=> {:one=>1, :three=>3}
|
243
|
+
|
244
|
+
{:one=>1, :two=>2, :three=>3, :four=>4}.select_by :one, :six
|
245
|
+
#=> {:one=>1}
|
246
|
+
|
247
|
+
{:one=>1, :two=>2, :three=>3, :four=>4}.select_by :six, :seven
|
248
|
+
#=> {}
|
249
|
+
```
|
250
|
+
|
251
|
+
Code
|
252
|
+
|
253
|
+
```ruby
|
254
|
+
def select_by! *collection
|
255
|
+
self.keep_if{ |field, _| collection.include? field.to_sym }
|
256
|
+
end
|
257
|
+
```
|
258
|
+
|
259
|
+
## Contributing
|
260
|
+
|
261
|
+
1. Fork it
|
262
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
263
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
264
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
265
|
+
5. Create new Pull Request
|
data/lib/hash_extend/version.rb
CHANGED
data/lib/hash_extend.rb
CHANGED
@@ -1,19 +1,114 @@
|
|
1
1
|
require "hash_extend/version"
|
2
2
|
|
3
3
|
class Hash
|
4
|
+
|
5
|
+
# ?> {1=>1, 2=>2}.stealth_delete(1)
|
6
|
+
# => {2=>2}
|
7
|
+
# delete key(s) but return self instead of deleted value
|
8
|
+
def stealth_delete! *keys
|
9
|
+
keys.each do |key|
|
10
|
+
delete key
|
11
|
+
end
|
12
|
+
return self
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
# ?> {1=>1, 2=>2}.map_values{ |v| v**2 }
|
17
|
+
# => {1=>1, 2=>4}
|
18
|
+
# modify values fro hash through block
|
19
|
+
def map_values!
|
20
|
+
self.each do |key, value|
|
21
|
+
self[key] = yield value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# ?> {1=>1, 2=>2}.map_keys{ |k| k.to_s }
|
26
|
+
# => {"2"=>2, "1"=>1}
|
27
|
+
# modify keys from hash through block
|
28
|
+
def map_keys
|
29
|
+
self.inject({}) do |hash, (key, value)|
|
30
|
+
hash[yield key] = value; hash
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def map_keys! &block
|
35
|
+
to_map = self.dup
|
36
|
+
self.clear.merge! to_map.map_keys &block
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# ?> h = Hash[:un, 1, :deux, 2, :trois, 3]
|
41
|
+
# => {:un=>1, :deux=>2, :trois=>3}
|
42
|
+
# ?> h.delete_many(:un, :trois)
|
43
|
+
# => [1, 3]
|
44
|
+
# ?> h
|
45
|
+
# => {:deux=>2}
|
46
|
+
#
|
47
|
+
# ?> h.delete_many(:six)
|
48
|
+
# => [nil]
|
49
|
+
# delete severals keys in one time
|
4
50
|
def delete_many *keys
|
5
51
|
keys.map{ |key| self.delete(key) }
|
6
52
|
end
|
7
|
-
|
8
|
-
|
9
|
-
|
53
|
+
|
54
|
+
|
55
|
+
# ?> insert("valeur", Hash.new, :key_one, :key_two, :key_wi)
|
56
|
+
# => {:key_one=>{:key_two=>{:key_wi=>"valeur"}}}
|
57
|
+
# insert a value trough severals "levels" of hashs
|
58
|
+
def insert value, *keys
|
59
|
+
if keys.size > 1
|
60
|
+
shifted = keys.shift
|
61
|
+
|
62
|
+
self[shifted] ||= Hash.new
|
63
|
+
self[shifted] = self[shifted].insert value, *keys
|
64
|
+
else
|
65
|
+
self[keys.first] = value
|
66
|
+
end
|
67
|
+
|
68
|
+
self
|
10
69
|
end
|
11
|
-
|
12
|
-
[
|
13
|
-
|
70
|
+
|
71
|
+
# ?> {:un=>1, :deux=>2, :trois=>3, :quatre=>nil, :cinq=>[]}.compact!
|
72
|
+
# => {:cinq=>[], :un=>1, :deux=>2, :trois=>3}
|
73
|
+
# ?> {:un=>1, :deux=>2, :trois=>3, :quatre=>nil, :cinq=>[]}.compact!(:with=>:blank?)
|
74
|
+
# => {:un=>1, :deux=>2, :trois=>3}
|
75
|
+
# ?> {:un=>1, :deux=>2, :trois=>3, :quatre=>nil, :cinq=>[]}.compact!(:with=>"is_a?(Fixnum)")
|
76
|
+
# => {:quatre=>nil, :cinq=>[]}
|
77
|
+
# allow to compact (like Array), default on value.nil?
|
78
|
+
def compact! options = Hash.new
|
79
|
+
compare = options.delete(:compare) || :value
|
80
|
+
raise ArgumentError, ":compare option must be in %w{key value}" unless [:key, :value].include? compare.to_sym
|
81
|
+
|
82
|
+
if (with = options.delete :with)
|
83
|
+
self.each do |key, value|
|
84
|
+
self.delete(key) if eval "#{ compare }.#{ with }"
|
85
|
+
end
|
86
|
+
|
87
|
+
else
|
88
|
+
self.each do |key, value|
|
89
|
+
self.delete(key) if eval "#{ compare }.nil?"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
self
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
# ?> {:action=>"index", :controller=>"home", :id=>"42", :firstname=>"thomas", :name=>"petrachi"}.select_from_collection! [:id, :firstname, :name]
|
98
|
+
# => {:firstname=>"thomas", :name=>"petrachi", :id=>"42"}
|
99
|
+
# something like #keep_if, but instead of block, pass collection of keys to select
|
100
|
+
def select_by! collection, *args, &block
|
101
|
+
self.keep_if{ |field, _| collection.include? field.to_sym }
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
# duplicate method without self modification
|
106
|
+
[:stealth_delete, :map_values, :compact, :select_by].each do |method_name|
|
107
|
+
define_method method_name do |*args, &block|
|
14
108
|
hash = self.dup
|
15
|
-
eval "hash.#{ method_name }! *args"
|
109
|
+
eval "hash.#{ method_name }! *args, &block"
|
16
110
|
return hash
|
17
111
|
end
|
18
112
|
end
|
113
|
+
|
19
114
|
end
|
metadata
CHANGED
@@ -1,33 +1,23 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: hash_extend
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
- 1
|
10
|
-
version: 0.0.1
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Thomas Petrachi
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
date: 2012-09-27 00:00:00 Z
|
12
|
+
date: 2012-09-30 00:00:00.000000000 Z
|
19
13
|
dependencies: []
|
20
|
-
|
21
|
-
|
22
|
-
email:
|
14
|
+
description: ! 'in dev : extend hash methods'
|
15
|
+
email:
|
23
16
|
- thomas.petrachi@vodeclic.com
|
24
17
|
executables: []
|
25
|
-
|
26
18
|
extensions: []
|
27
|
-
|
28
19
|
extra_rdoc_files: []
|
29
|
-
|
30
|
-
files:
|
20
|
+
files:
|
31
21
|
- .gitignore
|
32
22
|
- Gemfile
|
33
23
|
- LICENSE.txt
|
@@ -36,38 +26,28 @@ files:
|
|
36
26
|
- hash_extend.gemspec
|
37
27
|
- lib/hash_extend.rb
|
38
28
|
- lib/hash_extend/version.rb
|
39
|
-
homepage:
|
29
|
+
homepage: ''
|
40
30
|
licenses: []
|
41
|
-
|
42
31
|
post_install_message:
|
43
32
|
rdoc_options: []
|
44
|
-
|
45
|
-
require_paths:
|
33
|
+
require_paths:
|
46
34
|
- lib
|
47
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
36
|
none: false
|
49
|
-
requirements:
|
50
|
-
- -
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
|
53
|
-
|
54
|
-
- 0
|
55
|
-
version: "0"
|
56
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
42
|
none: false
|
58
|
-
requirements:
|
59
|
-
- -
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
|
62
|
-
segments:
|
63
|
-
- 0
|
64
|
-
version: "0"
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
65
47
|
requirements: []
|
66
|
-
|
67
48
|
rubyforge_project:
|
68
49
|
rubygems_version: 1.8.24
|
69
50
|
signing_key:
|
70
51
|
specification_version: 3
|
71
|
-
summary:
|
52
|
+
summary: ! 'in dev : add :delete_many'
|
72
53
|
test_files: []
|
73
|
-
|