lighttroupe/luz

View on GitHub
utils/reloadable_require.rb

Summary

Maintainability
A
1 hr
Test Coverage
require 'addons/exception'
require 'addons/dir'

module Kernel
    @@source_file_modification_times ||= {}
    @@loading_file_path = nil

    def optional_require(file)
        begin
            require file
            return true
        rescue LoadError
            return false
        end
    end

    # a new 'require' supporting multiple files
    #alias_method :single_require, :require
    def multi_require(*list)
        [*list].each { |file|
            if require(file)
                # Grab latest file name (which now includes the .rb) from $LOADED_FEATURES (list of all require'd files)
                ext = File.extname($LOADED_FEATURES.last)

                # Add on extension unless it already has it (seems to happen with .so files)
                file += ext unless file[-ext.length, ext.length] == ext

                # Find the full file path that was loaded by searching the path the way Ruby does
                path = $:.find { |path| File.exist?(File.join(path, file)) }
                next unless path        # seems to fail for some system libs (won't need reloading anyway)

                filepath = File.join(path, file)

                # Add to list
                @@source_file_modification_times[filepath] = File.new(filepath).mtime
            end
        }
    end

    def reload_if_newer(filepath)
        file = File.new(filepath) rescue nil
        return false unless file        # no longer exists?

        mtime = file.mtime
        file.close

        # Do we already have the current version?
        return false if mtime == @@source_file_modification_times[filepath]
        @@source_file_modification_times[filepath] = mtime

        begin
            @@loading_file_path = filepath
            #puts "Reloading - #{@@loading_file_path} ..."
            load filepath
            @@loading_file_path = nil
            return true
        rescue Exception => e
            $gui.positive_message "File Reload Failed" if $gui
            puts "File Reload Failed - #{@@loading_file_path}:"
            e.report
            @@loading_file_path = nil
            return false
        end
    end

    def load_directory(path, filter_pattern='*rb')
        count = 0
        paths = []        # collect and then sort to make load order consistent
        Dir.new(path).each_matching_recursive(filter_pattern) { |filepath| paths << filepath }
        paths.sort.each { |filepath| count += 1 if reload_if_newer(filepath) }
        return count
    end

    def reload_modified_source_files
        count = 0
        @@source_file_modification_times.each_key { |filepath| count += 1 if reload_if_newer(filepath) }
        count
    end

    def self.loading_file_path
        @@loading_file_path
    end
end