[SOLUTION] Please Forward: Ruby Quiz Subumission

From: Pedro <pedro.wotan@mundo-r.com>
Date: May 5, 2005 7:48:36 PM CDT
To: submission@rubyquiz.com
Subject: [SOLUTION] Please Forward: Ruby Quiz Subumission

This is my very first Ruby script, and I supose it could be terrific, but I enjoyed it very much :).

Bye
class Song
    def initialize(author, title, duration)
        @author=author
        @title=title
        @duration=duration
    end

    def to_s
        return "#{@title} - #{@author} - #{@duration/1000} ms"
    end

    attr_reader :author, :title, :duration
end

def parse(name)
    list = Hash.new
    artist = Regexp.new('<Artist name=\"([^>]+)\">')
    song = Regexp.new('<Song name=\"([^>]+)\" id=\'(\d+)\' duration=\'(\d+)\'/>')
    a, t, d = '', '', 0
    i=0
    File.open(name) do |file|
        file.each_line do |line|
            i+=1
            if ar=artist.match(line)
                a = ar[1]
            elsif ar=song.match(line)
                t = ar[1]
                d = ar[3].to_i
                key = getFirst(t)
                list[key] = Array.new unless list[key]
                list[key] << Song.new(a, t, d)
            end
        end
    end
    return list
end

def getFirst(name)
    return name[0, 1].capitalize
end

def getLast(name)
    return name[-1, 1].capitalize
end

def duration(seq)
    total=0
    seq.each { |c| total+=c.duration }
    return total
end

def search(songs, first, last)
        posibles = Array.new
        if songs.key?(getLast(first.title))
                if(songs[getLast(first.title)].find {|c| c.title==last.title})
                        return [last]
                end
                sig = songs.delete(getLast(first.title))
                for i in sig
                        if v=search(songs, i, last)
                                posibles << (v << i)
                        end
                end
        # what do you choose?
                unless posibles.empty?
            return yield(posibles) if block_given?
            return posibles[0]
                end
        end
        return nil
end

## SELECTION METHODS
min_dur = proc do |list|
    min = list[0]
        list.each do |i|
                min=i if duration(i)<duration(min)
        end
        min
end

min_len = proc do |list|
    min = list[0]
        list.each do |i|
                min=i if i.length<min.length
        end
        min
end

def exact_len(dur)
    return proc do |list|
        min = list[0]
        list.each do |i|
                    min=i if (duration(i)-dur).abs<(duration(min)-dur).abs
            end
            min
    end
end

songs = parse('SongLibrary.xml')

## PREDEFINED LIST
#title1, title2 = '21st Century Army', 'Deconstruction'
#v1, v2 = songs[getFirst(title1)], songs[getFirst(title2)]
#first = v1.find {|c| c.title == title1}
#last = v2.find {|c| c.title == title2}

## RANDOM LIST
v1 = songs[songs.keys[rand(songs.length)]]
v2 = songs[songs.keys[rand(songs.length)]]
first, last = v1[rand(v1.length)], v2[rand(v2.length)]

puts first.to_s + ' ===> ' + last.to_s

result=search(songs, first, last, &min_len)

if result
    result.push(first)
        puts result.reverse
else
        puts 'There is no way!'
end

···

Begin forwarded message: