Никола обнови решението на 04.11.2013 15:31 (преди около 11 години)
+class TodoList
+
+ include Enumerable
+
+ attr_reader :todos
+
+ def initialize(todos)
+ @todos = todos
+ end
+
+ def each
+ return @todos unless block_given?
+ @todos.each { |todo| yield todo }
+ end
+
+ def filter(criteria)
+ @todos.select { |todo| criteria.core.call(todo) }
+ end
+
+ def adjoin(other)
+ TodoList.new(@todos | other.todos)
+ end
+
+ def tasks_todo
+ @todos.select { |todo| todo.status == :todo }.count
+ end
+
+ def tasks_in_progress
+ @todos.select { |todo| todo.status == :current }.count
+ end
+
+ def tasks_completed
+ @todos.select { |todo| todo.status == :done }.count
+ end
+
+ def completed?
+ @todos.all? { |todo| todo.status == :done }
+ end
+
+ def self.parse(text)
+ todos = text.lines.map { |line| TodoParser.parse(line.chomp) }
+ TodoList.new(todos)
+ end
+end
+
+class Todo
+
+ attr_reader :status
+ attr_reader :description
+ attr_reader :priority
+ attr_reader :tags
+
+ def initialize(status, description, priority, tags)
+ @status = status
+ @description = description
+ @priority = priority
+ @tags = tags
+ end
+
+ def eql?(other)
+ return false unless @status == other.status and @priority == other.priority
+ return false unless @description == other.description
+ (@tags - other.tags).empty? and (other.tags - @tags).empty?
+ end
+
+ def hash
+ status.hash + description.hash + priority.hash + tags.sort.hash
+ end
+end
+
+class Criteria
+
+ attr_reader :core
+
+ def initialize(core)
+ @core = core
+ end
+
+ def self.status(todo_status)
+ core = proc { |todo| todo.status == todo_status }
+ Criteria.new(core)
+ end
+
+ def self.priority(todo_priority)
+ core = proc { |todo| todo.priority == todo_priority}
+ Criteria.new(core)
+ end
+ #TODO tags and !
+ def |(other)
+ union_core = proc { |todo| core.call(todos) or other.core.call(todos) }
+ Criteria.new(union_core)
+ end
+
+ def &(other)
+ section_core = proc { |todo| core.call(todo) and other.core.call(todo) }
+ Criteria.new(section_core)
+ end
+end
+
+class TodoParser
+ def self.parse(text)
+ todo_raw = text.split('|').map(&:strip)
+ [0, 2].each { |index| todo_raw[index] = todo_raw[index].downcase.to_sym }
+ todo_raw[3] = todo_raw[3].split(',').map(&:strip)
+ Todo.new(*todo_raw)
+ end
+end