Class | Camping::Reloader |
In: |
lib/camping/reloader.rb
|
Parent: | Object |
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.
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.
file | [R] |
# File lib/camping/reloader.rb, line 37 37: def initialize(file, &blk) 38: @file = file 39: @mtime = Time.at(0) 40: @requires = [] 41: @apps = {} 42: @callback = blk 43: end
Checks if both scripts watches the same file.
# File lib/camping/reloader.rb, line 128 128: def ==(other) 129: @file == other.file 130: end
# File lib/camping/reloader.rb, line 132 132: def apps 133: if @app 134: { name => @app } 135: else 136: @apps 137: end 138: end
Loads the apps availble in this script. Use apps to get the loaded apps.
# File lib/camping/reloader.rb, line 56 56: def load_apps(old_apps) 57: all_requires = $LOADED_FEATURES.dup 58: all_apps = Camping::Apps.dup 59: 60: load_file 61: ensure 62: @requires = [] 63: dirs = [] 64: new_apps = Camping::Apps - all_apps 65: 66: @apps = new_apps.inject({}) do |hash, app| 67: if file = app.options[:__FILE__] 68: full = File.expand_path(file) 69: @requires << [file, full] 70: dirs << full.sub(/\.[^.]+$/, '') 71: end 72: 73: key = app.name.to_sym 74: hash[key] = app 75: 76: if !old_apps.include?(key) 77: @callback.call(app) if @callback 78: app.create if app.respond_to?(:create) 79: end 80: 81: hash 82: end 83: 84: ($LOADED_FEATURES - all_requires).each do |req| 85: full = full_path(req) 86: @requires << [req, full] if dirs.any? { |x| full.index(x) == 0 } 87: end 88: 89: @mtime = mtime 90: 91: self 92: end
# File lib/camping/reloader.rb, line 94 94: def load_file 95: if @file =~ /\.ru$/ 96: @app,_ = Rack::Builder.parse_file(@file) 97: else 98: load(@file) 99: end 100: end
# File lib/camping/reloader.rb, line 45 45: def name 46: @name ||= begin 47: base = @file.dup 48: base = File.dirname(base) if base =~ /\bconfig\.ru$/ 49: base.sub!(/\.[^.]+/, '') 50: File.basename(base).to_sym 51: end 52: 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 118: def reload 119: return if @mtime >= mtime rescue nil 120: reload! 121: end
Removes all the apps defined in this script.
# File lib/camping/reloader.rb, line 103 103: def remove_apps 104: @requires.each do |(path, full)| 105: $LOADED_FEATURES.delete(path) 106: end 107: 108: @apps.each do |name, app| 109: Camping::Apps.delete(app) 110: Object.send :remove_const, name 111: end.dup 112: ensure 113: @apps.clear 114: end