Генади обнови решението на 26.10.2012 22:59 (преди около 12 години)
+class Collection
+ include Enumerable
+
+ def self.parse(text)
+ new text.split("\n\n").collect { |chunk| Song.new *chunk.split("\n") }
+ end
+
+ def initialize(songs)
+ @songs = songs
+ end
+
+ def filter(criteria)
+ Collection.new select { |song| criteria.match? song }
+ end
+
+ def adjoin(other)
+ Collection.new (Array(self) | Array(other)).uniq
+ end
+
+ def names
+ collect(&:name).uniq
+ end
+
+ def artists
+ collect(&:artist).uniq
+ end
+
+ def albums
+ collect(&:album).uniq
+ end
+
+ def each(&block)
+ @songs.each &block
+ end
+end
+
+class Criteria
+ def self.name(name)
+ Criteria.new { |song| name == song.name }
+ end
+
+ def self.artist(artist)
+ Criteria.new { |song| artist == song.artist }
+ end
+
+ def self.album(album)
+ Criteria.new { |song| album == song.album }
+ end
+
+ def initialize(&block)
+ @condition = block
+ end
+
+ def match?(song)
+ @condition.call song
+ end
+
+ def &(other)
+ Criteria.new { |song| match?(song) and other.match?(song) }
+ end
+
+ def |(other)
+ Criteria.new { |song| match?(song) or other.match?(song) }
+ end
+
+ def !
+ Criteria.new { |song| not match? song }
+ end
+end
+
+Song = Struct.new :name, :artist, :album