Кристиан обнови решението на 05.11.2013 01:20 (преди около 11 години)
+class Criteria
+ attr_accessor :predicate
+ class << self
+ def status(type)
+ Criteria.new lambda { |task| task.status == type}
+ end
+
+ def priority(type)
+ Criteria.new lambda { |task| task.priority == type}
+ end
+
+ def tags(criteria_tags)
+ Criteria.new lambda { |task| (criteria_tags - task.tags).empty? }
+ end
+ end
+
+ def initialize(pred)
+ @predicate = pred
+ end
+
+ def |(other)
+ comb = lambda { |task| predicate.call(task) || other.predicate.call(task) }
+ Criteria.new comb
+ end
+
+ def &(other)
+ comb = lambda { |task| predicate.call(task) && other.predicate.call(task) }
+ Criteria.new comb
+ end
+
+ def !
+ Criteria.new lambda { |task| !predicate.call(task) }
+ end
+end
+
+class Task
+ attr_reader :status
+ attr_reader :description
+ attr_reader :priority
+ attr_reader :tags
+
+ def self.from_string(string)
+ parts = string.split('|').map(&:strip)
+ status = parts[0].downcase.to_sym
+ priority = parts[2].downcase.to_sym
+ Task.new status, parts[1], priority, parts[3].split(', ')
+ end
+
+ def initialize(status, description, priority, tags)
+ @status = status
+ @description = description
+ @priority = priority
+ @tags = tags
+ end
+
+end
+
+class TodoList
+ include Enumerable
+
+ def self.parse(text)
+ tasks = text.each_line.map { |task_string| Task.from_string task_string}
+ TodoList.new tasks
+ end
+
+ def initialize(tasks)
+ @tasks = tasks
+ end
+
+ def each
+ @tasks.each { |task| yield task}
+ end
+
+ def filter(criteria)
+ TodoList.new(@tasks.select &criteria.predicate)
+ end
+
+ def adjoin(other)
+ TodoList.new (@tasks.to_set.merge other.to_set).to_a
+ end
+
+ def tasks_todo
+ @tasks.select { |task| task.status == :todo }.size
+ end
+
+ def tasks_in_progress
+ @tasks.select { |task| task.status == :current }.size
+ end
+
+ def tasks_completed
+ @tasks.select { |task| task.status == :done }.size
+ end
+
+ def completed?
+ @tasks.all? { |task| task.status == :done }
+ end
+end