Владимир обнови решението на 03.11.2013 15:35 (преди около 12 години)
+class Task
+  def initialize(task_data)
+    @status, @description, @priority, @tags = task_data
+    @tags = @tags.nil? ? [] : @tags.split(',').map(&:strip)
+  end
+
+  def status
+    @status.downcase.to_sym
+  end
+
+  def description
+    @description
+  end
+
+  def priority
+    @priority.downcase.to_sym
+  end
+
+  def tags
+    @tags
+  end
+end
+
+class Criteria
+  attr_accessor :filter
+
+  def initialize(filter)
+    @filter = filter
+  end
+
+  def self.status(status_filter)
+    Criteria.new(lambda { |task| task.status == status_filter })
+  end
+
+  def self.priority(priority_filter)
+    Criteria.new(lambda { |task| task.priority == priority_filter })
+  end
+
+  def self.tags(tags_filter)
+    Criteria.new(lambda { |task| (tags_filter - task.tags).size.zero? })
+  end
+
+  def &(other)
+    Criteria.new(lambda { |task| @filter.call task and other.filter.call task })
+  end
+
+  def |(other)
+    Criteria.new(lambda { |task| @filter.call task or other.filter.call task })
+  end
+
+  def !
+    Criteria.new(lambda { |task| !@filter.call task })
+  end
+end
+
+class TodoList
+  include Enumerable
+
+  attr_accessor :list_items
+
+  def initialize(list_items)
+    @list_items = list_items
+  end
+
+  def self.parse(text)
+    tasks = []
+    text.lines.each do |line|
+      tasks << Task.new(line.split('|').map(&:strip))
+    end
+    TodoList.new(tasks)
+  end
+
+  def each
+    @list_items.each do |task|
+      yield task
+    end
+  end
+
+  def filter(criteria)
+    TodoList.new @list_items.select(&criteria.filter)
+  end
+
+  def adjoin(other)
+    TodoList.new @list_items + other.list_items
+  end
+
+  def tasks_todo
+    filter(Criteria.status(:todo)).list_items.size
+  end
+
+  def tasks_in_progress
+    filter(Criteria.status(:current)).list_items.size
+  end
+
+  def tasks_completed
+    filter(Criteria.status(:done)).list_items.size
+  end
+
+  def completed?
+    filter(Criteria.status(:done)).list_items.size == list_items.size
+  end
+end
