class StandupMD

The class for handing reading/writing of entries.

@example

su = StandupMD.new

Public Class Methods

load(attributes = {}) click to toggle source

Convenience method for calling new + load

@param [Hash] attributes Attributes to set before loading.

@example

su = StandupMD.load(bullet_character: '*')
# File lib/standup_md.rb, line 21
def self.load(attributes = {})
  self.new do |s|
    attributes.each do |k, v|
      next unless s.respond_to?(k)
      s.send("#{k}=", v)
    end
  end.load
end

Attributes that are settable by the user, but have custom setters.

↑ top

Attributes

bullet_character[R]

Character used as bullets for list entries.

@return [String] either - (dash) or * (asterisk)

current_entry_tasks[R]

Array of tasks for today. This is the work expected to be performed today. Default is an empty array, but when writing to file, the default is

@return [Array]

@default

["<!-- ADD TODAY'S WORK HERE -->"]
directory[R]

The directory where the markdown files are kept.

@return [String]

@default

File.join(ENV['HOME'], '.cache', 'standup_md')
header_depth[R]

Number of octothorps that should preface entry headers.

@return [Integer] between 1 and 5

impediments[R]

Array of impediments for today's entry.

@return [Array]

notes[R]

Array of notes to add to today's entry.

@return [Array]

previous_entry_tasks[R]

The tasks from the previous task's “Current” section.

@return [Array]

sub_header_depth[R]

Number of octothorps that should preface sub-headers.

@return [Integer] between 2 and 6

Attributes that aren't settable by user, but are gettable.

↑ top

Attributes

all_entries[R]

Current entry plus all previous entries. This will be a hash in the same format at current_entry and all_previous_entries.

@return [Hash]

all_previous_entries[R]

All previous entry for the same month as today. If it's the first day of the month, all_previous_entries will be all of last month's entries. They will be a hash in the same format as current_entry.

@return [Hash]

current_entry[R]

The entry for today's date as a hash. If file already has an entry for today, it will be read and used as current_entry. If there is no entry for today, one should be generated from scaffolding.

@return [Hash]

@example

StandupMD.new.current_entry
# => {
#      '2020-04-02' => {
#        'Previous' => ['Task from yesterday'],
#        'Current' => ["<!-- ADD TODAY'S WORK HERE -->"],
#        'Impediments' => ['None'],
#        'Notes' => [],
#      }
#    }
file[R]

The file name should equal file_name_format parsed by Date.strftime. The default is +Date.today.strftime('%Y_%m.md')+

@return [String]

@example

su = StandupMD.new { |s| s.file_name_format = '%y_%m.markdown' }
su.file
# => Users/johnsmith/.cache/standup_md/20_04.markdown
header[R]

The string that will be used for the entry headers.

@return [String]

previous_file[R]

The file that contains previous entries. When last month's file exists, but this month's doesn't or is empty, previous_file should equal last month's file.

@return [String]

@example

# Assuming the current month is April, 2020

Dir.entries(su.directory)
# => []
su = StandupMD.new
su.previous_file
# => ''

Dir.entries(su.directory)
# => ['2020_03.md']
su = StandupMD.new
su.previous_file
# => '2020_03.md'

Dir.entries(su.directory)
# => ['2020_03.md', '2020_04.md']
su = StandupMD.new
su.previous_file
# => '2020_04.md'

Attributes with default getters and setters.

↑ top

Attributes

current_header[RW]

The header to use for the Current section.

@param [String] current_header

@return [String]

file_name_format[RW]

The format to use for file names. This should include a month (%m) and year (%y) so the file can rotate every month. This will prevent files from getting too large.

@param [String] file_name_format Parsed by strftime

@return [String]

header_date_format[RW]

The date format to use for entry headers.

@param [String] header_date_format Parsed by strftime

@return [String]

impediments_header[RW]

The header to use for the Impediments section.

@param [String] impediments_header

@return [String]

notes_header[RW]

The header to use for the Notes section.

@param [String] notes_header

@return [String]

previous_header[RW]

The header to use for the Previous section.

@param [String] previous_header

@return [String]

Public Class Methods

new() { |self| ... } click to toggle source

Constructor. Yields the instance so you can pass a block to access setters.

@return [self]

@example

su = StandupMD.new do |s|
  s.directory = @workdir
  s.file_name_format = '%y_%m.markdown'
  s.bullet_character = '*'
end
# File lib/standup_md.rb, line 233
def initialize
  @notes = []
  @header_depth = 1
  @sub_header_depth = 2
  @bullet_character = '-'
  @current_entry_tasks = ["<!-- ADD TODAY'S WORK HERE -->"]
  @impediments = ['None']
  @file_name_format = '%Y_%m.md'
  @directory = File.join(ENV['HOME'], '.cache', 'standup_md')
  @header_date_format = '%Y-%m-%d'
  @current_header = 'Current'
  @previous_header = 'Previous'
  @impediments_header = 'Impediments'
  @notes_header = 'Notes'
  @sub_header_order = %w[previous current impediments notes]

  yield self if block_given?
end

Booleans

↑ top

Public Instance Methods

entry_previously_added?() click to toggle source

Was today's entry already in the file?

@return [boolean] true if today's entry was already in the file

# File lib/standup_md.rb, line 275
def entry_previously_added?
  @entry_previously_added
end
file_written?() click to toggle source

Has the file been written since instantiated?

@return [boolean]

@example

su = StandupMD.new
su.file_written?
# => false
su.write
su.file_written?
# => true
# File lib/standup_md.rb, line 267
def file_written?
  @file_written
end

Custom setters

↑ top

Public Instance Methods

bullet_character=(character) click to toggle source

Setter for bullet_character. Must be * (asterisk) or - (dash).

@param [String] character

@return [String]

# File lib/standup_md.rb, line 332
def bullet_character=(character)
  raise 'Must be "-" or "*"' unless %w[- *].include?(character)
  @bullet_character = character
end
current_entry_tasks=(tasks) click to toggle source

Setter for current entry tasks.

@param [Array] tasks

@return [Array]

# File lib/standup_md.rb, line 310
def current_entry_tasks=(tasks)
  raise 'Must be an Array' unless tasks.is_a?(Array)
  @current_entry_tasks = tasks
end
directory=(directory) click to toggle source

Setter for directory. Must be expanded in case the user uses `~` for home. If the directory doesn't exist, it will be created. To reset instance variables after changing the directory, you'll need to call load.

@param [String] directory

@return [String]

# File lib/standup_md.rb, line 345
def directory=(directory)
  # TODO test this
  directory = File.expand_path(directory)
  FileUtils.mkdir_p(directory) unless File.directory?(directory)
  @directory = directory
end
header_depth=(depth) click to toggle source

Number of octothorps (#) to use before the main header.

@param [Integer] depth

@return [Integer]

# File lib/standup_md.rb, line 358
def header_depth=(depth)
  if !depth.between?(1, 5)
    raise 'Header depth out of bounds (1..5)'
  elsif depth >= sub_header_depth
    raise 'header_depth must be larger than sub_header_depth'
  end
  @header_depth = depth
end
impediments=(tasks) click to toggle source

Setter for impediments.

@param [Array] tasks

@return [Array]

# File lib/standup_md.rb, line 321
def impediments=(tasks)
  raise 'Must be an Array' unless tasks.is_a?(Array)
  @impediments = tasks
end
notes=(tasks) click to toggle source

Setter for notes.

@param [Array] notes

@return [Array]

# File lib/standup_md.rb, line 299
def notes=(tasks)
  raise 'Must be an Array' unless tasks.is_a?(Array)
  @notes = tasks
end
previous_entry_tasks=(tasks) click to toggle source

Setter for current entry tasks.

@param [Array] tasks

@return [Array]

# File lib/standup_md.rb, line 288
def previous_entry_tasks=(tasks)
  raise 'Must be an Array' unless tasks.is_a?(Array)
  @previous_entry_tasks = tasks
end
sub_header_depth=(depth) click to toggle source

Number of octothorps (#) to use before sub headers (Current, Previous, etc).

@param [Integer] depth

@return [Integer]

# File lib/standup_md.rb, line 373
def sub_header_depth=(depth)
  if !depth.between?(2, 6)
    raise 'Sub-header depth out of bounds (2..6)'
  elsif depth <= header_depth
    raise 'sub_header_depth must be smaller than header_depth'
  end
  @sub_header_depth = depth
end
sub_header_order=(array) click to toggle source

Preferred order for sub-headers.

@param [Array] Values must be %w[previous current impediment notes]

@return [Array]

# File lib/standup_md.rb, line 388
def sub_header_order=(array)
  order = %w[previous current impediments notes]
  raise "Values must be #{order.join{', '}}" unless order.sort == array.sort
  @sub_header_order = array
end

Misc

↑ top

Constants

VERSION

The gem verision

@example

StandupMD::VERSION
# => '0.1.1'

Public Instance Methods

load() click to toggle source

Sets internal instance variables. Called when first instantiated, or after directory is set.

@return [self]

# File lib/standup_md.rb, line 431
def load
  FileUtils.mkdir_p(directory) unless File.directory?(directory)

  @today = Date.today
  @header = today.strftime(header_date_format)
  @file_written = false
  @file = File.expand_path(File.join(directory, today.strftime(file_name_format)))
  @previous_file = get_previous_file
  @all_previous_entries = get_all_previous_entries
  @entry_previously_added = all_previous_entries.key?(header)
  @previous_entry_tasks = previous_entry[current_header]
  @current_entry = @all_previous_entries.delete(header) || new_entry
  @all_entries = {header => current_entry}.merge(all_previous_entries)

  FileUtils.touch(file) unless File.file?(file)
  self
end
Also aliased as: reload
new_month?() click to toggle source

Is today a different month than the previous entry?

# File lib/standup_md.rb, line 457
def new_month?
  file != previous_file
end
reload()

Alias of load

@return [self]

Alias for: load
sub_header_order() click to toggle source

Return a copy of the sub-header order so the user can't modify the array.

@return [Array]

# File lib/standup_md.rb, line 401
def sub_header_order
  @sub_header_order.dup
end
write() click to toggle source

Writes a new entry to the file if the first entry in the file isn't today.

@return [Boolean]

# File lib/standup_md.rb, line 409
def write
  File.open(file, 'w') do |f|
    all_entries.each do |head, s_heads|
      f.puts '#' * header_depth + ' ' + head
      sub_header_order.map { |value| "#{value}_header" }.each do |sub_head|
        sh = send(sub_head).capitalize
        next if !s_heads[sh] || s_heads[sh].empty?
        f.puts '#' * sub_header_depth + ' ' + sh
        s_heads[sh].each { |task| f.puts bullet_character + ' ' + task }
      end
      f.puts
      return @file_written = true if new_month?
    end
  end
  @file_written = true
end