Transmutable (?) Objects in Perl and Ruby
I have no idea if "transmutable" is the right word to describe this concept but I'm using it anyway.
In Perl, I sometimes find it useful to "transmute" objects. For example:
sub Grape::new {
my $class = shift;
bless {}, $class;
}
sub Grape::dehydrate {
my $self = shift;
bless $self, 'Raisin';
}
sub Raisin::new {
my $class = shift;
bless {}, $class;
}
my $x = Grape->new();
print ref($x), "\n"; # prints "Grape"
$x->dehydrate(); # it's not a Grape anymore
print ref($x), "\n"; # prints "Raisin"
$x->dehydrate(); # Raisin doesn't have a dehydrate() method, so it dies
To do this in Ruby, I first tried something like this:
class Grape
def dehydrate
self = Raisin.new
end
end
But Ruby complains "Can't change the value of self". I ended up trying something with Ruby's version of AUTOLOAD, method_missing:
class Grape
def initialize
@me = Hidden::Grape.new
end
def method_missing(method, *args)
r = @me.method(method).call(*args)
@me = r if /^Hidden::/.match(r.class.to_s)
return r
end
def class
@me.class.to_s.sub(/^Hidden::/, '')
end
def methods
@me.methods
end
end
module Hidden
class Grape
def dehydrate
Raisin.new
end
end
class Raisin
end
end
x = Grape.new
puts(x.class) # prints "Grape"
x.dehydrate
puts(x.class) # prints "Raisin"
x.dehydrate # NameError: undefined method `dehydrate' for class `Hidden::Raisin'
Various things seem wrong about it (especially overriding class() and methods()), but it pretty much does what I want.
11/15/2006 update: I no longer think the above seems "wrong". If anything it's probably considered insufficiently weird in Ruby circles.