hobosupport 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,5 @@
1
+ == 0.1
2
+
3
+ * First release as a separate gem
4
+
5
+
data/Manifest.txt ADDED
@@ -0,0 +1,25 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/hobosupport.rb
6
+ lib/hobosupport/array.rb
7
+ lib/hobosupport/blankslate.rb
8
+ lib/hobosupport/enumerable.rb
9
+ lib/hobosupport/fixes.rb
10
+ lib/hobosupport/fixes/chronic.rb
11
+ lib/hobosupport/fixes/module.rb
12
+ lib/hobosupport/fixes/pp.rb
13
+ lib/hobosupport/hash.rb
14
+ lib/hobosupport/implies.rb
15
+ lib/hobosupport/metaid.rb
16
+ lib/hobosupport/methodcall.rb
17
+ lib/hobosupport/methodphitamine.rb
18
+ lib/hobosupport/module.rb
19
+ test/hobosupport.rdoctest
20
+ test/hobosupport/enumerable.rdoctest
21
+ test/hobosupport/hash.rdoctest
22
+ test/hobosupport/implies.rdoctest
23
+ test/hobosupport/metaid.rdoctest
24
+ test/hobosupport/methodphitamine.rdoctest
25
+ test/hobosupport/module.rdoctest
data/README.txt ADDED
@@ -0,0 +1,36 @@
1
+ = hobosupport
2
+
3
+ * http://hobocentral.net/hobosupport
4
+
5
+ == DESCRIPTION:
6
+
7
+ A mixed bag of core Ruby extenstion that have been extracted from the Hobo project.
8
+
9
+ == INSTALL:
10
+
11
+ * sudo gem install hobosupport
12
+
13
+ == LICENSE:
14
+
15
+ (The MIT License)
16
+
17
+ Copyright (c) 2008 Tom Locke
18
+
19
+ Permission is hereby granted, free of charge, to any person obtaining
20
+ a copy of this software and associated documentation files (the
21
+ 'Software'), to deal in the Software without restriction, including
22
+ without limitation the rights to use, copy, modify, merge, publish,
23
+ distribute, sublicense, and/or sell copies of the Software, and to
24
+ permit persons to whom the Software is furnished to do so, subject to
25
+ the following conditions:
26
+
27
+ The above copyright notice and this permission notice shall be
28
+ included in all copies or substantial portions of the Software.
29
+
30
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
31
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
33
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
34
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
35
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
36
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'hoe'
3
+
4
+ $: << "./lib"
5
+
6
+ require 'hobosupport'
7
+
8
+ Hoe.new('hobosupport', HoboSupport::VERSION) do |p|
9
+ p.rubyforge_name = 'hobo'
10
+ p.author = 'Tom Locke'
11
+ p.email = 'tom@tomlocke.com'
12
+ p.url = "http://hobocentral.net/hobo-support"
13
+ p.summary = 'Core Ruby extensions from the Hobo project'
14
+ p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
15
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
16
+ end
17
+
@@ -0,0 +1,22 @@
1
+ class Array
2
+
3
+ alias_method :multiply, :*
4
+
5
+ def *(rhs=nil)
6
+ if rhs
7
+ multiply(rhs)
8
+ else
9
+ Enumerable::MultiSender.new(self, :map)
10
+ end
11
+ end
12
+
13
+ def drop_while!
14
+ drop = 0
15
+ drop += 1 while yield(self[drop])
16
+ self[0..drop-1] = []
17
+ self
18
+ end
19
+
20
+ end
21
+
22
+
@@ -0,0 +1,10 @@
1
+ # Define BlankSlate in case ActiveSupport aint present
2
+ unless defined? BlankSlate
3
+ class BlankSlate
4
+ instance_methods.reject { |m| m =~ /^__/ }.each { |m| undef_method m }
5
+ def initialize(me)
6
+ @me = me
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,92 @@
1
+ module Enumerable
2
+
3
+ def search(not_found=nil)
4
+ each do |x|
5
+ val = yield(x)
6
+ return val if val
7
+ end
8
+ not_found
9
+ end
10
+
11
+ def map_with_index
12
+ res = []
13
+ each_with_index {|x, i| res << yield(x, i)}
14
+ res
15
+ end
16
+
17
+ def build_hash
18
+ res = {}
19
+ each do |x|
20
+ pair = yield x
21
+ res[pair.first] = pair.last if pair
22
+ end
23
+ res
24
+ end
25
+
26
+ def map_hash
27
+ res = {}
28
+ each do |x|
29
+ v = yield x
30
+ res[x] = v
31
+ end
32
+ res
33
+ end
34
+
35
+ def rest
36
+ self[1..-1]
37
+ end
38
+
39
+ class MultiSender
40
+
41
+ undef_method(*(instance_methods - %w*__id__ __send__*))
42
+
43
+ def initialize(enumerable, method)
44
+ @enumerable = enumerable
45
+ @method = method
46
+ end
47
+
48
+ def method_missing(name, *args, &block)
49
+ @enumerable.send(@method) { |x| x.send(name, *args, &block) }
50
+ end
51
+
52
+ end
53
+
54
+ def *()
55
+ MultiSender.new(self, :map)
56
+ end
57
+
58
+ def where
59
+ MultiSender.new(self, :select)
60
+ end
61
+
62
+ def where_not
63
+ MultiSender.new(self, :reject)
64
+ end
65
+
66
+ def drop_while
67
+ drop = 0
68
+ drop += 1 while yield(self[drop])
69
+ self[drop..-1]
70
+ end
71
+
72
+
73
+ def take_while
74
+ take = 0
75
+ take += 1 while yield(self[take])
76
+ self[0..take-1]
77
+ end
78
+
79
+ end
80
+
81
+
82
+ class Object
83
+
84
+ def in?(enum)
85
+ enum.include?(self)
86
+ end
87
+
88
+ def not_in?(enum)
89
+ not enum.include?(self)
90
+ end
91
+
92
+ end
@@ -0,0 +1,18 @@
1
+ # --- Fix Chronic - can't parse '12th Jan' --- #
2
+ begin
3
+ require 'chronic'
4
+
5
+ module Chronic
6
+
7
+ class << self
8
+ def parse_with_hobo_fix(s)
9
+ parse_without_hobo_fix(if s =~ /^\s*\d+\s*(st|nd|rd|th)\s+[a-zA-Z]+(\s+\d+)?\s*$/
10
+ s.sub(/\s*\d+(st|nd|rd|th)/) {|s| s[0..-3]}
11
+ else
12
+ s
13
+ end)
14
+ end
15
+ alias_method_chain :parse, :hobo_fix
16
+ end
17
+ end
18
+ rescue LoadError; end
@@ -0,0 +1,37 @@
1
+ class Module
2
+
3
+ # Custom alias_method_chain that won't cause inifinite recursion if
4
+ # called twice.
5
+ # Calling alias_method_chain on alias_method_chain
6
+ # was just way to confusing, so I copied it :-/
7
+ def alias_method_chain(target, feature)
8
+ # Strip out punctuation on predicates or bang methods since
9
+ # e.g. target?_without_feature is not a valid method name.
10
+ aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
11
+ yield(aliased_target, punctuation) if block_given?
12
+ without = "#{aliased_target}_without_#{feature}#{punctuation}"
13
+ unless instance_methods.include?(without)
14
+ alias_method without, target
15
+ alias_method target, "#{aliased_target}_with_#{feature}#{punctuation}"
16
+ end
17
+ end
18
+
19
+
20
+ # Fix delegate so it doesn't go bang if 'to' is nil
21
+ def delegate(*methods)
22
+ options = methods.pop
23
+ unless options.is_a?(Hash) && to = options[:to]
24
+ raise ArgumentError, ("Delegation needs a target. Supply an options hash with a :to key" +
25
+ "as the last argument (e.g. delegate :hello, :to => :greeter).")
26
+ end
27
+
28
+ methods.each do |method|
29
+ module_eval(<<-EOS, "(__DELEGATION__)", 1)
30
+ def #{method}(*args, &block)
31
+ (_to = #{to}) && _to.__send__(#{method.inspect}, *args, &block)
32
+ end
33
+ EOS
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,13 @@
1
+ # --- Fix pp dumps - these break sometimes without this --- #
2
+ require 'pp'
3
+ module PP::ObjectMixin
4
+
5
+ alias_method :orig_pretty_print, :pretty_print
6
+ def pretty_print(q)
7
+ orig_pretty_print(q)
8
+ rescue
9
+ "[#PP-ERROR#]"
10
+ end
11
+
12
+ end
13
+
@@ -0,0 +1,3 @@
1
+ require "hobosupport/fixes/chronic"
2
+ require "hobosupport/fixes/pp"
3
+ require "hobosupport/fixes/module"
@@ -0,0 +1,100 @@
1
+ class Hash
2
+
3
+ def select_hash(&b)
4
+ res = {}
5
+ each {|k,v| res[k] = v if (b.arity == 1 ? yield(v) : yield(k, v)) }
6
+ res
7
+ end
8
+
9
+
10
+ def map_hash(&b)
11
+ res = {}
12
+ each {|k,v| res[k] = b.arity == 1 ? yield(v) : yield(k, v) }
13
+ res
14
+ end
15
+
16
+ def partition_hash(keys=nil)
17
+ yes = {}
18
+ no = {}
19
+ each do |k,v|
20
+ if block_given? ? yield(k,v) : keys.include?(k)
21
+ yes[k] = v
22
+ else
23
+ no[k] = v
24
+ end
25
+ end
26
+ [yes, no]
27
+ end
28
+
29
+ def recursive_update(hash)
30
+ hash.each_pair do |key, value|
31
+ current = self[key]
32
+ if current.is_a?(Hash) and value.is_a?(Hash)
33
+ current.recursive_update(value)
34
+ else
35
+ self[key] = value
36
+ end
37
+ end
38
+ end
39
+
40
+ def -(keys)
41
+ res = {}
42
+ each_pair {|k, v| res[k] = v unless k.in?(keys)}
43
+ res
44
+ end
45
+
46
+ def &(keys)
47
+ res = {}
48
+ keys.each {|k| res[k] = self[k] if has_key?(k)}
49
+ res
50
+ end
51
+
52
+ alias_method :| , :merge
53
+
54
+ def get(*args)
55
+ args.map {|a| self[a] }
56
+ end
57
+
58
+ end
59
+
60
+
61
+ # HashWithIndifferentAccess from ActiveSupport needs different
62
+ # versions of these
63
+
64
+ if defined? HashWithIndifferentAccess
65
+
66
+ class HashWithIndifferentAccess
67
+
68
+ def -(keys)
69
+ res = HashWithIndifferentAccess.new
70
+ keys = keys.map {|k| k.is_a?(Symbol) ? k.to_s : k }
71
+ each_pair { |k, v| res[k] = v unless k.in?(keys) }
72
+ res
73
+ end
74
+
75
+ def &(keys)
76
+ res = HashWithIndifferentAccess.new
77
+ keys.each do |k|
78
+ k = k.to_s if k.is_a?(Symbol)
79
+ res[k] = self[k] if has_key?(k)
80
+ end
81
+ res
82
+ end
83
+
84
+ def partition_hash(keys=nil)
85
+ keys = keys._?.map {|k| k.is_a?(Symbol) ? k.to_s : k }
86
+ yes = HashWithIndifferentAccess.new
87
+ no = HashWithIndifferentAccess.new
88
+ each do |k,v|
89
+ if block_given? ? yield(k,v) : keys.include?(k)
90
+ yes[k] = v
91
+ else
92
+ no[k] = v
93
+ end
94
+ end
95
+ [yes, no]
96
+ end
97
+
98
+ end
99
+
100
+ end
@@ -0,0 +1,15 @@
1
+ class TrueClass
2
+
3
+ def implies(x=nil)
4
+ block_given? ? yield : x
5
+ end
6
+
7
+ end
8
+
9
+ class FalseClass
10
+
11
+ def implies(x)
12
+ true
13
+ end
14
+
15
+ end
@@ -0,0 +1,28 @@
1
+ # Thanks to _why
2
+
3
+ class Object
4
+
5
+ def metaclass; class << self; self; end; end
6
+
7
+ def meta_eval(src=nil, &blk)
8
+ if src
9
+ metaclass.instance_eval(src)
10
+ else
11
+ metaclass.instance_eval &blk
12
+ end
13
+ end
14
+
15
+ def metaclass_eval(src=nil, &blk)
16
+ if src
17
+ metaclass.class_eval(src)
18
+ else
19
+ metaclass.class_eval &blk
20
+ end
21
+ end
22
+
23
+ # Adds methods to a metaclass
24
+ def meta_def(name, &blk)
25
+ meta_eval { define_method name, &blk }
26
+ end
27
+
28
+ end
@@ -0,0 +1,61 @@
1
+ # The dot operator calls methods on objects. Power Dots are dots with extra features
2
+ #
3
+ # .? calls a method if the reciever is not nil, returns nil
4
+ # otherwise. We have to write it ._?. in order to be valid Ruby
5
+ #
6
+ # .try. calls a mehod only if the recipient resonds to that method
7
+
8
+ require 'delegate'
9
+ require 'singleton'
10
+
11
+ class Object
12
+
13
+ def _?()
14
+ self
15
+ end
16
+
17
+ def try
18
+ CallIfAvailable.new(self)
19
+ end
20
+
21
+ end
22
+
23
+
24
+ class NilClass
25
+ def _?()
26
+ SafeNil.instance
27
+ end
28
+ end
29
+
30
+
31
+ class SafeNil
32
+ include Singleton
33
+
34
+ def method_missing(method, *args, &b)
35
+ return nil unless nil.respond_to? method
36
+ nil.send(method, *args, &b) rescue nil
37
+ end
38
+ end
39
+
40
+
41
+ alias DelegateClass_without_safe_nil DelegateClass
42
+ def DelegateClass(klass)
43
+ c = DelegateClass_without_safe_nil(klass)
44
+ c.class_eval do
45
+ def _?
46
+ self
47
+ end
48
+ end
49
+ c
50
+ end
51
+
52
+
53
+ class CallIfAvailable < BlankSlate
54
+
55
+ def method_missing(name, *args, &b)
56
+ @me.send(name, *args, &b) if @me.respond_to?(name)
57
+ end
58
+
59
+ end
60
+
61
+
@@ -0,0 +1,29 @@
1
+ # From: http://jicksta.com/articles/2007/08/04/the-methodphitamine
2
+
3
+ module Kernel
4
+
5
+ def it() It.new end
6
+ alias its it
7
+
8
+ end
9
+
10
+ class It < BlankSlate
11
+
12
+ def initialize
13
+ @methods = []
14
+ end
15
+
16
+ def method_missing(*args, &block)
17
+ @methods << [args, block] unless args == [:respond_to?, :to_proc]
18
+ self
19
+ end
20
+
21
+ def to_proc
22
+ lambda do |obj|
23
+ @methods.inject(obj) do |current,(args,block)|
24
+ current.send(*args, &block)
25
+ end
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,67 @@
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.included_in_class(base) if m.respond_to?(:included_in_class) }
14
+ end
15
+ end
16
+
17
+ # An attr_accessor for classes that will delegate to the superclass
18
+ # if not defined on self
19
+ def inheriting_attr_reader(*names)
20
+ for name in names
21
+ class_eval %{
22
+ def #{name}
23
+ if defined? @#{name}
24
+ @#{name}
25
+ elsif superclass.respond_to?('#{name}')
26
+ superclass.#{name}
27
+ end
28
+ end
29
+ }
30
+ end
31
+ end
32
+
33
+ # creates a #foo= and #foo? pair, with optional default values, e.g.
34
+ # bool_attr_accessor :happy => true
35
+ def bool_attr_accessor(*args)
36
+ options = args.extract_options!
37
+ (args + options.keys).each {|n| class_eval "def #{n}=(x); @#{n} = x; end" }
38
+
39
+ args.each {|n| class_eval "def #{n}?; @#{n}; end" }
40
+
41
+ options.keys.each do |n|
42
+ class_eval %(def #{n}?
43
+ if !defined? @#{n}
44
+ @#{n} = #{options[n] ? 'true' : 'false'}
45
+ else
46
+ @#{n}
47
+ end
48
+ end)
49
+ set_field_type(n => TrueClass) if respond_to?(:set_field_type)
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+
56
+ # classy_module lets you extract code from classes into modules, but
57
+ # still write it the same way
58
+ module Kernel
59
+
60
+ def classy_module(&b)
61
+ m = Module.new
62
+ m.meta_def :included do |base|
63
+ base.class_eval &b
64
+ end
65
+ end
66
+
67
+ end
@@ -0,0 +1,41 @@
1
+ require "hobosupport/fixes"
2
+ require 'hobosupport/blankslate'
3
+ require 'hobosupport/methodcall'
4
+ require 'hobosupport/methodphitamine'
5
+ require 'hobosupport/metaid'
6
+ require 'hobosupport/implies'
7
+ require 'hobosupport/enumerable'
8
+ require 'hobosupport/array'
9
+ require 'hobosupport/hash'
10
+ require 'hobosupport/module'
11
+
12
+ module HoboSupport
13
+
14
+ VERSION = "0.1"
15
+
16
+ end
17
+
18
+
19
+ # Some teeny fixes too diminutive to go elsewhere
20
+
21
+ class Object
22
+
23
+ # Often nice to ask e.g. some_object.is_a?(Symbol, String)
24
+ alias_method :is_a_without_multiple_args?, :is_a?
25
+ def is_a?(*args)
26
+ args.any? {|a| is_a_without_multiple_args?(a) }
27
+ end
28
+
29
+ end
30
+
31
+
32
+ # --- Rails extensions --- #
33
+
34
+ # Nice tip from Jamis Buck
35
+ if defined? ActiveRecord
36
+ class << ActiveRecord::Base
37
+ alias_method :[], :find
38
+ end
39
+ end
40
+
41
+
@@ -0,0 +1,120 @@
1
+ # HoboSupport - Eumerable extensions
2
+
3
+ >> require 'hobosupport'
4
+ >> HoboSupport::VERSION
5
+ => "0.1"
6
+
7
+ ## Enumerable#search
8
+
9
+ * `enum.search(not_found) { |element| block}`
10
+
11
+ 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.
12
+
13
+ E.g. The length of the first word that starts with a capital letter
14
+
15
+ >> %w(my name is Fred).search { |s| s.length if s =~ /^[A-Z]/ }
16
+ => 4
17
+
18
+ ## Enumerable#map_with_index
19
+
20
+ * `enum.map_with_index { |element, index| block }`
21
+
22
+ Just like #map but the block gets the element and the index.
23
+
24
+ >> %w(some short words).map_with_index { |s, i| s * i }
25
+ => ["", "short", "wordswords"]
26
+
27
+ ## Enumerable#build_hash
28
+
29
+ * `enum.build_hash { |element| block }`
30
+
31
+ 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.
32
+
33
+ >> %w(some short words).build_hash { |s| [s, s.length] unless s == "short" }
34
+ => {"some"=>4, "words"=>5}
35
+
36
+
37
+ ## Enumerable#map_hash
38
+
39
+ * `enum.map_hash { |element| block }`
40
+
41
+ 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.
42
+
43
+ >> %w(some short words).map_hash { |s| s.length }
44
+ => {"some"=>4, "short"=>5, "words"=>5}
45
+
46
+ ## Enumerable#rest
47
+
48
+ Shorthand for `enum[1..-1]`
49
+
50
+ >> %w(some short words).rest
51
+ => ["short", "words"]
52
+
53
+
54
+ ## Enumerable#*
55
+
56
+ Shorthand for `map` when you need to map a single method call on the elements.
57
+
58
+ >> %w(some short words).*.length
59
+ => [4, 5, 5]
60
+
61
+ ## Enumerable#where
62
+
63
+ Shorthand for `select` when you need to select on a single method call.
64
+
65
+ >> %w(some short words).where.include?("r")
66
+ => ["short", "words"]
67
+
68
+ ## Enumerable#where_not
69
+
70
+ Shorthand for `reject` when you need to reject on a single method call.
71
+
72
+ >> %w(some short words).where_not.include?("r")
73
+ => ["some"]
74
+
75
+ ## Enumerable#drop_while
76
+
77
+ * `enum.drop_while { |element| block }`
78
+
79
+ Passes each element in turn to the block until the block returns false. Returns the remaining elements in a new array.
80
+
81
+ >> %w(this is a nice example).drop_while { |s| s.length > 1 }
82
+ => ["a", "nice", "example"]
83
+
84
+ There is also a destructive version for arrays
85
+
86
+ >> a = %w(this is a nice example)
87
+ >> a.drop_while! { |s| s.length > 1 }
88
+ >> a
89
+ => ["a", "nice", "example"]
90
+
91
+
92
+ ## Enumerable#take_while
93
+
94
+ * `enum.take_while { |element| block }`
95
+
96
+ 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
97
+
98
+ >> %w(this is a nice example).take_while { |s| s.length > 1 }
99
+ => ["this", "is"]
100
+
101
+
102
+ ## Object#in?
103
+
104
+ * `obj.in?(enum)`
105
+
106
+ Shorthand for `enum.include?(obj)`
107
+
108
+ >> 3.in?(0..10)
109
+ => true
110
+ >> 300.in?(0..10)
111
+ => false
112
+
113
+ ## Object#not_in?
114
+
115
+ * `obj.not_in?(enum)`
116
+
117
+ >> 3.not_in?(0..10)
118
+ => false
119
+ >> 300.not_in?(0..10)
120
+ => true
@@ -0,0 +1,103 @@
1
+ # HoboSupport - Hash extensions
2
+
3
+ >> require 'hobosupport'
4
+ >> HoboSupport::VERSION
5
+ => "0.1"
6
+
7
+ ## Hash#select_hash
8
+
9
+ * `hash.select_hash { |key, value| block } => hash`
10
+ * `hash.select_hash { |value| block } => hash`
11
+
12
+ 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.
13
+
14
+ >> {1=>2, 3=>4, 6=>5}.select_hash { |key, value| key < value }
15
+ => {1=>2, 3=>4}
16
+
17
+ You can also give a block that takes one argument, in which case the block is given the value only
18
+
19
+ >> {1=>2, 3=>4, 6=>5}.select_hash { |value| value != 2 }
20
+ => {3=>4, 6=>5}
21
+
22
+
23
+ ## Hash#map_hash
24
+
25
+ * `hash.map_hash { |key, value| block } => hash`
26
+ * `hash.map_hash { |value| block } => hash`
27
+
28
+ 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
29
+
30
+ >> {1=>2, 3=>4, 6=>5}.map_hash { |key, value| key < value }
31
+ => {1=>true, 3=>true, 6=>false}
32
+
33
+ You can also give a block which takes one argument, in which case only the value is passed in
34
+
35
+ >> {1=>2, 3=>4, 6=>5}.map_hash { |value| value * 100 }
36
+ => {1=>200, 3=>400, 6=>500 }
37
+
38
+
39
+ ## Hash#partition_hash
40
+
41
+ * `hash.partition_hash(keys) => [hash1, hash2]`
42
+ * `hash.partition_hash { |key, value| block } => hash`
43
+
44
+ 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
45
+
46
+ >> {1=>2, 3=>4, 6=>5}.partition_hash([1, 3])
47
+ => [{1=>2, 3=>4}, {6=>5}]
48
+
49
+ 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
50
+
51
+ >> {1=>2, 3=>4, 6=>5}.partition_hash { |key, value| key < value }
52
+ => [{1=>2, 3=>4}, {6=>5}]
53
+
54
+ ## Hash.recursive_update
55
+
56
+ * `hash.recursive_update(hash2)`
57
+
58
+ Like `#update` but where a sub-hash would overwrite another sub-hash, they are instead also merged, recursively
59
+
60
+ >> h = { :a => 1, :b => { :x => 10 } }
61
+ >> h.recursive_update({ :c => 3, :b => { :y => 20 } })
62
+ >> h
63
+ => { :a => 1, :b => { :x => 10, :y => 20}, :c => 3 }
64
+
65
+
66
+ ## Hash#-
67
+
68
+ * `hash - array => hash`
69
+
70
+ Returns a new hash, the left-hand-side hash with all pairs removed where the key is present in the right-hand-side array.
71
+
72
+ >> {1=>2, 3=>4, 6=>5} - [1, 3]
73
+ => {6 => 5}
74
+
75
+ ## Hash#&
76
+
77
+ * `hash & array => array`
78
+
79
+ Returns a new array, the left hand side hash restricted to pairs where the key is present in the right-hand-side array
80
+
81
+ >> {1=>2, 3=>4, 6=>5} & [1, 3]
82
+ => {1=>2, 3=>4}
83
+
84
+ ## Hash#|
85
+
86
+ * `hash | hash => hash`
87
+
88
+ An alias for merge
89
+
90
+ >> {1 => 2} | {1 => 3, 2 => 4}
91
+ => {1 => 3, 2 => 4}
92
+
93
+
94
+ ## Hash#get
95
+
96
+ * `hash.get(*args) => hash`
97
+
98
+ Returns an array of values for the given keys. Useful for extracting a few options into local variables.
99
+
100
+ >> {1=>2, 3=>4, 6=>5}.get(1, 3)
101
+ => [2, 4]
102
+
103
+
@@ -0,0 +1,21 @@
1
+ # HoboSupport - implies
2
+
3
+ >> require 'hobosupport'
4
+ >> HoboSupport::VERSION
5
+ => "0.1"
6
+
7
+ The implies operator comes from Eiffel. Often comes in handy in Hobo's model-permission methods.
8
+
9
+ ## TrueClass#implies and FalseClass#implies
10
+
11
+ >> false.implies true
12
+ => true
13
+
14
+ >> false.implies false
15
+ => true
16
+
17
+ >> true.implies true
18
+ => true
19
+
20
+ >> true.implies false
21
+ => false
@@ -0,0 +1,60 @@
1
+ # HoboSupport - Metaid
2
+
3
+ >> require 'hobosupport'
4
+ >> HoboSupport::VERSION
5
+ => "0.1"
6
+
7
+ Why the Luck Stiff's essential meta-programming additions to Object. These are probably distributed elsewhere, but they're small enough to throw them in to HoboSupport and remove an external dependency.
8
+
9
+ ## Object#metaclass
10
+
11
+ Returns the "metaclass" (bad name) or "singleton class" of a given ruby Object
12
+
13
+ >> o = Object.new
14
+ >> def o.foo; ;123; end
15
+ >> o.foo
16
+ => 123
17
+ >> o.metaclass.instance_methods.grep "foo"
18
+ => ["foo"]
19
+
20
+ ## Object#meta_eval
21
+
22
+ * `object.meta_eval(string)`
23
+ * `object.meta_eval { block }`
24
+
25
+ Evaluates ruby source or a block in the context of the metaclass.
26
+
27
+ >> File.meta_eval "alias_method :b, :basename"
28
+ >> File.b "a/b"
29
+ => "b"
30
+
31
+ And with a block
32
+
33
+ >> File.meta_eval { alias_method :b2, :basename }
34
+ >> File.b2 "a/b"
35
+ => "b"
36
+
37
+ ## Object#metaclass_eval
38
+
39
+ * `object.metaclass_eval(string)`
40
+ * `object.metaclass_eval { block }`
41
+
42
+ Like #meta_eval, but does a `class_eval` instead of an `instance_eval`
43
+
44
+ >> File.metaclass_eval "def b3(path); basename(path); end"
45
+ >> File.b3 "a/b"
46
+ => "b"
47
+
48
+ And with a block
49
+
50
+ >> File.metaclass_eval { def b4(path); basename(path); end }
51
+ >> File.b4 "a/b"
52
+ => "b"
53
+
54
+
55
+ ## Object#meta_def
56
+
57
+ >> String.meta_def(:backwards_new) { |s| s.reverse }
58
+ >> String.backwards_new "strange"
59
+ => "egnarts"
60
+
@@ -0,0 +1,19 @@
1
+ # HoboSupport - Methodphitamine
2
+
3
+ >> require 'hobosupport'
4
+ >> HoboSupport::VERSION
5
+ => "0.1"
6
+
7
+ ## Kernel#it and Kernel#its
8
+
9
+ A nice hack from Jay Phillips, christened "Methodphitamine". The low-down is in the [original blog post][1].
10
+
11
+ [1]: http://jicksta.com/articles/2007/08/04/the-methodphitamine
12
+
13
+ >> (1..10).select &it % 2 == 0
14
+ => [2, 4, 6, 8, 10]
15
+ >> %w(a few short words).map &its.length
16
+ => [1, 3, 5, 5]
17
+
18
+ Note that `it` and `its` are identical. They just read better in different contexts. Note that methodphitamine is also released directly by Jay (simply `gem install methodphitamine`) but it's small enough that it seemed easier to add it to HoboSupport and avoid an extra dependency. Thanks to Jay.
19
+
@@ -0,0 +1,72 @@
1
+ # HoboSupport - Module extensions
2
+
3
+ >> require 'hobosupport'
4
+ >> HoboSupport::VERSION
5
+ => "0.1"
6
+
7
+ ## Module#included_in_class_callbacks
8
+
9
+ Bit involved, this one :-)
10
+
11
+ When a module is included in a class, it gets a callback on the `included` method, with the class passed as argument. However, if a module M2 is included in M1, and a class C includes M1, then M2 never gets to know about C. So, for example, M2 could not `alias_method_chain` a class method on C.
12
+
13
+ `included_in_class_callbacks` makes it easy to implement a notification from M1 to M2, so that M2 does have full access to the class. All you do is insert a call to `included_in_class_callbacks(base)` as the end of the module's `self.included` method.
14
+
15
+ (Note we're using the metaid extensions here too)
16
+
17
+ >>
18
+ module M2
19
+ def self.included_in_class(klass)
20
+ klass.metaclass_eval do
21
+ def name_with_shouting; name_without_shouting.upcase; end
22
+ alias_method_chain :name, :shouting
23
+ end
24
+ end
25
+ end
26
+
27
+ module M1
28
+ def self.included(base)
29
+ included_in_class_callbacks(base)
30
+ end
31
+ include M2
32
+ end
33
+
34
+ class C
35
+ def self.name
36
+ "my name is C"
37
+ end
38
+ include M1
39
+ end
40
+
41
+ C.name
42
+ => "MY NAME IS C"
43
+
44
+
45
+ ## Module#interiting_attr_accessor
46
+
47
+ Only for use on classes. Like `attr_accessor`, but the attribute is looked up on the superclass if not defined on the receiving class. In other words, the superclass defines a default that subclasses can override.
48
+
49
+ >>
50
+ class A
51
+ class << self
52
+ inheriting_attr_reader :name
53
+ end
54
+ @name = "Andy"
55
+ end
56
+
57
+ class B < A; end
58
+
59
+ `B` has the same name as its superclass `A`
60
+
61
+ >> A.name
62
+ => "Andy"
63
+ >> B.name
64
+ => "Andy"
65
+
66
+ Now we change the name of `B`. `A` retains it's existing name.
67
+
68
+ >> class B; @name = "Bob"; end
69
+ >> B.name
70
+ => "Bob"
71
+ >> A.name
72
+ => "Andy"
@@ -0,0 +1,53 @@
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
+ >> require 'hobosupport'
8
+ >> HoboSupport::VERSION
9
+ => "0.1"
10
+
11
+ ## Object extensions
12
+
13
+ ### Object#is_a?
14
+
15
+ Extended to allow multiple types to be checked in one go
16
+
17
+ >> "foo".is_a?(String, Symbol)
18
+ => true
19
+ >> :foo.is_a?(String, Symbol)
20
+ => true
21
+ >> 1.is_a?(String, Symbol)
22
+ => false
23
+
24
+ Still works the old way
25
+
26
+ >> "foo".is_a?(String)
27
+ => true
28
+ >> :foo.is_a?(String)
29
+ => false
30
+
31
+
32
+ ## Method call extensions
33
+
34
+ ### Object#_?
35
+
36
+ We have the "." operator to call methods on objects. These extensions introduce two "special dots". "`._?.`" only calls the method if the receiver is not `nil`.
37
+
38
+ >> "foo"._?.length
39
+ => 3
40
+ >> nil._?.length
41
+ => nil
42
+
43
+
44
+ ### Object#try
45
+
46
+ "`.try`" only calls the method if the receiver responds to that method.
47
+
48
+ >> "foo".try.length
49
+ => 3
50
+ >> :foo.try.length
51
+ => nil
52
+
53
+
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
4
+ name: hobosupport
5
+ version: !ruby/object:Gem::Version
6
+ version: "0.1"
7
+ date: 2008-02-11 00:00:00 +00:00
8
+ summary: Core Ruby extensions from the Hobo project
9
+ require_paths:
10
+ - lib
11
+ email: tom@tomlocke.com
12
+ homepage: http://hobocentral.net/hobo-support
13
+ rubyforge_project: hobo
14
+ description: "== DESCRIPTION: A mixed bag of core Ruby extenstion that have been extracted from the Hobo project. == INSTALL: * sudo gem install hobosupport"
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Tom Locke
31
+ files:
32
+ - History.txt
33
+ - Manifest.txt
34
+ - README.txt
35
+ - Rakefile
36
+ - lib/hobosupport.rb
37
+ - lib/hobosupport/array.rb
38
+ - lib/hobosupport/blankslate.rb
39
+ - lib/hobosupport/enumerable.rb
40
+ - lib/hobosupport/fixes.rb
41
+ - lib/hobosupport/fixes/chronic.rb
42
+ - lib/hobosupport/fixes/module.rb
43
+ - lib/hobosupport/fixes/pp.rb
44
+ - lib/hobosupport/hash.rb
45
+ - lib/hobosupport/implies.rb
46
+ - lib/hobosupport/metaid.rb
47
+ - lib/hobosupport/methodcall.rb
48
+ - lib/hobosupport/methodphitamine.rb
49
+ - lib/hobosupport/module.rb
50
+ - test/hobosupport.rdoctest
51
+ - test/hobosupport/enumerable.rdoctest
52
+ - test/hobosupport/hash.rdoctest
53
+ - test/hobosupport/implies.rdoctest
54
+ - test/hobosupport/metaid.rdoctest
55
+ - test/hobosupport/methodphitamine.rdoctest
56
+ - test/hobosupport/module.rdoctest
57
+ test_files: []
58
+
59
+ rdoc_options:
60
+ - --main
61
+ - README.txt
62
+ extra_rdoc_files:
63
+ - History.txt
64
+ - Manifest.txt
65
+ - README.txt
66
+ executables: []
67
+
68
+ extensions: []
69
+
70
+ requirements: []
71
+
72
+ dependencies:
73
+ - !ruby/object:Gem::Dependency
74
+ name: hoe
75
+ version_requirement:
76
+ version_requirements: !ruby/object:Gem::Version::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: 1.5.0
81
+ version: