gorillib 0.0.2

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.
Files changed (67) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/LICENSE.textile +81 -0
  4. data/README.textile +153 -0
  5. data/Rakefile +26 -0
  6. data/VERSION +1 -0
  7. data/fiddle/hubahuba.rb +62 -0
  8. data/gorillib.gemspec +142 -0
  9. data/lib/gorillib/array/compact_blank.rb +17 -0
  10. data/lib/gorillib/array/extract_options.rb +29 -0
  11. data/lib/gorillib/base.rb +7 -0
  12. data/lib/gorillib/datetime/flat.rb +29 -0
  13. data/lib/gorillib/datetime/parse.rb +21 -0
  14. data/lib/gorillib/enumerable/sum.rb +38 -0
  15. data/lib/gorillib/hash/compact.rb +31 -0
  16. data/lib/gorillib/hash/deep_merge.rb +16 -0
  17. data/lib/gorillib/hash/keys.rb +42 -0
  18. data/lib/gorillib/hash/reverse_merge.rb +26 -0
  19. data/lib/gorillib/hash/slice.rb +53 -0
  20. data/lib/gorillib/hash/zip.rb +10 -0
  21. data/lib/gorillib/logger/log.rb +14 -0
  22. data/lib/gorillib/metaprogramming/aliasing.rb +43 -0
  23. data/lib/gorillib/metaprogramming/cattr_accessor.rb +79 -0
  24. data/lib/gorillib/metaprogramming/class_attribute.rb +90 -0
  25. data/lib/gorillib/metaprogramming/delegation.rb +146 -0
  26. data/lib/gorillib/metaprogramming/mattr_accessor.rb +61 -0
  27. data/lib/gorillib/metaprogramming/remove_method.rb +11 -0
  28. data/lib/gorillib/metaprogramming/singleton_class.rb +8 -0
  29. data/lib/gorillib/object/blank.rb +89 -0
  30. data/lib/gorillib/some.rb +12 -0
  31. data/lib/gorillib/string/constantize.rb +21 -0
  32. data/lib/gorillib/string/human.rb +52 -0
  33. data/lib/gorillib/string/inflections.rb +78 -0
  34. data/lib/gorillib/string/truncate.rb +33 -0
  35. data/lib/gorillib.rb +1 -0
  36. data/spec/blank_spec.rb +86 -0
  37. data/spec/gorillib_spec.rb +7 -0
  38. data/spec/rcov.opts +6 -0
  39. data/spec/spec.opts +4 -0
  40. data/spec/spec_helper.rb +12 -0
  41. data/spec/spec_tasks.rake +15 -0
  42. data/test/abstract_unit.rb +25 -0
  43. data/test/array/compact_blank_test.rb +33 -0
  44. data/test/array/extract_options_test.rb +39 -0
  45. data/test/datetime/flat_test.rb +0 -0
  46. data/test/datetime/parse_test.rb +0 -0
  47. data/test/enumerable/sum_test.rb +50 -0
  48. data/test/hash/compact_test.rb +38 -0
  49. data/test/hash/deep_merge_test.rb +30 -0
  50. data/test/hash/keys_test.rb +110 -0
  51. data/test/hash/reverse_merge_test.rb +20 -0
  52. data/test/hash/slice_test.rb +47 -0
  53. data/test/hash/zip_test.rb +0 -0
  54. data/test/logger/log_test.rb +0 -0
  55. data/test/metaprogramming/aliasing_test.rb +188 -0
  56. data/test/metaprogramming/cattr_accessor_test.rb +38 -0
  57. data/test/metaprogramming/class_attribute_test.rb +73 -0
  58. data/test/metaprogramming/delegation_test.rb +166 -0
  59. data/test/metaprogramming/mattr_accessor_test.rb +40 -0
  60. data/test/metaprogramming/singleton_class_test.rb +9 -0
  61. data/test/object/blank_test.rb +22 -0
  62. data/test/string/constantize_test.rb +30 -0
  63. data/test/string/human_test.rb +65 -0
  64. data/test/string/inflections_test.rb +57 -0
  65. data/test/string/inflector_test_cases.rb +50 -0
  66. data/test/string/truncate_test.rb +37 -0
  67. metadata +199 -0
@@ -0,0 +1,16 @@
1
+ class Hash
2
+ # Returns a new hash with +self+ and +other_hash+ merged recursively.
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!)
16
+ end
@@ -0,0 +1,42 @@
1
+ class Hash
2
+ # Return a new hash with all keys converted to strings.
3
+ def stringify_keys
4
+ dup.stringify_keys!
5
+ end unless method_defined?(:stringify_keys)
6
+
7
+ # Destructively convert all keys to strings.
8
+ def stringify_keys!
9
+ keys.each do |key|
10
+ self[key.to_s] = delete(key)
11
+ end
12
+ self
13
+ end unless method_defined?(:stringify_keys!)
14
+
15
+ # Return a new hash with all keys converted to symbols, as long as
16
+ # they respond to +to_sym+.
17
+ def symbolize_keys
18
+ dup.symbolize_keys!
19
+ end unless method_defined?(:symbolize_keys)
20
+
21
+ # Destructively convert all keys to symbols, as long as they respond
22
+ # to +to_sym+.
23
+ def symbolize_keys!
24
+ keys.each do |key|
25
+ self[(key.to_sym rescue key) || key] = delete(key)
26
+ end
27
+ self
28
+ end unless method_defined?(:symbolize_keys!)
29
+
30
+ # Validate all keys in a hash match *valid keys, raising ArgumentError on a mismatch.
31
+ # Note that keys are NOT treated indifferently, meaning if you use strings for keys but assert symbols
32
+ # as keys, this will fail.
33
+ #
34
+ # ==== Examples
35
+ # { :name => "Rob", :years => "28" }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key(s): years"
36
+ # { :name => "Rob", :age => "28" }.assert_valid_keys("name", "age") # => raises "ArgumentError: Unknown key(s): name, age"
37
+ # { :name => "Rob", :age => "28" }.assert_valid_keys(:name, :age) # => passes, raises nothing
38
+ def assert_valid_keys(*valid_keys)
39
+ unknown_keys = keys - [valid_keys].flatten
40
+ raise(ArgumentError, "Unknown key(s): #{unknown_keys.join(", ")}") unless unknown_keys.empty?
41
+ end unless method_defined?(:assert_valid_keys)
42
+ end
@@ -0,0 +1,26 @@
1
+ class Hash
2
+ # Allows for reverse merging two hashes where the keys in the calling hash take precedence over those
3
+ # in the <tt>other_hash</tt>. This is particularly useful for initializing an option hash with default values:
4
+ #
5
+ # def setup(options = {})
6
+ # options.reverse_merge! :size => 25, :velocity => 10
7
+ # end
8
+ #
9
+ # Using <tt>merge</tt>, the above example would look as follows:
10
+ #
11
+ # def setup(options = {})
12
+ # { :size => 25, :velocity => 10 }.merge(options)
13
+ # end
14
+ #
15
+ # The default <tt>:size</tt> and <tt>:velocity</tt> are only set if the +options+ hash passed in doesn't already
16
+ # have the respective key.
17
+ def reverse_merge(other_hash)
18
+ other_hash.merge(self)
19
+ end unless method_defined?(:reverse_merge)
20
+
21
+ # Performs the opposite of <tt>merge</tt>, with the keys and values from the first hash taking precedence over the second.
22
+ # Modifies the receiver in place.
23
+ def reverse_merge!(other_hash)
24
+ merge!( other_hash ){|k,o,n| o }
25
+ end unless method_defined?(:reverse_merge!)
26
+ end
@@ -0,0 +1,53 @@
1
+ class Hash
2
+ # Slice a hash to include only the given keys. This is useful for
3
+ # limiting an options hash to valid keys before passing to a method:
4
+ #
5
+ # def search(criteria = {})
6
+ # assert_valid_keys(:mass, :velocity, :time)
7
+ # end
8
+ #
9
+ # search(options.slice(:mass, :velocity, :time))
10
+ #
11
+ # If you have an array of keys you want to limit to, you should splat them:
12
+ #
13
+ # valid_keys = [:mass, :velocity, :time]
14
+ # search(options.slice(*valid_keys))
15
+ def slice(*keys)
16
+ keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
17
+ hash = self.class.new
18
+ keys.each { |k| hash[k] = self[k] if has_key?(k) }
19
+ hash
20
+ end unless method_defined?(:slice)
21
+
22
+ # Replaces the hash with only the given keys.
23
+ # Returns a hash containing the removed key/value pairs
24
+ # @example
25
+ # hsh = {:a => 1, :b => 2, :c => 3, :d => 4}
26
+ # hsh.slice!(:a, :b)
27
+ # # => {:c => 3, :d =>4}
28
+ # hsh
29
+ # # => {:a => 1, :b => 2}
30
+ def slice!(*keys)
31
+ keys = keys.map! { |key| convert_key(key) } if respond_to?(:convert_key)
32
+ omit = slice(*self.keys - keys)
33
+ hash = slice(*keys)
34
+ replace(hash)
35
+ omit
36
+ end unless method_defined?(:slice!)
37
+
38
+ # Removes the given keys from the hash
39
+ # Returns a hash containing the removed key/value pairs
40
+ #
41
+ # @example
42
+ # hsh = {:a => 1, :b => 2, :c => 3, :d => 4}
43
+ # hsh.extract!(:a, :b)
44
+ # # => {:a => 1, :b => 2}
45
+ # hsh
46
+ # # => {:c => 3, :d =>4}
47
+ def extract!(*keys)
48
+ result = {}
49
+ keys.each {|key| result[key] = delete(key) }
50
+ result
51
+ end unless method_defined?(:extract!)
52
+ end
53
+
@@ -0,0 +1,10 @@
1
+ class Hash
2
+ #
3
+ # Create a hash from an array of keys and corresponding values.
4
+ #
5
+ def self.zip(keys, values, default=nil, &block)
6
+ hash = block_given? ? Hash.new(&block) : Hash.new(default)
7
+ keys.zip(values){|key,val| hash[key]=val }
8
+ hash
9
+ end unless respond_to?(:zip)
10
+ end
@@ -0,0 +1,14 @@
1
+ require 'logger'
2
+
3
+ #
4
+ # A convenient logger.
5
+ #
6
+ # define Log yourself to prevent its creation
7
+ #
8
+ ::Log = Logger.new(STDERR) unless defined?(::Log)
9
+
10
+ def Log.dump *args
11
+ debug args.map(&:inspect).join("\t")
12
+ end unless Log.respond_to?(:dump)
13
+
14
+
@@ -0,0 +1,43 @@
1
+ class Module
2
+ # Encapsulates the common pattern of:
3
+ #
4
+ # alias_method :foo_without_feature, :foo
5
+ # alias_method :foo, :foo_with_feature
6
+ #
7
+ # With this, you simply do:
8
+ #
9
+ # alias_method_chain :foo, :feature
10
+ #
11
+ # And both aliases are set up for you.
12
+ #
13
+ # Query and bang methods (foo?, foo!) keep the same punctuation:
14
+ #
15
+ # alias_method_chain :foo?, :feature
16
+ #
17
+ # is equivalent to
18
+ #
19
+ # alias_method :foo_without_feature?, :foo?
20
+ # alias_method :foo?, :foo_with_feature?
21
+ #
22
+ # so you can safely chain foo, foo?, and foo! with the same feature.
23
+ def alias_method_chain(target, feature)
24
+ # Strip out punctuation on predicates or bang methods since
25
+ # e.g. target?_without_feature is not a valid method name.
26
+ aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
27
+ yield(aliased_target, punctuation) if block_given?
28
+
29
+ with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}"
30
+
31
+ alias_method without_method, target
32
+ alias_method target, with_method
33
+
34
+ case
35
+ when public_method_defined?(without_method)
36
+ public target
37
+ when protected_method_defined?(without_method)
38
+ protected target
39
+ when private_method_defined?(without_method)
40
+ private target
41
+ end
42
+ end unless method_defined?(:alias_method_chain)
43
+ end
@@ -0,0 +1,79 @@
1
+ require 'gorillib/array/extract_options'
2
+
3
+ # Extends the class object with class and instance accessors for class attributes,
4
+ # just like the native attr* accessors for instance attributes.
5
+ #
6
+ # Note that unlike +class_attribute+, if a subclass changes the value then that would
7
+ # also change the value for parent class. Similarly if parent class changes the value
8
+ # then that would change the value of subclasses too.
9
+ #
10
+ # class Person
11
+ # cattr_accessor :hair_colors
12
+ # end
13
+ #
14
+ # Person.hair_colors = [:brown, :black, :blonde, :red]
15
+ # Person.hair_colors # => [:brown, :black, :blonde, :red]
16
+ # Person.new.hair_colors # => [:brown, :black, :blonde, :red]
17
+ #
18
+ # To opt out of the instance writer method, pass :instance_writer => false.
19
+ # To opt out of the instance reader method, pass :instance_reader => false.
20
+ #
21
+ # class Person
22
+ # cattr_accessor :hair_colors, :instance_writer => false, :instance_reader => false
23
+ # end
24
+ #
25
+ # Person.new.hair_colors = [:brown] # => NoMethodError
26
+ # Person.new.hair_colors # => NoMethodError
27
+ class Class
28
+ def cattr_reader(*syms)
29
+ options = syms.extract_options!
30
+ syms.each do |sym|
31
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
32
+ unless defined? @@#{sym}
33
+ @@#{sym} = nil
34
+ end
35
+
36
+ def self.#{sym}
37
+ @@#{sym}
38
+ end
39
+ EOS
40
+
41
+ unless options[:instance_reader] == false
42
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
43
+ def #{sym}
44
+ @@#{sym}
45
+ end
46
+ EOS
47
+ end
48
+ end
49
+ end unless method_defined?(:cattr_reader)
50
+
51
+ def cattr_writer(*syms)
52
+ options = syms.extract_options!
53
+ syms.each do |sym|
54
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
55
+ unless defined? @@#{sym}
56
+ @@#{sym} = nil
57
+ end
58
+
59
+ def self.#{sym}=(obj)
60
+ @@#{sym} = obj
61
+ end
62
+ EOS
63
+
64
+ unless options[:instance_writer] == false
65
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
66
+ def #{sym}=(obj)
67
+ @@#{sym} = obj
68
+ end
69
+ EOS
70
+ end
71
+ self.send("#{sym}=", yield) if block_given?
72
+ end
73
+ end unless method_defined?(:cattr_writer)
74
+
75
+ def cattr_accessor(*syms, &blk)
76
+ cattr_reader(*syms)
77
+ cattr_writer(*syms, &blk)
78
+ end unless method_defined?(:cattr_accessor)
79
+ end
@@ -0,0 +1,90 @@
1
+ require 'gorillib/metaprogramming/singleton_class'
2
+ require 'gorillib/metaprogramming/remove_method'
3
+
4
+ class Class
5
+ # Declare a class-level attribute whose value is inheritable by subclasses.
6
+ # Subclasses can change their own value and it will not impact parent class.
7
+ #
8
+ # class Base
9
+ # class_attribute :setting
10
+ # end
11
+ #
12
+ # class Subclass < Base
13
+ # end
14
+ #
15
+ # Base.setting = true
16
+ # Subclass.setting # => true
17
+ # Subclass.setting = false
18
+ # Subclass.setting # => false
19
+ # Base.setting # => true
20
+ #
21
+ # In the above case as long as Subclass does not assign a value to setting
22
+ # by performing <tt>Subclass.setting = _something_ </tt>, <tt>Subclass.setting</tt>
23
+ # would read value assigned to parent class. Once Subclass assigns a value then
24
+ # the value assigned by Subclass would be returned.
25
+ #
26
+ # This matches normal Ruby method inheritance: think of writing an attribute
27
+ # on a subclass as overriding the reader method. However, you need to be aware
28
+ # when using +class_attribute+ with mutable structures as +Array+ or +Hash+.
29
+ # In such cases, you don't want to do changes in places but use setters:
30
+ #
31
+ # Base.setting = []
32
+ # Base.setting # => []
33
+ # Subclass.setting # => []
34
+ #
35
+ # # Appending in child changes both parent and child because it is the same object:
36
+ # Subclass.setting << :foo
37
+ # Base.setting # => [:foo]
38
+ # Subclass.setting # => [:foo]
39
+ #
40
+ # # Use setters to not propagate changes:
41
+ # Base.setting = []
42
+ # Subclass.setting += [:foo]
43
+ # Base.setting # => []
44
+ # Subclass.setting # => [:foo]
45
+ #
46
+ # For convenience, a query method is defined as well:
47
+ #
48
+ # Subclass.setting? # => false
49
+ #
50
+ # Instances may overwrite the class value in the same way:
51
+ #
52
+ # Base.setting = true
53
+ # object = Base.new
54
+ # object.setting # => true
55
+ # object.setting = false
56
+ # object.setting # => false
57
+ # Base.setting # => true
58
+ #
59
+ # To opt out of the instance writer method, pass :instance_writer => false.
60
+ #
61
+ # object.setting = false # => NoMethodError
62
+ def class_attribute(*attrs)
63
+ instance_writer = !attrs.last.is_a?(Hash) || attrs.pop[:instance_writer]
64
+
65
+ attrs.each do |name|
66
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
67
+ def self.#{name}() nil end
68
+ def self.#{name}?() !!#{name} end
69
+
70
+ def self.#{name}=(val)
71
+ singleton_class.class_eval do
72
+ remove_possible_method(:#{name})
73
+ define_method(:#{name}) { val }
74
+ end
75
+ val
76
+ end
77
+
78
+ def #{name}
79
+ defined?(@#{name}) ? @#{name} : singleton_class.#{name}
80
+ end
81
+
82
+ def #{name}?
83
+ !!#{name}
84
+ end
85
+ RUBY
86
+
87
+ attr_writer name if instance_writer
88
+ end
89
+ end unless method_defined?(:class_attribute)
90
+ end
@@ -0,0 +1,146 @@
1
+ require "gorillib/metaprogramming/remove_method"
2
+
3
+ class Module
4
+ # Provides a delegate class method to easily expose contained objects' methods
5
+ # as your own. Pass one or more methods (specified as symbols or strings)
6
+ # and the name of the target object via the <tt>:to</tt> option (also a symbol
7
+ # or string). At least one method and the <tt>:to</tt> option are required.
8
+ #
9
+ # Delegation is particularly useful with Active Record associations:
10
+ #
11
+ # class Greeter < ActiveRecord::Base
12
+ # def hello
13
+ # "hello"
14
+ # end
15
+ #
16
+ # def goodbye
17
+ # "goodbye"
18
+ # end
19
+ # end
20
+ #
21
+ # class Foo < ActiveRecord::Base
22
+ # belongs_to :greeter
23
+ # delegate :hello, :to => :greeter
24
+ # end
25
+ #
26
+ # Foo.new.hello # => "hello"
27
+ # Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>
28
+ #
29
+ # Multiple delegates to the same target are allowed:
30
+ #
31
+ # class Foo < ActiveRecord::Base
32
+ # belongs_to :greeter
33
+ # delegate :hello, :goodbye, :to => :greeter
34
+ # end
35
+ #
36
+ # Foo.new.goodbye # => "goodbye"
37
+ #
38
+ # Methods can be delegated to instance variables, class variables, or constants
39
+ # by providing them as a symbols:
40
+ #
41
+ # class Foo
42
+ # CONSTANT_ARRAY = [0,1,2,3]
43
+ # @@class_array = [4,5,6,7]
44
+ #
45
+ # def initialize
46
+ # @instance_array = [8,9,10,11]
47
+ # end
48
+ # delegate :sum, :to => :CONSTANT_ARRAY
49
+ # delegate :min, :to => :@@class_array
50
+ # delegate :max, :to => :@instance_array
51
+ # end
52
+ #
53
+ # Foo.new.sum # => 6
54
+ # Foo.new.min # => 4
55
+ # Foo.new.max # => 11
56
+ #
57
+ # Delegates can optionally be prefixed using the <tt>:prefix</tt> option. If the value
58
+ # is <tt>true</tt>, the delegate methods are prefixed with the name of the object being
59
+ # delegated to.
60
+ #
61
+ # Person = Struct.new(:name, :address)
62
+ #
63
+ # class Invoice < Struct.new(:client)
64
+ # delegate :name, :address, :to => :client, :prefix => true
65
+ # end
66
+ #
67
+ # john_doe = Person.new("John Doe", "Vimmersvej 13")
68
+ # invoice = Invoice.new(john_doe)
69
+ # invoice.client_name # => "John Doe"
70
+ # invoice.client_address # => "Vimmersvej 13"
71
+ #
72
+ # It is also possible to supply a custom prefix.
73
+ #
74
+ # class Invoice < Struct.new(:client)
75
+ # delegate :name, :address, :to => :client, :prefix => :customer
76
+ # end
77
+ #
78
+ # invoice = Invoice.new(john_doe)
79
+ # invoice.customer_name # => "John Doe"
80
+ # invoice.customer_address # => "Vimmersvej 13"
81
+ #
82
+ # If the delegate object is +nil+ an exception is raised, and that happens
83
+ # no matter whether +nil+ responds to the delegated method. You can get a
84
+ # +nil+ instead with the +:allow_nil+ option.
85
+ #
86
+ # class Foo
87
+ # attr_accessor :bar
88
+ # def initialize(bar = nil)
89
+ # @bar = bar
90
+ # end
91
+ # delegate :zoo, :to => :bar
92
+ # end
93
+ #
94
+ # Foo.new.zoo # raises NoMethodError exception (you called nil.zoo)
95
+ #
96
+ # class Foo
97
+ # attr_accessor :bar
98
+ # def initialize(bar = nil)
99
+ # @bar = bar
100
+ # end
101
+ # delegate :zoo, :to => :bar, :allow_nil => true
102
+ # end
103
+ #
104
+ # Foo.new.zoo # returns nil
105
+ #
106
+ def delegate(*methods)
107
+ options = methods.pop
108
+ unless options.is_a?(Hash) && to = options[:to]
109
+ raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)."
110
+ end
111
+
112
+ if options[:prefix] == true && options[:to].to_s =~ /^[^a-z_]/
113
+ raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
114
+ end
115
+
116
+ prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_" || ''
117
+
118
+ file, line = caller.first.split(':', 2)
119
+ line = line.to_i
120
+
121
+ methods.each do |method|
122
+ on_nil =
123
+ if options[:allow_nil]
124
+ 'return'
125
+ else
126
+ %(raise "#{self}##{prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
127
+ end
128
+
129
+ module_eval(<<-EOS, file, line - 5)
130
+ if instance_methods(false).map(&:to_s).include?("#{prefix}#{method}")
131
+ remove_possible_method("#{prefix}#{method}")
132
+ end
133
+
134
+ def #{prefix}#{method}(*args, &block) # def customer_name(*args, &block)
135
+ #{to}.__send__(#{method.inspect}, *args, &block) # client.__send__(:name, *args, &block)
136
+ rescue NoMethodError # rescue NoMethodError
137
+ if #{to}.nil? # if client.nil?
138
+ #{on_nil} # return # depends on :allow_nil
139
+ else # else
140
+ raise # raise
141
+ end # end
142
+ end # end
143
+ EOS
144
+ end
145
+ end unless method_defined?(:delegate)
146
+ end
@@ -0,0 +1,61 @@
1
+ require 'gorillib/array/extract_options'
2
+
3
+ class Module
4
+ def mattr_reader(*syms)
5
+ options = syms.extract_options!
6
+ syms.each do |sym|
7
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
8
+ @@#{sym} = nil unless defined? @@#{sym}
9
+
10
+ def self.#{sym}
11
+ @@#{sym}
12
+ end
13
+ EOS
14
+
15
+ unless options[:instance_reader] == false
16
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
17
+ def #{sym}
18
+ @@#{sym}
19
+ end
20
+ EOS
21
+ end
22
+ end
23
+ end unless method_defined?(:mattr_reader)
24
+
25
+ def mattr_writer(*syms)
26
+ options = syms.extract_options!
27
+ syms.each do |sym|
28
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
29
+ def self.#{sym}=(obj)
30
+ @@#{sym} = obj
31
+ end
32
+ EOS
33
+
34
+ unless options[:instance_writer] == false
35
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
36
+ def #{sym}=(obj)
37
+ @@#{sym} = obj
38
+ end
39
+ EOS
40
+ end
41
+ end
42
+ end unless method_defined?(:mattr_writer)
43
+
44
+ # Extends the module object with module and instance accessors for class attributes,
45
+ # just like the native attr* accessors for instance attributes.
46
+ #
47
+ # module AppConfiguration
48
+ # mattr_accessor :google_api_key
49
+ # self.google_api_key = "123456789"
50
+ #
51
+ # mattr_accessor :paypal_url
52
+ # self.paypal_url = "www.sandbox.paypal.com"
53
+ # end
54
+ #
55
+ # AppConfiguration.google_api_key = "overriding the api key!"
56
+ def mattr_accessor(*syms)
57
+ mattr_reader(*syms)
58
+ mattr_writer(*syms)
59
+ end unless method_defined?(:mattr_accessor)
60
+
61
+ end
@@ -0,0 +1,11 @@
1
+ class Module
2
+ def remove_possible_method(method)
3
+ remove_method(method)
4
+ rescue NameError
5
+ end unless method_defined?(:remove_possible_method)
6
+
7
+ def redefine_method(method, &block)
8
+ remove_possible_method(method)
9
+ define_method(method, &block)
10
+ end unless method_defined?(:redefine_method)
11
+ end
@@ -0,0 +1,8 @@
1
+ module Kernel
2
+ # Returns the object's singleton class.
3
+ def singleton_class
4
+ class << self
5
+ self
6
+ end
7
+ end unless respond_to?(:singleton_class) # exists in 1.9.2
8
+ end