A random post for the fam – here is Trygve making some noise as he plays>
Autumn Respite
Posted by Jenny, Mon, 16 Oct 2006 09:24:33 GMTI thought that after the last couple techy posts (informative and enlightening as they are) I would change the pace a touch.
I am continually amazed at how quickly time passes. I look at our son who is coming up for 12 weeks on Thursday and think, when did he get to be such a little person? Last time I checked it was the beginning of August and now in the blink of an eye we are in the thick of October. I’m usually heard complaining about the weather in Edinburgh, but as of late, it has been absolutely beautiful and I wanted to put it on record that I am enjoying this Autumn fully.
Yesterday afternoon I went for a walk with a new friend Jennie and her 13 week old son Louis. We meandered through the cobbled streets, enjoying the crisp air and the lovely colours. We walked towards the “Hermitage” which is a large ‘park’ just south of our flat with fields, a large hill, pond, creek, and woodland as well. I love that in just 20 minutes walking I can go from the upbeat pace of the city to tranquil countryside. We walked through a field and sat on a bench overlooking it all as the sun was beginning to set. The trees were showing off their full colours, the sky was a lovely hue of pink, and both our sons were peacefully sleeping—a virtual moment of heaven. It was a lovely break in the midst of what can feel like a busy and hectic life filled with feeding, nappy changing, and trying to get chores done around the house. We paused for several blissful moments and took it all in before walking back to home, city, and the clambering needs of our wee little men. A short Autumn respite indeed, but it made for a restorative Sunday evening.
~Jenny
Final methods in ruby (prevent method override)
Posted by haakon, Fri, 06 Oct 2006 14:10:00 GMTIn a reversal of fortune, I recently found myself wishing Ruby was more like Java. Java has the ideas of abstract base classes and final methods (methods which should not be overridden in child classes). Such ideas don’t really exist in Ruby.
My problem was this. I had a base class Cronjob which represented some job which was going to run under cron. This class managed stuff like setting up logging, db connections, etc. I then wanted other jobs to be able to extend Cronjob and take advantage of the base class:
class Cronjob
def initialize
# do useful stuff here, setting up db connections, logging, etc.
end
def run # method which no child class should override
start = Time.now
puts "starting at #{start}"
run_job # method which child class should override
stop = Time.now
puts "finished at #{stop}, took #{stop-start} seconds"
end
endclass MyJob < Cronjob
def run_job
# real work goes here
end
end job = MyJob.new
job.runAll well and good. If people use the base class correctly, they get some nice bits of functionality. However, I eventually noticed that someone had written this class:
class TheirJob < Cronjob
def run
# real work goes here
end
end class Cronjob
final :run
def run
end
endclass Object
@@final_methods = {}
class < < self
def prevent_override?(method_name)
@@final_methods.each do |class_name, final_methods|
ancestors = self.ancestors
ancestors.shift # remove myself from the list
if ancestors.include?(class_name) and
final_methods.include?(method_name)
raise "Child class '#{self}' should not override parent class method '#{class_name}.#{method_name}'."
end
end
end
def method_added(method_name)
prevent_override?(method_name)
end
def final(*names)
@@final_methods[self] = names
end
end
end in `prevent_override?': Child class 'TheirJob' should not
override parent class method 'Cronjob.run'.(RuntimeError)How does it work? The magic is possible because Ruby has a method called method_added. This gets called when a method is added to a class. So, when a source code file is being processed, if a method is defined with “def foo”, after the method has been added to the class this method_added method gets fired with “foo” as the argument. We can then implement the method with our desired behavior. In my case, I just wanted to blow up with an exception which is easy enough to do.
Ruby also has a method to get an object’s “ancestors”.>> true.class.ancestors
=> [TrueClass, Object, Kernel]
>> [].class.ancestors
=> [Array, Enumerable, Object, Kernel]So, the logic becomes simple. The final method just stores a hash of class => [methods which you cannot override]. Then, on method_added we do a check to see if the method being added is in this hash, and Bob’s your uncle!
So, while it was mildly surprising to find Ruby missing a language feature that I wanted, the language is powerful enough that you can “add to” the language! I’m also half expecting people to weigh in with suggestions of a better way to do this. I would be pleased to hear better variations. This solution definitely doesn’t make it impossible to override the method in a child class; a determined person could get around it. But it does solve my problem of someone inadvertently overriding the method.
Update: Now available via gems, thanks to Dr. Nic’s newgem magic:
gem install finalizer
.