
Type-checking a Dynamic Language - fogus
http://journal.stuffwithstuff.com/2010/08/31/type-checking-a-dynamic-language/
======
mcantor
Lately I've been following an approach that I suppose you could call "strict
duck-checking in danger zones." I define a very lightweight "contract checker"
and drop it into the beginning of methods that make a lot of assumptions about
their arguments. For example, in a ruby app that wants certain keys in the
dictionary you give to it:

    
    
        class MethodContractException < StandardError
        end
    
    
        class Expecter
    
            def initialize(suspect)
                @suspect = suspect
            end
    
            def has_all_keys(keys)
                missing_keys = keys.reject { |key| @suspect.has_key? key }
    
                if !missing_keys.empty?
                    raise MethodContractException, "Method contract violated: "\
                       "#{@suspect.keys.inspect} should contain "\
                       "#{missing_keys.inspect}."
                end
    
                true
            end
    
        end
    
    
        def expect(suspect)
            Expecter.new(suspect)
        end
    
    
        class Widget
    
            REQUIRED_SPECS = [:splines, :cogs, :thingamabobs]
    
            def reticulate(dct_spec)
                expect(dct_spec).has_all_keys(REQUIRED_SPECS)
    
                @dct_spec = dct_spec
                process(dct_spec)
            end
    
        end
    

Though, it may be better to encapsulate this kind of contract by creating a
WidgetSpec class that demands each spec in the form of arguments to its
constructor, and simply checking that the argument supplied to
Widget::reticulate() is an instance of WidgetSpec. That is probably one of the
few instances where instance checking is sensible; in other situations, using
respond_to?() is preferable, because we are only concerned as to whether the
object we are given can :quack, not that it is an instance of a Duck.

For everything else, I try to follow Joel Spolsky's advice on making wrong
code look wrong: <http://www.joelonsoftware.com/articles/Wrong.html>

