hobo_support 1.3.0.RC
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.
- data/CHANGES.txt +5 -0
- data/README.txt +36 -0
- data/Rakefile +16 -0
- data/VERSION +1 -0
- data/hobo_support.gemspec +29 -0
- data/lib/generators/hobo_support/eval_template.rb +14 -0
- data/lib/generators/hobo_support/model.rb +50 -0
- data/lib/generators/hobo_support/thor_shell.rb +40 -0
- data/lib/hobo_support.rb +25 -0
- data/lib/hobo_support/array.rb +40 -0
- data/lib/hobo_support/blankslate.rb +13 -0
- data/lib/hobo_support/command.rb +156 -0
- data/lib/hobo_support/common_tasks.rb +33 -0
- data/lib/hobo_support/enumerable.rb +89 -0
- data/lib/hobo_support/fixes/chronic.rb +21 -0
- data/lib/hobo_support/fixes/module.rb +37 -0
- data/lib/hobo_support/fixes/pp.rb +13 -0
- data/lib/hobo_support/hash.rb +124 -0
- data/lib/hobo_support/implies.rb +15 -0
- data/lib/hobo_support/kernel.rb +16 -0
- data/lib/hobo_support/metaid.rb +28 -0
- data/lib/hobo_support/methodcall.rb +117 -0
- data/lib/hobo_support/methodphitamine.rb +33 -0
- data/lib/hobo_support/module.rb +102 -0
- data/lib/hobo_support/string.rb +34 -0
- data/lib/hobo_support/xss.rb +11 -0
- data/test/hobosupport.rdoctest +75 -0
- data/test/hobosupport/chronic.rdoctest +18 -0
- data/test/hobosupport/enumerable.rdoctest +130 -0
- data/test/hobosupport/hash.rdoctest +123 -0
- data/test/hobosupport/implies.rdoctest +20 -0
- data/test/hobosupport/metaid.rdoctest +59 -0
- data/test/hobosupport/methodphitamine.rdoctest +18 -0
- data/test/hobosupport/module.rdoctest +108 -0
- data/test/hobosupport/xss.rdoctest +44 -0
- metadata +111 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
# From: http://jicksta.com/articles/2007/08/04/the-methodphitamine
|
2
|
+
|
3
|
+
require 'blankslate'
|
4
|
+
|
5
|
+
module Kernel
|
6
|
+
|
7
|
+
def it() It.new end
|
8
|
+
alias its it
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
class It
|
13
|
+
|
14
|
+
instance_methods.reject { |m| m =~ /^__/ || m.to_s == 'object_id' }.each { |m| undef_method m }
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@methods = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def method_missing(*args, &block)
|
21
|
+
@methods << [args, block] unless args == [:respond_to?, :to_proc]
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_proc
|
26
|
+
lambda do |obj|
|
27
|
+
@methods.inject(obj) do |current,(args,block)|
|
28
|
+
current.send(*args, &block)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
class Module
|
2
|
+
|
3
|
+
private
|
4
|
+
|
5
|
+
# In a module definition you can include a call to
|
6
|
+
# included_in_class_callbacks(base) at the end of the
|
7
|
+
# self.included(base) callback. Any modules that your module includes
|
8
|
+
# will receive an included_in_class callback when your module is
|
9
|
+
# included in a class. Useful if the sub-module wants to do something
|
10
|
+
# like alias_method_chain on the class.
|
11
|
+
def included_in_class_callbacks(base)
|
12
|
+
if base.is_a?(Class)
|
13
|
+
included_modules.each { |m| m.try.included_in_class(base) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Creates a class attribute reader that will delegate to the superclass
|
18
|
+
# if not defined on self. Default values can be a Proc object that takes the class as a parameter.
|
19
|
+
def inheriting_cattr_reader(*names)
|
20
|
+
names_with_defaults = (names.pop if names.last.is_a?(Hash)) || {}
|
21
|
+
|
22
|
+
(names + names_with_defaults.keys).each do |name|
|
23
|
+
ivar_name = "@#{name}"
|
24
|
+
block = names_with_defaults[name]
|
25
|
+
self.send(self.class == Module ? :define_method : :meta_def, name) do
|
26
|
+
if instance_variable_defined? ivar_name
|
27
|
+
instance_variable_get(ivar_name)
|
28
|
+
else
|
29
|
+
superclass.respond_to?(name) && superclass.send(name) ||
|
30
|
+
block && begin
|
31
|
+
result = block.is_a?(Proc) ? block.call(self) : block
|
32
|
+
instance_variable_set(ivar_name, result) if result
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def inheriting_cattr_accessor(*names)
|
40
|
+
names_with_defaults = (names.pop if names.last.is_a?(Hash)) || {}
|
41
|
+
|
42
|
+
names_with_defaults.keys.each do |name|
|
43
|
+
attr_writer name
|
44
|
+
inheriting_cattr_reader names_with_defaults.slice(name)
|
45
|
+
end
|
46
|
+
names.each do |name|
|
47
|
+
attr_writer name
|
48
|
+
inheriting_cattr_reader name
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
# creates a #foo= and #foo? pair, with optional default values, e.g.
|
54
|
+
# bool_attr_accessor :happy => true
|
55
|
+
def bool_attr_accessor(*args)
|
56
|
+
options = (args.pop if args.last.is_a?(Hash)) || {}
|
57
|
+
|
58
|
+
(args + options.keys).each {|n| class_eval "def #{n}=(x); @#{n} = x; end" }
|
59
|
+
|
60
|
+
args.each {|n| class_eval "def #{n}?; @#{n}; end" }
|
61
|
+
|
62
|
+
options.keys.each do |n|
|
63
|
+
class_eval %(def #{n}?
|
64
|
+
if !defined? @#{n}
|
65
|
+
@#{n} = #{options[n] ? 'true' : 'false'}
|
66
|
+
else
|
67
|
+
@#{n}
|
68
|
+
end
|
69
|
+
end)
|
70
|
+
set_field_type(n => TrueClass) if respond_to?(:set_field_type)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def alias_class_method_chain(method, feature)
|
75
|
+
meta_eval do
|
76
|
+
alias_method_chain method, feature
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# classy_module lets you extract code from classes into modules, but
|
84
|
+
# still write it the same way
|
85
|
+
module Kernel
|
86
|
+
|
87
|
+
def classy_module(mod=Module.new, &b)
|
88
|
+
mod.meta_def :included do |base|
|
89
|
+
base.class_eval &b
|
90
|
+
end
|
91
|
+
mod
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
class Object
|
97
|
+
|
98
|
+
def is_one_of?(*args)
|
99
|
+
args.any? {|a| is_a?(a) }
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class String
|
2
|
+
|
3
|
+
def remove(string_or_rx)
|
4
|
+
sub(string_or_rx, '')
|
5
|
+
end
|
6
|
+
|
7
|
+
def remove!(string_or_rx)
|
8
|
+
sub!(string_or_rx, '')
|
9
|
+
end
|
10
|
+
|
11
|
+
def remove_all(string_or_rx)
|
12
|
+
gsub(string_or_rx, '')
|
13
|
+
end
|
14
|
+
|
15
|
+
def remove_all!(string_or_rx)
|
16
|
+
gsub!(string_or_rx, '')
|
17
|
+
end
|
18
|
+
|
19
|
+
# Return the constant that this string refers to, or nil if ActiveSupport cannot load such a
|
20
|
+
# constant. This is much safer than `rescue NameError`, as that will mask genuine NameErrors
|
21
|
+
# that have been made in the code being loaded (#safe_constantize will not)
|
22
|
+
def safe_constantize
|
23
|
+
Object.class_eval self
|
24
|
+
rescue NameError => e
|
25
|
+
if e.missing_name != self
|
26
|
+
# oops - some other name error
|
27
|
+
raise
|
28
|
+
else
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'active_support/core_ext/string/output_safety'
|
2
|
+
class Array
|
3
|
+
# it always returns an html_safe? string preserving the html_safe?
|
4
|
+
# items and separator, excaping the rest
|
5
|
+
def safe_join(sep=$,)
|
6
|
+
map {|i| ERB::Util.html_escape(i)}.join(ERB::Util.html_escape(sep)).html_safe
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# HoboSupport
|
2
|
+
|
3
|
+
HoboSupport is a mixed bag of core ruby extensions that have been extracted from the [Hobo][] project
|
4
|
+
|
5
|
+
[Hobo]: http://hobocentral.net
|
6
|
+
|
7
|
+
doctest_require: '../lib/hobo_support'
|
8
|
+
{.hidden}
|
9
|
+
|
10
|
+
|
11
|
+
## Contents
|
12
|
+
|
13
|
+
* [Enumerable](/manual/hobo_support/enumerable)
|
14
|
+
* [Hash](/manual/hobo_support/hash)
|
15
|
+
* [Implies](/manual/hobo_support/implies)
|
16
|
+
* [Metaid](/manual/hobo_support/metaid)
|
17
|
+
* [Methodphitamine](/manual/hobo_support/methodphitamine)
|
18
|
+
* [Module](/manual/hobo_support/module)
|
19
|
+
|
20
|
+
## Object extensions
|
21
|
+
|
22
|
+
### `Object#is_one_of?`
|
23
|
+
|
24
|
+
Like `is_a?` but multiple types to be checked in one go
|
25
|
+
|
26
|
+
>> "foo".is_one_of?(String, Symbol)
|
27
|
+
=> true
|
28
|
+
>> :foo.is_one_of?(String, Symbol)
|
29
|
+
=> true
|
30
|
+
>> 1.is_one_of?(String, Symbol)
|
31
|
+
=> false
|
32
|
+
|
33
|
+
## Method call extensions
|
34
|
+
|
35
|
+
We have the "." operator to call methods on objects. These extensions introduce two "special dots".
|
36
|
+
|
37
|
+
### `Object#_?`
|
38
|
+
|
39
|
+
"`._?.`" only calls the method if the receiver is not `nil`. Otherwise it returns nil. So `x._?.method(*args)` is equivalent to `(nil == x ? nil : x.method(*args))`.
|
40
|
+
|
41
|
+
>> "foo"._?.length
|
42
|
+
=> 3
|
43
|
+
>> nil._?.length
|
44
|
+
=> nil
|
45
|
+
|
46
|
+
When the receiver is nil, any method with any arguments will return nil. You can use Ruby's || idiom to provide a different value when nil.
|
47
|
+
|
48
|
+
>> expires = nil
|
49
|
+
>> expires._?.to_s( :default ) || "never"
|
50
|
+
=> "never"
|
51
|
+
|
52
|
+
Note that `_?` should *always* be followed by a method call. It is not intended to store the intermediate result. Don't do this!
|
53
|
+
|
54
|
+
intermediate = nil._?
|
55
|
+
|
56
|
+
### `Object#try`
|
57
|
+
|
58
|
+
"`.try`" only calls the method if the receiver responds to that method. Otherwise it returns nil. So `x.try.method(*args)` is equivalent to `(x.respond_to?(:method) ? x.method(*args) : nil)`.
|
59
|
+
|
60
|
+
>> "foo".try.reverse
|
61
|
+
=> "oof"
|
62
|
+
>> :foo.try.reverse
|
63
|
+
=> nil
|
64
|
+
|
65
|
+
### What's the difference?
|
66
|
+
|
67
|
+
Use `_?` when you want to call a method but you know the receiver may be nil.
|
68
|
+
Use `try` when you want to call a method but you know the receiver may not respond to it. For instance, you
|
69
|
+
may use `try` to call a Rails 2.3 function that doesn't exist on Rails
|
70
|
+
2.2. Note that nil responds to some functions that may surprise you.
|
71
|
+
|
72
|
+
>> nil.try.to_i
|
73
|
+
=> 0
|
74
|
+
>> nil._?.to_i
|
75
|
+
=> nil
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# HoboSupport - Chronic extensions
|
2
|
+
|
3
|
+
doctest_require: '../../lib/hobo_support'
|
4
|
+
{.hidden}
|
5
|
+
|
6
|
+
## `Chronic.parse`
|
7
|
+
|
8
|
+
Chronic.parse can't parse 'M/D/Y H:S', so convert it to 'M/D/Y @ H:S'.
|
9
|
+
|
10
|
+
>> Chronic.parse('1/1/2008 1:00') == Chronic.parse('1/1/2008 @ 1:00')
|
11
|
+
|
12
|
+
=> true
|
13
|
+
|
14
|
+
Chronic.parse takes additional options (see Chronic.parse).
|
15
|
+
|
16
|
+
>> Chronic.parse('today', :guess => false).instance_of? Chronic::Span
|
17
|
+
|
18
|
+
=> true
|
@@ -0,0 +1,130 @@
|
|
1
|
+
# HoboSupport - Eumerable extensions
|
2
|
+
|
3
|
+
doctest_require: '../../lib/hobo_support'
|
4
|
+
|
5
|
+
## `Enumerable#map_and_find`
|
6
|
+
|
7
|
+
* `enum.map_and_find(not_found) { |element| block}`
|
8
|
+
|
9
|
+
Iterates through an enumerable passing each element in turn to the block. Returns the first true value returned by the block, or `not_found` if the block never returns a true value.
|
10
|
+
|
11
|
+
E.g. The length of the first word that starts with a capital letter
|
12
|
+
|
13
|
+
>> %w(my name is Fred).map_and_find { |s| s.length if s =~ /^[A-Z]/ }
|
14
|
+
=> 4
|
15
|
+
|
16
|
+
## `Enumerable#map_with_index`
|
17
|
+
|
18
|
+
* `enum.map_with_index { |element, index| block }`
|
19
|
+
|
20
|
+
Just like #map but the block gets the element and the index.
|
21
|
+
|
22
|
+
>> %w(some short words).map_with_index { |s, i| s * i }
|
23
|
+
=> ["", "short", "wordswords"]
|
24
|
+
|
25
|
+
## `Enumerable#build_hash`
|
26
|
+
|
27
|
+
* `enum.build_hash { |element| block }`
|
28
|
+
|
29
|
+
The block is passed each element in turn and should return a key/value pair. If the block returns nil, nothing is added to the hash.
|
30
|
+
|
31
|
+
>> %w(some short words).build_hash { |s| [s, s.length] unless s == "short" }
|
32
|
+
=> {"some"=>4, "words"=>5}
|
33
|
+
|
34
|
+
|
35
|
+
## `Enumerable#map_hash`
|
36
|
+
|
37
|
+
* `enum.map_hash { |element| block }`
|
38
|
+
|
39
|
+
Each element is passed to the block. Returns a hash where the keys are the elements from the enumerable, and the values are those returned by the block for the given key.
|
40
|
+
|
41
|
+
>> %w(some short words).map_hash { |s| s.length }
|
42
|
+
=> {"some"=>4, "short"=>5, "words"=>5}
|
43
|
+
|
44
|
+
## `Enumerable#rest`
|
45
|
+
|
46
|
+
Shorthand for `enum[1..-1]`
|
47
|
+
|
48
|
+
>> %w(some short words).rest
|
49
|
+
=> ["short", "words"]
|
50
|
+
|
51
|
+
|
52
|
+
## `Enumerable#*`
|
53
|
+
|
54
|
+
Shorthand for `map` when you need to map a single method call on the elements.
|
55
|
+
|
56
|
+
>> %w(some short words).*.length
|
57
|
+
=> [4, 5, 5]
|
58
|
+
|
59
|
+
## `Enumerable#where`
|
60
|
+
|
61
|
+
Shorthand for `select` when you need to select on a single method call.
|
62
|
+
|
63
|
+
>> %w(some short words).where.include?("r")
|
64
|
+
=> ["short", "words"]
|
65
|
+
|
66
|
+
## `Enumerable#where_not`
|
67
|
+
|
68
|
+
Shorthand for `reject` when you need to reject on a single method call.
|
69
|
+
|
70
|
+
>> %w(some short words).where_not.include?("r")
|
71
|
+
=> ["some"]
|
72
|
+
|
73
|
+
## `Enumerable#drop_while`
|
74
|
+
|
75
|
+
* `enum.drop_while { |element| block }`
|
76
|
+
|
77
|
+
Passes each element in turn to the block until the block returns false. Returns the remaining elements in a new array.
|
78
|
+
|
79
|
+
>> %w(this is a nice example).drop_while { |s| s.length > 1 }
|
80
|
+
=> ["a", "nice", "example"]
|
81
|
+
|
82
|
+
There is also a destructive version for arrays
|
83
|
+
|
84
|
+
>> a = %w(this is a nice example)
|
85
|
+
>> a.drop_while! { |s| s.length > 1 }
|
86
|
+
>> a
|
87
|
+
=> ["a", "nice", "example"]
|
88
|
+
|
89
|
+
|
90
|
+
## `Enumerable#take_while`
|
91
|
+
|
92
|
+
* `enum.take_while { |element| block }`
|
93
|
+
|
94
|
+
Passes each element in turn to the block until the block returns false. Returns a new with the elements for which the block returned true
|
95
|
+
|
96
|
+
>> %w(this is a nice example).take_while { |s| s.length > 1 }
|
97
|
+
=> ["this", "is"]
|
98
|
+
|
99
|
+
|
100
|
+
## `Object#in?`
|
101
|
+
|
102
|
+
* `obj.in?(enum)`
|
103
|
+
|
104
|
+
Shorthand for `enum.include?(obj)`
|
105
|
+
|
106
|
+
>> 3.in?(0..10)
|
107
|
+
=> true
|
108
|
+
>> 300.in?(0..10)
|
109
|
+
=> false
|
110
|
+
|
111
|
+
`in?` treats nil as an empty enumeration:
|
112
|
+
|
113
|
+
>> 3.in?(nil)
|
114
|
+
=> false
|
115
|
+
|
116
|
+
## `Object#not_in?`
|
117
|
+
|
118
|
+
* `obj.not_in?(enum)`
|
119
|
+
|
120
|
+
Negation of `in?`
|
121
|
+
|
122
|
+
>> 3.not_in?(0..10)
|
123
|
+
=> false
|
124
|
+
>> 300.not_in?(0..10)
|
125
|
+
=> true
|
126
|
+
|
127
|
+
`not_in?` treats nil as an empty enumeration:
|
128
|
+
|
129
|
+
>> 3.not_in?(nil)
|
130
|
+
=> true
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# HoboSupport - Hash extensions
|
2
|
+
|
3
|
+
doctest_require: '../../lib/hobo_support'
|
4
|
+
{.hidden}
|
5
|
+
|
6
|
+
## `Hash#select_hash`
|
7
|
+
|
8
|
+
* `hash.select_hash { |key, value| block } => hash`
|
9
|
+
* `hash.select_hash { |value| block } => hash`
|
10
|
+
|
11
|
+
This is the Hash version of `Enumerable#select`. i.e. a way to create a new hash with only some of the items still present. The block is passed each key value pair. The new hash only contains items for which the block returned true.
|
12
|
+
|
13
|
+
>> {1=>2, 3=>4, 6=>5}.select_hash { |key, value| key < value }
|
14
|
+
=> {1=>2, 3=>4}
|
15
|
+
|
16
|
+
You can also give a block that takes one argument, in which case the block is given the value only
|
17
|
+
|
18
|
+
>> {1=>2, 3=>4, 6=>5}.select_hash { |value| value != 2 }
|
19
|
+
=> {3=>4, 6=>5}
|
20
|
+
|
21
|
+
|
22
|
+
## `Hash#map_hash`
|
23
|
+
|
24
|
+
* `hash.map_hash { |key, value| block } => hash`
|
25
|
+
* `hash.map_hash { |value| block } => hash`
|
26
|
+
|
27
|
+
Applies a function to each *value* in a Hash, resulting in a new hash with the same keys but new values. The block is passed each key, value pair and should return the new value
|
28
|
+
|
29
|
+
>> {1=>2, 3=>4, 6=>5}.map_hash { |key, value| key < value }
|
30
|
+
=> {1=>true, 3=>true, 6=>false}
|
31
|
+
|
32
|
+
You can also give a block which takes one argument, in which case only the value is passed in
|
33
|
+
|
34
|
+
>> {1=>2, 3=>4, 6=>5}.map_hash { |value| value * 100 }
|
35
|
+
=> {1=>200, 3=>400, 6=>500 }
|
36
|
+
|
37
|
+
|
38
|
+
## `Hash#partition_hash`
|
39
|
+
|
40
|
+
* `hash.partition_hash(keys) => [hash1, hash2]`
|
41
|
+
* `hash.partition_hash { |key, value| block } => hash`
|
42
|
+
|
43
|
+
Returns an array of two hashes, the first with all the key/value pairs where the key was in passed Enumerable, the second with the remaining key/value pairs
|
44
|
+
|
45
|
+
>> {1=>2, 3=>4, 6=>5}.partition_hash([1, 3])
|
46
|
+
=> [{1=>2, 3=>4}, {6=>5}]
|
47
|
+
|
48
|
+
When passed a block, each pair is passed to the block in turn. The result is two hashes, the first containing those pairs for which the block returned true, the second with the remaining pairs
|
49
|
+
|
50
|
+
>> {1=>2, 3=>4, 6=>5}.partition_hash { |key, value| key < value }
|
51
|
+
=> [{1=>2, 3=>4}, {6=>5}]
|
52
|
+
|
53
|
+
## `Hash.recursive_update`
|
54
|
+
|
55
|
+
* `hash.recursive_update(hash2)`
|
56
|
+
|
57
|
+
Like `#update` but where a sub-hash would overwrite another sub-hash, they are instead also merged, recursively
|
58
|
+
|
59
|
+
>> h = { :a => 1, :b => { :x => 10 } }
|
60
|
+
>> h.recursive_update({ :c => 3, :b => { :y => 20 } })
|
61
|
+
>> h
|
62
|
+
=> { :a => 1, :b => { :x => 10, :y => 20}, :c => 3 }
|
63
|
+
|
64
|
+
|
65
|
+
## `Hash#-`
|
66
|
+
|
67
|
+
* `hash - array => hash`
|
68
|
+
|
69
|
+
Returns a new hash, the left-hand-side hash with all pairs removed where the key is present in the right-hand-side array.
|
70
|
+
|
71
|
+
>> {1=>2, 3=>4, 6=>5} - [1, 3]
|
72
|
+
=> {6 => 5}
|
73
|
+
|
74
|
+
## `Hash#&`
|
75
|
+
|
76
|
+
* `hash & array => array`
|
77
|
+
|
78
|
+
Returns a new array, the left hand side hash restricted to pairs where the key is present in the right-hand-side array
|
79
|
+
|
80
|
+
>> {1=>2, 3=>4, 6=>5} & [1, 3]
|
81
|
+
=> {1=>2, 3=>4}
|
82
|
+
|
83
|
+
## `Hash#|`
|
84
|
+
|
85
|
+
* `hash | hash => hash`
|
86
|
+
|
87
|
+
An alias for merge
|
88
|
+
|
89
|
+
>> {1 => 2} | {1 => 3, 2 => 4}
|
90
|
+
=> {1 => 3, 2 => 4}
|
91
|
+
|
92
|
+
|
93
|
+
## `Hash#get`
|
94
|
+
|
95
|
+
* `hash.get(*args) => hash`
|
96
|
+
|
97
|
+
Returns an array of values for the given keys. Useful for extracting a few options into local variables.
|
98
|
+
|
99
|
+
>> {1=>2, 3=>4, 6=>5}.get(1, 3)
|
100
|
+
=> [2, 4]
|
101
|
+
|
102
|
+
## `Hash#compact`
|
103
|
+
|
104
|
+
* `hash.compact => hash`
|
105
|
+
|
106
|
+
Returns a hash with the same items as the receiver except those where the value is nil
|
107
|
+
|
108
|
+
>> {1=>'a', 2=>nil, 3=>'b'}.compact
|
109
|
+
=> {1=>'a', 3=>'b'}
|
110
|
+
|
111
|
+
## `Hash#compact`
|
112
|
+
|
113
|
+
* `hash.compact!`
|
114
|
+
|
115
|
+
Removes every pair from the hash where the value is nil
|
116
|
+
|
117
|
+
>> h = {1=>'a', 2=>nil, 3=>'b'}
|
118
|
+
>> h.compact!
|
119
|
+
>> h
|
120
|
+
=> {1=>'a', 3=>'b'}
|
121
|
+
|
122
|
+
|
123
|
+
|