Филарета обнови решението на 28.10.2012 20:01 (преди около 12 години)
+class Song
+ include Enumerable
+
+ def each
+ yield @name
+ yield @artist
+ yield @album
+ end
+
+ attr_accessor :name, :artist, :album
+
+ def initialize(name, artist, album)
+ @name = name
+ @artist = artist
+ @album = album
+ end
+
+ def Song.parse_song(song)
+ song_attributes = song.split(/\n/)
+ Song.new song_attributes[0],song_attributes[1],song_attributes[2]
+ end
+
+ def name
+ @name
+ end
+
+ def artist
+ @artist
+ end
+
+ def album
+ @album
+ end
+end
+
+class Collection
+ include Enumerable
+
+ def each
+ @songs.each do |song|
+ yield song
+ end
+ end
+
+ attr_accessor :songs
+
+ def initialize(songs)
+ @songs = songs
+ end
+
+ def Collection.parse(text)
+ songs = text.split(/\n\n/).map{ |item| Song.parse_song(item) }
+ Collection.new songs
+ end
+
+ def names
+ @songs.map{ |song| song.name }.uniq
+ end
+
+ def artists
+ @songs.map{ |song| song.artist }.uniq
+ end
+
+ def albums
+ @songs.map{ |song| song.album }.uniq
+ end
+
+ def filter(filter_by)
+ new_songs = select(&filter_by.criteria).map do |i|
+ Song.new(i.name,i.artist,i.album)
+ end
+ Collection.new new_songs
+ end
+
+ def adjoin(collection)
+ songs = @songs | collection.songs
+ Collection.new songs
+ end
+end
+
+class Criteria
+ attr_accessor :criteria
+
+ def initialize(criteria)
+ @criteria = criteria
+ end
+
+ def Criteria.name(name)
+ Criteria.new proc { |item| item.name == name }
+ end
+
+ def Criteria.artist(artist)
+ Criteria.new proc { |item| item.artist == artist }
+ end
+
+ def Criteria.album(album)
+ Criteria.new proc { |item| item.album == album }
+ end
+
+ def |(other)
+ Criteria.new proc { |song| criteria.call(song) | other.criteria.call(song) }
+ end
+
+ def &(other)
+ Criteria.new proc { |song| criteria.call(song) & other.criteria.call(song) }
+ end
+
+ def !(other)
+ Criteria.new proc { |song| criteria.call(song) - other.criteria.call(song) }
+ end
+end
Добре, но има няколко неща.
- Защо
Song
еEnumerable
? Какъв е смисъла от това? -
select(&filter_by.criteria)
не ми харесва. Защо не го направиш сselect { |song| filter_by.matches? song }
пробвай да видиш, че ще стане по-добре. - Вместо да подаваш
proc
на конструктора наCriteria
, можеш да подадеш блок. Пак ще стане по-добре. - Защо във
filter
правиш копие на песните? По принцип са immutable и няма нужда. А дори да имаше, това става с#dup
и#clone
, а не "на ръка"