Here's my solution: it implements two optional extensions.

  morse.rb [-d dictionary] [-m] [morse-sequence]

The -d option names a file that is a dictionary, one word per line.
If given, results will be limited to words in that file.  The -m
option ("multi") causes it to read lines from standard input until
EOF, and perform the Morse->English expansion on each line.  If the
morse sequence isn't given as the first argument, it reads a single
line from standard input.  (That is, with no arguments or options, it
behaves as the quiz spec said it should)

Also, I allow spaces in the morse code sequence to force a letter
break at that point.  For example ".- ." produces only "AE" and "ETE",
whereas ".-." produces those two results plus "EN" and "R".

Without further ado:

#!ruby -x

# Copied from quiz description, with a regexp search/replace that
# my editor (SciTE) made easy to do:
MORSE = [
%w{A .-}, %w{N -.},
%w{B -...}, %w{O ---},
%w{C -.-.}, %w{P .--.},
%w{D -..}, %w{Q --.-},
%w{E .}, %w{R .-.},
%w{F ..-.}, %w{S ...},
%w{G --.}, %w{T -},
%w{H ....}, %w{U ..-},
%w{I ..}, %w{V ...-},
%w{J .---}, %w{W .--},
%w{K -.-}, %w{X -..-},
%w{L .-..}, %w{Y -.--},
%w{M --}, %w{Z --..},
].map {|c, morse| [c, /^#{Regexp.escape(morse)} ?(.*)/]}.sort;

# Given a morse-code input string, yield the initial letter we
# could be starting with and the rest of the morse code string.
def get_letters(instr)
    MORSE.each { |c, re|
        if (instr =~ re) then
          yield c,$1
        end
    }
end

# Generate all possible decodings of the given morse code string.
# The algorithm's pretty simple - the only twist is storing the
# intermediate results in a hash so that they don't get calculated
# more than once.
def gencode(instr)
    memoizer = Hash.new { |h,morse|
        retval = []
        get_letters(morse) { |c,rest|
            h[rest].each {|s| retval << (c+s)}
        }
        h[morse] = retval
    }
    memoizer[''] = ['']
    memoizer[instr]
end

# And that's it as far as the fundamental algorithm is concerned.
# The rest is all option handling and dictionary filtering

$dictfunc = lambda {|x| 1}
$opt_m = nil
$usage = "morse.rb [-d dictionary] [-m] [codestring]"

while ARGV[0] and ARGV[0] =~ /^-/ do
    case ARGV[0]
    when /^-d/
        dictionary = {}
        File.open(ARGV[1]) { |f| f.each { |w|
            w.chomp!.upcase!.strip!
            dictionary[w] = 1
        } }
        $dictfunc = lambda {|x| dictionary[x]}
        ARGV.shift
    when /^-m/
        $opt_m = 1
    else
        STDERR.puts "Unknown option #{ARGV[0]}"
        STDERR.puts $usage
        exit 1
    end
    ARGV.shift
end

if ARGV[0] then
    if ARGV[1] then
        STDERR.puts $usage
        exit 1
    end
    gencode(ARGV[0]).select{|w|$dictfunc.call(w)}.each{|w| puts w}
    exit 0 unless $opt_m
end

STDIN.each do |l|
    gencode(l).select{|w|$dictfunc.call(w)}.each{|w| puts w}
    exit 0 unless $opt_m
end
__END__

-- 
s=%q(  Daniel Martin -- martin / snowplow.org
       puts "s=%q(#{s})",s.map{|i|i}[1]       )
       puts "s=%q(#{s})",s.map{|i|i}[1]