Илиян обнови решението на 31.10.2012 13:39 (преди около 12 години)
+class Collection
+ include Enumerable
+
+ def initialize(songs_array)
+ @songs = songs_array
+ end
+
+ def self.parse(text)
+ songs = []
+ text.split("\n\n").collect do |song_data|
+ songs << Song.new(*song_data.split("\n"))
+ end
+ Collection.new songs
+ end
+
+ def artists
+ songs.collect { |song| song.artist }.uniq
+ end
+
+ def albums
+ songs.collect { |song| song.album }.uniq
+ end
+
+ def names
+ songs.collect { |song| song.name }.uniq
+ end
+
+ def filter(criteria)
+ Collection.new songs.select { |song| criteria.fulfil? song }
+ end
+
+ def adjoin(other)
+ Collection.new songs | other.songs
+ end
+
+ def each(&block)
+ songs.each &block
+ end
+
+ protected
+ attr_reader :songs
+end
+
+class Song
+ attr_reader :name, :artist, :album
+
+ def initialize name, artist, album
+ @name = name
+ @artist = artist
+ @album = album
+ end
+end
+
+module Criteria
+ def self.name(text)
+ Criterion.new(lambda { |song| song.name == text })
+ end
+
+ def self.artist(text)
+ Criterion.new(lambda { |song| song.artist == text })
+ end
+
+ def self.album(text)
+ Criterion.new(lambda { |song| song.album == text })
+ end
+
+ class Criterion
+ attr_reader :fulfil_criterion
+
+ def initialize(given_criterion)
+ @fulfil_criterion = given_criterion
+ end
+
+ def fulfil?(song)
+ fulfil_criterion.call(song)
+ end
+
+ def &(other)
+ Criterion.new lambda { |song| fulfil? song and other.fulfil? song }
+ end
+
+ def |(other)
+ Criterion.new lambda { |song| fulfil? song or other.fulfil? song }
+ end
+
+ def !
+ Criterion.new lambda { |song| !fulfil? song }
+ end
+ end
+end