class Journal

Journal is the datastore class for the todo list managed by rodolib.

Responsible for:

- Parsing a md file into a rodolib Journal
- Serialization into a md file
- Splitting into days

Attributes

days[RW]

Public Class Methods

from_s(s) click to toggle source
# File lib/rodo/rodolib.rb, line 38
def self.from_s(s)

  j = Journal.new
  j.days = []

  next_day = []
  s.each_line { |line|
    if line =~ /^\s*\#\s*(\d\d\d\d-\d\d-\d\d)/ && next_day.size > 0
      j.days << TodoDay.new(next_day)
      next_day = []
    end
    next_day << line.rstrip if next_day.size > 0 || line.strip.length > 0 # Skip leading empty lines
  }
  if (next_day.size > 0 && next_day.any? { |line| line.strip.length > 0 })
    j.days << TodoDay.new(next_day)
  end

  return j
end

Public Instance Methods

close(day) click to toggle source

Postpones all unfinished todos to today's date Returns the index of the target date to which things were postponed

# File lib/rodo/rodolib.rb, line 142
def close(day)

  unfinished_lines = [nil] * day.lines.size

  day.lines.each_with_index { |line, index|
    if line =~ /^\s*(-\s+)?\[(.)\]/

      if $2 == " "
        # Copy all unfinished tasks and...
        unfinished_lines[index] = line.dup

        # ...their parent entries (recursively)
        parent_index = index
        while (parent_index = day.parent_index(parent_index)) != nil
          unfinished_lines[parent_index] ||= day.lines[parent_index].dup
        end
        line.sub!(/\[\s\]/, "[>]")
      end

    # Copy top level structure:
    elsif !(line =~ /^\s*[-*]\s+/ || line =~ /^\s*#\s/)
      unfinished_lines[index] = line.dup
    end
  }

  if unfinished_lines[0] =~ /^\s*\#\s*(\d\d\d\d-\d\d-\d\d)/
    unfinished_lines.shift
  end

  target_day = ensure_day(Date.today)
  if target_day == day
    # When closing on the same day: append hour and minutes
    newDate = "# #{Time.now.strftime("%Y-%m-%d %a %H:%M")}"
    target_day = TodoDay.new([newDate])
    insertion_index = days.index { |d| target_day.date >= d.date } || 0
    days.insert(insertion_index, target_day)
  end

  # Only append non-empty lines
  unfinished_lines.select! { |l| l != nil }

  target_day.merge_lines(unfinished_lines)

  return days.find_index(target_day)
end
ensure_day(target_date) click to toggle source

Returns the TodoDay for the given date creating it if it doesn't exist

# File lib/rodo/rodolib.rb, line 63
def ensure_day(target_date)
  index = days.find_index { |x| x.date <= target_date } || -1

  if index < 0 || days[index].date != target_date
    days.insert(index, TodoDay.new(["# #{target_date.strftime("%Y-%m-%d")}"]))
  end
  return days[index]
end
most_recent_index() click to toggle source
# File lib/rodo/rodolib.rb, line 188
def most_recent_index
  today = Date.today
  return days.find_index { |x| x.date <= today } || 0
end
postpone_day(day, number_of_days_to_postpone=1) click to toggle source

Returns the day, number of days in the future from the given day, but at never before today

# File lib/rodo/rodolib.rb, line 73
def postpone_day(day, number_of_days_to_postpone=1)

  number_of_days_to_postpone = 1 if number_of_days_to_postpone < 1

  target_date = (day.date || Date.today).next_day(number_of_days_to_postpone)

  # target_date shouldn't be in the past
  target_date = Date.today if target_date.to_date < Date.today

  return ensure_day(target_date)
end
postpone_line(day, line_index, number_of_days_to_postpone=1) click to toggle source

Postpone the given line on the given day by the given number of days, default=1

Returns false, if there is no todo which can be postponed on the given line Returns the target date to which the line was moved if successful.

# File lib/rodo/rodolib.rb, line 89
def postpone_line(day, line_index, number_of_days_to_postpone=1)

  line = day.lines[line_index]

  # Postpone only works for todos
  return false if !(line =~ /^\s*(-\s+)?\[(.)\]/)

  # Postpone only works for unfinished todos
  return false if $2 != " "

  # First create the target day
  target_day = postpone_day(day, number_of_days_to_postpone)

  # Determine all affected lines
  unfinished_lines = [nil] * day.lines.size

  # Copy all unfinished tasks and...
  unfinished_lines[line_index] = line.dup

  # ...their parent entries (recursively)
  parent_index = line_index
  while (parent_index = day.parent_index(parent_index)) != nil
    unfinished_lines[parent_index] ||= day.lines[parent_index].dup
  end

  # Copy up to 1 whitespace line preceeding
  unfinished_lines.each_with_index { |e, i|
    if e != nil && i != 0 && day.indent_depth(i - 1) == nil
      unfinished_lines[i-1] = ""
    end
  }

  # ...and the children as well!
  # TODO

  # Mark line itself as postponed
  line.sub!(/\[\s\]/, "[>]")

  # Get rid of primary header
  if unfinished_lines[0] =~ /^\s*\#\s*(\d\d\d\d-\d\d-\d\d)/
    unfinished_lines.shift
  end

  # Only append non-empty lines
  unfinished_lines.select! { |l| l != nil }

  target_day.merge_lines(unfinished_lines)

  return target_day
end
to_s() click to toggle source
# File lib/rodo/rodolib.rb, line 58
def to_s
  days.map { |day| day.to_s }.join("\n\n") + (days.empty? ? "" : "\n")
end