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 available 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