Евгени обнови решението на 28.10.2011 00:56 (преди около 13 години)
+class Song
+ attr_accessor :name, :artist,
+ :genre, :subgenre,
+ :tags
+
+ def initialize(song_hash)
+ @name = song_hash[:name].strip
+ @artist = song_hash[:artist].strip
+ @genre = song_hash[:genre].strip
+ @subgenre = song_hash[:subgenre].strip if song_hash[:subgenre]
+ @tags = song_hash[:tags].map!{|tag| tag.strip}
+ end
+
+ def matches_criteria?(criteria_hash)
+ criteria_hash.each do |attribute, value|
+ return false unless matches_criterion? attribute, value
+ end
+ true
+ end
+
+ def matches_criterion?(attribute, value)
+ value = Array(value)
+ if attribute == :filter
+ return value.all? { |filter| filter.(self) }
+ end
+ if attribute == :tags
+ match_positive_tags?(value) and match_negative_tags?(value)
+ else
+ value.include? attribute.to_proc.(self)
+ end
+ end
+
+ def match_positive_tags?(tags)
+ tags.select { |tag| not tag.end_with?'!' }.all?{ |tag| @tags.include?tag }
+ end
+
+ def match_negative_tags?(tags)
+ tags.select { |tag| tag.end_with?'!' }.none?{ |tag| @tags.include?tag.chop }
+ end
+end
+
+class Collection
+ attr_reader :songs
+
+ def initialize(songs_string, artist_tags)
+ @songs = songs_string.lines.map do |line|
+ Song.new Collection.song_line_to_hash line, artist_tags
+ end
+ end
+
+ def find(criteria)
+ @songs.select { |song| song.matches_criteria? criteria }
+ end
+
+ private
+
+ def self.song_line_to_hash(line, artist_tags)
+ values = line.split('.').map{|str| str.strip}
+ pairs = [ :name, :artist, :genre_subgenre, :tags ].zip(values)
+ fix_hash(Hash[pairs], artist_tags)
+ end
+
+ def self.fix_hash(song_hash, artist_tags)
+ song_hash[:genre_subgenre] = song_hash[:genre_subgenre].split /\s*,\s*/
+ song_hash[:genre], song_hash[:subgenre] = song_hash[:genre_subgenre]
+ song_hash[:tags] = song_hash[:tags] ? song_hash[:tags].split(',') : []
+ song_hash[:tags] << song_hash[:genre].downcase if song_hash[:genre]
+ song_hash[:tags] << song_hash[:subgenre].downcase if song_hash[:subgenre]
+ song_hash[:tags] += (artist_tags[song_hash[:artist]] or [])
+ song_hash
+ end
+end
Идентацията ти е омазана и song_line_to_hash
има ужасно дълги редове.
Коментарите към твоето решение ги чу на лекцията и ги има в слайдовете.
Мога само да довабя, че strip
-овете от Song#initialize
са по-подходящи за Collection.song_line_to_hash
.