Skip to content

Instantly share code, notes, and snippets.

@deepak
Created July 19, 2009 10:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save deepak/149878 to your computer and use it in GitHub Desktop.
Save deepak/149878 to your computer and use it in GitHub Desktop.
unextend a module | ruby-talk-183401
# 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"
# 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
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