Тодор обнови решението на 31.10.2012 14:30 (преди около 12 години)
+
+require 'enumerator'
+
+class Song
+ attr_reader :album, :artist, :name
+
+ def initialize(name, artist, album)
+ @album, @artist, @name = album, artist, name
+ end
+end
+
+
+class Collection
+ include Enumerable
+
+ def initialize(songs)
+ @songs = songs
+ end
+
+ def self.parse(text)
+ song_attr_lst = text.split("\n").select{ |s| s != ""}.each_slice(3)
+ songs_lst = song_attr_lst.map{ |s| Song.new *s}
+ Collection.new songs_lst
+ end
+
+ def each
+ @songs.each{ |s| yield s}
+ end
+
+ def albums()
+ @songs.group_by{ |s| s.album }.map{ |k, v| k}
+ end
+
+ def artists()
+ @songs.group_by{ |s| s.artist }.map{ |k, v| k}
+ end
+
+ def names()
+ @songs.group_by{ |s| s.name }.map{ |k, v| k}
+ end
+
+ def filter criteria
+ Collection.new @songs.find_all{ |s| criteria.call_filter s}
+ end
+
+ def name(value)
+ lambda{ |s| s.name == value}
+ end
+
+ def adjoin(other_songs)
+ Collection.new @songs.to_a + other_songs.select{|s| s}
+ end
+end
+
+class Criteria
+ attr_reader :filter
+
+ def initialize(filter)
+ @filter = filter
+ end
+
+ def call_filter(song)
+ filter.call(song)
+ end
+
+ def self.name(value)
+ name_filter = lambda { |song| song.name == value}
+ Criteria.new name_filter
+ end
+
+ def self.artist(value)
+ artist_filter = lambda { |song| song.artist == value}
+ Criteria.new artist_filter
+ end
+
+ def self.album(value)
+ album_filter = lambda { |song| song.album == value}
+ Criteria.new album_filter
+ end
+
+ def |(other)
+ r_filter = lambda{ |song| self.filter.call(song) | other.call_filter(song)}
+ Criteria.new r_filter
+ end
+
+ def &(other)
+ r_filter = lambda{ |song| self.filter.call(song) & other.call_filter(song)}
+ Criteria.new r_filter
+ end
+
+ def !@
+ not_filter = lambda{ |song| !self.filter.call(song)}
+ Criteria.new not_filter
+ end
+
+end