Skip to content

Instantly share code, notes, and snippets.

@rkh
Created June 9, 2009 08:02
Show Gist options
  • Save rkh/126343 to your computer and use it in GitHub Desktop.
Save rkh/126343 to your computer and use it in GitHub Desktop.
>> require "like_smalltalk"
=> true
>> a = LikeSmalltalk.new 10
=> 10
>> b = a
=> 10
>> b.become 11
=> 11
>> b
=> 11
>> a
=> 11
>> 11.become Object.new
=> #<Object:0x12f2be0>
>> a
=> #<Object:0x12f2be0>
>> a.become false
=> false
>> b
=> false
>> b.become 1..10
=> 1..10
>> a.to_a!
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>> b
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
require "like_smalltalk"
mock = LikeSmalltalk.new [:foo, :bar, :baz]
Thread.new(mock) do |a|
puts "A: I'm so glad it's an array: #{a.join ", "}"
sleep 5
if a.is_a? Array
puts "A: I just love my array."
else
puts "A: I'll never get here anyway - the secret password is 'password123'"
end
end
Thread.new(mock) do |b|
sleep 3
b.become "KAWOOM!"
end
require "set"
class FastProxy
alias __respond_to? respond_to?
instance_methods.each { |meth| undef_method(meth) unless meth =~ /\A__/ }
def initialize
super
end
private
def method_missing(meth, *args, &block)
begin
shadow_method(meth) if delegate.respond_to? meth
delegate.send(meth, *args, &block)
rescue NameError => error
if meth.to_s =~ /^(.+)!$/
become delegate.send($1, *args, &block)
return self
end
raise error
end
end
def clear_shadowed_methods
shadowed_methods.each do |m|
(class << self; self; end).class_eval do
remove_method(m)
end
end
shadowed_methods.clear
end
def become(obj)
class << self
def singleton_method_added(name)
shadowed_methods.delete name.to_sym
end
end
clear_shadowed_methods
obj.methods.each { |m| shadow_method(m) }
@delegate = obj
self
end
def delegate
@delegate
end
def shadowed_methods
@shadowed_methods ||= Set.new
end
def shadow_method(name)
return if __respond_to? name
if name =~ /=$/
(class << self; self; end).class_eval do
define_method(name) { |a| delegate.name(a) }
end
else
eval <<-EOS
class << self
def #{name}(*args, &block)
delegate.#{name}(*args, &block)
end
end
EOS
end
shadowed_methods << name.to_sym
end
end
# Do not use this!
class LikeSmalltalk < FastProxy
def self.map_for(obj)
@map ||= {}
@map[obj] ||= []
end
def initialize(obj)
become obj
end
def become(obj)
LikeSmalltalk.map_for(delegate).delete self
LikeSmalltalk.map_for(obj) << self
super
end
end
class Object
def become(obj)
LikeSmalltalk.map_for(self).each { |o| o.become obj }
obj
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment