Сияна обнови решението на 05.11.2013 21:56 (преди около 11 години)
+module Criteria
+ def self.status(status)
+ FindByStatus.new status
+ end
+
+ def self.priority(priority)
+ FindByPriority.new priority
+ end
+
+ def self.tags(tags)
+ FindByTags.new tags
+ end
+
+ def |(second)
+ JoinOperators.new self, second, :or
+ end
+
+ def &(second)
+ JoinOperators.new self, second, :and
+ end
+
+ def !
+ OperatorNot.new self
+ end
+
+ def completed?
+ (@task_list.to_a - tasks_completed.to_a).empty?
+ end
+end
+
+class JoinOperators
+ include Criteria
+ def initialize(first_criterium, second_criterium, operator)
+ @first_criterium = first_criterium
+ @second_criterium = second_criterium
+ @operator = operator
+ end
+
+ def find(task)
+ if(@operator == :or)
+ (@first_criterium.find(task) or @second_criterium.find(task))
+ elsif
+ first_criterium_result = @first_criterium.find(task)
+ @second_criterium.find(first_criterium_result)
+ end
+ end
+end
+
+class OperatorNot
+ include Criteria
+ def initialize(criterium)
+ @criterium = criterium
+ end
+
+ def find (task)
+ not @criterium.find(task)
+ end
+end
+
+class FindByStatus
+ include Criteria
+ def initialize(status)
+ @status = status
+ end
+
+ def find (task)
+ task if task.status == @status
+ end
+end
+
+class FindByPriority
+ include Criteria
+ def initialize(priority)
+ @priority = priority
+ end
+
+ def find (task)
+ task if task.priority == @priority
+ end
+end
+
+class FindByTags
+ include Criteria
+ def initialize(tags)
+ @tags = tags
+ end
+
+ def find (task)
+ task if (@tags - task.tags).empty?
+ end
+end
+
+class ListItem
+ attr_accessor :status, :description, :priority, :tags
+ def initialize(status, description, priority, tags)
+ @status = status
+ @description = description
+ @priority = priority
+ @tags = tags
+ end
+
+ def status
+ @status.match(/[\S]+/).to_s.downcase.to_sym
+ end
+
+ def description
+ @description.scan(/[\S]+/).join(' ')
+ end
+
+ def priority
+ @priority.match(/[\S]+/).to_s.downcase.to_sym
+ end
+
+ def tags
+ @tags.nil? ? [] : @tags.scan(/[\w]+/)
+ end
+end
+
+class TodoList
+ include Enumerable
+ include Criteria
+
+ def each(&block)
+ @task_list.each(&block)
+ end
+
+ def self.parse (todo_list)
+ task_list = []
+ todo_list.scan(/[^\n]+/) do |current|
+ task_list << make_list_items(current)
+ end
+ TodoList.new task_list
+ end
+
+ def self.make_list_items(initial_item)
+ items = initial_item.scan(/[^\|]+/)
+ ListItem.new(items[0], items[1], items[2], items[3])
+ end
+
+ def initialize (task_list)
+ @task_list = task_list
+ end
+
+ def filter(criteria)
+ TodoList.new @task_list.select { |item| criteria.find(item)}
+ end
+
+ def adjoin(second)
+ TodoList.new (self.to_a + second.to_a).uniq
+ end
+
+ def tasks_todo
+ filter(Criteria.status(:todo)).count
+ end
+
+ def tasks_in_progress
+ filter(Criteria.status(:current)).count
+ end
+
+ def tasks_completed
+ filter(Criteria.status(:done)).count
+ end
+end