Class: Module
- Defined in:
- lib/gorillib/utils/console.rb,
lib/gorillib/object/try_dup.rb,
lib/gorillib/utils/nuke_constants.rb,
lib/gorillib/metaprogramming/delegation.rb,
lib/gorillib/metaprogramming/remove_method.rb,
lib/gorillib/deprecated/metaprogramming/aliasing.rb
Instance Method Summary collapse
-
#alias_method_chain(target, feature) {|aliased_target, punctuation| ... } ⇒ Object
Encapsulates the common pattern of:.
-
#compare_methods(other = Object, show_common = false) ⇒ Object
Lists the differences in methods between two modules/classes.
-
#delegate(*methods) ⇒ Object
Provides a delegate class method to easily expose contained objects' methods as your own.
-
#nuke_constants ⇒ Object
Removes all constants in the module's namespace -- this is useful when writing specs for metaprogramming methods.
- #redefine_method(method, &block) ⇒ Object
- #remove_possible_method(method) ⇒ Object
- #try_dup ⇒ Object
Instance Method Details
#alias_method_chain(target, feature) {|aliased_target, punctuation| ... } ⇒ Object
Encapsulates the common pattern of:
alias_method :foo_without_feature, :foo alias_method :foo, :foo_with_feature
With this, you simply do:
alias_method_chain :foo, :feature
And both aliases are set up for you.
Query and bang methods (foo?, foo!) keep the same punctuation:
alias_method_chain :foo?, :feature
is equivalent to
alias_method :foo_without_feature?, :foo? alias_method :foo?, :foo_with_feature?
so you can safely chain foo, foo?, and foo! with the same feature.
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/gorillib/deprecated/metaprogramming/aliasing.rb', line 23 def alias_method_chain(target, feature) # Strip out punctuation on predicates or bang methods since # e.g. target?_without_feature is not a valid method name. aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1 yield(aliased_target, punctuation) if block_given? with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}" alias_method without_method, target alias_method target, with_method case when public_method_defined?(without_method) public target when protected_method_defined?(without_method) protected target when private_method_defined?(without_method) private target end end |
#compare_methods(other = Object, show_common = false) ⇒ Object
Lists the differences in methods between two modules/classes
Breaks them down by providing module, and shows class and instance methods.
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/gorillib/utils/console.rb', line 89 def compare_methods(other=Object, show_common=false) result = Hash.new{|h,k| h[k] = Hash.new{|hh,hk| hh[hk] = [] } } inst_ancestors_both = ancestors & other.ancestors klass_ancestors_both = singleton_class.ancestors & other.singleton_class.ancestors inst_meths = (self.instance_methods | other.instance_methods) klass_meths = (self.methods | other.methods) [ [:both, inst_ancestors_both, klass_ancestors_both], [self, (self.ancestors - inst_ancestors_both), (self.singleton_class.ancestors - klass_ancestors_both)], [other, (other.ancestors - inst_ancestors_both), (other.singleton_class.ancestors - klass_ancestors_both)], ].each do |mod, inst_anc, klass_anc| inst_anc.reverse.each do |ancestor| result["#{mod}#"][ancestor] = inst_meths & ancestor.instance_methods inst_meths -= ancestor.instance_methods end klass_anc.reverse.each do |ancestor| result["#{mod}."][ancestor] = klass_meths & ancestor.instance_methods klass_meths -= ancestor.instance_methods end end unless show_common then result.delete("both#") ; result.delete("both.") ; end result.each{|type,hsh| hsh.reject!{|k,v| v.empty? } } result.reject!{|type,hsh| hsh.empty? } result end |
#delegate(*methods) ⇒ Object
Provides a delegate class method to easily expose contained objects' methods as your own. Pass one or more methods (specified as symbols or strings) and the name of the target object via the :to option (also a symbol or string). At least one method and the :to option are required.
Delegation is particularly useful with Active Record associations:
class Greeter < ActiveRecord::Base def hello "hello" end
def goodbye
"goodbye"
end
end
class Foo < ActiveRecord::Base belongs_to :greeter delegate :hello, :to => :greeter end
Foo.new.hello # => "hello" Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #Foo:0x1af30c
Multiple delegates to the same target are allowed:
class Foo < ActiveRecord::Base belongs_to :greeter delegate :hello, :goodbye, :to => :greeter end
Foo.new.goodbye # => "goodbye"
Methods can be delegated to instance variables, class variables, or constants by providing them as a symbols:
class Foo CONSTANT_ARRAY = [0,1,2,3] @@class_array = [4,5,6,7]
def initialize
@instance_array = [8,9,10,11]
end
delegate :sum, :to => :CONSTANT_ARRAY
delegate :min, :to => :@@class_array
delegate :max, :to => :@instance_array
end
Foo.new.sum # => 6 Foo.new.min # => 4 Foo.new.max # => 11
Delegates can optionally be prefixed using the :prefix option. If the value is true, the delegate methods are prefixed with the name of the object being delegated to.
Person = Struct.new(:name, :address)
class Invoice < Struct.new(:client) delegate :name, :address, :to => :client, :prefix => true end
john_doe = Person.new("John Doe", "Vimmersvej 13") invoice = Invoice.new(john_doe) invoice.client_name # => "John Doe" invoice.client_address # => "Vimmersvej 13"
It is also possible to supply a custom prefix.
class Invoice < Struct.new(:client) delegate :name, :address, :to => :client, :prefix => :customer end
invoice = Invoice.new(john_doe) invoice.customer_name # => "John Doe" invoice.customer_address # => "Vimmersvej 13"
If the delegate object is +nil+ an exception is raised, and that happens no matter whether +nil+ responds to the delegated method. You can get a +nil+ instead with the +:allow_nil+ option.
class Foo attr_accessor :bar def initialize(bar = nil) @bar = bar end delegate :zoo, :to => :bar end
Foo.new.zoo # raises NoMethodError exception (you called nil.zoo)
class Foo attr_accessor :bar def initialize(bar = nil) @bar = bar end delegate :zoo, :to => :bar, :allow_nil => true end
Foo.new.zoo # returns nil
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/gorillib/metaprogramming/delegation.rb', line 106 def delegate(*methods) = methods.pop unless .is_a?(Hash) && to = [:to] raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)." end if [:prefix] == true && [:to].to_s =~ /^[^a-z_]/ raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method." end prefix = [:prefix] && "#{[:prefix] == true ? to : [:prefix]}_" || '' file, line = caller.first.split(':', 2) line = line.to_i methods.each do |method| on_nil = if [:allow_nil] 'return' else %(raise "#{self}##{prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") end module_eval(<<-EOS, file, line - 5) if instance_methods(false).map(&:to_s).include?("#{prefix}#{method}") remove_possible_method("#{prefix}#{method}") end def #{prefix}#{method}(*args, &block) # def customer_name(*args, &block) #{to}.__send__(#{method.inspect}, *args, &block) # client.__send__(:name, *args, &block) rescue NoMethodError # rescue NoMethodError if #{to}.nil? # if client.nil? #{on_nil} # return # depends on :allow_nil else # else raise # raise end # end end # end EOS end end |
#nuke_constants ⇒ Object
Removes all constants in the module's namespace -- this is useful when writing specs for metaprogramming methods
6 7 8 |
# File 'lib/gorillib/utils/nuke_constants.rb', line 6 def nuke_constants constants.each{|const| remove_const(const) } end |
#redefine_method(method, &block) ⇒ Object
7 8 9 10 |
# File 'lib/gorillib/metaprogramming/remove_method.rb', line 7 def redefine_method(method, &block) remove_possible_method(method) define_method(method, &block) end |
#remove_possible_method(method) ⇒ Object
2 3 4 5 |
# File 'lib/gorillib/metaprogramming/remove_method.rb', line 2 def remove_possible_method(method) remove_method(method) rescue NameError end |
#try_dup ⇒ Object
23 24 25 |
# File 'lib/gorillib/object/try_dup.rb', line 23 def try_dup self end |