botanicus/scheduled-format

View on GitHub
lib/scheduled-format/task_group.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

require 'date'

class TaskGroup
  # @since 0.2
  attr_reader :header, :tasks

  # @param header [String] header of the task group.
  # @param tasks [Array<String>] tasks of the group.
  # @since 0.2
  #
  # @example
  #   TaskGroup = import('scheduled-format/task_group')
  #
  #   tasks = ['Buy milk. #errands', '[9:20] Call with Mike.']
  #   group = TaskGroup.new(header: 'Tomorrow', tasks: tasks)
  def initialize(header:, tasks: Array.new)
    @header, @tasks = header, tasks
    if tasks.any? { |task| !task.is_a?(Task) }
      raise ArgumentError, "Task objects expected."
    end
  end

  # Add a task to the task group.
  #
  # @since 0.2
  def <<(task)
    raise ArgumentError, "Task expected, got #{task.class}." unless task.is_a?(Task)

    @tasks << task unless @tasks.map(&:to_s).include?(task.to_s)
  end

  # Remove a task from the task group.
  #
  # @since 0.2
  def delete(task)
    raise ArgumentError, "Task expected, got #{task.class}." unless task.is_a?(Task)

    @tasks.delete_if { |t2| t2.to_s == task.to_s }
  end

  # Return a scheduled task list formatted string.
  #
  # @since 0.2
  def to_s
    [@header, @tasks.map(&:to_s), nil].flatten.join("\n")
  end

  def save(path)
    data = self.to_s
    File.open(path, 'w:utf-8') do |file|
      file.puts(data)
    end
  end

  # TODO: Next Monday
  # NOTE: For parsing we don't use %-d etc, only %d.
  # TODO: Use some configuration object, so this could be modified from the outside.
  DATE_FORMATS = {
    '%d/%m'    => :next_month,    # 1/1
    '%d/%m/%Y' => nil,            # 1/1/2018
    '%A %d/%m' => :next_week,     # Monday 1/1  Note: Higher specifity has to come first.
    '%A'       => :next_week      # Monday
  }.freeze

  # labels = ['Tomorrow', date.strftime('%A'), date.strftime('%-d/%m'), date.strftime('%-d/%m/%Y')]
  def scheduled_date
    return Date.today if @header == 'Today' # Change tomorrow to Today if you're generating it in the morning.
    return Date.today + 1 if @header == 'Tomorrow'
    parse_date_in_the_future(@header)
  end

  def tomorrow?
    self.scheduled_date == Date.today + 1
  end

  private

  # TODO: We need base_date, Date.today wouldn't cut it if we run "now g +3".
  def parse_date_in_the_future(header)
    DATE_FORMATS.each do |format, adjustment_method|
        date = Date.strptime(header, format)
        date.define_singleton_method(:next_week) { self + 7 } # TODO: DataExts, extract it from commands.rb.
        return ensure_in_the_future(date, adjustment_method)
    rescue ArgumentError
    end

    nil
  end

  def ensure_in_the_future(date, adjustment_method)
    return date if adjustment_method.nil? || Date.today <= date
    date.send(adjustment_method)
  end
end

export { TaskGroup }