Class: Plansheet::Pool

Inherits:
Object
  • Object
show all
Defined in:
lib/plansheet/pool.rb

Overview

The “pool” is the aggregated collection of projects, calendar events, etc.

Constant Summary collapse

DEFAULT_COMPARISON_ORDER =
%w[
  completeness
  completed_on
  dependency
  priority
  defer
  due
  time_roi
  status
  name
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config, debug: false) ⇒ Pool

Returns a new instance of Pool.



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/plansheet/pool.rb', line 24

def initialize(config, debug: false)
  @projects_dir = config[:projects_dir]
  @sort_order = config[:sort_order]

  # This bit of trickiness is because we don't know what the sort order is
  # until runtime. I'm sure this design decision definitely won't bite me
  # in the future ;-) Fortunately, it's also not a problem that can't be
  # walked back from.
  # rubocop:disable Lint/OrAssignmentToConstant
  Plansheet::Pool::POOL_COMPARISON_ORDER ||= config[:sort_order] if config[:sort_order]
  puts "using config sort order" if config[:sort_order]
  Plansheet::Pool::POOL_COMPARISON_ORDER ||= Plansheet::Pool::DEFAULT_COMPARISON_ORDER
  # rubocop:enable Lint/OrAssignmentToConstant
  require_relative "project"

  load_projects_dir(@projects_dir) unless debug
  sort_projects if @projects
end

Instance Attribute Details

#projectsObject

Returns the value of attribute projects.



10
11
12
# File 'lib/plansheet/pool.rb', line 10

def projects
  @projects
end

Instance Method Details

#archive_projectsObject



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/plansheet/pool.rb', line 80

def archive_projects
  archive_dir = "#{@projects_dir}/archive/"
  FileUtils.mkdir_p archive_dir

  # NOTE: It would save writes if we sorted and did all month/namespaces
  # writes only once, but as the normal case only sees a few projects
  # archived at a time, I'll leave that for someone else to implement ;-)
  projects_to_archive = @projects.select(&:archivable?)
  projects_to_archive.each do |project|
    path = Pathname.new "#{archive_dir}/#{project.archive_month}/#{project.namespace}.yml"
    Dir.mkdir path.dirname unless path.dirname.exist?
    pyf = ProjectYAMLFile.new path
    pyf.append_project project
  end

  # Now that the projects have been archived, remove them from the pool
  @projects.reject!(&:archivable?)
end

#load_projects_dir(dir) ⇒ Object



121
122
123
124
125
126
127
128
129
# File 'lib/plansheet/pool.rb', line 121

def load_projects_dir(dir)
  project_arr = []
  projects = Dir.glob("*yml", base: dir)
  projects.each do |l|
    project_arr << ProjectYAMLFile.new(File.join(dir, l)).load_file
  end

  @projects = project_arr.flatten!
end

#project_namespacesObject



99
100
101
# File 'lib/plansheet/pool.rb', line 99

def project_namespaces
  @projects.collect(&:namespace).uniq.sort
end

#projects_in_namespace(namespace) ⇒ Object



103
104
105
# File 'lib/plansheet/pool.rb', line 103

def projects_in_namespace(namespace)
  @projects.select { |x| x.namespace == namespace }
end

#sort_projectsObject



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/plansheet/pool.rb', line 43

def sort_projects
  @projects ||= []
  @projects.sort!
  # lookup_hash returns the index of a project
  lookup_hash = Hash.new nil

  # initialize the lookups
  @projects.each_index do |i|
    lookup_hash[@projects[i].name] = i
  end

  pg = RGL::DirectedAdjacencyGraph.new
  pg.add_vertices @projects
  @projects.each_index do |proj_index|
    next if @projects[proj_index].dropped_or_done?

    @projects[proj_index]&.dependencies&.each do |dep|
      di = lookup_hash[dep]
      if di
        # Don't add edges for dropped/done projects, they'll be sorted out
        # later
        next if @projects[di].dropped_or_done?

        pg.add_edge(@projects[di], @projects[proj_index])
      end
    end
  end

  # The topological sort of pg is the correct dependency order of the
  # projects
  @projects = pg.topsort_iterator.to_a.flatten.uniq

  # TODO: second sort doesn't deal with problems where deferred task gets
  # pushed below.
  @projects.sort!
end

#write_projectsObject



107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/plansheet/pool.rb', line 107

def write_projects
  # Collect the namespaces *before* archiving is done, for the case where
  # all active projects in a namespace have been completed and archived
  namespaces_before_archiving = project_namespaces

  archive_projects

  namespaces_before_archiving.each do |ns|
    projects = projects_in_namespace(ns)
    pyf = ProjectYAMLFile.new "#{@projects_dir}/#{ns}.yml"
    pyf.compare_and_write projects
  end
end