En ruby il n'existe pas à proprement parler de destructeur.
Toutefois il est possible de mettre en place des finalizer qui agissent comme des callbacks.

Ex :

#!/usr/bin/env ruby
 
class Foo
  def initialize
    puts "Object #{object_id} borned."
    ObjectSpace.define_finalizer(self, self.class.method(:finalize).to_proc)
  end
 
  def self.finalize(id)
    puts "Object #{id} died."
  end
end
 
puts "start"
f = Foo.new
f = nil
puts "end"

La notion de finalizer peut être particulièrement pratique (dans le cas d'un debug par exemple) mais elle est à manier avec précaution.

Pourquoi finalize est une méthode de classe ?
Parce que la méthode est appelée une fois l'élément déréférencé ; la méthode doit donc être une méthode de classe.

A l'éxécution on se rend compte que le finalizer est appelé après le end, même en mettant l'objet à nil.
Cela est dû au garbage collector de ruby, qui est de type mark-and-sweep. Ce type de garbage ne libère pas instantanément les objets déréférencés.
Ceux ci sont accumulés, et une fois en grand nombre le programme se suspend pour libérer ces objets.