Hey all, here's another one for you.  I admit that there isn't anything
special about it... I think it's one of the more direct solutions (i.e.
Nothing clever here guys).  I didn't see a reason to include the entire
genre, so it's attached in a separate file.  It simply declares a constant
(an array which is indexed in read_tags).

Tom


--BEGIN SOLUTION--
require 'id3_tag_genre'

class NoTagError < RuntimeError; end

class Mp3
  attr_reader :song, :artist, :album, :year, :comment, :genre, :track
  
  def initialize(file)
    read_tags(file)
  end
  
  def read_tags(file)
    begin
      size = File.stat(file).size
      f = File.open(file)
      f.pos = size - 128
      tag = f.read
      raise NoTagError unless tag[0..2] == "TAG"
      @song = tag[3..32].strip
      @artist = tag[33..62].strip
      @album = tag[63..92].strip
      @year = tag[93..96].strip
      @comment = tag[97..126]
        if @comment[28] == 0 && @comment[29] != 0
          @track = @comment[29..29].to_i
          @comment = @comment[0..28].strip
        end
      @genre = Genre[tag[127]]
    rescue NoTagError
      puts "No tags found!"
      return false
    end
    true
  end
end

R2VucmUgPSAiQmx1ZXMKQ2xhc3NpYyBSb2NrCkNvdW50cnkKRGFuY2UKRGlzY28KRnVuawpH
cnVuZ2UKSGlwLUhvcApKYXp6Ck1ldGFsCk5ldyBBZ2UKT2xkaWVzCk90aGVyClBvcApSJkIK
UmFwClJlZ2dhZQpSb2NrClRlY2hubwpJbmR1c3RyaWFsCkFsdGVybmF0aXZlClNrYQpEZWF0
aCBNZXRhbApQcmFua3MKU291bmR0cmFjawpFdXJvLVRlY2hubwpBbWJpZW50ClRyaXAtSG9w
ClZvY2FsCkphenorRnVuawpGdXNpb24KVHJhbmNlCkNsYXNzaWNhbApJbnN0cnVtZW50YWwK
QWNpZApIb3VzZQpHYW1lClNvdW5kIENsaXAKR29zcGVsCk5vaXNlCkFsdGVyblJvY2sKQmFz
cwpTb3VsClB1bmsKU3BhY2UKTWVkaXRhdGl2ZQpJbnN0cnVtZW50YWwgUG9wCkluc3RydW1l
bnRhbCBSb2NrCkV0aG5pYwpHb3RoaWMKRGFya3dhdmUKVGVjaG5vLUluZHVzdHJpYWwKRWxl
Y3Ryb25pYwpQb3AtRm9sawpFdXJvZGFuY2UKRHJlYW0KU291dGhlcm4gUm9jawpDb21lZHkK
Q3VsdApHYW5nc3RhClRvcCA0MApDaHJpc3RpYW4gUmFwClBvcC9GdW5rCkp1bmdsZQpOYXRp
dmUgQW1lcmljYW4KQ2FiYXJldApOZXcgV2F2ZQpQc3ljaGFkZWxpYwpSYXZlClNob3d0dW5l
cwpUcmFpbGVyCkxvLUZpClRyaWJhbApBY2lkIFB1bmsKQWNpZCBKYXp6ClBvbGthClJldHJv
Ck11c2ljYWwKUm9jayAmIFJvbGwKSGFyZCBSb2NrCkZvbGsKRm9say1Sb2NrCk5hdGlvbmFs
IEZvbGsKU3dpbmcKRmFzdCBGdXNpb24KQmVib2IKTGF0aW4KUmV2aXZhbApDZWx0aWMKQmx1
ZWdyYXNzCkF2YW50Z2FyZGUKR290aGljIFJvY2sKUHJvZ3Jlc3NpdmUgUm9jawpQc3ljaGVk
ZWxpYyBSb2NrClN5bXBob25pYyBSb2NrClNsb3cgUm9jawpCaWcgQmFuZApDaG9ydXMKRWFz
eSBMaXN0ZW5pbmcKQWNvdXN0aWMKSHVtb3VyClNwZWVjaApDaGFuc29uCk9wZXJhCkNoYW1i
ZXIgTXVzaWMKU29uYXRhClN5bXBob255CkJvb3R5IEJhc3MKUHJpbXVzClBvcm4gR3Jvb3Zl
ClNhdGlyZQpTbG93IEphbQpDbHViClRhbmdvClNhbWJhCkZvbGtsb3JlCkJhbGxhZApQb3dl
ciBCYWxsYWQKUmh5dGhtaWMgU291bApGcmVlc3R5bGUKRHVldApQdW5rIFJvY2sKRHJ1bSBT
b2xvCkEgY2FwZWxsYQpFdXJvLUhvdXNlCkRhbmNlIEhhbGwiLnNwbGl0KCJcbiIp