Skip to content

Instantly share code, notes, and snippets.

@simonoff
Forked from josevalim/1_README.md
Created December 13, 2011 12:33
Show Gist options
  • Save simonoff/1471983 to your computer and use it in GitHub Desktop.
Save simonoff/1471983 to your computer and use it in GitHub Desktop.
FSSM based FileWatcher for Rails

Rails 3.2 ships with a simple FileWatcher that only reloads your app if any of the files changed.

Besides, it also provides a mechanism to hook up your own file watcher mechanism, so we can use tools like FSSM that hooks into Mac OS X fsevents and does the hard work for us. This is an example on how to hook your own mechanism (you need Rails master, soon to be Rails 3.2):

  1. Copy the 2_file_watcher.rb file below to lib/file_watcher.rb

  2. Add the following inside your Application in config/application.rb

    if Rails.env.development? require "file_watcher" config.file_watcher = FileWatcher end

  3. Add to your Gemfile

    group :development do gem "fssm" end

  4. Profit!

More information about this behavior can be read on ActiveSupport::FileUpdateChecker

Note: if you are using Windows (or any operating system that does not have filesystem events supported by FSSM), you should stick with Rails implementation as it is checks for timestamps just when required instead of having a pooling thread.

# From: https://gist.github.com/1471391
# Copyright José Valim 2011 MIT-LICENSE
require "active_support/core_ext/array/wrap"
require "active_support/core_ext/array/extract_options"
require "fssm"
class FileWatcher
def initialize(files, dirs={}, &block)
@block = block
@last_update_at = Time.at(0)
@updated_at = Time.at(0)
start_monitor(files, dirs) { |base, relative| update(base, relative) }
end
def updated?
raise "Error on FileWatcher. FSSM thread is dead." unless @thread.alive?
@updated_at > @last_update_at
end
def execute_if_updated
if updated?
execute
true
else
false
end
end
def execute
@last_update_at = @updated_at
@block.call
end
private
def update(base, relative)
timestamp = File.mtime(File.join(base, relative))
@updated_at = timestamp if timestamp > @updated_at
end
def compile_glob(exts)
array = Array.wrap(array)
return "**/*" if array.empty?
"**/*.{#{array.join(",")}}"
end
def start_monitor(files, dirs, &block)
exprs = Hash.new { |h,k| h[k] = [] }
files.each do |file|
exprs[File.dirname(file)] << File.basename(file)
end
dirs.each do |dir, exts|
exprs[dir] << compile_glob(exts)
end
files.freeze
dirs.freeze
@monitor = FSSM::Monitor.new
exprs.each do |dir, globs|
@monitor.path dir do
glob "{#{globs.join(",")}}"
update(&block)
create(&block)
end
end
@thread = Thread.new { @monitor.run }
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment