Радослав обнови решението на 04.11.2013 12:28 (преди около 11 години)
+# Predicate - a 'call'-able object. Supports compositions using & | !
+#
+class Predicate
+
+ def initialize &block
+ @condition = block
+ end
+
+ def call x
+ @condition.call(x)
+ end
+
+ def & other
+ Predicate.new { |x| self.call(x) and other.call(x) }
+ end
+
+ def | other
+ Predicate.new { |x| self.call(x) or other.call(x) }
+ end
+
+ def !
+ Predicate.new { |x| not self.call(x) }
+ end
+
+end
+
+# Task - Represents single entry(line) in the To-do list.
+#
+class Task
+
+ def initialize tokens
+ @status = tokens[0].strip.downcase.to_sym
+ @description = tokens[1].strip
+ @priority = tokens[2].strip.downcase.to_sym
+ @tags = tokens[3].strip.split(',').map(&:strip)
+ end
+
+ def status
+ @status
+ end
+
+ def description
+ @description
+ end
+
+ def priority
+ @priority
+ end
+
+ def tags
+ @tags
+ end
+
+ def has_tags? tags
+ tags.lazy.map {|tag| @tags.include? tag }.all?
+ end
+
+end
+
+# TaskList - An Enumerable array of Task objects
+#
+class TaskList
+ include Enumerable
+
+ def initialize tasks
+ @tasks = tasks
+ end
+
+ def tasks
+ @tasks
+ end
+
+ def each
+ @tasks.each { |task| yield task }
+ end
+
+ # Create a sub-list of taks, matching the predicate provided by Criteria#..
+ def filter predicate
+ TaskList.new self.select { |task| predicate.call(task) }
+ end
+
+ # Create union of the 2 task lists
+ def adjoin other
+ TaskList.new self.tasks | other.tasks
+ end
+
+end
+
+# Criteria - creates task filter predicates used by TaskList::filter
+#
+class Criteria
+
+ # Task::status equals value
+ def self.status value
+ Predicate.new { |task| task.status == value }
+ end
+
+ # Task::priority equals value
+ def self.priority value
+ Predicate.new { |task| task.priority == value }
+ end
+
+ # Task::tags contains all values
+ def self.tags values
+ Predicate.new { |task| task.has_tags? values }
+ end
+
+end
+
+# TodoList
+#
+class TodoList
+
+ # Parse a To-od list from a string.
+ # To-do entries are new-line delimited.
+ # To-do entry parameters are '|' delimited
+ def self.parse(text)
+ TaskList.new text.each_line.collect { |line| Task.new line.split('|') }
+ end
+
+ # Counts the :todo tasks
+ def self.tasks_todo tasks
+ tasks.count { |task| task.status == :todo }
+ end
+
+ # Counts the :current tasks
+ def self.tasks_in_progress tasks
+ tasks.count { |task| task.status == :current }
+ end
+
+ # Counts the :done tasks
+ def self.tasks_completed tasks
+ tasks.count { |task| task.status == :done }
+ end
+
+ # Checks if all tasks are :done
+ def self.completed? tasks
+ tasks.lazy.map { |task| task.status == :done }.all?
+ end
+
+end