Мартин обнови решението на 30.10.2012 02:07 (преди около 12 години)
+class Song
+
+ attr_accessor :name, :artist, :album
+
+ def initialize(text)
+ song_array = text.split("\n")
+ @name = song_array.fetch(0)
+ @artist = song_array.fetch(1)
+ @album = song_array.fetch(2)
+ end
+
+end
+
+class Collection
+
+ include Enumerable
+
+ attr_accessor :songs_array
+
+ def Collection.parse(file)
+ collection = Collection.new
+ array_songs = file.split("\n\n")
+ collection.songs_array = array_songs.map { |song| Song.new(song) }
+ collection
+ end
+
+ def initialize(array_of_songs=[])
+ @songs_array = array_of_songs
+ end
+
+ def each
+ songs_array.each { |song| yield song }
+ end
+
+ def artists
+ result = map { |song| song.artist }
+ result & result
+ end
+
+ def names
+ result = map { |song| song.name }
+ result & result
+ end
+
+ def albums
+ result = map { |song| song.album }
+ result & result
+ end
+
+ def filter(criteria)
+ result = Collection.new
+ result.songs_array = select { |song| criteria.approve(song) }
+ result
+ end
+
+ def adjoin(other_collection)
+ result = Collection.new
+ result.songs_array = songs_array + other_collection.songs_array
+ result.songs_array = result.songs_array & result.songs_array
+ result
+ end
+
+end
+
+class Criteria
+
+ attr_accessor :type, :criteria
+
+ def initialize(type, criteria)
+ @type = type
+ @criteria = criteria
+ end
+
+ def approve(song)
+ if type == :name and criteria == song.name then true
+ elsif type == :artist and criteria == song.artist then true
+ elsif type == :album and criteria == song.album then true
+ else false
+ end
+ end
+
+ def Criteria.artist(artist)
+ result = Criteria.new(:artist, artist)
+ end
+
+ def Criteria.name(name)
+ result = Criteria.new(:name, name)
+ end
+
+ def Criteria.album(album)
+ result = Criteria.new(:album,album)
+ end
+
+ def !
+ result = NotCriteria.new(type, criteria)
+ end
+
+ def &(other_criteria)
+ result = AndCriteria.new(self, other_criteria)
+ end
+
+ def |(other_criteria)
+ result = OrCriteria.new(self, other_criteria)
+ end
+
+end
+
+class NotCriteria < Criteria
+
+ attr_accessor :type, :criteria
+
+ def initialize(type, criteria)
+ @type = type
+ @criteria = criteria
+ end
+
+ def approve(song)
+ if type == :name and criteria != song.name then true
+ elsif type == :artist and criteria != song.artist then true
+ elsif type == :album and criteria != song.album then true
+ else false
+ end
+ end
+
+end
+
+class OrCriteria < Criteria
+
+ include Enumerable
+
+ attr_accessor :list_of_criteria
+
+ def initialize(first_criteria, second_criteria)
+ @list_of_criteria = []
+ list_of_criteria << first_criteria
+ list_of_criteria << second_criteria
+ end
+
+ def each
+ list_of_criteria.each { |criteria| yield criteria }
+ end
+
+ def approve(song)
+ any? { |criteria| criteria.approve(song) }
+ end
+
+end
+
+class AndCriteria < Criteria
+
+ include Enumerable
+
+ attr_accessor :list_of_criteria
+
+ def initialize(first_criteria, second_criteria)
+ @list_of_criteria = []
+ list_of_criteria << first_criteria
+ list_of_criteria << second_criteria
+ end
+
+ def each
+ list_of_criteria.each { |criteria| yield criteria }
+ end
+
+ def approve(song)
+ all? { |criteria| criteria.approve(song) }
+ end
+
+end