Решение на Втора задача от Деян Хаджиев

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

Към профила на Деян Хаджиев

Резултати

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

Код

module TaskConstants
STATUS = { "TODO" => :todo, "CURRENT" => :current, "DONE" => :done }.freeze
PRIORITY = { "Low" => :low, "Normal" => :normal, "High" => :high }.freeze
STATUSES = STATUS.values.freeze
PRIORITIES = PRIORITY.values.freeze
end
class TodoTask
attr_accessor :status, :description, :priority, :tags
def initialize(status, description, priority, tags)
@status = status
@description = description
@priority = priority
@tags = tags
end
def ==(other)
equal = @status == other.status
equal &= @description == other.description
equal &= @priority == other.priority
equal &= @tags == other.tags
end
end
module TaskParser
include TaskConstants
def self.parse_task(task_string)
attribs = task_string.split('|').map { |attribute| attribute.strip }
tags = attribs[3].split(',').map { |tag| tag.strip }
TodoTask.new STATUS[attribs[0]], attribs[1], PRIORITY[attribs[2]], tags
end
end
class EnumerableList
include Enumerable
def each(&block)
@list.each(&block)
end
def filter(criteria)
EnumerableList.new @list.select { |item| criteria.pass? item }
end
def adjoin(other)
EnumerableList.new(@list.to_a | other.to_a)
end
def initialize(enumerator)
@list = enumerator
end
private
attr_accessor :list
end
class TodoList < EnumerableList
include TaskParser
def self.parse(task_list)
TodoList.new task_list.each_line.map { |line| TaskParser.parse_task line }
end
def filter(criteria)
TodoList.new select { |task| criteria.pass? task }
end
def adjoin(other)
TodoList.new(to_a | other.to_a)
end
def tasks_todo
filter(Criteria.status :todo).to_a.size
end
def tasks_in_progress
filter(Criteria.status :current).to_a.size
end
def tasks_completed
filter(Criteria.status :done).to_a.size
end
def completed?
to_a.map { |task| task.status }.all? { |stat| stat == :done }
end
end
class Criteria
attr_reader :criteries
def initialize(criteria_conjunct)
@criteries = [criteria_conjunct].flatten
end
def pass?(todo_task)
@criteries.any? { |criteria_conjunct| criteria_conjunct.pass? todo_task }
end
def self.status(positive_status)
Criteria.new CriteriaConjunct.new.add_status positive_status
end
def self.priority(positive_priority)
Criteria.new CriteriaConjunct.new.add_priority positive_priority
end
def self.tags(tags_array)
Criteria.new CriteriaConjunct.new.add_tags tags_array
end
def |(other)
Criteria.new(@criteries + other.criteries)
end
def &(other)
Criteria.new @criteries.product(other.criteries).map { |p| p[0] & p[1] }
end
def !
acc = CriteriaConjunct.new
acc = @criteries.map { |crit| !crit }.reduce(acc) { |a, c| a = a & c }
@criteries = [acc]
self
end
end
module CriteriaInspector
def status_unfiltered?
@status.values.all?
end
def priority_unfiltered?
@priority.values.all?
end
def tags_unfiltered?
@tags.empty?
end
end
module CriteriaOperations
include TaskConstants
#I know the names are bad, but I barely get into 80 symbols as it is
def simple_conjunction(lhs, rhs)
@status = lhs.status.merge(rhs.status) { |_, l, r| l & r }
@priority = lhs.priority.merge(rhs.priority) { |_, l, r| l & r }
@tags = lhs.tags.merge rhs.tags
self
end
def negate_statuses
@status.each { |key, value| @status[key] = ! value }
self
end
def negate_priorities
@priority.each { |key, value| @priority[key] = ! value }
self
end
def negate_tags
@tags.each { |key, value| @tags[key] = ! value }
self
end
end
class CriteriaConjunct
include TaskConstants
include CriteriaInspector
include CriteriaOperations
attr_accessor :status, :priority, :tags
def initialize
@status = Hash[STATUSES.zip Array.new STATUSES.size, true]
@priority = Hash[PRIORITIES.zip Array.new PRIORITIES.size, true]
@tags = {}
end
def add_status(positive_status)
@status.each_key { |key| @status[key] = false }
@status[positive_status] = true
self
end
def add_priority(positive_priority)
@priority.each_key { |key| @priority[key] = false }
@priority[positive_priority] = true
self
end
def add_tags(tags_array)
tags_array.each { |tag| @tags[tag] = true }
self
end
def pass?(task)
valid = @status[task.status]
valid &= @priority[task.priority]
valid &= @tags.all? { |key, value| value == task.tags.include?(key) }
valid
end
def &(other)
CriteriaConjunct.new.simple_conjunction self, other
end
def !
negate_statuses unless status_unfiltered?
negate_priorities unless priority_unfiltered?
negate_tags unless tags_unfiltered?
self
end
end

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

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

Finished in 0.33336 seconds
22 examples, 0 failures

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

Деян обнови решението на 05.11.2013 01:47 (преди около 11 години)

+module TaskConstants
+ STATUS = { "TODO" => :todo, "CURRENT" => :current, "DONE" => :done }.freeze
+ PRIORITY = { "Low" => :low, "Normal" => :normal, "High" => :high }.freeze
+ STATUSES = STATUS.values.freeze
+ PRIORITIES = PRIORITY.values.freeze
+end
+
+class TodoTask
+ attr_accessor :status, :description, :priority, :tags
+
+ def initialize(status, description, priority, tags)
+ @status = status
+ @description = description
+ @priority = priority
+ @tags = tags
+ end
+
+ def ==(other)
+ equal = @status == other.status
+ equal &= @description == other.description
+ equal &= @priority == other.priority
+ equal &= @tags == other.tags
+ end
+end
+
+module TaskParser
+ include TaskConstants
+
+ def self.parse_task(task_string)
+ attribs = task_string.split('|').map { |attribute| attribute.strip }
+ tags = attribs[3].split(',').map { |tag| tag.strip }
+ TodoTask.new STATUS[attribs[0]], attribs[1], PRIORITY[attribs[2]], tags
+ end
+end
+
+class EnumerableList
+ include Enumerable
+
+ def each(&block)
+ @list.each(&block)
+ end
+
+ def filter(criteria)
+ EnumerableList.new @list.select { |item| criteria.pass? item }
+ end
+
+ def adjoin(other)
+ EnumerableList.new(@list.to_a | other.to_a)
+ end
+
+ def initialize(enumerator)
+ @list = enumerator
+ end
+
+ private
+ attr_accessor :list
+end
+
+class TodoList < EnumerableList
+ include TaskParser
+
+ def self.parse(task_list)
+ TodoList.new task_list.each_line.map { |line| TaskParser.parse_task line }
+ end
+
+ def filter(criteria)
+ TodoList.new select { |task| criteria.pass? task }
+ end
+
+ def adjoin(other)
+ TodoList.new(to_a | other.to_a)
+ end
+
+ def tasks_todo
+ filter(Criteria.status :todo).to_a.size
+ end
+
+ def tasks_in_progress
+ filter(Criteria.status :current).to_a.size
+ end
+
+ def tasks_completed
+ filter(Criteria.status :done).to_a.size
+ end
+
+ def completed?
+ to_a.map { |task| task.status }.all? { |stat| stat == :done }
+ end
+end
+
+class Criteria
+ attr_reader :criteries
+ def initialize(criteria_conjunct)
+ @criteries = [criteria_conjunct].flatten
+ end
+
+ def pass?(todo_task)
+ @criteries.any? { |criteria_conjunct| criteria_conjunct.pass? todo_task }
+ end
+
+ def self.status(positive_status)
+ Criteria.new CriteriaConjunct.new.add_status positive_status
+ end
+
+ def self.priority(positive_priority)
+ Criteria.new CriteriaConjunct.new.add_priority positive_priority
+ end
+
+ def self.tags(tags_array)
+ Criteria.new CriteriaConjunct.new.add_tags tags_array
+ end
+
+ def |(other)
+ Criteria.new(@criteries + other.criteries)
+ end
+
+ def &(other)
+ Criteria.new @criteries.product(other.criteries).map { |p| p[0] & p[1] }
+ end
+
+ def !
+ acc = CriteriaConjunct.new
+ acc = @criteries.map { |crit| !crit }.reduce(acc) { |a, c| a = a & c }
+ @criteries = [acc]
+ self
+ end
+end
+
+module CriteriaInspector
+ def status_unfiltered?
+ @status.values.all?
+ end
+
+ def priority_unfiltered?
+ @priority.values.all?
+ end
+
+ def tags_unfiltered?
+ @tags.empty?
+ end
+end
+
+module CriteriaOperations
+ include TaskConstants
+
+ #I know the names are bad, but I barely get into 80 symbols as it is
+ def simple_conjunction(lhs, rhs)
+ @status = lhs.status.merge(rhs.status) { |_, l, r| l & r }
+ @priority = lhs.priority.merge(rhs.priority) { |_, l, r| l & r }
+ @tags = lhs.tags.merge rhs.tags
+ self
+ end
+
+ def negate_statuses
+ @status.each { |key, value| @status[key] = ! value }
+ self
+ end
+
+ def negate_priorities
+ @priority.each { |key, value| @priority[key] = ! value }
+ self
+ end
+
+ def negate_tags
+ @tags.each { |key, value| @tags[key] = ! value }
+ self
+ end
+end
+
+class CriteriaConjunct
+ include TaskConstants
+ include CriteriaInspector
+ include CriteriaOperations
+ attr_accessor :status, :priority, :tags
+
+ def initialize
+ @status = Hash[STATUSES.zip Array.new STATUSES.size, true]
+ @priority = Hash[PRIORITIES.zip Array.new PRIORITIES.size, true]
+ @tags = {}
+ end
+
+ def add_status(positive_status)
+ @status.each_key { |key| @status[key] = false }
+ @status[positive_status] = true
+ self
+ end
+
+ def add_priority(positive_priority)
+ @priority.each_key { |key| @priority[key] = false }
+ @priority[positive_priority] = true
+ self
+ end
+
+ def add_tags(tags_array)
+ tags_array.each { |tag| @tags[tag] = true }
+ self
+ end
+
+ def pass?(task)
+ valid = @status[task.status]
+ valid &= @priority[task.priority]
+ valid &= @tags.all? { |key, value| value == task.tags.include?(key) }
+ valid
+ end
+
+ def &(other)
+ CriteriaConjunct.new.simple_conjunction self, other
+ end
+
+ def !
+ negate_statuses unless status_unfiltered?
+ negate_priorities unless priority_unfiltered?
+ negate_tags unless tags_unfiltered?
+ self
+ end
+end