Ростислав обнови решението на 31.10.2012 01:11 (преди около 12 години)
+class Song
+ attr_accessor :name, :artist, :album
+
+ def initialize(name, artist, album)
+ @name = name
+ @artist = artist
+ @album = album
+ end
+end
+
+class Collection
+ attr_accessor :songs
+
+ include Enumerable
+
+ def initialize(list_of_songs)
+ @songs = list_of_songs
+ end
+
+ def self.parse(text)
+ arr = generate_song_array(text)
+ songs = generate_songs_from_array(arr)
+ Collection.new(songs)
+ end
+
+ def artists
+ array_of_artists = []
+ @songs.each { |song| array_of_artists << song.artist }
+ array_of_artists.uniq
+ end
+
+ def albums
+ array_of_albums = []
+ @songs.each { |song| array_of_albums << song.album }
+ array_of_albums.uniq
+ end
+
+ def names
+ array_of_song_names = []
+ @songs.each { |song| array_of_song_names << song.name }
+ array_of_song_names.uniq
+ end
+
+ def filter(filter_array)
+ collection = Collection.new([])
+ collection.songs = @songs.select { |song| filter_array.contains?(song) }
+ collection
+ end
+
+ def adjoin(collection)
+ new_collection = Collection.new([])
+ new_collection = @songs | collection.songs
+ new_collection
+ end
+
+ private
+
+ def self.generate_song_array(text)
+ song_array = []
+ text.each_line do |line|
+ song_array << line.chomp
+ end
+ song_array.reject { |line| line.empty? }
+ end
+
+ def self.generate_songs_from_array(song_array)
+ array_of_songs = []
+ song_array.each_slice(3) do |sub_array|
+ array_of_songs << Song.new(sub_array[0], sub_array[1], sub_array[2])
+ end
+ array_of_songs
+ end
+end
+
+class FilterSong < Song
+ attr_accessor :not_name, :not_artist, :not_album
+
+ def initialize(name, artist, album)
+ @name, @artist, @album = name, artist, album
+ @not_name, @not_artist, @not_album = nil, nil, nil
+ end
+
+ def combine_filter(filter_array)
+ filter_array.filter_songs.map do |filter_song|
+ filter_song.combine_with(self)
+ end
+ end
+
+ def !
+ song = FilterSong.new(@not_name, @not_artist, @not_album)
+ song.not_name, song.not_artist, song.not_album = @name, @artist, @album
+ song
+ end
+
+ def compare_with(other)
+ song = generateCompareSong(FilterSong.new(@name, @artist, @album), other)
+ other.name == song.name && other.name != song.not_name &&
+ other.artist == song.artist && other.artist != song.not_artist &&
+ other.album == song.album && other.album != song.not_album
+ end
+
+ def generateCompareSong(song, other)
+ song.name = other.name if song.name == nil && song.not_name == nil
+ song.artist = other.artist if song.artist == nil && song.not_artist == nil
+ song.album = other.album if song.album == nil && song.not_album == nil
+ song
+ end
+
+ def combine_with(other)
+ @name = other.name if @name == nil
+ @artist = other.artist if @artist == nil
+ @album = other.album if @album == nil
+ combine_not_fields_with(other)
+ end
+
+ def combine_not_fields_with(other)
+ @not_name = other.not_name if @not_name == nil
+ @not_artist = other.not_artist if @not_artist == nil
+ @not_album = other.not_album if @not_album == nil
+ self
+ end
+
+ def empty?
+ @name == nil && @artist == nil && @album == nil &&
+ @not_name == nil && @not_artist == nil && @not_album == nil
+ end
+end
+
+class Filter
+ attr_accessor :filter_songs
+
+ def initialize(name, artist, album)
+ @filter_songs = []
+ @filter_songs << FilterSong.new(name, artist, album)
+ end
+
+ def &(other)
+ f = Filter.new(nil, nil, nil)
+ @filter_songs.each { |song| f.filter_songs << song.combine_filter(other) }
+ f.filter_songs = f.filter_songs.reject { |song| song.empty? }.flatten
+ f
+ end
+
+ def |(other)
+ filter = Filter.new(nil, nil, nil)
+ filter.filter_songs = @filter_songs | other.filter_songs
+ filter
+ end
+
+ def !
+ filter = Filter.new(nil, nil, nil)
+ filter.filter_songs = @filter_songs.map { |song| !song }
+ filter
+ end
+
+ def contains?(other_song)
+ @filter_songs.any? do |song|
+ song = generate_empty_strings(song)
+ song.compare_with(other_song)
+ end
+ end
+
+ private
+
+ def generate_empty_strings(song)
+ song.not_name == "1" if song.not_name == nil
+ song.not_artist == "1" if song.not_artist == nil
+ song.not_album == "1" if song.not_album == nil
+ song
+ end
+end
+
+module Criteria
+ def self.name(song_name)
+ Filter.new(song_name, nil, nil)
+ end
+
+ def self.artist(song_artist)
+ Filter.new(nil, song_artist, nil)
+ end
+
+ def self.album(song_album)
+ Filter.new(nil, nil, song_album)
+ end
+end