Мая обнови решението на 30.10.2011 23:44 (преди около 13 години)
+class Song
+ def initialize(spec)
+ @name, @artist, genre_spec, tag_spec = spec.split('.').map { |s| s.strip }
+ @genre, @subgenre = genre_spec.split(',').map { |s| s.strip }
+ @tags = [@genre.downcase()]
+ @subgenre and @tags.push(@subgenre.downcase())
+ tag_spec and tag_spec.lines(',') { |tag| @tags.push(tag.strip.delete(',')) }
+ end
+
+ def add_tags(tags)
+ @tags.concat(tags).uniq!
+ end
+
+ attr_accessor :name
+ attr_accessor :artist
+ attr_accessor :genre
+ attr_accessor :subgenre
+ attr_accessor :tags
+
+ def matches?(criteria)
+ match_tags(criteria[:tags]) and
+ match_name(criteria[:name]) and
+ match_artist(criteria[:artist]) and
+ match_filter(criteria[:filter])
+ end
+
+ def match_tags(tags)
+ return true unless tags
+
+ negative = tags.select { |tag| tag.end_with?('!') }
+ positive = tags - negative
+
+ negative = negative.map{ |str| str.delete('!') }
+ return false unless (@tags & negative).empty?()
+
+ (@tags & positive).eql? positive
+ end
+
+ def match_name(name)
+ !name or @name.eql? name
+ end
+
+ def match_artist(artist)
+ !artist or @artist.eql? artist
+ end
+
+ def match_filter(pred)
+ !pred or pred.call(self)
+ end
+end
+
+class Collection
+ def initialize(songs_as_string, artist_tags)
+ @songs = []
+ songs_as_string.lines { |line| @songs.push(Song.new(line)) }
+ artist_tags.map { |entry| add_to_songs(entry) }
+ end
+
+ def add_to_songs(tags)
+ matching_songs = @songs.select { |song| song.artist.eql? tags[0] }
+ matching_songs.map { |song| song.add_tags(tags[1]) }
+ end
+
+ def find(criteria)
+ @songs.select { |s| s.matches?(criteria) }
+ end
+end