Николай обнови решението на 06.11.2013 01:27 (преди около 11 години)
+class TodoItem < Struct.new(:status, :description, :priority, :tags)
+ def self.parse(line)
+ parts = line.split('|').map { |item| item.strip }
+ tags = parts[3].split(',').map { |item| item.strip }
+
+ self.new(parts[0].downcase.to_sym, parts[1], parts[2].downcase.to_sym, tags)
+ end
+
+ def to_s
+ "#{status} | #{description} | #{priority} | #{tags}"
+ end
+end
+
+class TodoList
+ attr_reader :items
+
+ def initialize(items)
+ @items = items
+ end
+
+ def self.parse(text)
+ instance = self.new([])
+ text.each_line do |line|
+ instance.items << TodoItem.parse(line)
+ end
+
+ instance
+ end
+
+ def filter(criteria)
+ self.class.new(@items.select { |item| criteria.match(item) })
+ end
+
+ def adjoin(other)
+ self.class.new(@items | other.items)
+ end
+
+ def tasks_todo
+ @items.select { |item| item.status == :todo }.size
+ end
+
+ def tasks_in_progress
+ @items.select { |item| item.status == :current }.size
+ end
+
+ def tasks_completed
+ @items.select { |item| item.status == :done }.size
+ end
+
+ def completed?
+ tasks_completed == @items
+ end
+
+ include Enumerable
+
+ def each
+ @items.each { |item| yield item }
+ end
+end
+
+class Criteria
+ def initialize(predicate)
+ @predicate = predicate
+ end
+
+ def match(item)
+ @predicate.(item)
+ end
+
+ def &(other)
+ Criteria.new(->(item) { match(item) && other.match(item) })
+ end
+
+ def |(other)
+ Criteria.new(->(item) { match(item) || other.match(item) })
+ end
+
+ def !(other)
+ Criteria.new(->(item) { !match(item) })
+ end
+
+ class << self
+ def status(s)
+ Criteria.new(->(item) { item.status == s })
+ end
+
+ def priority(p)
+ Criteria.new(->(item) { item.priority == p })
+ end
+
+ def tags(t)
+ Criteria.new(->(item) { (t - item.tags).empty? })
+ end
+ end
+end