Решение на Втора задача от Марин Иванов

Обратно към всички решения

Към профила на Марин Иванов

Резултати

  • 6 точки от тестове
  • 2 бонус точки
  • 8 точки общо
  • 12 успешни тест(а)
  • 0 неуспешни тест(а)

Код

# Author:: Marin Ivanov (mailto:metala@metala.org)
# Copyright:: Copyright (c) 2011
# License:: BSD 2-clause license
#
# Copyright (c) 2011, Marin Valeriev Ivanov
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY Marin Valeriev Ivanov ''AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL Marin Valeriev Ivanov BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# NOTE:: roflmaodsedong
# This class has 5 properties, that's it. LOL, not LoL, cause HoN > LoL
class Song
def initialize(name, artist, genre, subgenre, tags = [])
@name = name
@artist = artist
@genre = genre
@subgenre = subgenre
@tags = tags
[genre, subgenre].compact.each {|genre| @tags << genre.downcase}
end
attr_accessor :name, :artist, :genre, :subgenre, :tags
end
# This module contains the "pluggable" mixins
# used in result filtering
module CollectionFilterPlugins
private
def filter_plugin_name(criteria, list)
return list if criteria[:name] == nil
name = criteria[:name]
list.select { |song| song.name == name }
end
def filter_plugin_artist(criteria, list)
return list if criteria[:artist] == nil
artist = criteria[:artist]
list.select { |song| song.artist == artist }
end
def filter_plugin_filter(criteria, list)
return list if criteria[:filter] == nil
filter = criteria[:filter]
list.select { |song| filter.(song) }
end
def filter_plugin_tags(criteria, list)
return list if criteria[:tags] == nil
tags = [criteria[:tags]].flatten
exclude_tags = tags.select {|tag| tag.end_with? '!'}.map {|tag| tag.chop}
include_tags = tags.select {|tag| not tag.end_with? '!'}
list.select do |song|
(song.tags & include_tags).size == include_tags.size \
and (song.tags & exclude_tags).empty?
end
end
end
# This is Collection class in the specification, that
# parses all the data, builds Song objects, and then, on
# Collection#find, filters the results using plugin methods
# atm. not as pluggable as excepted
class Collection
include CollectionFilterPlugins
def initialize(songs_as_text, artist_tags = {})
@plugin_methods = []
load_filter_plugin_methods()
@artist_tags = artist_tags
@all = []
parse(songs_as_text)
end
def find(criteria = {})
list = Array.new(@all)
@plugin_methods.each do |filter_method|
list = filter_method.(criteria, list)
end
list
end
def get_tags_for_artist(artist)
@artist_tags[artist] or []
end
private
# TODO: refactor
def load_filter_plugin_methods()
@plugin_methods = []
self.class.private_instance_methods.each do |method_symbol|
if method_symbol.to_s.start_with? 'filter_plugin_'
@plugin_methods << method(method_symbol)
end
end
end
def parse(songs_text)
songs_text.lines.each do |line|
parts = get_line_parts(line)
name = parts[:name]
artist = parts[:artist]
genre, subgenre = parts[:genres]
tags = (parts[:tags] or []) + get_tags_for_artist(artist)
song = Song.new(parts[:name], parts[:artist], genre, subgenre, tags)
@all << song
end
end
def get_line_parts(line)
parts = line.split('.').map(&:strip)
parts[2..3] = parts[2..3].map {|str| str.split(',').map(&:strip)}
Hash[*[:name, :artist, :genres, :tags].zip(parts).flatten(1)]
end
end

Лог от изпълнението

............

Finished in 0.54652 seconds
12 examples, 0 failures

История (1 версия и 6 коментара)

Марин обнови решението на 30.10.2011 06:55 (преди около 13 години)

+# Author:: Marin Ivanov (mailto:metala@metala.org)
+# Copyright:: Copyright (c) 2011
+# License:: BSD 2-clause license
+#
+# Copyright (c) 2011, Marin Valeriev Ivanov
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY Marin Valeriev Ivanov ''AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL Marin Valeriev Ivanov BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# NOTE:: roflmaodsedong
+
+# This class has 5 properties, that's it. LOL, not LoL, cause HoN > LoL
+class Song
+ def initialize(name, artist, genre, subgenre, tags = [])
+ @name = name
+ @artist = artist
+ @genre = genre
+ @subgenre = subgenre
+ @tags = tags
+ [genre, subgenre].compact.each {|genre| @tags << genre.downcase}
+ end
+
+ attr_accessor :name, :artist, :genre, :subgenre, :tags
+
+end
+
+# This module contains the "pluggable" mixins
+# used in result filtering
+module CollectionFilterPlugins
+ private
+
+ def filter_plugin_name(criteria, list)
+ return list if criteria[:name] == nil
+ name = criteria[:name]
+ list.select { |song| song.name == name }
+ end
+
+ def filter_plugin_artist(criteria, list)
+ return list if criteria[:artist] == nil
+ artist = criteria[:artist]
+ list.select { |song| song.artist == artist }
+ end
+
+ def filter_plugin_filter(criteria, list)
+ return list if criteria[:filter] == nil
+ filter = criteria[:filter]
+ list.select { |song| filter.(song) }
+ end
+
+ def filter_plugin_tags(criteria, list)
+ return list if criteria[:tags] == nil
+ tags = [criteria[:tags]].flatten
+ exclude_tags = tags.select {|tag| tag.end_with? '!'}.map {|tag| tag.chop}
+ include_tags = tags.select {|tag| not tag.end_with? '!'}
+ list.select do |song|
+ (song.tags & include_tags).size == include_tags.size \
+ and (song.tags & exclude_tags).empty?
+ end
+ end
+
+end
+
+# This is Collection class in the specification, that
+# parses all the data, builds Song objects, and then, on
+# Collection#find, filters the results using plugin methods
+# atm. not as pluggable as excepted
+class Collection
+ include CollectionFilterPlugins
+
+ def initialize(songs_as_text, artist_tags = {})
+ @plugin_methods = []
+ load_filter_plugin_methods()
+ @artist_tags = artist_tags
+ @all = []
+ parse(songs_as_text)
+ end
+
+ def find(criteria = {})
+ list = Array.new(@all)
+ @plugin_methods.each do |filter_method|
+ list = filter_method.(criteria, list)
+ end
+ list
+ end
+
+ def get_tags_for_artist(artist)
+ @artist_tags[artist] or []
+ end
+
+ private
+
+ # TODO: refactor
+ def load_filter_plugin_methods()
+ @plugin_methods = []
+ self.class.private_instance_methods.each do |method_symbol|
+ if method_symbol.to_s.start_with? 'filter_plugin_'
+ @plugin_methods << method(method_symbol)
+ end
+ end
+ end
+
+ def parse(songs_text)
+ songs_text.lines.each do |line|
+ parts = get_line_parts(line)
+ name = parts[:name]
+ artist = parts[:artist]
+ genre, subgenre = parts[:genres]
+ tags = (parts[:tags] or []) + get_tags_for_artist(artist)
+ song = Song.new(parts[:name], parts[:artist], genre, subgenre, tags)
+ @all << song
+ end
+ end
+
+ def get_line_parts(line)
+ parts = line.split('.').map(&:strip)
+ parts[2..3] = parts[2..3].map {|str| str.split(',').map(&:strip)}
+ Hash[*[:name, :artist, :genres, :tags].zip(parts).flatten(1)]
+ end
+end

По условие този клас можеше да има каквото и да е наименование, но изискването беше да има 5 свойства/полета/умни члена.

И описанието на класа е: "Този клас има 5 свойства." Което води до LOL - laughing out laugh. От тук следва нелогичното продължение: "Но това не го бъркайте с LoL (League of Legends), защото Heroes of Newerth > League of Legends и попринцип LoL изобщо даже не трябва да съществува като дума поради този факт." Приемете го, че смисъла просто беше да каже LoL < HoN, и някой запален фен да възрази и да фърчат trollfaces :)

PS. рофлмаодзедун е по-засилена форма от рофлмао, което е-по силна форма на рофл

  • Не вземаме точки за лош хумор. Може би трябва :)
  • И с лиценз, и без лиценз...
  • self.class.private_instance_methods е интересно, обаче разчита на това, които методи са частни. Можеше просто да минеш с self.methods.grep(/^filter_plugin/).
  • Няма нужда да събираш методите в @plugin_methods. Всъщност, лоша идея е. Това може би е ОК в Python, но не в Ruby. Тук просто можеш да send-ваш.
  • Тази plugin думичка е излишна в методите, които я имат. Звучи тежко. Това не са плъгини.
  • Това за модула ми харесва. По-точно, харесва ми, че си експериментирал. Трябваше да го миксираш в Song, обаче. Така методите му щяха да са по-прости.
  • Последния ред на Song#initialize трябваше да е @tags += [genre, subgenre].compact.map(&:strip).
  • Трябва ти повече #all? и #map, но това го чу в час.
  • Масив се копира така: array.dup, а не така: Array.new(@array).
  • Парсенето ти е по-сложно, отколкото трябва.

Иначе, ще ти дам две бонус точки. Едната е, защото в решението ти има някои добри идеи. Другата е за да насърча експеримента с модула, макар че се е получило твърде дълго.