Skip to content

Instantly share code, notes, and snippets.

@foysavas
Forked from carllerche/gist:105316
Created May 2, 2009 00:36
Show Gist options
  • Save foysavas/105339 to your computer and use it in GitHub Desktop.
Save foysavas/105339 to your computer and use it in GitHub Desktop.
class Module
alias_method :include_without_hooks, :include
def include(*modules)
include_before_hook(*modules)
include_without_hooks(*modules)
include_after_hook(*modules)
end
def include_before_hook(*modules)
end
def include_after_hook(*modules)
end
end
module ClassStates
@@class_states = {}
def self.class_states
@@class_states
end
def self.remove_module(klass,mod)
if class_state_before_mod(klass, mod)
present_class_state = remove_class_state(klass, mod)
klass_sym = "#{klass}".to_sym
Object.send :remove_const, klass_sym
Object.send :const_set, klass_sym, present_class_state
end
end
def self.class_state_before_mod(klass, mod)
@@class_states[klass.to_s].find do |at_mod, klass_state|
klass_state if at_mod == mod
end
end
def self.remove_class_state(klass, mod)
past_mod = false
present_state = nil
@@class_states[klass.to_s] = @@class_states[klass.to_s].map do |at_mod, klass_state|
if past_mod
present_state = present_state.dup
present_state.class_eval do
include at_mod
end
@@class_states.delete_if {|n,v| present_state.to_s == n}
[at_mod, present_state]
elsif at_mod == mod
past_mod = true
present_state = klass_state
nil
else
[at_mod, klass_state]
end
end.compact!
present_state
end
def self.add_class_state(klass, mod)
@@class_states[klass.to_s] = [] unless @@class_states[klass.to_s]
@@class_states[klass.to_s].push [mod, klass.clone]
end
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def include_before_hook(mod)
ClassStates.add_class_state(self,mod)
end
end
end
#
# Let's see it go!
#
class Foo
include ClassStates
end
module Mod1
def method1
puts "method1"
end
end
module Mod2
def method2
puts "method2"
end
end
module Mod3
def method3
puts "method3"
end
end
class Foo
include Mod1
include Mod2
include Mod3
end
#
# Alright, now all the methods are there
#
Foo.new.method1 # => method1
Foo.new.method2 # => method2
Foo.new.method3 # => method3
#
# But let's remove the middle module
#
p ClassStates.class_states
# => {"Foo"=>[[Mod1, #<Class:0x7fe35bcac448>], [Mod2, #<Class:0x7fe35bcac308>], [Mod3, #<Class:0x7fe35bcac1c8>]]}
ClassStates.remove_module(Foo, Mod2)
p ClassStates.class_states
# => {"Foo"=>[[Mod1, #<Class:0x7fe35bcac448>], [Mod3, Foo]]}
#
# And now method2 is gone!
#
Foo.new.method3 # => method3
Foo.new.method1 # => method1
Foo.new.method2 # undefined method `method2' for #<Foo:0x7fe35bcab840> (NoMethodError)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment