I've mentioned it before, but if you don't know Perl programmers maintain a "Quiz of the Week". If you want to know more, the page is here:
This week's Regular Quiz (there also an Expert Quiz) came out last night. The curious can read it here:
http://article.gmane.org/gmane.comp.lang.perl.qotw.quiz-of-the-week/105
*** SPOILER WARNING ***
Stop reading this message if you read the Quiz and would like to solve it yourself, without seeing a solution first.
Okay, now to my point, finally...
I've solved the Quiz in Ruby. If you've seen my earlier posts, you know I'm brand new to Ruby. I've spent the last week and a half learning it and this is really my first attempt to put it to use.
If any of you can spare the time, I would appreciate an honest review of the code I generated. I'm interested in any opinions you might have about constructs, style, whatever. I'm especially looking for things I'm handling in a non-Ruby fashion. Break my bad habits before they take hold... <laughs>
Thanks in advance for sharing your time. Here's the code:
#!/usr/bin/ruby -w
require "getoptlong"
class Event
attr_reader :category, :day, :month, :year, :name
def Event.parse( string, cat )
if string =~ /^\s*(?:(\d+)\/)?(\d+)(?:\/(\d+))?\s+(.+?)\s*$/
return Event.new( cat, $4, $2, $1, $3 )
else
return
end
end
def initialize( cat, event, dd, mm = nil, yyyy = nil )
@category = cat
@name = event
@day = dd.to_i
@month = mm.to_i
@year = yyyy.to_i
end
def <=>( other )
if not year.zero? and not other.year.zero? and year != other.year
return year <=> other.year
elsif not month.zero? and not other.month.zero? and month != other.month
return month <=> other.month
else
return day <=> other.day
end
end
def between?( min, max )
times = [ min ]
until times[-1].year == max.year and times[-1].month == max.month and
times[-1].day == max.day
times << times[-1] + (60 * 60 * 24)
end
result = times.find do | time |
(year == 0 or year == time.year) and
(month == 0 or month == time.month) and
day == time.day
end
if result
times.index result
else
return
end
end
def date
date = day.to_s
unless month.zero?
date = month.to_s + "/" + date
end
unless year.zero?
date += "/" + year.to_s
end
return date
end
end
delta = 7
GetoptLong.new( [ "-n", GetoptLong::REQUIRED_ARGUMENT ] ).each do | opt, arg |
delta = arg.to_i if opt == "-n"
end
NOW = Time.now
LIMIT = NOW + (delta * 24 * 60 * 60)
OFFSETS = [ " ===>", " -->", " -->", " -->", "-->", "->", ">", "" ]
DIR = File.join ENV["HOME"], '.upcoming';
events = { }
Dir.foreach DIR do | file_name |
next if file_name =~ /^\./
File.open File.join( DIR, file_name ) do | file |
while line = file.gets
e = Event.parse line, file_name
if e
events[file_name] = [ ] unless events.key? file_name
events[file_name] << e
end
end
end
end
puts
events.each do | key, value |
next unless value.find { | e | e.between? NOW, LIMIT }
puts key
value.sort.each do | e |
offset = e.between? NOW, LIMIT
next unless offset
case offset
when 0..7
printf "%-7s ", OFFSETS[offset]
else
printf "%-7s ", "(" + offset.to_s + ")"
end
printf "%-10s %s\n", e.date, e.name
end
puts
end
__END__
James Edward Gray II