class TPS::Task

Attributes

id[R]
list[R]
name[R]
owner[R]
parent[R]
pivotal_id[R]
tags[R]
tasks[R]
trello_id[R]
url[R]

Public Class Methods

new(parent, name, data=nil, list) click to toggle source
# File lib/tps/task.rb, line 17
def initialize(parent, name, data=nil, list)
  @name   = name
  @tasks  = Array.new
  @tags   = Array.new
  @parent = parent
  @list   = list

  if data.is_a?(Array)
    tags = data
    tasks = nil
  elsif data.is_a?(Hash) && data['_']
    tags = data.delete('_')
    tasks = data
  else
    tags = Array.new
    tasks = data
  end

  # Parse crap from name
  if @name
    @name = @name.dup

    # Get URL
    @name.gsub!(/https?:\/\/[^ ]+/) { |url| @url = url; "" }
    @name.strip!
  end

  # Parse tags.
  tags.each do |t|
    # [done]
    if ['done', 'ok'].include?(t)
      @status = :done
    elsif ['in progress', '...'].include?(t)
      @status = :in_progress
    # [@rstacruz]
    elsif t =~ /^@/
      @owner = t[1..-1]
    # [pt/28394] -- Pivotal tracker
    elsif t =~ /^pt\/(.*)$/i
      @pivotal_id = $1.strip
    # [tl/28394] -- Trello
    elsif t =~ /^tr\/(.*)$/i
      @trello_id = $1.strip
    # [50%] -- percentage
    elsif t =~ /^([\d\.]+)%$/
      @status = :in_progress
      @percent = $1.strip.to_f / 100
    # [0pt] -- points
    elsif t =~ /^([\d\.]+)pts?/i
      @points = $1.strip.to_f
    # [-all] -- tags
    elsif %w[- #].include?(t[0])
      @tags.push t[1..-1]
    # Sprint name
    elsif list && list.sprints[t]
      @sprints ||= Array.new
      @sprints << list.sprints[t]
    end
  end

  @tasks = tasks.map { |task, data| Task.new self, task, data, self.list }  if tasks

  @id = list.get_id  if list
end

Public Instance Methods

[](name) click to toggle source

Looks up a task.

@list['Login']
# File lib/tps/task.rb, line 249
def [](name)
  tasks.detect { |t| t.name == name }
end
all_tasks_done?() click to toggle source
# File lib/tps/task.rb, line 127
def all_tasks_done?
  tasks? and !tasks.any? { |t| ! t.done? }
end
ancestor?(&blk) click to toggle source
# File lib/tps/task.rb, line 183
def ancestor?(&blk)
  blk.call(self) || parent && parent.ancestor?(&blk)
end
bar_formatter() click to toggle source

Returns the presenter

# File lib/tps/task.rb, line 352
def bar_formatter
  TPS::BarFormatter.new self
end
breadcrumbs(include_self=true) click to toggle source

Returns a list of a task's ancestors, excluding the list.

contains?(&blk) click to toggle source

Filters a task list by tasks that match a given block, preserving its ancestors even if they don't match.

@list.contains? { |t| t.done? }
@list.contains? { |t| t.sprint == sprint }
# File lib/tps/task.rb, line 179
def contains?(&blk)
  blk.call(self) || tasks.detect { |t| t.contains?(&blk) }
end
contains_sprint?(sprint) click to toggle source
# File lib/tps/task.rb, line 169
def contains_sprint?(sprint)
  contains? { |t| t.sprints.include?(sprint) }
end
css_class() click to toggle source
# File lib/tps/task.rb, line 204
def css_class
  [
    "level-#{level}",
    "status-#{status}",
    (tasks? ? 'parent' : 'leaf'),
    ('root' if root?),
    ('feature' if feature?),
    ('milestone' if milestone?),
    ('subtask' if subtask?),
    (sprints.map { |s| "sprint-#{s.slug}" } if sprints?),
    sprint_css_classes,
    breadcrumbs(false).map { |t| "in_task_#{t.id}" }
  ].flatten.compact.join(' ')
end
done?() click to toggle source
# File lib/tps/task.rb, line 139
def done?
  status == :done
end
feature?() click to toggle source
# File lib/tps/task.rb, line 285
def feature?
  root? or parent.milestone?
end
filter(&blk) click to toggle source

Filters a task tree to tasks of a given criteria, preserving its ancestors even if they don't match.

@list.filter { |t| t.done? }
# File lib/tps/task.rb, line 192
def filter(&blk)
  filter_by { |t| t.contains?(&blk) || t.ancestor?(&blk) }
end
filter_by(&blk) click to toggle source

Works like filter, but only preserves ancestors if they match.

# File lib/tps/task.rb, line 234
def filter_by(&blk)
  return nil  unless blk.call(self)
  task = self.dup
  task.instance_variable_set :@tasks, tasks.map { |t| t.filter_by(&blk) }.compact
  task
end
filter_by_sprint(sprint) click to toggle source
# File lib/tps/task.rb, line 229
def filter_by_sprint(sprint)
  filter { |t| t.sprints.include?(sprint) }
end
find(name) click to toggle source

Finds a task named `name` in the task's descendants. Returns a `Task` instance.

list.find("Login")

# Accounts:
#   Login:
# File lib/tps/task.rb, line 297
def find(name)
  return self  if name == self.name
  tasks.inject(nil) { |result, task| result || task.find(name) }
end
has_started_tasks?() click to toggle source
# File lib/tps/task.rb, line 131
def has_started_tasks?
  tasks? and tasks.any? { |t| t.in_progress? or t.done? }
end
in_progress?() click to toggle source
# File lib/tps/task.rb, line 143
def in_progress?
  status == :in_progress
end
inspekt() click to toggle source
# File lib/tps/task.rb, line 331
def inspekt
  [
    root? ? "__Root__" : name,
    ("(%ipt)" % [points]),
    ("- %s" % [sprint.id]  if sprint?)
  ].compact.join(" ")
end
leaf?() click to toggle source
# File lib/tps/task.rb, line 306
def leaf?
  tasks.empty?
end
level() click to toggle source
# File lib/tps/task.rb, line 277
def level
  parent ? parent.level + 1 : 0
end
milestone?() click to toggle source
# File lib/tps/task.rb, line 302
def milestone?
  level == 0
end
percent() click to toggle source
# File lib/tps/task.rb, line 264
def percent
  if done?
    1.0
  elsif @percent
    @percent
  elsif tasks?
    total = tasks.inject(0.0) { |pts, task| pts + task.points }
    tasks.inject(0) { |i, task| i + task.points_done } / total
  else
    in_progress? ? 0.5 : 0
  end
end
pivotal_url() click to toggle source
# File lib/tps/task.rb, line 241
def pivotal_url
  "https://www.pivotaltracker.com/story/show/#{pivotal_id}"  if pivotal_id
end
points() click to toggle source
# File lib/tps/task.rb, line 103
def points
  if @points
    @points
  elsif tasks?
    tasks.inject(0.0) { |pts, task| pts + task.points }
  else
    1.0
  end
end
points_done() click to toggle source
# File lib/tps/task.rb, line 123
def points_done
  points * percent
end
points_for(sprint) click to toggle source
# File lib/tps/task.rb, line 113
def points_for(sprint)
  if tasks?
    tasks.inject(0.0) { |pts, task| pts + task.points_for(sprint) }
  elsif sprints? && self.sprints.include?(sprint)
    @points || 1.0
  else
    0
  end
end
root?() click to toggle source
# File lib/tps/task.rb, line 281
def root?
  ! parent
end
sprint_css_classes() click to toggle source
# File lib/tps/task.rb, line 219
def sprint_css_classes
  list.sprints.values.map { |sprint|
    "has_sprint-#{sprint.slug}"  if contains_sprint?(sprint)
  }.compact
end
sprints() click to toggle source
# File lib/tps/task.rb, line 159
def sprints
  if @sprints
    @sprints
  elsif parent
    parent.sprints
  else
    Array.new
  end
end
sprints?() click to toggle source
# File lib/tps/task.rb, line 155
def sprints?
  sprints.any?
end
status() click to toggle source
# File lib/tps/task.rb, line 90
def status
  # If no status is given, infer the status based on tasks.
  if !@status && tasks?
    if all_tasks_done?
      return :done
    elsif has_started_tasks?
      return :in_progress
    end
  end

  @status or :unstarted
end
subtask?() click to toggle source
# File lib/tps/task.rb, line 225
def subtask?
  !feature? && !milestone?
end
tasks?() click to toggle source
# File lib/tps/task.rb, line 151
def tasks?
  tasks.any?
end
to_html(template=nil) click to toggle source
# File lib/tps/task.rb, line 323
def to_html(template=nil)
  require 'tilt'
  template ||= TPS.root('data', 'index.haml')

  tpl = Tilt.new(template)
  tpl.evaluate({}, list: self)
end
to_markdown() click to toggle source

Returns it as a simple markdown string. Great for tests.

# File lib/tps/task.rb, line 341
def to_markdown
  str = " - #{inspekt}"

  if tasks?
    str += "\n" + tasks.map { |t| t.to_markdown.gsub(/^/, "  ") }.join("\n")
  end

  str
end
to_s() click to toggle source
# File lib/tps/task.rb, line 135
def to_s
  name
end
trello_url() click to toggle source
# File lib/tps/task.rb, line 253
def trello_url
  if trello_id
    id = trello_id.match(/([A-Za-z0-9]+)$/) && $1.strip
    if list.trello_board_url && id.match(/^[0-9]+/)
      "#{list.trello_board_url}/#{id}"
    else
      "https://trello.com/c/#{id}"
    end
  end
end
unstarted?() click to toggle source
# File lib/tps/task.rb, line 147
def unstarted?
  status == :unstarted
end
url_label() click to toggle source

The label of the link, if applicable.

# File lib/tps/task.rb, line 83
def url_label
  return unless url
  if url =~ /github\.com\/.*?\/(\d+)$/
    $1.strip
  end
end
walk() { |task, lambda { walk { |t, recurse| call t, recurse }| ... } click to toggle source
  • list.walk do |task, recurse| %ul

    %li
      = task
      - recurse.call  if recurse
# File lib/tps/task.rb, line 315
def walk(&blk)
  tasks.each do |task|
    yield task, lambda {
      task.walk { |t, recurse| blk.call t, recurse }
    }
  end
end