I have a little side-project, which I might actually do something practical with. It is nothing ground breaking, just a little interpreter I want to write. As my language of choice is Ruby at the moment, I have been playing with various ideas about how to write it. One which I rather like is using a PEG, for which there is a nice gem called Treetop. However, here I am just looking at dynamically creating classes and methods for them.
I rather fancied the idea of being able to dynamically create classes and methods based on the script I was interpreting, so played around a little this evening with some ideas. The following is some horribly formatted code, but it works as a proof of concept. I am sure other people have done the same before, of course, but I am rather pleased with the result. And yes, I know there are far better ways of writing test, and probably of timing things...
def create_class(name, classes={})
#prepend a string to avoid clashes. Probably not the best way
tname="KK_"+name
classes[name]=Object::const_set(tname.intern, Class::new {})
end
def add_to_class(name,method,classes)
classes[name].class_eval(method)
end
def test(klass,objekt,meffods,kall,test)
create_class(klass,@classes)
meffods.each {|m|
add_to_class(klass,m,@classes)
}
@objects[objekt]=@classes[klass].new
if @objects[objekt].send(test)
raise "Error - test succeeded when it should have failed"
end
@objects[objekt].send(kall)
if !@objects[objekt].send(test)
raise "Error - test failed when it should have succeeded"
end
end
tim=Time.now()
meffs=[]
meffs << "def initialize() @has_barked=false end"
meffs << "def has_barked?() @has_barked end"
#meffs << "def bark() puts 'Woof';@has_barked=true end"
meffs << "def bark() @has_barked=true end"
kl="dog"
nm="Freda"
cl="bark"
tst="has_barked?"
@classes={}
@objects={}
100000.times do
test(kl,nm,meffs,cl,tst)
#I should really write this so it does both sets of tests, rather than commenting one out :-)
Object.send(:remove_const, ("KK_"+kl).intern)
#nm=nm.next
#kl=kl.next
end
puts (Time.now()-tim)
Anyway, quite pleased with that really. Also fairly impressed that even when I use the version which has a puts (screen output is slow), it does 100,000 dynamic creations of a class, instantiates an object, adds 3 methods and calls them in 28.078 seconds. Without the puts, it does the same in 10.485 seconds, and when removing the classes (though not the objects) it gets down to 9.141 seconds.
This work is licensed under a Attribution Non-commercial Creative Commons license