botanicus/now-task-manager

View on GitHub
lib/pomodoro/formats/scheduled/task_list.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

module Pomodoro::Formats::Scheduled
  class TaskList
    include Enumerable

    # List of {TaskGroup task groups}. Or more precisely objects responding to `#header` and `#tasks`.
    # @since 0.2
    attr_reader :data

    # @param [Array<TaskGroup>] data List of task groups.
    #   Or more precisely objects responding to `#header` and `#tasks`.
    # @raise [ArgumentError] if data is not an array or if its content doesn't
    #   respond to `#header` and `#tasks`.
    #
    # @example
    #   require 'pomodoro/formats/scheduled'
    #
    #   tasks = ['Buy milk. #errands', '[9:20] Call with Mike.']
    #   group = Pomodoro::Formats::Scheduled::TaskGroup.new(header: 'Tomorrow', tasks: tasks)
    #   list  = Pomodoro::Formats::Scheduled::TaskList.new([group])
    # @since 0.2
    def initialize(data)
      @data = data

      unless data.is_a?(Array) && data.all? { |item| item.respond_to?(:header) && item.respond_to?(:tasks) }
        raise ArgumentError, "Data is supposed to be an array of TaskGroup instances."
      end
    end

    # Find a task group that matches given header.
    #
    # @return [TaskGroup, nil] matching the header.
    # @since 0.2
    #
    # @example
    #   # Using the code from the initialiser.
    #   list['Tomorrow']
    def [](header)
      @data.find do |task_group|
        task_group.header == header
      end
    end

    # Add a task group onto the task list.
    #
    # @raise [ArgumentError] if the task group is already in the list.
    # @param [TaskGroup] task_group the task group.
    # @since 0.2
    def <<(task_group)
      unless task_group.is_a?(TaskGroup)
        raise ArgumentError, "TaskGroup expected, got #{task_group.class}."
      end

      if self[task_group.header]
        raise ArgumentError, "Task group with header #{task_group.header} is already on the list."
      end

      @data << task_group
      self.sort!
    end

    def scheduled_task_groups
      @data.group_by { |tg| tg.scheduled_date.nil? }[false] || Array.new
    end

    def non_scheduled_task_groups
      @data.group_by { |tg| tg.scheduled_date.nil? }[true] || Array.new
    end

    def sort!
      @data = self.scheduled_task_groups.sort_by(&:scheduled_date) +
              self.non_scheduled_task_groups

      self
    end

    # Remove a task group from the task list.
    #
    # @param [TaskGroup] task_group the task group.
    # @since 0.2
    def delete(task_group)
      @data.delete(task_group)
    end

    # Iterate over the task groups.
    #
    # @yieldparam [TaskGroup] task_group
    # @since 0.2
    def each(&block)
      @data.each(&block)
    end

    # Return a scheduled task list formatted string.
    #
    # @since 0.2
    def to_s
      @data.map(&:to_s).join("\n")
    end

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