-
-
Save foysavas/105339 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
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