Николай обнови решението на 27.10.2012 12:52 (преди около 12 години)
+class Collection
+ include Enumerable
+ attr_reader :songs
+
+ def Collection.parse(text)
+ lines = text.lines.map(&:chomp)
+ songs = lines.each_slice(4)
+ song_objects = songs.map { |song| Song.new(song[0], song[1], song[2]) }
+ Collection.new(song_objects)
+ end
+
+ def initialize(songs)
+ @songs = songs
+ end
+
+ def artists
+ all_artists = @songs.map(&:artist)
+ all_artists.uniq
+ end
+
+ def albums
+ all_albums = @songs.map(&:album)
+ all_albums.uniq
+ end
+
+ def names
+ all_names = @songs.map(&:name)
+ all_names.uniq
+ end
+
+ def each
+ @songs.each { |song| yield song }
+ end
+
+ def filter(criteria)
+ songs = @songs.select &criteria.expression
+ Collection.new(songs)
+ end
+
+ def adjoin(other)
+ songs = @songs | other.songs
+ Collection.new(songs)
+ end
+end
+
+class Song
+ attr_reader :name, :artist, :album
+
+ def initialize(name, artist, album)
+ @name = name
+ @artist = artist
+ @album = album
+ end
+end
+
+class Criteria
+ attr_reader :expression
+
+ def Criteria.name(value)
+ Criteria.new(-> song { song.name == value })
+ end
+
+ def Criteria.artist(value)
+ Criteria.new(-> song { song.artist == value })
+ end
+
+ def Criteria.album(value)
+ Criteria.new(-> song { song.album == value })
+ end
+
+ def initialize(expression)
+ @expression = expression
+ end
+
+ def &(other)
+ Criteria.new(-> song { expression[song] & other.expression[song] })
+ end
+
+ def |(other)
+ Criteria.new(-> song { expression[song] | other.expression[song] })
+ end
+
+ def !
+ Criteria.new(-> song { !expression[song] })
+ end
+end