Владимир обнови решението на 03.11.2013 15:35 (преди около 11 години)
+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