Стоян обнови решението на 29.10.2012 00:20 (преди около 12 години)
+class Collection
+ include Enumerable
+ def Collection.parse(text)
+ list = text.split(/\n/).each_slice(4).map { |a| Song.new(a[0], a[1], a[2]) }
+ Collection.new list
+ end
+ attr_reader :songs
+
+ def initialize(songs)
+ @songs = songs
+ end
+ def each
+ @songs.each { |song| yield song }
+ end
+ def artists
+ map { |s| s.artist }.uniq
+ end
+ def albums
+ map { |s| s.album }.uniq
+ end
+ def names
+ map { |s| s.name }.uniq
+ end
+ def filter(criteria)
+ Collection.new select { |s| criteria.filter.call(s) }
+ end
+ def adjoin(other)
+ Collection.new @songs | other.songs
+ end
+ def |(other)
+ adjoin other
+ end
+end
+
+class Criteria
+ def initialize(filter)
+ @filter = filter
+ end
+ attr_reader :filter
+
+ def Criteria.artist(artist_name)
+ Criteria.new(Proc.new { |s| s.artist == artist_name })
+ end
+ def Criteria.album(album_name)
+ Criteria.new(Proc.new { |s| s.album == album_name })
+ end
+ def Criteria.name(song_name)
+ Criteria.new(Proc.new { |s| s.name == song_name })
+ end
+ def |(other)
+ Criteria.new(Proc.new { |s| self.filter.call(s) | other.filter.call(s) })
+ end
+ def &(other)
+ Criteria.new(Proc.new { |s| self.filter.call(s) & other.filter.call(s) })
+ end
+ def !
+ Criteria.new(Proc.new { |s| !self.filter.call(s) })
+ end
+end
+
+class Song
+ def initialize(name, artist, album)
+ @name = name
+ @artist = artist
+ @album = album
+ end
+ attr_reader :artist, :album, :name
+end