Изабела обнови решението на 30.10.2012 01:03 (преди около 12 години)
+class Song
+ attr_accessor :name, :artist, :album
+
+ def initialize(name, artist, album)
+ @name, @artist, @album = name, artist, album
+ end
+end
+
+class Collection
+ include Enumerable
+
+ attr_accessor :songs
+
+ def initialize(songs)
+ @songs = songs
+ end
+
+ def each
+ @songs.each { |song| yield song }
+ end
+
+ def self.parse(text)
+ parsed_songs = text.split("\n").each_slice(4).
+ map { |name, artist, album| Song.new(name, artist, album) }
+ Collection.new(parsed_songs)
+ end
+
+ def names
+ @songs.map(&:name).uniq
+ end
+
+ def artists
+ @songs.map(&:artist).uniq
+ end
+
+ def albums
+ @songs.map(&:album).uniq
+ end
+
+ def filter(criteria)
+ filtered_songs = @songs.select { |song| criteria.selector.call(song) }
+ Collection.new(filtered_songs)
+ end
+
+ def adjoin(collection)
+ Collection.new(songs + collection.songs)
+ end
+end
+
+class Criteria
+ attr_accessor :selector
+
+ def initialize(selector)
+ @selector = selector
+ end
+
+ def self.name(request)
+ Criteria.new ->(song) { request == song.name }
+ end
+
+ def self.artist(request)
+ Criteria.new ->(song) { request == song.artist }
+ end
+
+ def self.album(request)
+ Criteria.new ->(song) { request == song.album }
+ end
+
+ def &(other)
+ Criteria.new ->(song) { selector.call(song) & other.selector.call(song) }
+ end
+
+ def |(other)
+ Criteria.new ->(song) { selector.call(song) | other.selector.call(song) }
+ end
+
+ def !
+ Criteria.new ->(song) { !selector.call(song) }
+ end
+end