One of the things I miss most about Rails when working in gems is the reload! function, which rebuilds the environment to update anything that’s changed since the last save. Well, I wanted to recreate that functionality, but hopefully in a really simple way.
The good news is, it’s actually pretty easy. I have two ways of doing it, pick the one you like best.
module AutoReload @mes = {} def reload! diffs = AutoReload.differences # we can only call it once per reload, obviously if diffs.size > 0 diffs.each {|f| Kernel.load(f)} puts "reloaded #{diffs.size} file(s): #{diffs.join(', ')}" else puts "nothing to reload" end end def self.update_modtimes $".each do |f| @mes[f] = File.mtime(f) if File.exists?(f) end end def self.differences oldlist = @mes.clone AutoReload.update_modtimes newlist = @mes.clone oldlist.delete_if {|key, value| newlist[key] == value } oldlist.keys.uniq end end include AutoReload
You will then need to initialise it somewhere after all your requires. AutoReload.update_modtimes
will do the trick. If you can’t manage that, it will only work properly after the first time you use reload!
.
This is the way to do it if you have a lot of files, I think, since it maintains a list of what was changed when, and then only reloads changed files.
Note that it’s not perfect. It will only be able to find files which are in local path, ie won’t be able to reload gems. However, that’s all I need for now.
The next way is even simpler, since it doesn’t bother to maintain a list – it just blindly reloads everything it can:
def reload! diffs = [] $".each {|f| diffs << f if File.exists?(f)} if diffs.size > 0 diffs.each {|f| Kernel.load(f)} puts "reloaded #{diffs.size} file(s): #{diffs.join(', ')}" else puts "nothing to reload" end end
As you can see, this just blindly reloads everything it can find. Probably not the best if you have a lot of constants etc, but for a simple project could be just the ticket. The good news is you don’t need to initialise it. if you have a lot of files you probably should return "OK"
or something, else you’ll have pages of reloads scrolling past.
Let’s bear in mind that this kind of trick is always a bit of a hack. Kernel.load() has no ability to unload anything, even if it doesn’t appear in the file anymore. All it can do is overwrite. If you break your code by deleting something important, then reloading using this kind of trick won’t show it up – the object is still there until you reload ruby itself. It’s a convenience thing only, so don’t rely on it too much, do a full reload once in a while.
However, for my use case – making a lot of small changes and working in a very interactive manner with irb – this is a real time-saver, hope you find it useful too.
If you’d prefer it to happen automatically, rspec-style, there is a gem available which will do this for you here which basically does the same thing, just every 1 second instead of manually.