Class: Plan::Item

Inherits:
Object
  • Object
show all
Defined in:
lib/plan/item.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(label, finished = nil, hidden = nil) ⇒ Item

Create a new item



8
9
10
11
12
13
# File 'lib/plan/item.rb', line 8

def initialize(label, finished = nil, hidden = nil)
  @label = label.strip
  @finished = finished.is_a?(Fixnum) ? Time.at(finished) : nil
  @hidden = hidden
  @children = []
end

Instance Attribute Details

#childrenObject (readonly)

Returns the value of attribute children.



5
6
7
# File 'lib/plan/item.rb', line 5

def children
  @children
end

#finishedObject (readonly)

Returns the value of attribute finished.



5
6
7
# File 'lib/plan/item.rb', line 5

def finished
  @finished
end

#labelObject (readonly)

Returns the value of attribute label.



5
6
7
# File 'lib/plan/item.rb', line 5

def label
  @label
end

Class Method Details

.load(data) ⇒ Object

Load a Item from a data hash



95
96
97
98
99
100
101
# File 'lib/plan/item.rb', line 95

def self.load(data)
  item = Item.new data['label'], data['finished'], data['hidden']
  data['children'] && data['children'].each do |child|
    item.children << Item.load(child) 
  end
  item
end

Instance Method Details

#cleanupObject

remove all finished items from this tree, by hiding them



34
35
36
37
# File 'lib/plan/item.rb', line 34

def cleanup
  @hidden = true if finished?
  children.each { |c| c.cleanup }
end

#descend(paths) ⇒ Object

recursively descent through children until you find the given item



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/plan/item.rb', line 63

def descend(paths)
  return self if paths.empty?
  # prefer exact matches
  next_items = children.select { |c| !c.hidden? && c.has_label?(paths.first) }
  # fall back on approximates
  if next_items.empty?
    next_items = children.select { |c| !c.hidden? && c.has_label_like?(paths.first) }
  end
  # give an error if we have no matches
  if next_items.empty?
    lines = []
    lines << "no match for #{paths.first}"
    unless children.empty?
      avail = children.map { |c| c.label unless c.hidden? }.compact
      lines << "available options are: #{avail.join(', ')}"
    end
    raise Plan::Advice.new(*lines)
  end
  # give an error if we have too many matches
  if next_items.size > 1
    lines = []
    lines << "ambiguous match for '#{paths.first}' - please choose one of:"
    next_items.each do |np|
      lines << "* #{np.label}"
    end
    raise Plan::Advice.new(*lines)
  end 
  # and off we go, continuing to descent
  next_items.first.descend(paths[1..-1])
end

#dumpObject

dump a nested representation of this item



104
105
106
107
108
109
110
111
# File 'lib/plan/item.rb', line 104

def dump
  data = {}
  data['label'] = label
  data['finished'] = finished.nil? ? nil : finished.to_i
  data['children'] = children.map { |c| c.dump }
  data['hidden'] = true if hidden?
  data
end

#finish!(at = Time.now) ⇒ Object

mark a finish date for this item



40
41
42
43
# File 'lib/plan/item.rb', line 40

def finish!(at = Time.now)
  @finished = at unless finished? # don't overwrite
  children.each { |c| c.finish!(at) unless c.hidden? } # and finish each child
end

#finished?Boolean

return whether this item is finished

Returns:

  • (Boolean)


58
59
60
# File 'lib/plan/item.rb', line 58

def finished?
  !!@finished && children.all? { |c| c.finished? || c.hidden? }
end

#has_label?(other_label) ⇒ Boolean

determine whether a label is a duplicate of this item’s label downcases to get rid of basic mistakes

Returns:

  • (Boolean)


17
18
19
# File 'lib/plan/item.rb', line 17

def has_label?(other_label)
  label.downcase == other_label.downcase
end

#has_label_like?(other_label) ⇒ Boolean

for fuzzy matching on descending - so you can do things like todo create so hi - instead of todo create something hi

Returns:

  • (Boolean)


24
25
26
# File 'lib/plan/item.rb', line 24

def has_label_like?(other_label)
  label.downcase.include? other_label.downcase
end

#hidden?Boolean

return a boolean indicating whether or not this item is hidden

Returns:

  • (Boolean)


53
54
55
# File 'lib/plan/item.rb', line 53

def hidden?
  !!@hidden
end

#unfinish!Object

mark a finished item as unfinished and all descendents



47
48
49
50
# File 'lib/plan/item.rb', line 47

def unfinish!
  @finished = nil
  children.each { |c| c.unfinish! unless c.hidden? }
end

#visible_child_countObject

count of the visible children



29
30
31
# File 'lib/plan/item.rb', line 29

def visible_child_count
  children.select { |c| !c.hidden? }.size
end