Георги обнови решението на 01.11.2013 23:51 (преди около 11 години)
+class Task
+ class << self
+ def parse(line)
+ status, description, priority, tags = line.split('|').map(&:strip)
+ tags = tags.nil? ? [] : tags.split(', ')
+
+ Task.new status, description, priority, tags
+ end
+ end
+
+ attr_accessor :status, :description, :priority, :tags
+
+ def initialize(status, description, priority, tags)
+ @status = status.downcase.to_sym
+ @description = description
+ @priority = priority.downcase.to_sym
+ @tags = tags
+ end
+end
+
+class TodoList
+ TASK_STATUSES = {done: 'completed', current: 'in_progress', todo: 'todo'}
+
+ class << self
+ def parse(input)
+ lines = input.split("\n")
+ TodoList.new lines.map { |line| Task.parse(line) }
+ end
+ end
+
+ include Enumerable
+ attr_accessor :tasks
+
+ def initialize(tasks)
+ @tasks = tasks
+ end
+
+ def each(&block)
+ @tasks.each(&block)
+ end
+
+ def completed?
+ @tasks.all? { |task| task.status == :done }
+ end
+
+ def filter(criteria)
+ TodoList.new @tasks.select { |task| criteria.criterion.call task }
+ end
+
+ def adjoin(other)
+ TodoList.new @tasks + other.tasks
+ end
+
+ def method_missing(method, *args, &block)
+ method.to_s =~ /^tasks_(.+)$/
+ status = TASK_STATUSES.key($1)
+
+ @tasks.select { |task| task.status == status }.size
+ end
+end
+
+class Criteria
+ class << self
+ def status(status)
+ Criteria.new -> (task) { task.status == status }
+ end
+
+ def priority(priority)
+ Criteria.new -> (task) { task.priority == priority }
+ end
+
+ def tags(tags)
+ Criteria.new -> (task) do
+ (task.tags & tags).length == tags.length
+ end
+ end
+ end
+
+ attr_reader :criterion
+
+ def initialize(criterion)
+ @criterion = criterion
+ end
+
+ def &(other)
+ Criteria.new -> (task) do
+ criterion.call(task) & other.criterion.call(task)
+ end
+ end
+
+ def |(other)
+ Criteria.new -> (task) do
+ criterion.call(task) || other.criterion.call(task)
+ end
+ end
+
+ def !
+ Criteria.new -> (task) { not criterion.call(task) }
+ end
+end