class TheFox::Timr::Model::Track

Attributes

is_billed[R]
message[R]

Track Message. What have you done?

paused[RW]

Is this even in use? ;D

task[RW]

Parent Task instance

Public Class Methods

create_track_from_hash(hash) click to toggle source

Create a new Track instance from a Hash.

# File lib/timr/model/track.rb, line 589
def create_track_from_hash(hash)
    unless hash.is_a?(Hash)
        raise TrackError, "hash variable must be a Hash instance. #{hash.class} given."
    end
    
    track = Track.new
    if hash['id']
        track.id = hash['id']
    end
    if hash['created']
        track.created = hash['created']
    end
    if hash['modified']
        track.modified = hash['modified']
    end
    if hash['is_billed']
        track.is_billed = hash['is_billed']
    end
    if hash['message']
        track.message = hash['message']
    end
    if hash['begin_datetime']
        track.begin_datetime = hash['begin_datetime']
    end
    if hash['end_datetime']
        track.end_datetime = hash['end_datetime']
    end
    track.has_changed = false
    track
end
find_track_by_id(base_path, track_id) click to toggle source

This is really bad. Do not use this.

# File lib/timr/model/track.rb, line 621
def find_track_by_id(base_path, track_id)
    found_track = nil
    
    # Iterate all files.
    base_path.find.each do |file|
        # Filter all directories.
        unless file.file?
            next
        end
        
        # Filter all non-yaml files.
        unless file.basename.fnmatch('*.yml')
            next
        end
        
        task = Task.load_task_from_file(file)
        tmp_track = task.find_track_by_id(track_id)
        if tmp_track
            if found_track
                raise TrackError, "Track ID '#{track_id}' is not a unique identifier."
            else
                found_track = tmp_track
                
                # Do not break the loop here.
            end
        end
    end
    
    found_track
end
new() click to toggle source
Calls superclass method TheFox::Timr::Model::BasicModel.new
# File lib/timr/model/track.rb, line 24
def initialize
    super()
    
    @task = nil
    
    @begin_datetime = nil
    @end_datetime = nil
    @is_billed = false
    @message = nil
    @paused = false
end

Public Instance Methods

begin_datetime(options = Hash.new) click to toggle source

Get begin_datetime.

Options:

  • :from (Time)
    See documentation about :to on end_datetime().

# File lib/timr/model/track.rb, line 63
def begin_datetime(options = Hash.new)
    from_opt = options.fetch(:from, nil)
    
    if @begin_datetime
        if from_opt && from_opt > @begin_datetime
            bdt = from_opt
        else
            bdt = @begin_datetime
        end
        bdt.localtime
    end
end
begin_datetime=(begin_datetime) click to toggle source

Set begin_datetime.

# File lib/timr/model/track.rb, line 37
def begin_datetime=(begin_datetime)
    case begin_datetime
    when String
        begin_datetime = Time.parse(begin_datetime)
    when Time
        # OK
    else
        raise TrackError, "begin_datetime needs to be a String or Time, #{begin_datetime.class} given."
    end
    
    if @end_datetime && begin_datetime >= @end_datetime
        raise TrackError, 'begin_datetime must be lesser than end_datetime.'
    end
    
    @begin_datetime = begin_datetime
    
    # Mark Track as changed.
    changed
end
begin_datetime_s(options = Hash.new) click to toggle source

Get #begin_datetime String.

Options:

  • :format (String)

# File lib/timr/model/track.rb, line 81
def begin_datetime_s(options = Hash.new)
    format_opt = options.fetch(:format, HUMAN_DATETIME_FOMRAT)
    
    bdt = begin_datetime(options)
    if bdt
        bdt.strftime(format_opt)
    else
        '---'
    end
end
billed_duration(options = Hash.new) click to toggle source

Alias method.

# File lib/timr/model/track.rb, line 268
def billed_duration(options = Hash.new)
    duration(options.merge({:billed => true}))
end
changed() click to toggle source

When the Track is marked as changed it needs to mark the Task as changed.

A single Track cannot be stored to a file. Tracks are assiged to a Task and are stored to the Task file.

Calls superclass method TheFox::Timr::Model::BasicModel#changed
# File lib/timr/model/track.rb, line 359
def changed
    super()
    
    if @task
        @task.changed
    end
end
days() click to toggle source

When #begin_datetime is 2017-01-01 01:15
and #end_datetime is 2017-01-03 02:17
this function returns

[
  Date.new(2017, 1, 1),
  Date.new(2017, 1, 2),
  Date.new(2017, 1, 3),
]
# File lib/timr/model/track.rb, line 288
def days
    begin_date = @begin_datetime.to_date
    end_date = @end_datetime.to_date
    
    begin_date.upto(end_date)
end
dup() click to toggle source

Duplicate this Track using the same Message. This is used almost by every Command.
Start, Continue, Push, etc.

# File lib/timr/model/track.rb, line 376
def dup
    track = Track.new
    track.task = @task
    track.message = @message.clone
    track
end
duration(options = Hash.new) click to toggle source

Cacluates the secondes between begin and end datetime and returns a new Duration instance.

Options:

  • :from (Time), :to (Time)
    Limit the begin and end datetimes to a specific range.

  • :billed (Boolean)

# File lib/timr/model/track.rb, line 227
def duration(options = Hash.new)
    from_opt = options.fetch(:from, nil)
    to_opt = options.fetch(:to, nil)
    billed_opt = options.fetch(:billed, nil)
    
    unless billed_opt.nil?
        if @is_billed != billed_opt
            return Duration.new(0)
        end
    end
    
    if @begin_datetime
        bdt = @begin_datetime.utc
    end
    if @end_datetime
        edt = @end_datetime.utc
    else
        edt = Time.now.utc
    end
    
    # Cut Start
    if from_opt && bdt && from_opt > bdt
        bdt = from_opt.utc
    end
    
    # Cut End
    if to_opt && edt && to_opt < edt
        edt = to_opt.utc
    end
    
    seconds = 0
    if bdt && edt
        if bdt < edt
            seconds = (edt - bdt).to_i
        end
    end
    
    Duration.new(seconds)
end
end_datetime(options = Hash.new) click to toggle source

Get end_datetime.

Options:

  • :to (Time)
    This limits @end_datetime. If :to > @end_datetime it returns the original @end_datetime. Otherwise it will return :to. The same applies for :from on begin_datetime() but just the other way round.

# File lib/timr/model/track.rb, line 125
def end_datetime(options = Hash.new)
    to_opt = options.fetch(:to, nil)
    
    if @end_datetime
        if to_opt && to_opt < @end_datetime
            edt = to_opt
        else
            edt = @end_datetime
        end
        edt.localtime
    end
end
end_datetime=(end_datetime) click to toggle source

Set end_datetime.

# File lib/timr/model/track.rb, line 93
def end_datetime=(end_datetime)
    if !@begin_datetime
        raise TrackError, 'end_datetime cannot be set until begin_datetime is set.'
    end
    
    case end_datetime
    when String
        end_datetime = Time.parse(end_datetime)
    when Time
        # OK
    else
        raise TrackError, "end_datetime needs to be a String or Time, #{end_datetime.class} given."
    end
    
    if end_datetime <= @begin_datetime
        raise TrackError, 'end_datetime must be greater than begin_datetime.'
    end
    
    @end_datetime = end_datetime
    
    # Mark Track as changed.
    changed
end
end_datetime_s(options = Hash.new) click to toggle source

Get #end_datetime String.

Options:

  • :format (String)

# File lib/timr/model/track.rb, line 143
def end_datetime_s(options = Hash.new)
    format_opt = options.fetch(:format, HUMAN_DATETIME_FOMRAT)
    
    edt = end_datetime(options)
    if edt
        edt.strftime(format_opt)
    else
        '---'
    end
end
eql?(track) click to toggle source

Are two Tracks equal?

Uses ID for comparision.

# File lib/timr/model/track.rb, line 509
def eql?(track)
    unless track.is_a?(Track)
        raise TrackError, "track variable must be a Track instance. #{track.class} given."
    end
    
    self.id == track.id
end
formatted(options = Hash.new) click to toggle source

Return formatted String.

Options:

  • :format

Format:

  • %id - ID

  • %sid - Short ID

  • %t - Title generated from message.

  • %m - Message

  • %bdt - Begin DateTime

  • %bd - Begin Date

  • %bt - Begin Time

  • %edt - End DateTime

  • %ed - End Date

  • %et - End Time

  • %ds - Duration Seconds

  • %dh - Duration Human Format

  • %bi - Billed Integer

  • %bh - Billed Human Format (YES, NO)

# File lib/timr/model/track.rb, line 539
def formatted(options = Hash.new)
    format = options.fetch(:format, '')
    
    formatted_s = format
        .gsub('%id', self.id)
        .gsub('%sid', self.short_id)
        .gsub('%t', self.title ? self.title : '')
        .gsub('%m', self.message ? self.message : '')
        .gsub('%bdt', self.begin_datetime ? self.begin_datetime.strftime('%F %H:%M') : '')
        .gsub('%bd', self.begin_datetime ? self.begin_datetime.strftime('%F') : '')
        .gsub('%bt', self.begin_datetime ? self.begin_datetime.strftime('%H:%M') : '')
        .gsub('%edt', self.end_datetime ? self.end_datetime.strftime('%F %H:%M') : '')
        .gsub('%ed', self.end_datetime ? self.end_datetime.strftime('%F') : '')
        .gsub('%et', self.end_datetime ? self.end_datetime.strftime('%H:%M') : '')
        .gsub('%ds', self.duration.to_s)
        .gsub('%bi', self.is_billed.to_i.to_s)
        .gsub('%bh', self.is_billed ? 'YES' : 'NO')
    
    duration_human = self.duration.to_human
    if duration_human
        formatted_s.gsub!('%dh', self.duration.to_human)
    else
        formatted_s.gsub!('%dh', '')
    end
    
    task_formating_options = {
        :format => formatted_s,
        :prefix => '%T',
    }
    
    if @task
        formatted_s = @task.formatted(task_formating_options)
    else
        tmp_task = Task.new
        tmp_task.id = ''
        
        formatted_s = tmp_task.formatted(task_formating_options)
    end
    
    formatted_s
end
inspect() click to toggle source
# File lib/timr/model/track.rb, line 581
def inspect
    "#<Track #{short_id}>"
end
is_billed=(is_billed) click to toggle source

Set is_billed.

# File lib/timr/model/track.rb, line 349
def is_billed=(is_billed)
    @is_billed = is_billed
    
    # Mark Track as changed.
    changed
end
message=(message) click to toggle source

Set message.

# File lib/timr/model/track.rb, line 155
def message=(message)
    @message = message
    
    # Mark Track as changed.
    changed
end
name(max_length = nil) click to toggle source

Title Alias

# File lib/timr/model/track.rb, line 344
def name(max_length = nil)
    title(max_length)
end
remove() click to toggle source

Removes itself from parent Task.

# File lib/timr/model/track.rb, line 384
def remove
    if @task
        @task.remove_track(self)
    else
        false
    end
end
running?() click to toggle source

Is the Track running?

# File lib/timr/model/track.rb, line 316
def running?
    status.short_status == 'R' # running
end
save_to_file(path = nil, force = false) click to toggle source

Alias for Task. A Track cannot saved to a file. Only the whole Task.

# File lib/timr/model/track.rb, line 368
def save_to_file(path = nil, force = false)
    if @task
        @task.save_to_file(path, force)
    end
end
start(options = Hash.new) click to toggle source

Start this Track. A Track cannot be restarted because it's the smallest time unit.

# File lib/timr/model/track.rb, line 163
def start(options = Hash.new)
    message_opt = options.fetch(:message, nil)
    
    if @begin_datetime
        raise TrackError, 'Cannot restart Track. Use dup() on this instance or create a new instance by using Track.new().'
    end
    
    @begin_datetime = DateTimeHelper.get_datetime_from_options(options)
    
    if message_opt
        @message = message_opt
    end
end
status() click to toggle source

Evaluates the Short Status and returns a new Status instance.

# File lib/timr/model/track.rb, line 296
def status
    if @begin_datetime.nil?
        short_status = '-' # not started
    elsif @end_datetime.nil?
        short_status = 'R' # running
    elsif @end_datetime
        if @paused
            # It's actually stopped but with an additional flag.
            short_status = 'P' # paused
        else
            short_status = 'S' # stopped
        end
    else
        short_status = 'U' # unknown
    end
    
    Status.new(short_status)
end
stop(options = Hash.new) click to toggle source

Stop this Track.

Options:

  • :start_date

  • :start_time

  • :end_date, :date

  • :end_time, :time

  • :message (String)

# File lib/timr/model/track.rb, line 186
def stop(options = Hash.new)
    start_date_opt = options.fetch(:start_date, nil)
    start_time_opt = options.fetch(:start_time, nil)
    end_date_opt = options.fetch(:end_date, options.fetch(:date, nil))
    end_time_opt = options.fetch(:end_time, options.fetch(:time, nil))
    message_opt = options.fetch(:message, nil)
    # paused_opt = options.fetch(:paused, false)
    
    # Set Start DateTime
    if start_date_opt || start_time_opt
        begin_options = {
            :date => start_date_opt,
            :time => start_time_opt,
        }
        @begin_datetime = DateTimeHelper.get_datetime_from_options(begin_options)
    end
    
    # Set End DateTime
    end_options = {
        :date => end_date_opt,
        :time => end_time_opt,
    }
    @end_datetime = DateTimeHelper.get_datetime_from_options(end_options)
    
    if message_opt
        @message = message_opt
    end
    
    # @paused = paused_opt
    
    # Mark Track as changed.
    changed
end
stopped?() click to toggle source

Is the Track stopped?

# File lib/timr/model/track.rb, line 321
def stopped?
    status.short_status == 'S' # stopped
end
title(max_length = nil) click to toggle source

Title generated from message. If the message has multiple lines only the first line will be taken to create the title.

max_length can be used to define a maximum length. Three dots ... will be appended at the end if the title is longer than max_length.

# File lib/timr/model/track.rb, line 330
def title(max_length = nil)
    unless @message
        return
    end
    
    msg = @message.split("\n\n").first.split("\n").first
    
    if max_length && msg.length > max_length + 2
        msg = msg[0, max_length] << '...'
    end
    msg
end
to_compact_array() click to toggle source

Used to print informations to STDOUT.

# File lib/timr/model/track.rb, line 422
def to_compact_array
    to_ax = Array.new
    
    if @task
        to_ax.concat(@task.to_track_array)
    end
    
    to_ax << 'Track: %s %s' % [self.short_id, self.title]
    
    # if self.title
    #  to_ax << 'Title: %s' % [self.title]
    # end
    if self.begin_datetime
        to_ax << 'Start: %s' % [self.begin_datetime_s]
    end
    if self.end_datetime
        to_ax << 'End:   %s' % [self.end_datetime_s]
    end
    
    if self.duration && self.duration.to_i > 0
        to_ax << 'Duration: %s' % [self.duration.to_human_s]
    end
    
    to_ax << 'Status: %s' % [self.status.colorized]
    
    # if self.message
    #  to_ax << 'Message: %s' % [self.message]
    # end
    
    to_ax
end
to_compact_str() click to toggle source

Used to print informations to STDOUT.

# File lib/timr/model/track.rb, line 417
def to_compact_str
    to_compact_array.join("\n")
end
to_detailed_array(options = Hash.new) click to toggle source

Used to print informations to STDOUT.

Options:

  • :full_id (Boolean) Show full Task and Track IDs.

# File lib/timr/model/track.rb, line 464
def to_detailed_array(options = Hash.new)
    full_id_opt = options.fetch(:full_id, false) # @TODO full_id unit test
    
    to_ax = Array.new
    
    if @task
        to_ax.concat(@task.to_track_array(options))
    end
    
    if full_id_opt
        to_ax << 'Track: %s' % [self.id]
    else
        to_ax << 'Track: %s' % [self.short_id]
    end
    
    if self.begin_datetime
        to_ax << 'Start: %s' % [self.begin_datetime_s]
    end
    if self.end_datetime
        to_ax << 'End:   %s' % [self.end_datetime_s]
    end
    
    if self.duration && self.duration.to_i > 0
        duration_human = self.duration.to_human_s
        to_ax << 'Duration: %s' % [duration_human]
        
        duration_man_days = self.duration.to_man_days
        if duration_human != duration_man_days
            to_ax << 'Man Unit: %s' % [duration_man_days]
        end
    end
    
    to_ax << 'Billed: %s' % [self.is_billed ? 'Yes' : 'No']
    to_ax << 'Status: %s' % [self.status.colorized]
    
    if self.message
        to_ax << 'Message: %s' % [self.message]
    end
    
    to_ax
end
to_detailed_str(options = Hash.new) click to toggle source

Used to print informations to STDOUT.

# File lib/timr/model/track.rb, line 455
def to_detailed_str(options = Hash.new)
    to_detailed_array(options).join("\n")
end
to_h() click to toggle source

To Hash

# File lib/timr/model/track.rb, line 398
def to_h
    h = {
        'id' => @meta['id'],
        'short_id' => short_id, # Not used.
        'created' => @meta['created'],
        'modified' => @meta['modified'],
        'is_billed' => @is_billed,
        'message' => @message,
    }
    if @begin_datetime
        h['begin_datetime'] = @begin_datetime.utc.strftime(MODEL_DATETIME_FORMAT)
    end
    if @end_datetime
        h['end_datetime'] = @end_datetime.utc.strftime(MODEL_DATETIME_FORMAT)
    end
    h
end
to_s() click to toggle source

To String

# File lib/timr/model/track.rb, line 393
def to_s
    "Track_#{short_id}"
end
unbilled_duration(options = Hash.new) click to toggle source

Alias method.

# File lib/timr/model/track.rb, line 273
def unbilled_duration(options = Hash.new)
    duration(options.merge({:billed => false}))
end