Created
July 19, 2009 10:25
-
-
Save deepak/149878 to your computer and use it in GitHub Desktop.
unextend a module | ruby-talk-183401
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
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/183650 | |
# Have you tried #dup? | |
module Actor | |
def work | |
"actor" | |
end | |
end | |
module Waiter | |
def work | |
"waiter" | |
end | |
end | |
class Human; end | |
dirk = Human.new | |
dirk.extend Actor | |
p dirk.work | |
begin | |
dirk = dirk.dup | |
p dirk.work | |
rescue | |
puts "dirk has no job" | |
end | |
dirk.extend Waiter | |
p dirk.work | |
__END__ | |
# DRY RUN | |
"actor" | |
dirk has no job | |
"waiter" | |
And, to put it in the nice #unextend method: | |
class Object | |
def unextend | |
self.replace dup | |
end | |
end | |
module Actor | |
def work | |
"actor" | |
end | |
end | |
module Waiter | |
def work | |
"waiter" | |
end | |
end | |
class Human; end | |
dirk = Human.new | |
dirk.extend Actor | |
p dirk.work | |
begin | |
dirk.unextend | |
p dirk.work | |
rescue | |
puts "dirk has no job" | |
end | |
dirk.extend Waiter | |
p dirk.work | |
% ruby unextend | |
"actor" | |
dirk has no job | |
"waiter" | |
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
# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/183401 | |
require 'delegate' | |
module QuasiExtender | |
def quasi_extend(mod) | |
@__quasi_extensions ||= [] | |
@__quasi_extensions << mod | |
end | |
def quasi_retract(mod) | |
@__quasi_extensions ||= [] | |
@__quasi_extensions.delete_if { |ext| ext == mod } | |
end | |
def method_missing(name, *args, &block) | |
@__quasi_extensions ||= [] | |
meth = nil | |
found_mod = nil | |
@__quasi_extensions.each do |ext| | |
begin | |
meth = ext.instance_method(name.to_sym) | |
found_mod = ext | |
rescue NameError, NoMethodError | |
next | |
else | |
break | |
end | |
end | |
if meth.nil? # we didn't find it | |
super | |
else | |
sneaky_class = Class.new(SimpleDelegator) { | |
include(found_mod) | |
} | |
sneaky_obj = sneaky_class.new(self) | |
meth.bind(sneaky_obj).call(*args, &block) | |
end | |
end | |
end |
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
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/183401 | |
Subject: Re: unextend ? | |
From: Logan Capaldo <logancapaldo gmail.com> | |
Date: Fri, 10 Mar 2006 06:36:23 +0900 | |
References: 183334 | |
In-reply-to: 183334 | |
On Mar 9, 2006, at 11:03 AM, Dirk van Deun wrote: | |
> A very short and simple question: is there a function to "unextend" an | |
> object ? Obviously it does not exist under that name, nor could I | |
> find | |
> anything like it. It would be useful though to do "traits": | |
> | |
> dirk = Human.new | |
> dirk.extend(actor) | |
> dirk.work | |
> if dirk.income < PITTANCE | |
> dirk.unextend(actor) | |
> dirk.extend(waiter) | |
> dirk.work | |
> end | |
> | |
> Dirk van Deun | |
> -- | |
> Ceterum censeo Redmond delendum | |
> | |
I don't believe there is an unextend method, however if you're | |
willing to live with some dark magic that I haven't extensively tested: | |
irb(main):001:0> require 'quasiextender' | |
=> true | |
irb(main):002:0> class A | |
irb(main):003:1> def each | |
irb(main):004:2> yield 1 | |
irb(main):005:2> end | |
irb(main):006:1> include QuasiExtender | |
irb(main):007:1> end | |
=> A | |
irb(main):008:0> a = A.new | |
=> #<A:0x370718> | |
irb(main):009:0> a.quasi_extend(Enumerable) | |
=> [Enumerable] | |
irb(main):010:0> a.map { |x| x.to_s } | |
=> ["1"] | |
irb(main):011:0> a.quasi_retract(Enumerable) | |
=> [] | |
irb(main):012:0> a.map { |x| x } | |
NoMethodError: undefined method `map' for #<A:0x370718 | |
@__quasi_extensions=[]> | |
from ./quasiextender.rb:30:in `method_missing' | |
from (irb):12 | |
And here's the evil code. Its actually not terribly long: (in quasiextender.rb) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment