High performance source code reloader middleware
The list of object constants and classes loaded as part of the project.
The list of files loaded as part of a project.
The modification times for every file in a project.
Returns true if any file changes are detected and populates the MTIMES cache
# File lib/padrino-core/reloader.rb, line 85 def changed? changed = false rotation do |file, mtime| new_file = MTIMES[file].nil? previous_mtime = MTIMES[file] changed = true if new_file || mtime > previous_mtime end changed end
Remove files and classes loaded with stat
# File lib/padrino-core/reloader.rb, line 76 def clear! clear_modification_times clear_loaded_classes clear_loaded_files_and_features end
Specified folders can be excluded from the code reload detection process. Default excluded directories at Padrino.root are: test, spec, features, tmp, config, db and public
# File lib/padrino-core/reloader.rb, line 28 def exclude @_exclude ||= %(test spec tmp features config public db).map { |path| Padrino.root(path) } end
Specified constants can be excluded from the code unloading process.
# File lib/padrino-core/reloader.rb, line 35 def exclude_constants @_exclude_constants ||= Set.new end
Returns true if the file is defined in our padrino root
# File lib/padrino-core/reloader.rb, line 159 def figure_path(file) return file if Pathname.new(file).absolute? $:.each do |path| found = File.join(path, file) return File.expand_path(found) if File.exist?(found) end file end
Specified constants can be configured to be reloaded on every request. Default included constants are: [none]
# File lib/padrino-core/reloader.rb, line 43 def include_constants @_include_constants ||= Set.new end
We lock dependencies sets to prevent reloading of protected constants
# File lib/padrino-core/reloader.rb, line 99 def lock! klasses = ObjectSpace.classes do |klass| klass._orig_klass_name.split('::')[0] end klasses = klasses | Padrino.mounted_apps.map { |app| app.app_class } Padrino::Reloader.exclude_constants.merge(klasses) end
Reload all files with changes detected.
# File lib/padrino-core/reloader.rb, line 50 def reload! # Detect changed files rotation do |file, mtime| # Retrive the last modified time new_file = MTIMES[file].nil? previous_mtime = MTIMES[file] ||= mtime logger.devel "Detected a new file #{file}" if new_file # We skip to next file if it is not new and not modified next unless new_file || mtime > previous_mtime # Now we can reload our file apps = mounted_apps_of(file) if apps.present? apps.each { |app| app.app_obj.reload! } else safe_load(file, :force => new_file) # Reload also apps Padrino.mounted_apps.each do |app| app.app_obj.reload! if app.app_obj.dependencies.include?(file) end end end end
Removes the specified class and constant.
# File lib/padrino-core/reloader.rb, line 171 def remove_constant(const) return if exclude_constants.any? { |c| const._orig_klass_name.index(c) == 0 } && !include_constants.any? { |c| const._orig_klass_name.index(c) == 0 } begin parts = const.to_s.sub(/^::(Object)?/, 'Object::').split('::') object = parts.pop base = parts.empty? ? Object : Inflector.constantize(parts * '::') base.send :remove_const, object logger.devel "Removed constant: #{const} from #{base}" rescue NameError; end end
A safe Kernel::require which issues the necessary hooks depending on results
# File lib/padrino-core/reloader.rb, line 111 def safe_load(file, options={}) began_at = Time.now force = options[:force] file = figure_path(file) reload = should_reload?(file) m_time = modification_time(file) return if !force && m_time && !reload remove_loaded_file_classes(file) remove_loaded_file_features(file) # Duplicate objects and loaded features before load file klasses = ObjectSpace.classes files = Set.new($LOADED_FEATURES.dup) reload_deps_of_file(file) # And finally load the specified file begin logger.devel :loading, began_at, file if !reload logger.debug :reload, began_at, file if reload $LOADED_FEATURES.delete(file) if files.include?(file) Padrino::Utils.silence_output loaded = false require(file) loaded = true update_modification_time(file) rescue SyntaxError => e logger.error "Cannot require #{file} due to a syntax error: #{e.message}" ensure Padrino::Utils.unsilence_output new_constants = ObjectSpace.new_classes(klasses) if loaded process_loaded_file(:file => file, :constants => new_constants, :files => files) else logger.devel "Failed to load #{file}; removing partially defined constants" unload_constants(new_constants) end end end
Generated with the Darkfish Rdoc Generator 2.