rrichards
7/21/2010 - 7:06 PM

_notes.md

A replacement for "livereload" gem on OS X

This script is a replacement for livereload server component designed for working with Rails. It watches the filesystem with FS Events (Mac OS X) rather than with EventMachine. This is better for large projects for wich EventMachine fails with "too many open files" exception.

Sass is supported; .sass files can also be stored in "app/styles/" directory.

Command line options are "-D" to enable debug mode. All other parameters (if given) specify a list of directories to watch. This is not compatible with livereload gem, which supports many more options and customization. If you want customization, edit this script. It's simple.

Visit the official livereload project for instructions on how to install the browser component.

#!/usr/bin/ruby -rubygems

# Replacement for "livereload" gem for working with Rails
#
# Dependencies:
#   $ sudo /usr/bin/gem install mislav-rspactor em-websocket json haml

# uncomment to force loading the correct rspactor version
# gem 'mislav-rspactor', '~> 0.4.0'
require 'rspactor'
require 'em-websocket'
require 'json'
require 'sass/plugin'

API_VERSION = '1.3'

web_sockets = []
debug = !!ARGV.delete('-D')
dirs = ARGV.empty?? [Dir.pwd] : ARGV

Sass::Plugin.add_template_location(Dir.pwd + '/app/styles')

listener = RSpactor::Listener.new(:extensions => %w[html erb haml sass css js], :relative_paths => false) { |files|
  for file in files
    case file
    when %r{/app/.+\.(erb|haml)$}, %r{/public/.+\.(css|js|html)$}
      data = ['refresh', { :path => file, :apply_js_live  => false, :apply_css_live => true }].to_json
      puts data if debug
      web_sockets.each do |ws|
        ws.send data
      end
    when %r{\.sass$}
      Sass::Plugin.update_stylesheets
    end
  end
}

Sass::Plugin.on_updating_stylesheet do |template, css|
  listener.force_changed << File.expand_path(css, Dir.pwd)
end

EventMachine.run do
  puts "LiveReload is waiting for a browser to connect."
  EventMachine::WebSocket.start(:host => '0.0.0.0', :port => '10083', :debug => debug) do |ws|
    ws.onopen do
      begin
        puts "Browser connected."
        ws.send "!!ver:#{API_VERSION}"
        web_sockets << ws
      rescue
        puts $!
        puts $!.backtrace
      end
    end
  
    ws.onmessage do |msg|
      puts "Browser URL: #{msg}"
    end
  
    ws.onclose do
      web_sockets.delete ws
      puts "Browser disconnected."
    end
  end
  
  puts "Starting file watcher for directories: #{dirs.inspect}"
  listener.start(dirs)
  
  # Disable the RubyCocoa thread hook as apparently Laurent did not apply the
  # thread patches to the OS X system Ruby
  ENV['RUBYCOCOA_THREAD_HOOK_DISABLE'] = 'kampai'
  
  Thread.new { OSX.CFRunLoopRun }
end