class Camping::Reloader
The Camping Reloader¶ ↑
Camping apps are generally small and predictable. Many Camping apps are contained within a single file. Larger apps are split into a handful of other Ruby libraries within the same directory.
Since Camping apps (and their dependencies) are loaded with Ruby's require method, there is a record of them in $LOADED_FEATURES. Which leaves a perfect space for this class to manage auto-reloading an app if any of its immediate dependencies changes.
Wrapping Your Apps¶ ↑
Since bin/camping and the Camping::Server class already use the Reloader, you probably don't need to hack it on your own. But, if you're rolling your own situation, here's how.
Rather than this:
require 'yourapp'
Use this:
require 'camping/reloader' reloader = Camping::Reloader.new('/path/to/yourapp.rb') blog = reloader.apps[:Blog] wiki = reloader.apps[:Wiki]
The blog
and wiki
objects will behave exactly
like your Blog and Wiki, but they will update themselves if yourapp.rb
changes.
You can also give Reloader more than one script.
Attributes
Public Class Methods
# File lib/camping/reloader.rb, line 37 def initialize(file, &blk) @file = file @mtime = Time.at(0) @requires = [] @apps = {} @callback = blk end
Public Instance Methods
Checks if both scripts watches the same file.
# File lib/camping/reloader.rb, line 128 def ==(other) @file == other.file end
# File lib/camping/reloader.rb, line 132 def apps if @app { name => @app } else @apps end end
Loads the apps availble in this script. Use apps
to get the
loaded apps.
# File lib/camping/reloader.rb, line 56 def load_apps(old_apps) all_requires = $LOADED_FEATURES.dup all_apps = Camping::Apps.dup load_file ensure @requires = [] dirs = [] new_apps = Camping::Apps - all_apps @apps = new_apps.inject({}) do |hash, app| if file = app.options[:__FILE__] full = File.expand_path(file) @requires << [file, full] dirs << full.sub(/\.[^.]+$/, '') end key = app.name.to_sym hash[key] = app if !old_apps.include?(key) @callback.call(app) if @callback app.create if app.respond_to?(:create) end hash end ($LOADED_FEATURES - all_requires).each do |req| full = full_path(req) @requires << [req, full] if dirs.any? { |x| full.index(x) == 0 } end @mtime = mtime self end
# File lib/camping/reloader.rb, line 94 def load_file if @file =~ /\.ru$/ @app,_ = Rack::Builder.parse_file(@file) else load(@file) end end
# File lib/camping/reloader.rb, line 45 def name @name ||= begin base = @file.dup base = File.dirname(base) if base =~ /\bconfig\.ru$/ base.sub!(/\.[^.]+/, '') File.basename(base).to_sym end end
Reloads the file if needed. No harm is done by calling this multiple times, so feel free call just to be sure.
# File lib/camping/reloader.rb, line 118 def reload return if @mtime >= mtime rescue nil reload! end
# File lib/camping/reloader.rb, line 123 def reload! load_apps(remove_apps) end
Removes all the apps defined in this script.
# File lib/camping/reloader.rb, line 103 def remove_apps @requires.each do |(path, full)| $LOADED_FEATURES.delete(path) end @apps.each do |name, app| Camping::Apps.delete(app) Object.send :remove_const, name end.dup ensure @apps.clear end