Ангел обнови решението на 30.10.2011 22:11 (преди около 13 години)
+class Song
+ attr_reader :name
+ attr_reader :artist
+ attr_reader :genre, :subgenre
+ attr_reader :tags
+
+ def initialize(name, artist, genre, subgenre=nil, tags=[])
+ @name = name
+ @artist = artist
+ @genre = genre
+ @subgenre = subgenre
+ @tags = tags
+ end
+
+ def tags
+ all_tags = @tags | [genre.downcase]
+ all_tags |= [subgenre.downcase] if subgenre != nil
+ all_tags
+ end
+end
+
+class Collection
+ def initialize(songs_as_string, artist_tags)
+ @songs = parse_all_songs(songs_as_string, artist_tags)
+ end
+
+ def find(criteria)
+ @songs.select {|song| meets_criteria? song, criteria}
+ end
+
+ private
+
+ def parse_single_song(song_as_string, artist_tags)
+ attributes = song_as_string.split('.')
+ name = attributes[0].strip
+ artist = attributes[1].strip
+ genre = attributes[2].split(',')[0].strip
+ subgenre = attributes[2].split(',').fetch(1,'').strip
+ subgenre = nil if subgenre == ''
+ tags = attributes.fetch(3, '').split(',').map{|attr| attr.strip}
+ additional_tags = artist_tags.fetch(artist, [])
+ Song.new(name, artist, genre, subgenre, tags|additional_tags)
+ end
+
+ def parse_all_songs(songs_as_string, artist_tags)
+ songs = []
+ songs_as_string.lines {|s| songs.push(parse_single_song(s, artist_tags))}
+ songs
+ end
+
+ def meets_criteria?(song, criteria)
+ has_tags = [criteria.fetch(:tags,[])].flatten.all? do |tag|
+ if tag.end_with?('!')
+ !song.tags.include? tag.chop
+ else
+ song.tags.include? tag
+ end
+ end
+ same_name = song.name == criteria.fetch(:name, song.name)
+ same_artist = song.artist == criteria.fetch(:artist, song.artist)
+ meets_filter = criteria.fetch(:filter, ->(s){true}).(song)
+ [has_tags, same_name, same_artist, meets_filter].all?
+ end
+end