Reloading the source code to your application while it is still running is a tremendous time saver during development. You can tweak formulas, fix typos, even refactor code without losing the program state.
Below is how I implemented this feature for Luz. I’m not convinced it is the most robust implementation, but it has worked well so far.
module Kernel $source_file_modification_times ||= {} # a new 'require' supporting multiple files alias_method :single_require, :require def require(*list) [*list].each { |file| # Was the file successfully 'require'd? if single_require(file) # Grab latest file name (which now includes the .rb) from $LOADED_FEATURES (list of all 'require'd files) file = $LOADED_FEATURES.last # Find the full file path that was loaded by searching the path the way Ruby does filepath = $LOAD_PATH.find { |path| File.exist?("#{path}/#{file}") } + "/#{file}" # Add to list $source_file_modification_times[filepath] = File.new(filepath).mtime end } end def reload_if_newer(filepath) mtime = File.new(filepath).mtime # Do we already have the current version? return false if mtime == $source_file_modification_times[filepath] begin load filepath $source_file_modification_times[filepath] = mtime return true rescue Exception => e # report exception to user somehow... return false end end def reload_modified_source_files $source_file_modification_times.each_key { |filepath| reload_if_newer(filepath) } end end
Then simply create a keyboard shortcut (I use Ctrl-Shift-R) that calls reload_modified_source_files. Because it only reloads files that have changed on disk, it’s quite fast.
The exception handling around the “load filepath” statement prevents syntax errors from bringing down the application.
(Note that this also adds multi-file “require”, which I discussed earlier.)