Георги обнови решението на 06.11.2013 15:22 (преди около 11 години)
+class Item
+ attr_reader :status, :description, :priority, :tags
+
+ def initialize(status, description, priority, tags)
+ @status = status.downcase.to_sym
+ @description = description
+ @priority = priority.downcase.to_sym
+ @tags = tags.split(", ")
+ end
+
+ def ==(other)
+ @status == other.status and
+ @description == other.description and
+ @priority == other.priority and
+ @tags == other.tags
+ end
+
+ alias eql? ==
+
+ def hash
+ [@status, @description, @priority, @tags].hash
+ end
+end
+
+class TodoList
+ include Enumerable
+ attr_reader :tasks
+
+ def initialize(tasks)
+ @tasks = tasks
+ end
+
+ def self.parse(text)
+ tasks = text.lines.each.map do |l|
+ Item.new l.split('|')[0].strip, l.split('|')[1].strip,
+ l.split('|')[2].strip, l.split('|')[3].strip
+ end
+
+ TodoList.new tasks
+ end
+
+ def each(&block)
+ @tasks.each(&block)
+ end
+
+ def filter(criteria)
+ TodoList.new @tasks.select { |task| criteria.is_like? task }
+ end
+
+ def adjoin(other)
+ adjoinedList = (@tasks + other.tasks).uniq
+ TodoList.new adjoinedList
+ end
+
+ def tasks_todo
+ self.filter(Criteria.status(:todo)).tasks.size
+ end
+
+ def tasks_in_progress
+ self.filter(Criteria.status(:current)).tasks.size
+ end
+
+ def tasks_completed
+ self.filter(Criteria.status(:done)).tasks.size
+ end
+
+ def completed?
+ @tasks.size == tasks_completed
+ end
+end
+
+class Criteria
+ def self.status(status)
+ Matcher.new :status, status.downcase
+ end
+
+ def self.priority(priority)
+ Matcher.new :priority, priority.downcase
+ end
+
+ def self.tags(tags)
+ Matcher.new :tags, tags
+ end
+end
+
+class Matcher
+ def initialize(attr, value)
+ @attr = attr
+ @value = value
+ end
+
+ def is_like?(other)
+ attr = other.send(@attr)
+ return attr == @value unless attr.is_a? Enumerable
+ return value.all? { |a| attr.member? a }
+ end
+
+ def &(other)
+ ComboMatcher.new "and", self, other
+ end
+
+ def |(other)
+ ComboMatcher.new "or", self, other
+ end
+
+ def !
+ ComboMatcher.new "not", self, nil
+ end
+end
+
+class ComboMatcher
+ def initialize(operation, left_matcher, right_matcher)
+ @operation = operation
+ @left = left_matcher
+ @right = right_matcher
+ end
+
+ def is_like?(other)
+ case @operation
+ when "or" then @left.is_like?(other) or @right.is_like?(other)
+ when "and" then @left.is_like?(other) and @right.is_like?(other)
+ when "not" then not @left.is_like?(other)
+ end
+ end
+end