Class: Rack::Unreloader::Reloader
- Inherits:
-
Object
- Object
- Rack::Unreloader::Reloader
- Defined in:
- lib/rack/unreloader/reloader.rb
Direct Known Subclasses
Constant Summary collapse
- File =
::File
Instance Method Summary collapse
-
#clear! ⇒ Object
Unload all reloadable constants and features, and clear the list of files to monitor.
-
#initialize(opts = {}) ⇒ Reloader
constructor
Setup the reloader.
-
#record_dependency(path, files) ⇒ Object
Record a dependency the given files, such that each file in
files
depends onpath
. -
#reload! ⇒ Object
If there are any changed files, reload them.
-
#require_dependencies(paths, opts = {}, &block) ⇒ Object
Require the given dependencies, monitoring them for changes.
-
#skip_reload(files) ⇒ Object
Skip reloading the given files.
Constructor Details
#initialize(opts = {}) ⇒ Reloader
Setup the reloader. Supports :logger and :subclasses options, see Rack::Unloader.new for details.
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/rack/unreloader/reloader.rb', line 10 def initialize(opts={}) @logger = opts[:logger] @classes = opts[:subclasses] ? Array(opts[:subclasses]).map(&:to_s) : %w'Object' # Hash of files being monitored for changes, keyed by absolute path of file name, # with values being an array containing the last modified time (or nil if the file has # not yet been loaded) and the delete hook. @monitor_files = {} # Hash of directories being monitored for changes, keyed by absolute path of directory name, # with values being the an array with a hash of modified times for the directory and # subdirectories (or nil if the directory has not yet been checked), an array of files in # the directory, a block to pass to require_dependency for new files, and the delete_hook # for the files in the directory. @monitor_dirs = {} # Hash of procs returning constants defined in files, keyed by absolute path # of file name. If there is no proc, must call ObjectSpace before and after # loading files to detect changes, which is slower. @constants_defined = {} # Hash keyed by absolute path of file name, storing constants and other # filenames that the key loads. Values should be hashes with :constants # and :features keys, and arrays of values. @files = {} # Similar to @files, but stores previous entries, used when rolling back. @old_entries = {} # Records dependencies on files. Keys are absolute paths, values are arrays of absolute paths, # where each entry depends on the key, so that if the key path is modified, all values are # reloaded. @dependencies = {} # Array of the order in which to load dependencies @dependency_order = [] # Array of absolute paths which should be unloaded, but not reloaded on changes, # because files that depend on them will load them automatically. @skip_reload = [] end |
Instance Method Details
#clear! ⇒ Object
Unload all reloadable constants and features, and clear the list of files to monitor.
54 55 56 57 58 59 60 |
# File 'lib/rack/unreloader/reloader.rb', line 54 def clear! @files.keys.each do |file| remove(file) end @monitor_files = {} @old_entries = {} end |
#record_dependency(path, files) ⇒ Object
Record a dependency the given files, such that each file in files
depends on path
. If path
changes, each file in files
should be reloaded as well.
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
# File 'lib/rack/unreloader/reloader.rb', line 65 def record_dependency(path, files) files = (@dependencies[path] ||= []).concat(files) files.uniq! order = @dependency_order i = order.find_index{|v| files.include?(v)} || -1 order.insert(i, path) order.concat(files) order.uniq! if File.directory?(path) (@monitor_files.keys & Unreloader.ruby_files(path)).each do |file| record_dependency(file, files) end end nil end |
#reload! ⇒ Object
If there are any changed files, reload them. If there are no changed files, do nothing.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/rack/unreloader/reloader.rb', line 86 def reload! changed_files = [] @monitor_dirs.keys.each do |dir| check_monitor_dir(dir, changed_files) end removed_files = [] delete_hooks = [] @monitor_files.to_a.each do |file, (time, delete_hook)| if File.file?(file) if file_changed?(file, time) changed_files << file end else delete_hooks << [delete_hook, file] if delete_hook removed_files << file end end remove_files(removed_files) delete_hooks.each{|hook, file| hook.call(file)} return if changed_files.empty? unless @dependencies.empty? changed_files = Unreloader.(reload_files(changed_files)) order = @dependency_order order &= changed_files changed_files = order + (changed_files - order) end unless @skip_reload.empty? changed_files -= Unreloader.(@skip_reload) end changed_files.select! do |file| @monitor_files.has_key?(file) end changed_files.each do |file| safe_load(file) end end |
#require_dependencies(paths, opts = {}, &block) ⇒ Object
Require the given dependencies, monitoring them for changes. Paths should be a file glob or an array of file globs.
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/rack/unreloader/reloader.rb', line 134 def require_dependencies(paths, opts={}, &block) = {:cyclic => true} delete_hook = opts[:delete_hook] error = nil Unreloader.(paths).each do |file| if File.directory?(file) @monitor_dirs[file] = [nil, [], block, delete_hook] check_monitor_dir(file) next else @constants_defined[file] = block @monitor_files[file] = [nil, delete_hook] end begin safe_load(file, ) rescue NameError, LoadError => error log "Cyclic dependency reload for #{error.class}: #{error.}" rescue Exception => error log "Error: #{error.class}: #{error.}" break end end if error raise error end end |
#skip_reload(files) ⇒ Object
Skip reloading the given files. Should only be used if other files depend on these files and the other files require these files when loaded.
167 168 169 170 171 |
# File 'lib/rack/unreloader/reloader.rb', line 167 def skip_reload(files) @skip_reload.concat(files) @skip_reload.uniq! nil end |