Skip to content

Instantly share code, notes, and snippets.

@rklemme
Created October 24, 2009 17:58
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save rklemme/217641 to your computer and use it in GitHub Desktop.
Save rklemme/217641 to your computer and use it in GitHub Desktop.
Complete file for blog entry "The Complete Class"
require 'yaml'
Track = Struct.new :title, :duration
# An Album represents an audio medium which has title,
# interpret, a pause duration between tracks and a list
# of individual tracks.
class Album
attr_reader :title, :interpret, :pause
# initialization
def initialize(title, interpret, pause = 0)
super()
# main properties
self.title = title
self.interpret = interpret
@tracks = []
# additional properties
self.pause = pause
# redundant properties
# left out
end
def title=(t)
@title = t.dup.freeze
end
def interpret=(i)
@interpret = i.dup.freeze
end
def pause=(time)
@pause = time
@duration = nil
end
def each_track(&b)
@tracks.each(&b)
self
end
def add_track(tr)
@tracks << tr
@duration = nil
self
end
def clear_tracks
@tracks.clear
@duration = nil
self
end
alias << add_track
def tracks
@tracks.dup
end
def duration
@duration ||= @tracks.empty? ?
0 :
@tracks.inject(-pause) do |sum, tr|
sum + pause + tr.duration
end
end
# conversion to a printable string
def to_s
"Album '#{title}' by '#{interpret}' (#{tracks.size} tracks)"
end
# equivalence
def eql?(album)
self.class.equal?(album.class) &&
title == album.title &&
interpret == album.interpret &&
tracks == album.tracks
end
alias == eql?
# hash code calculation
def hash
title.hash ^
interpret.hash ^
tracks.hash
end
# comparability
include Comparable
def <=>(o)
self.class == o.class ?
(interpret <=> o.interpret).nonzero? ||
(title <=> o.title).nonzero? ||
(tracks <=> o.tracks).nonzero? ||
(pause <=> o.pause) ||
0 :
nil
end
# cloning
def initialize_copy(source)
super
@tracks = @tracks.dup
end
# freezing
def freeze
# unless frozen?
@tracks.freeze
duration
# end
super
end
# customized persistence
def marshal_dump
a = (super rescue [])
a.push(@title, @interpret, @pause, @tracks)
end
def marshal_load(dumped)
super rescue nil
@title, @interpret, @pause, @tracks = *dumped.shift(4)
end
def to_yaml_properties
a = super
a.delete :@duration
a
end
# matching
def ===(track)
t = (track.title rescue track)
tracks.find {|tr| t == tr.title}
end
def =~(rx)
rx =~ title
end
end
# ===== Test Code ===================================================
alb = Album.new "In through the out door", "Led Zeppelin", 2
printf "%-30s %p\n", 'empty album', alb
alb << Track.new("In the Evening", 6 * 60 + 49)
alb << Track.new("South Bound Saurez", 4 * 60 + 12)
alb << Track.new("Fool in the Rain", 6 * 60 + 12)
alb << Track.new("Hot Dog", 3 * 60 + 17)
printf "%-30s %p\n", 'page 1 completed', alb
printf "%-30s %p\n", 'duration', alb.duration
printf "%-30s %p\n", 'after duration calculation', alb
page1 = alb.dup
printf "%-30s %p\n", 'copy of page 1', page1
printf "%-30s %p\n", 'copy equivalent?', alb == page1
printf "%-30s %p\n", 'really?', page1 == alb
alb << Track.new("Carouselambra", 10 * 60 + 32)
alb << Track.new("All my Love", 5 * 60 + 51)
alb << Track.new("I'm gonna crawl", 5 * 60 + 30)
alb.duration
printf "%-30s %p\n", 'full album', alb
printf "%-30s %p\n", 'page 1', page1
printf "%-30s %p\n", 'track found?', alb === "All my Love"
printf "%-30s %p\n", 'track on page 1', page1 === "All my Love"
puts alb, page1
2.times { alb.freeze }
printf "%-30s %p\n", 'full album', alb
alb2 = Marshal.load(Marshal.dump(alb))
printf "%-30s %p\n", 'marshaled', alb2
alb3 = YAML.load(YAML.dump(alb))
printf "%-30s %p\n", 'yamld', alb3
printf "%-30s %p\n", 'yamld duration', alb3.duration
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment