class TheFox::Timr::Timr

Core Class

Loads and saves Models to files. Tasks are loaded to `@tasks`.

Holds the [Stack](TheFox::Timr::Model::Stack) instance. Responsible to call Stack methods.

Attributes

foreign_id_db[R]

ForeignIdDb instance.

stack[R]

Stack instance.

Public Class Methods

new(cwd) click to toggle source
# File lib/timr/timr.rb, line 23
def initialize(cwd)
        # Current Working Directory
        case cwd
        when String
                @cwd = Pathname.new(cwd)
        else
                @cwd = cwd
        end
        
        if @cwd && !@cwd.exist?
                puts "Initialize Timr in #{@cwd}"
                @cwd.mkpath
        end
        
        @config = Config.new
        @config.file_path = Pathname.new('config.yml').expand_path(@cwd)
        if @config.file_path.exist?
                @config.load_from_file
        else
                @config.save_to_file(nil, true)
        end
        
        @foreign_id_db = ForeignIdDb.new
        @foreign_id_db.file_path = Pathname.new('foreign_id_db.yml').expand_path(@cwd)
        if @foreign_id_db.file_path.exist?
                @foreign_id_db.load_from_file
        end
        
        @tasks_path = Pathname.new('tasks').expand_path(@cwd)
        unless @tasks_path.exist?
                @tasks_path.mkpath
        end
        
        # Holds all loaded Tasks.
        @tasks = Hash.new
        
        # Stack Path
        stack_path = Pathname.new('stack.yml').expand_path(@cwd)
        
        # Stack
        @stack = Stack.new
        @stack.timr = self
        @stack.file_path = stack_path
        if stack_path.exist?
                @stack.load_from_file
        end
end

Public Instance Methods

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

Create a new [Task](TheFox::Timr::Model::Task) based on the `options` Hash. Will not be started or something else.

Uses [Task#create_task_from_hash](TheFox::Timr::Model::Task::create_task_from_hash) to create a new Task instance and [BasicModel#create_path_by_id](TheFox::Timr::Model::BasicModel.create_path_by_id) to create a new file path.

Returns the new created Task instance.

Options:

  • `:foreign_id` (String)

# File lib/timr/timr.rb, line 413
def add_task(options = Hash.new)
        foreign_id_opt = options.fetch(:foreign_id, nil)
        
        task = Task.create_task_from_hash(options)
        
        if foreign_id_opt
                # Throws exception when Foreign ID already exists in DB.
                # Break before Task save.
                @foreign_id_db.add_task(task, foreign_id_opt)
                @foreign_id_db.save_to_file
        end
        
        # Task Path
        task_file_path = BasicModel.create_path_by_id(@tasks_path, task.id)
        
        # Save Task to file.
        task.save_to_file(task_file_path)
        
        # Leave Stack untouched.
        
        task
end
continue(options = Hash.new) click to toggle source

Continues the Top [Track](TheFox::Timr::Model::Track).

Options:

  • `:track` (Track)

# File lib/timr/timr.rb, line 226
def continue(options = Hash.new)
        # Get current Track from Stack.
        track = @stack.current_track
        unless track
                return
        end
        options[:track] = track
        
        # Get Task from Track.
        task = track.task
        
        # Continue Task
        track = task.continue(options)
        
        # Save Task
        task.save_to_file
        
        @stack.stop
        @stack.push(track)
        @stack.save_to_file
        
        track
end
get_task_by_id(task_id) click to toggle source

Find a [Task](TheFox::Timr::Model::Task) by ID (internal or foreign).

Tasks always should be loaded with this methods to check if a Task instance already exist at `@tasks`. This is like a cache.

`task_id` can be a short ID or a Foreign ID. If a Task is already loaded with full ID another search by short ID would lead to generate a new object_id. Then there would be two Tasks instances loaded for the same Task ID. The Check Cache if condition prohibits this.

# File lib/timr/timr.rb, line 505
def get_task_by_id(task_id)
        # First search in Foreign ID DB.
        tmp_task_id = @foreign_id_db.get_task_id(task_id)
        if tmp_task_id
                task_id = tmp_task_id
        end
        
        task = @tasks[task_id]
        
        if task
                # Take Task from cache.
        else
                task = Task.load_task_from_file_with_id(@tasks_path, task_id)
                
                # Check cache.
                if @tasks[task.id]
                        # Task already loaded.
                        task = @tasks[task.id]
                else
                        # Set new loaded Task.
                        @tasks[task.id] = task
                end
        end
        
        task
end
get_track_by_id(track_id) click to toggle source

Find a [Track](TheFox::Timr::Model::Track) by ID.

# File lib/timr/timr.rb, line 533
def get_track_by_id(track_id)
        @tasks.each do |task_id, task|
                track = task.find_track_by_id(track_id)
                if track
                        return track
                end
        end
        
        nil
end
get_track_by_task_id(task_id, track_id) click to toggle source

Get a Track by a specific Task ID and Track ID.

# File lib/timr/timr.rb, line 545
def get_track_by_task_id(task_id, track_id)
        if task_id && track_id
                task = get_task_by_id(task_id)
                if task
                        return task.find_track_by_id(track_id)
                end
        end
        
        nil
end
load_all_tracks() click to toggle source

Load all [Tracks](TheFox::Timr::Model::Track) using `get_task_by_id`.

# File lib/timr/timr.rb, line 615
def load_all_tracks
        # Iterate all files.
        @tasks_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
                
                track_id = BasicModel.get_id_from_path(@tasks_path, file)
                
                # Loads the Task from file into @tasks.
                get_task_by_id(track_id)
        end
end
pause(options = Hash.new) click to toggle source

Stops the current running [Track](TheFox::Timr::Model::Track) but does not remove it from the Stack.

# File lib/timr/timr.rb, line 195
def pause(options = Hash.new)
        # Get current Track from Stack.
        track = @stack.current_track
        unless track
                return
        end
        
        # Track Status
        if track.stopped?
                raise TrackError, "Cannot pause current Track #{track.short_id}, is not running."
        end
        
        # Get Task from Track.
        task = track.task
        
        # Pause Task
        track = task.pause(options)
        
        # Save Task
        task.save_to_file
        
        # Do nothing on the Stack.
        
        track
end
pop(options = Hash.new) click to toggle source

Stops the Top [Track](TheFox::Timr::Model::Track), removes it from the [Stack](TheFox::Timr::Model::Stack) and continues the next underlying (new Top) Track.

# File lib/timr/timr.rb, line 357
def pop(options = Hash.new)
        stop(options)
        continue(options)
end
push(options = Hash.new) click to toggle source

Starts a new [Track](TheFox::Timr::Model::Track) and pauses the underlying one.

Options:

  • `:foreign_id` (String)

  • `:task_id` (String)

  • `:track_id` (String)

# File lib/timr/timr.rb, line 257
def push(options = Hash.new)
        foreign_id_opt = options.fetch(:foreign_id, nil)
        task_id_opt = options.fetch(:task_id, nil)
        track_id_opt = options.fetch(:track_id, nil)
        
        # Get current Track from Stack.
        old_track = @stack.current_track
        
        # Stop current running Track.
        if old_track
                # Get Task from Track.
                old_task = old_track.task
                unless old_task
                        raise TrackError, "Track #{old_track.short_id} has no Task."
                end
                
                # Stop Task here because on pop we need to take the
                # current Track from Stack instead from Task.
                # You can push another Track from an already existing
                # Task on the Stack. A Task can hold only one current Track.
                old_task.stop
                
                # Save Task
                old_task.save_to_file
                
                old_task = nil
        end
        
        if task_id_opt
                task = get_task_by_id(task_id_opt)
                
                if foreign_id_opt
                        # Throws exception when Foreign ID already exists in DB.
                        # Break before new Track creation.
                        @foreign_id_db.add_task(task, foreign_id_opt)
                        @foreign_id_db.save_to_file
                end
                
                # Start Task
                track = task.start(options)
                
                # Save Task
                task.save_to_file
                
                @stack.push(track)
                @stack.save_to_file
        else
                if track_id_opt
                        # The long way. Should be avoided.
                        # Search all files.
                        
                        track = Track.find_track_by_id(@tasks_path, track_id_opt)
                        if track
                                options[:track_id] = track.id
                                
                                # Get Task from Track.
                                task = track.task
                                unless task
                                        raise TrackError, "Track #{track.short_id} has no Task."
                                end
                                
                                # Start Task
                                track = task.start(options)
                                
                                # Save Task
                                task.save_to_file
                                
                                @stack.push(track)
                                @stack.save_to_file
                        end
                else
                        # Create completely new Task.
                        task = Task.create_task_from_hash(options)
                        
                        if foreign_id_opt
                                # Throws exception when Foreign ID already exists in DB.
                                # Break before new Track creation.
                                @foreign_id_db.add_task(task, foreign_id_opt)
                                @foreign_id_db.save_to_file
                        end
                        
                        # Start Task
                        track = task.start(options)
                        
                        # Task Path
                        task_file_path = BasicModel.create_path_by_id(@tasks_path, task.id)
                        
                        # Save Task to file.
                        task.save_to_file(task_file_path)
                        
                        @stack.push(track)
                        @stack.save_to_file
                end
        end
        
        track
end
remove_task(options = Hash.new) click to toggle source

Remove a [Task](TheFox::Timr::Model::Task).

Options:

  • `:task_id` (String) Can be either a internal ID (hex) or Foreign ID, because `get_task_by_id` searches also the Foreign ID DB.

# File lib/timr/timr.rb, line 441
def remove_task(options = Hash.new)
        task_id_opt = options.fetch(:task_id, nil)
        
        unless task_id_opt
                raise TaskError, 'No Task ID given.'
        end
        
        task = get_task_by_id(task_id_opt)
        
        @tasks.delete(task.id)
        
        # Get running Tracks and remove these from Stack.
        task.tracks({:status => ?R}).each do |track_id, track|
                @stack.remove(track)
        end
        @stack.save_to_file
        
        # Remove Task from Foreign ID DB.
        @foreign_id_db.remove_task(task)
        @foreign_id_db.save_to_file
        
        task.delete_file
        
        task
end
remove_track(options = Hash.new) click to toggle source

Remove a Track.

Options:

  • `:track_id` (String)

# File lib/timr/timr.rb, line 472
def remove_track(options = Hash.new)
        track_id_opt = options.fetch(:track_id, nil)
        
        unless track_id_opt
                raise TrackError, 'No Track ID given.'
        end
        
        track = get_track_by_id(track_id_opt)
        unless track
                raise TrackError, "Track for ID '#{track_id_opt}' not found."
        end
        
        task = track.task
        
        track.remove
        
        task.save_to_file
        
        # Remove Track from Stack.
        @stack.remove(track)
        @stack.save_to_file
        
        {
                :task => task,
                :track => track,
        }
end
reset(options = Hash.new) click to toggle source

Remove current running Track.

Options:

  • `:stack` (Boolean) Reset the Stack.

# File lib/timr/timr.rb, line 367
def reset(options = Hash.new)
        stack_opt = options.fetch(:stack, false)
        
        track = @stack.current_track
        if track && track.running?
                task = track.task
                if task
                        task.reset
                end
                
                track.remove
                
                # Save Task to file.
                task.save_to_file
                
                @stack.remove(track)
        end
        
        if stack_opt
                @stack.tracks.each do |track|
                        task = track.task
                        if task
                                task.reset
                                
                                # Save Task to file.
                                task.save_to_file
                        end
                end
                
                @stack.reset
        end
        
        @stack.save_to_file
        
        nil
end
shutdown() click to toggle source

Save [Stack](TheFox::Timr::Model::Stack) and [Config](TheFox::Timr::Model::Config).

# File lib/timr/timr.rb, line 603
def shutdown
        # Save Stack
        @stack.save_to_file
        
        # Save config
        @config.save_to_file
        
        # Save Foreign ID DB
        @foreign_id_db.save_to_file
end
start(options = Hash.new) click to toggle source

Removes all previous [Tracks](TheFox::Timr::Model::Track) and starts a new one.

Options:

  • `:foreign_id` (String)

  • `:task_id` (String)

  • `:track_id` (String)

# File lib/timr/timr.rb, line 78
def start(options = Hash.new)
        foreign_id_opt = options.fetch(:foreign_id, nil)
        task_id_opt = options.fetch(:task_id, nil)
        track_id_opt = options.fetch(:track_id, nil)
        
        # Get current Track from Stack.
        old_track = @stack.current_track
        
        # Stop current running Track.
        if old_track
                # Get Task from Track.
                old_task = old_track.task
                unless old_task
                        raise TrackError, "Track #{old_track.short_id} has no Task."
                end
                
                # Stop Task
                old_task.stop
                
                # Save Task
                old_task.save_to_file
                
                old_task = nil
        end
        
        if task_id_opt
                task = get_task_by_id(task_id_opt)
                
                if foreign_id_opt
                        # Throws exception when Foreign ID already exists in DB.
                        # Break before new Track creation.
                        @foreign_id_db.add_task(task, foreign_id_opt)
                        @foreign_id_db.save_to_file
                end
                
                track = task.start(options)
                
                task.save_to_file
                
                @stack.start(track)
                @stack.save_to_file
        else
                if track_id_opt
                        # Seach Track ID the long way. Should be avoided.
                        # Searches all files.
                        
                        track = Track.find_track_by_id(@tasks_path, track_id_opt)
                        if track
                                options[:track_id] = track.id
                                
                                # Get Task from Track.
                                task = track.task
                                unless task
                                        raise TrackError, "Track #{track.short_id} has no Task."
                                end
                                
                                # Start Task
                                track = task.start(options)
                                
                                # Save Task
                                task.save_to_file
                                
                                @stack.start(track)
                                @stack.save_to_file
                        end
                else
                        # Create completely new Task.
                        task = Task.create_task_from_hash(options)
                        
                        if foreign_id_opt
                                # Throws exception when Foreign ID already exists in DB.
                                # Break before new Track creation.
                                @foreign_id_db.add_task(task, foreign_id_opt)
                                @foreign_id_db.save_to_file
                        end
                        
                        # Start Task
                        track = task.start(options)
                        
                        # Task Path
                        task_file_path = BasicModel.create_path_by_id(@tasks_path, task.id)
                        
                        # Save Task to file.
                        task.save_to_file(task_file_path)
                        
                        @stack.start(track)
                        @stack.save_to_file
                end
        end
        
        track
end
stop(options = Hash.new) click to toggle source

Stops the current running [Track](TheFox::Timr::Model::Track) and removes it from the Stack.

# File lib/timr/timr.rb, line 172
def stop(options = Hash.new)
        # Get current Track from Stack.
        track = @stack.current_track
        unless track
                return
        end
        
        # Get Task from Track.
        task = track.task
        
        # Stop Task
        task.stop(options)
        
        # Save Task
        task.save_to_file
        
        @stack.stop
        @stack.save_to_file
        
        track
end
tasks() click to toggle source

Get all [Tasks](TheFox::Timr::Model::Task).

# File lib/timr/timr.rb, line 557
def tasks
        load_all_tracks
        
        @tasks
end
to_s() click to toggle source
# File lib/timr/timr.rb, line 635
def to_s
        'Timr'
end
tracks(options = Hash.new) click to toggle source

Get all [Tracks](TheFox::Timr::Model::Track).

Options:

  • `:sort` (Boolean)

# File lib/timr/timr.rb, line 568
def tracks(options = Hash.new)
        sort_opt = options.fetch(:sort, true)
        
        load_all_tracks
        
        filtered_tracks = Hash.new
        @tasks.each do |task_id, task|
                tracks = task.tracks(options)
                filtered_tracks.merge!(tracks)
        end
        
        if sort_opt
                # Sort ASC by Begin DateTime, End DateTime.
                filtered_tracks.sort{ |t1, t2|
                        t1 = t1.last
                        t2 = t2.last
                        
                        cmp1 = t1.begin_datetime <=> t2.begin_datetime
                        
                        if cmp1 == 0
                                t1.end_datetime <=> t2.end_datetime
                        else
                                cmp1
                        end
                }.to_h
        else
                filtered_tracks
        end
end