Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > class destruction (evil genius metaprogramming)

Reply
Thread Tools

class destruction (evil genius metaprogramming)

 
 
Giles Bowkett
Guest
Posts: n/a
 
      06-15-2007
I want to write a module which, when included in another module,
destroys every method of a class in that module. I realize this isn't
really a very useful thing to do, but I want to do it to see if it can
be done. I want to actually include the module and have it replace all
existing methods of this class with just one method.

In Python you can change an object's class in the middle of your
program by reassigning its magical __class__ variable. That would be a
very simple way to implement this idea. Doesn't seem possible here,
though.

Here's an attempt which failed:

>> class Muppet
>> def show
>> "it's the muppet show!"
>> end
>> end

=> nil
>> kermit = Muppet.new

=> #<Muppet:0x123129c>
>> kermit.show

=> "it's the muppet show!"
>> class Muppet
>> remove_method(:show)
>> end

=> Muppet
>> kermit.show

NoMethodError: undefined method `show' for #<Muppet:0x123129c>
from (irb):36
from :0

So far so good, but I want to get rid of *every* method. Doing what I
just did programmatically, iterating over all available methods,
that's the thing which still eludes me.

None of these attempts work:

>> kermit.methods.each{|m| class << Muppet ; (remove_method(m)) ; end}

NameError: undefined local variable or method `m' for #<Class:Muppet>
from (irb):43
from (irb):43:in `each'
from (irb):43
from :0
>> kermit.methods.each{|m| class Muppet; remove_method(m.to_sym) ; end}

NameError: undefined local variable or method `m' for Muppet:Class
from (irb):44
from (irb):44:in `each'
from (irb):44
from :0
>> kermit.methods.each{|m| Muppet.class_eval(remove_method(m))}

NoMethodError: undefined method `remove_method' for #<Object:0x349f4>
from (irb):45
from (irb):45:in `each'
from (irb):45
from :0

I have to admit, it's not necessarily a bad thing if this task proves
impossible, but I feel like it *should* be possible.

--
Giles Bowkett

Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org

 
Reply With Quote
 
 
 
 
Rick DeNatale
Guest
Posts: n/a
 
      06-15-2007
On 6/14/07, Giles Bowkett <(E-Mail Removed)> wrote:
> I want to write a module which, when included in another module,
> destroys every method of a class in that module. I realize this isn't
> really a very useful thing to do, but I want to do it to see if it can
> be done. I want to actually include the module and have it replace all
> existing methods of this class with just one method.
>
> In Python you can change an object's class in the middle of your
> program by reassigning its magical __class__ variable. That would be a
> very simple way to implement this idea. Doesn't seem possible here,
> though.
>
> Here's an attempt which failed:
>
> >> class Muppet
> >> def show
> >> "it's the muppet show!"
> >> end
> >> end

> => nil
> >> kermit = Muppet.new

> => #<Muppet:0x123129c>
> >> kermit.show

> => "it's the muppet show!"
> >> class Muppet
> >> remove_method(:show)
> >> end

> => Muppet
> >> kermit.show

> NoMethodError: undefined method `show' for #<Muppet:0x123129c>
> from (irb):36
> from :0
>
> So far so good, but I want to get rid of *every* method. Doing what I
> just did programmatically, iterating over all available methods,
> that's the thing which still eludes me.
>
> None of these attempts work:
>
> >> kermit.methods.each{|m| class << Muppet ; (remove_method(m)) ; end}

> NameError: undefined local variable or method `m' for #<Class:Muppet>
> from (irb):43
> from (irb):43:in `each'
> from (irb):43
> from :0
> >> kermit.methods.each{|m| class Muppet; remove_method(m.to_sym) ; end}

> NameError: undefined local variable or method `m' for Muppet:Class
> from (irb):44
> from (irb):44:in `each'
> from (irb):44
> from :0
> >> kermit.methods.each{|m| Muppet.class_eval(remove_method(m))}

> NoMethodError: undefined method `remove_method' for #<Object:0x349f4>
> from (irb):45
> from (irb):45:in `each'
> from (irb):45
> from :0
>
> I have to admit, it's not necessarily a bad thing if this task proves
> impossible, but I feel like it *should* be possible.


kermit.class.instance_methods(false).each{|m|
Muppet.instance_eval("remove_method #{m.inspect}")}

Note 1. kermit.methods will return all methods inherited or not.
Note 2. remove method is a class method, so it's evaluated in the
context of the class object, hence Muppet.instance_eval
Note 3: you could alternatively pass symbols for the method names

kermit.class.instance_methods(false).each{|m|
Muppet.instance_eval("remove_method :#{m}")}



--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

IPMS/USA Region 12 Coordinator
http://ipmsr12.denhaven2.com/

Visit the Project Mercury Wiki Site
http://www.mercuryspacecraft.com/

 
Reply With Quote
 
 
 
 
Giles Bowkett
Guest
Posts: n/a
 
      06-15-2007
> kermit.class.instance_methods(false).each{|m|
> Muppet.instance_eval("remove_method #{m.inspect}")}
>
> Note 1. kermit.methods will return all methods inherited or not.
> Note 2. remove method is a class method, so it's evaluated in the
> context of the class object, hence Muppet.instance_eval
> Note 3: you could alternatively pass symbols for the method names
>
> kermit.class.instance_methods(false).each{|m|
> Muppet.instance_eval("remove_method :#{m}")}


Muahahaha! That was awesome! Soon the world will quake in fear when I
put this information to use!

But why doesn't this work?

>> kermit.methods(false).each do |m|

?> Object.instance_eval("remove_method :#{m}")
>> end

=> []
>> kermit.methods

=> 53

I tried it with Kernel also and no dice.

Tried it with something else, though, and got a great error message:

(eval):1: warning: removing `initialize' may cause serious problem

Muahahaha!

--
Giles Bowkett

Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org

 
Reply With Quote
 
dblack@wobblini.net
Guest
Posts: n/a
 
      06-15-2007
Hi --

On Fri, 15 Jun 2007, Rick DeNatale wrote:

> kermit.class.instance_methods(false).each{|m|
> Muppet.instance_eval("remove_method #{m.inspect}")}
>
> Note 1. kermit.methods will return all methods inherited or not.
> Note 2. remove method is a class method, so it's evaluated in the
> context of the class object, hence Muppet.instance_eval
> Note 3: you could alternatively pass symbols for the method names
>
> kermit.class.instance_methods(false).each{|m|
> Muppet.instance_eval("remove_method :#{m}")}


You can also just use the block form of instance_eval:

Muppet.instance_eval { remove_method(m) }


David

--
* Books:
RAILS ROUTING (new! http://safari.awprofessional.com/9780321509246)
RUBY FOR RAILS (http://www.manning.com/black)
* Ruby/Rails training
& consulting: Ruby Power and Light, LLC (http://www.rubypal.com)

 
Reply With Quote
 
Robert Dober
Guest
Posts: n/a
 
      06-15-2007
On 6/15/07, http://www.velocityreviews.com/forums/(E-Mail Removed) <(E-Mail Removed)> wrote:
> Hi --
>
> On Fri, 15 Jun 2007, Rick DeNatale wrote:
>
> > kermit.class.instance_methods(false).each{|m|
> > Muppet.instance_eval("remove_method #{m.inspect}")}
> >
> > Note 1. kermit.methods will return all methods inherited or not.
> > Note 2. remove method is a class method, so it's evaluated in the
> > context of the class object, hence Muppet.instance_eval
> > Note 3: you could alternatively pass symbols for the method names
> >
> > kermit.class.instance_methods(false).each{|m|
> > Muppet.instance_eval("remove_method :#{m}")}

>
> You can also just use the block form of instance_eval:
>
> Muppet.instance_eval { remove_method(m) }


or Muppet.send :remove_method, :m

Cheers
Robert


--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw

 
Reply With Quote
 
dblack@wobblini.net
Guest
Posts: n/a
 
      06-15-2007
Hi --

On Fri, 15 Jun 2007, Robert Dober wrote:

> On 6/15/07, (E-Mail Removed) <(E-Mail Removed)> wrote:
>> Hi --
>>
>> On Fri, 15 Jun 2007, Rick DeNatale wrote:
>>
>> > kermit.class.instance_methods(false).each{|m|
>> > Muppet.instance_eval("remove_method #{m.inspect}")}
>> >
>> > Note 1. kermit.methods will return all methods inherited or not.
>> > Note 2. remove method is a class method, so it's evaluated in the
>> > context of the class object, hence Muppet.instance_eval
>> > Note 3: you could alternatively pass symbols for the method names
>> >
>> > kermit.class.instance_methods(false).each{|m|
>> > Muppet.instance_eval("remove_method :#{m}")}

>>
>> You can also just use the block form of instance_eval:
>>
>> Muppet.instance_eval { remove_method(m) }

>
> or Muppet.send :remove_method, :m


If you have a method called "m"


David

--
* Books:
RAILS ROUTING (new! http://safari.awprofessional.com/9780321509246)
RUBY FOR RAILS (http://www.manning.com/black)
* Ruby/Rails training
& consulting: Ruby Power and Light, LLC (http://www.rubypal.com)

 
Reply With Quote
 
dblack@wobblini.net
Guest
Posts: n/a
 
      06-15-2007
Hi --

On Fri, 15 Jun 2007, Giles Bowkett wrote:

>> kermit.class.instance_methods(false).each{|m|
>> Muppet.instance_eval("remove_method #{m.inspect}")}
>>
>> Note 1. kermit.methods will return all methods inherited or not.
>> Note 2. remove method is a class method, so it's evaluated in the
>> context of the class object, hence Muppet.instance_eval
>> Note 3: you could alternatively pass symbols for the method names
>>
>> kermit.class.instance_methods(false).each{|m|
>> Muppet.instance_eval("remove_method :#{m}")}

>
> Muahahaha! That was awesome! Soon the world will quake in fear when I
> put this information to use!
>
> But why doesn't this work?
>
>>> kermit.methods(false).each do |m|

> ?> Object.instance_eval("remove_method :#{m}")
>>> end

> => []
>>> kermit.methods

> => 53


kermit.methods(false) will give you kermit's singleton methods:

irb(main):019:0> s = ""
=> ""
irb(main):020:0> def s.x; end
=> nil
irb(main):021:0> s.methods(false)
=> ["x"]

Also, you can't remove these methods from Object because they're not
defined there. You'd have to do:

class << s
remove_method()
end


David

--
* Books:
RAILS ROUTING (new! http://safari.awprofessional.com/9780321509246)
RUBY FOR RAILS (http://www.manning.com/black)
* Ruby/Rails training
& consulting: Ruby Power and Light, LLC (http://www.rubypal.com)

 
Reply With Quote
 
Robert Dober
Guest
Posts: n/a
 
      06-15-2007
On 6/15/07, (E-Mail Removed) <(E-Mail Removed)> wrote:
> Hi --
>
> On Fri, 15 Jun 2007, Robert Dober wrote:
>
> > On 6/15/07, (E-Mail Removed) <(E-Mail Removed)> wrote:
> >> Hi --
> >>
> >> On Fri, 15 Jun 2007, Rick DeNatale wrote:
> >>
> >> > kermit.class.instance_methods(false).each{|m|
> >> > Muppet.instance_eval("remove_method #{m.inspect}")}
> >> >
> >> > Note 1. kermit.methods will return all methods inherited or not.
> >> > Note 2. remove method is a class method, so it's evaluated in the
> >> > context of the class object, hence Muppet.instance_eval
> >> > Note 3: you could alternatively pass symbols for the method names
> >> >
> >> > kermit.class.instance_methods(false).each{|m|
> >> > Muppet.instance_eval("remove_method :#{m}")}
> >>
> >> You can also just use the block form of instance_eval:
> >>
> >> Muppet.instance_eval { remove_method(m) }

> >
> > or Muppet.send :remove_method, :m

>
> If you have a method called "m"

Ah I see , Probably 50% of my errors come from spurious ":" ARRRRG

Muppet.send :remove_method, m ### TESTED

Sorry.
Robert


--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw

 
Reply With Quote
 
Giles Bowkett
Guest
Posts: n/a
 
      06-15-2007
> > Why should this inspire fear?
>
> Code injection attack to own a RoR site possibly? That would be my guess.


Sort of. I'm trying to use it to build a Rails plugin called
acts_as_fox, which overrides every method on a model to return "chunky
bacon!" (It's not really that terrifying, I just kind of had a Dr.
Frankenstein moment, drunk on power type thing.)

Unfortunately, applying Rick's code directly to an ActiveRecord model
doesn't quite accomplish this, because it's missing the superclass
methods, but applying it to ActiveRecord::Base doesn't work either. I
did get it to work by doing it twice, both on the actual model and on
ActiveRecord::Base itself, but that's very unsatisfying, because I
solved the problem by cutting and pasting. (I think I understand why
it worked; ActiveRecord::Base attaches a lot of methods to its
subclasses, instead of having them inherited directly.) It also fails
to really accomplish what I want to do, because it means that making
one model acts_as_fox destroys all the other models. (I also need to
attach a method_missing to return "chunky bacon!" but that part's
obviously trivial.)

Really the quickest way to accomplish this would be to simply pop the
model out of its inheritance hierarchy - redefine the model not to
have any superclass except Object - but I don't know if that's
possible. Trying it in the most obvious way (class Foo < Object; end,
where Foo was already defined Foo < ActiveRecord::Base) results in a
TypeError with the message "superclass mismatch."

But there must be a clean way to open up the class, grab all its
methods, including those derived from superclasses, and simply
reassign them. Something like

Foo.instance_methods(true).each{|m| Foo.instance_eval("alias
:chunky_bacon " + m)}

--
Giles Bowkett

Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org

 
Reply With Quote
 
dblack@wobblini.net
Guest
Posts: n/a
 
      06-16-2007
Hi --

On Sat, 16 Jun 2007, Giles Bowkett wrote:

>> > Why should this inspire fear?

>>
>> Code injection attack to own a RoR site possibly? That would be my guess.

>
> Sort of. I'm trying to use it to build a Rails plugin called
> acts_as_fox, which overrides every method on a model to return "chunky
> bacon!" (It's not really that terrifying, I just kind of had a Dr.
> Frankenstein moment, drunk on power type thing.)
>
> Unfortunately, applying Rick's code directly to an ActiveRecord model
> doesn't quite accomplish this, because it's missing the superclass
> methods, but applying it to ActiveRecord::Base doesn't work either. I
> did get it to work by doing it twice, both on the actual model and on
> ActiveRecord::Base itself, but that's very unsatisfying, because I
> solved the problem by cutting and pasting. (I think I understand why
> it worked; ActiveRecord::Base attaches a lot of methods to its
> subclasses, instead of having them inherited directly.) It also fails
> to really accomplish what I want to do, because it means that making
> one model acts_as_fox destroys all the other models. (I also need to
> attach a method_missing to return "chunky bacon!" but that part's
> obviously trivial.)
>
> Really the quickest way to accomplish this would be to simply pop the
> model out of its inheritance hierarchy - redefine the model not to
> have any superclass except Object - but I don't know if that's
> possible. Trying it in the most obvious way (class Foo < Object; end,
> where Foo was already defined Foo < ActiveRecord::Base) results in a
> TypeError with the message "superclass mismatch."


I do sometimes wonder what would happen if the ancestry array were
writeable. It could be interesting. I haven't thought through the
possible pitfalls.

> But there must be a clean way to open up the class, grab all its
> methods, including those derived from superclasses, and simply
> reassign them. Something like
>
> Foo.instance_methods(true).each{|m| Foo.instance_eval("alias
> :chunky_bacon " + m)}


Here's a little demo that does pretty much that (sparing the _ methods
like __send__):

class Object
def mask
puts "I'm masking a method"
end
end

class C
def x
puts "x"
end

def y
puts "y"
end
end

class D < C
def z
puts "z"
end
end

class D
instance_methods.reject {|m| /^_/.match(m) }.each do |m|
alias_method m, :mask
end
end

C.new.x # x
D.new.x # I'm masking a method
D.new.z # I'm masking a method


David

--
* Books:
RAILS ROUTING (new! http://safari.awprofessional.com/9780321509246)
RUBY FOR RAILS (http://www.manning.com/black)
* Ruby/Rails training
& consulting: Ruby Power and Light, LLC (http://www.rubypal.com)

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Proper Destruction of Class Members when an Exception is Thrown inDestructor AnonMail2005@gmail.com C++ 8 03-02-2009 01:07 AM
Re: Class destruction Marshall T. Vandegrift Python 0 08-22-2007 11:06 PM
virtual base class and construction/destruction order BeautifulMind C++ 7 02-08-2007 12:35 PM
initialization and destruction order for class members Dennis Jones C++ 2 01-05-2007 12:53 AM
Purest genius: <abbr/> working in Internet Explorer Toby A Inkster HTML 0 12-11-2003 10:41 PM



Advertisments