Христо обнови решението на 05.11.2013 02:14 (преди около 11 години)
+class Task
+ attr_accessor :status, :description, :priority, :tags
+
+ def initialize task
+ @status, @description, @priority, @tags = task
+ @status, @priority = [@status, @priority].map { |i| i.downcase.to_sym }
+ @tags = @tags.split(/,\s*/)
+ end
+end
+
+
+class TodoList
+ include Enumerable
+
+ attr_accessor :tasks
+
+ def initialize tasks
+ @tasks = tasks
+ end
+
+ def self.parse(text)
+ tasks = text.lines.map { |task| task.split('|') }
+ tasks.map { |task_parts| task_parts.map! &:strip }
+ new(tasks.map { |task| Task.new(task) })
+ end
+
+ def each
+ @tasks.each { |task| yield task }
+ end
+
+ def filter(criteria)
+ self.class.new @tasks.select(&criteria.condition)
+ end
+
+ def tasks_todo
+ @tasks.map { |task| task.status == :todo }.count(true)
+ end
+
+ def tasks_in_progress
+ @tasks.map { |task| task.status == :current }.count(true)
+ end
+
+ def tasks_completed
+ @tasks.map { |task| task.status == :done }.count(true)
+ end
+
+ def completed?
+ @tasks.map { |task| task.status == :done }.count(false).zero?
+ end
+
+ def adjoin(other)
+ self.class.new @tasks | other.tasks
+ end
+end
+
+
+class Criteria
+ attr_accessor :condition
+
+ def initialize(condition)
+ @condition = condition
+ end
+
+ def |(other)
+ Criteria.new(->(task) { condition.(task) or other.condition.(task) })
+ end
+
+ def &(other)
+ Criteria.new(->(task) { condition.(task) and other.condition.(task) })
+ end
+
+ def !
+ Criteria.new(->(task) { !condition.(task) })
+ end
+
+ class << self
+ def status(task_status)
+ Criteria.new(->(task) { task.status == task_status })
+ end
+
+ def priority(task_priority)
+ Criteria.new(->(task) { task.priority == task_priority })
+ end
+
+ def tags(task_tags)
+ Criteria.new(->(task) { (task_tags - task.tags).size.zero? })
+ end
+ end
+end