Иван обнови решението на 31.10.2012 11:52 (преди около 12 години)
+class Song
+ attr_reader :name, :artist, :album
+
+ def initialize(info)
+ @name, @artist, @album = *info.first(3).map(&:chomp)
+ end
+
+ def hash
+ [@name, @artist, @album].hash
+ end
+
+ def eql?(other)
+ hash == other.hash
+ end
+end
+
+class Collection
+ include Enumerable
+
+ @songs = []
+
+ attr_reader :songs
+
+ def initialize(songs)
+ @songs = songs
+ end
+
+ def self.parse(input)
+ Collection.new input.lines.each_slice(4).map { |rows| Song.new rows }
+ end
+
+ def names
+ get_details :name
+ end
+
+ def artists
+ get_details :artist
+ end
+
+ def albums
+ get_details :album
+ end
+
+ def filter(criteria)
+ Collection.new @songs.select { |song| criteria.compiled[song] }
+ end
+
+ def each(&block)
+ @songs.each(&block)
+ end
+
+ def adjoin(other)
+ Collection.new (@songs + other.songs).uniq
+ end
+
+ private
+ def get_details(method)
+ @songs.map { |song| song.send method }.uniq
+ end
+end
+
+class Criteria
+ attr_reader :compiled
+
+ def initialize(compiled)
+ @compiled = compiled
+ end
+
+ def self.name(wanted_name)
+ Criteria.new ->(song) { song.name == wanted_name }
+ end
+
+ def self.artist(wanted_artist)
+ Criteria.new ->(song) { song.artist == wanted_artist }
+ end
+
+ def self.album(wanted_album)
+ Criteria.new ->(song) { song.album == wanted_album }
+ end
+
+ def !
+ Criteria.new ->(song) { not @compiled[song] }
+ end
+
+ def |(criteria)
+ Criteria.new ->(song) { @compiled[song] or criteria.compiled[song] }
+ end
+
+ def &(criteria)
+ Criteria.new ->(song) { @compiled[song] and criteria.compiled[song] }
+ end
+end