-
-
Save tenderlove/7312899 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
class Module | |
private | |
def delegate(*args) | |
_define_delegators(caller.first, args, false) | |
end | |
def delegate_maybe(*args) | |
_define_delegators(caller.first, args, true) | |
end | |
def _define_delegators(from, args, fallback) | |
file, line = from.split(':', 2) | |
dest, prefix = _extract_valid_delegation_options(args.pop) | |
args.each do |arg| | |
module_eval( | |
_delegator_method([prefix, arg].compact.join('_'), dest, arg, fallback), | |
file, line.to_i - 4 | |
) | |
end | |
end | |
def _delegator_method(method_name, dest, dest_method, fallback = false) | |
fallback_code = 'to = NilDelegate.new if to.nil?' if fallback | |
%{ | |
def #{method_name}(*args, &block) | |
to = __send__(:#{dest}) | |
#{fallback_code} | |
to.__send__(:#{dest_method}, *args, &block) | |
end | |
} | |
end | |
def _extract_valid_delegation_options(opts) | |
if Hash === opts && opts.has_key?(:to) | |
opts.values_at(:to, :prefix) | |
else | |
raise ArgumentError, 'Invalid delegation options. Delegate with :to.' | |
end | |
end | |
end | |
class NilDelegate < BasicObject | |
delegate *(nil.methods - [:__send__, :object_id]), :to => :__nil__ | |
private | |
def __nil__ | |
nil | |
end | |
def method_missing(method_id, *args, &block) | |
nil | |
end | |
def respond_to_missing?(method_id, include_private = false) | |
true | |
end | |
end | |
class Owner | |
attr_accessor :name | |
def initialize(name) | |
@name = name | |
end | |
def play | |
puts 'ZOMG PLAYTIME!' | |
end | |
end | |
class Cat | |
attr_accessor :name, :owner | |
delegate :name, :name=, :to => :owner, :prefix => 'servant' | |
delegate_maybe :play, :to => :owner | |
def initialize(name, owner = nil) | |
@name, @owner = name, owner | |
end | |
end | |
ernie = Owner.new('Ernie') | |
esther = Cat.new('Esther', ernie) | |
esther.name # => "Esther" | |
esther.servant_name # => "Ernie" | |
esther.play # => "ZOMG PLAYTIME!" | |
esther.servant_name = 'Ernest' | |
ernie.name # => "Ernest" | |
esther.owner = nil | |
esther.play # => nil | |
esther.servant_name | |
# => undefined method `name' for nil:NilClass (NoMethodError) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment