Станислав обнови решението на 26.10.2012 10:00 (преди над 12 години)
+class Criteria
+ attr_reader :condition
+
+ def initialize(condition)
+ @condition = condition
+ end
+
+ def check(song)
+ @condition.(song)
+ end
+
+ def !
+ Criteria.new(lambda { |song| !condition.(song) })
+ end
+
+ def |(other)
+ Criteria.new(lambda { |song| other.condition.(song) or @condition.(song) })
+ end
+
+ def &(other)
+ Criteria.new(lambda { |song| other.condition.(song) and @condition.(song) })
+ end
+
+ def Criteria.name(name)
+ Criteria.new(lambda { |song| song.name == name })
+ end
+
+ def Criteria.artist(artist)
+ Criteria.new(lambda { |song| song.artist == artist })
+ end
+
+ def Criteria.album(album)
+ Criteria.new(lambda { |song| song.album == album })
+ end
+end
+
+class Song
+ attr_accessor :name, :artist, :album
+
+ def initialize(name, artist, album)
+ @name, @artist, @album = name, artist, album
+ end
+end
+
+class Collection
+ include Enumerable
+
+ attr_accessor :songs
+
+ def initialize
+ @songs = []
+ yield self
+ end
+
+ def Collection.parse(text)
+ new { |result| result.fill(text) }
+ end
+
+ def fill(text)
+ text.lines.each_slice(4) do |name, artist, album|
+ @songs << Song.new(name.chomp, artist.chomp, album.chomp)
+ end
+ end
+
+ def each
+ @songs.each { |song| yield song }
+ end
+
+ def names
+ @songs.map { |song| song.name }.uniq
+ end
+
+ def artists
+ @songs.map { |song| song.artist }.uniq
+ end
+
+ def albums
+ @songs.map { |song| song.album }.uniq
+ end
+
+ def filter(criteria)
+ filtered_songs = @songs.select { |song| criteria.check song }
+ Collection.new { |result| result.songs = filtered_songs }
+ end
+
+ def adjoin(other)
+ Collection.new { |result| result.songs.concat(songs + other.songs) }
+ end
+end