Skip to content

Commit

Permalink
Update to Guard 2.0 + some refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
thibaudgg committed Oct 6, 2013
1 parent 5304fd2 commit ea244f3
Show file tree
Hide file tree
Showing 12 changed files with 160 additions and 173 deletions.
10 changes: 1 addition & 9 deletions .travis.yml
@@ -1,22 +1,14 @@
language: ruby language: ruby
bundler_args: --without development bundler_args: --without development
rvm: rvm:
- 1.8.7
- 1.9.3 - 1.9.3
- 2.0.0 - 2.0.0
- ruby-head
- ree
- jruby-18mode
- jruby-19mode - jruby-19mode
- jruby-head
- rbx-18mode
- rbx-19mode - rbx-19mode
matrix: matrix:
allow_failures: allow_failures:
- rvm: rbx-18mode - jruby-19mode
- rvm: rbx-19mode - rvm: rbx-19mode
- rvm: ruby-head
- rvm: jruby-head
notifications: notifications:
recipients: recipients:
- thibaud@thibaud.me - thibaud@thibaud.me
2 changes: 1 addition & 1 deletion Gemfile
Expand Up @@ -11,5 +11,5 @@ end


group :test do group :test do
gem 'rspec' gem 'rspec'
gem 'coveralls', :require => false gem 'coveralls', require: false
end end
4 changes: 2 additions & 2 deletions Guardfile
@@ -1,5 +1,5 @@
guard 'rspec', :cli => '-f doc' do guard :rspec do
watch(%r{spec/.+_spec.rb}) watch(%r{spec/.+_spec.rb})
watch(%r{lib/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" } watch(%r{lib/(.+)\.rb}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" } watch('spec/spec_helper.rb') { "spec" }
end end
20 changes: 11 additions & 9 deletions README.md
@@ -1,4 +1,6 @@
# Guard::LiveReload [![Gem Version](https://badge.fury.io/rb/guard-livereload.png)](http://badge.fury.io/rb/guard-livereload) [![Build Status](https://travis-ci.org/guard/guard-livereload.png?branch=master)](http://travis-ci.org/guard/guard-livereload) [![Dependency Status](https://gemnasium.com/guard/guard-livereload.png)](https://gemnasium.com/guard/guard-livereload) [![Code Climate](https://codeclimate.com/github/guard/guard-livereload.png)](https://codeclimate.com/github/guard/guard-livereload) [![Coverage Status](https://coveralls.io/repos/guard/guard-livereload/badge.png?branch=master)](https://coveralls.io/r/guard/guard-livereload) # Guard::LiveReload

[![Gem Version](https://badge.fury.io/rb/guard-livereload.png)](http://badge.fury.io/rb/guard-livereload) [![Build Status](https://travis-ci.org/guard/guard-livereload.png?branch=master)](http://travis-ci.org/guard/guard-livereload) [![Dependency Status](https://gemnasium.com/guard/guard-livereload.png)](https://gemnasium.com/guard/guard-livereload) [![Code Climate](https://codeclimate.com/github/guard/guard-livereload.png)](https://codeclimate.com/github/guard/guard-livereload) [![Coverage Status](https://coveralls.io/repos/guard/guard-livereload/badge.png?branch=master)](https://coveralls.io/r/guard/guard-livereload)


LiveReload guard allows to automatically reload your browser when 'view' files are modified. LiveReload guard allows to automatically reload your browser when 'view' files are modified.


Expand Down Expand Up @@ -34,12 +36,12 @@ Use [rack-livereload](https://github.com/johnbintz/rack-livereload) or install [


## Usage ## Usage


Please read [Guard usage doc](http://github.com/guard/guard#readme) and [rack-livereload how it works readme section](https://github.com/johnbintz/rack-livereload#readme) or [LiveReload extension usage doc](http://github.com/mockko/livereload#readme) Please read [Guard usage doc](https://github.com/guard/guard#readme) and [rack-livereload how it works readme section](https://github.com/johnbintz/rack-livereload#readme) or [LiveReload extension usage doc](http://github.com/mockko/livereload#readme)


## Guardfile ## Guardfile


You can adapt your 'view' files like you want. You can adapt your 'view' files like you want.
Please read [Guard doc](http://github.com/guard/guard#readme) for more info about Guardfile DSL. Please read [Guard doc](https://github.com/guard/guard#readme) for more info about Guardfile DSL.


``` ruby ``` ruby
guard 'livereload' do guard 'livereload' do
Expand All @@ -65,14 +67,14 @@ end
Available options: Available options:


``` ruby ``` ruby
:host => '127.3.3.1' # default '0.0.0.0' host: '127.3.3.1' # default '0.0.0.0'
:port => '12345' # default '35729' port: '12345' # default '35729'
:apply_css_live => false # default true apply_css_live: false # default true
:override_url => false # default false override_url: false # default false
:grace_period => 0.5 # default 0 (seconds) grace_period: 0.5 # default 0 (seconds)
``` ```


See [LiveReload configuration doc](http://github.com/mockko/livereload#readme) for more info about those options. See [LiveReload configuration doc](https://github.com/mockko/livereload#readme) for more info about those options.


## Development ## Development


Expand Down
18 changes: 1 addition & 17 deletions Rakefile
@@ -1,21 +1,5 @@
require 'bundler' require "bundler/gem_tasks"
Bundler::GemHelper.install_tasks


require 'rspec/core/rake_task' require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec) RSpec::Core::RakeTask.new(:spec)
task :default => :spec task :default => :spec

namespace(:spec) do
desc "Run all specs on multiple ruby versions (requires rvm)"
task(:portability) do
%w[1.8.6 1.8.7 1.9.2 ree rbx jruby].each do |version|
system <<-BASH
bash -c 'source ~/.rvm/scripts/rvm;
rvm #{version};
echo "--------- version #{version} ----------\n";
bundle install 1> /dev/null;
rake spec'
BASH
end
end
end
38 changes: 19 additions & 19 deletions guard-livereload.gemspec
@@ -1,27 +1,27 @@
# -*- encoding: utf-8 -*- # coding: utf-8
$:.push File.expand_path("../lib", __FILE__) lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'guard/livereload/version' require 'guard/livereload/version'


Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = "guard-livereload" s.name = "guard-livereload"
s.version = Guard::LiveReloadVersion::VERSION s.version = Guard::LiveReloadVersion::VERSION
s.platform = Gem::Platform::RUBY s.author = 'Thibaud Guillaume-Gentil'
s.authors = ['Thibaud Guillaume-Gentil'] s.email = 'thibaud@thibaud.me'
s.email = ['thibaud@thibaud.me'] s.summary = 'Guard plugin for livereload'
s.homepage = 'http://rubygems.org/gems/guard-livereload' s.description = "Guard::LiveReload automatically reloads your browser when 'view' files are modified."
s.summary = 'Guard gem for livereload' s.homepage = 'https://rubygems.org/gems/guard-livereload'
s.description = "Guard::LiveReload automatically reloads your browser when 'view' files are modified." s.license = "MIT"


s.required_rubygems_version = '>= 1.3.6' s.files = `git ls-files`.split($/)
s.rubyforge_project = "guard-livereload" s.test_files = s.files.grep(%r{^spec/})
s.require_path = 'lib'


s.add_dependency 'guard', '>= 1.8.0' s.add_dependency 'guard', '~> 2.0'
s.add_dependency 'em-websocket', '>= 0.5.0' s.add_dependency 'em-websocket', '~> 0.5'
s.add_dependency 'multi_json', '~> 1.7' s.add_dependency 'multi_json', '~> 1.8'


s.add_development_dependency 'bundler' s.add_development_dependency 'bundler', '>= 1.3.5'
s.add_development_dependency 'rake'
s.add_development_dependency 'rspec' s.add_development_dependency 'rspec'

s.files = Dir.glob('{lib}/**/*') + %w[LICENSE README.md js/livereload.js]
s.require_path = 'lib'
end end
14 changes: 7 additions & 7 deletions lib/guard/livereload.rb
Expand Up @@ -12,15 +12,15 @@ class LiveReload < Guard
# = Guard methods = # = Guard methods =
# ================= # =================


def initialize(watchers = [], options = {}) def initialize(options = {})
super super
@options = { @options = {
:host => '0.0.0.0', host: '0.0.0.0',
:port => '35729', port: '35729',
:apply_css_live => true, apply_css_live: true,
:override_url => false, override_url: false,
:grace_period => 0 grace_period: 0
}.update(options) }.merge(options)
end end


def start def start
Expand Down
87 changes: 45 additions & 42 deletions lib/guard/livereload/reactor.rb
Expand Up @@ -8,7 +8,7 @@ class Reactor
def initialize(options) def initialize(options)
@web_sockets = [] @web_sockets = []
@options = options @options = options
@thread = start_threaded_reactor(options) @thread = Thread.new { _start_reactor }
end end


def stop def stop
Expand All @@ -18,58 +18,61 @@ def stop
def reload_browser(paths = []) def reload_browser(paths = [])
UI.info "Reloading browser: #{paths.join(' ')}" UI.info "Reloading browser: #{paths.join(' ')}"
paths.each do |path| paths.each do |path|
data = { data = _data(path)
:command => 'reload', UI.debug(data)
:path => "#{Dir.pwd}/#{path}",
:liveCSS => @options[:apply_css_live]
}
if options[:override_url] && File.exist?(path)
data[:overrideURL] = '/' + path
end
UI.debug data
web_sockets.each { |ws| ws.send(MultiJson.encode(data)) } web_sockets.each { |ws| ws.send(MultiJson.encode(data)) }
end end
end end


private private


def start_threaded_reactor(options) def _data(path)
Thread.new do data = {
EventMachine.epoll command: 'reload',
EventMachine.run do path: "#{Dir.pwd}/#{path}",
UI.info "LiveReload is waiting for a browser to connect." liveCSS: options[:apply_css_live]
EventMachine.start_server(options[:host], options[:port], WebSocket, {}) do |ws| }
ws.onopen do if options[:override_url] && File.exist?(path)
begin data[:overrideURL] = '/' + path
UI.info "Browser connected." end
ws.send MultiJson.encode({ data
:command => 'hello', end
:protocols => ['http://livereload.com/protocols/official-7'],
:serverName => 'guard-livereload'
})
@web_sockets << ws
rescue
UI.errror $!
UI.errror $!.backtrace
end
end

ws.onmessage do |msg|
msg = MultiJson.decode(msg)
if msg['command'] == 'url'
UI.info "Browser URL: #{msg['url']}"
end
end


ws.onclose do def _start_reactor
@web_sockets.delete(ws) EventMachine.epoll
UI.info "Browser disconnected." EventMachine.run do
end UI.info "LiveReload is waiting for a browser to connect."
end EventMachine.start_server(options[:host], options[:port], WebSocket) do |ws|
ws.onopen &_on_open
ws.onmessage &_on_message
ws.onmessage &_on_close
end end
end end
end end


def _on_open
UI.info "Browser connected."
self.send MultiJson.encode(
command: 'hello',
protocols: ['http://livereload.com/protocols/official-7'],
serverName: 'guard-livereload'
)
@web_sockets << self
rescue
UI.errror $!
UI.errror $!.backtrace
end

def _on_message(message)
message = MultiJson.decode(message)
UI.info"Browser URL: #{message['url']}" if message['command'] == 'url'
end

def _on_close
UI.info "Browser disconnected."
@web_sockets.delete(self)
end

end end
end end
end end
28 changes: 19 additions & 9 deletions lib/guard/livereload/websocket.rb
@@ -1,37 +1,47 @@
require 'eventmachine' require 'eventmachine'
require 'em-websocket' require 'em-websocket'
require "http/parser" require 'http/parser'


module Guard module Guard
class LiveReload class LiveReload
class WebSocket < EventMachine::WebSocket::Connection class WebSocket < EventMachine::WebSocket::Connection
def dispatch data
def dispatch(data)
parser = Http::Parser.new parser = Http::Parser.new
parser << data parser << data
if parser.http_method != 'GET' || parser.upgrade? if parser.http_method != 'GET' || parser.upgrade?
super #pass the request to websocket super #pass the request to websocket
elsif parser.request_path == '/livereload.js' elsif parser.request_path == '/livereload.js'
serve_file File.expand_path("../../../../js/livereload.js", __FILE__) _serve_file(_livereload_js_file)
elsif File.exist?(parser.request_path[1..-1]) elsif File.exist?(parser.request_path[1..-1])
serve_file parser.request_path[1..-1] # Strip leading slash _serve_file(parser.request_path[1..-1]) # Strip leading slash
else else
send_data "HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 13\r\n\r\n404 Not Found" send_data("HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 13\r\n\r\n404 Not Found")
close_connection_after_writing close_connection_after_writing
end end
end end


def serve_file path private

def _serve_file(path)
UI.debug "Serving file #{path}" UI.debug "Serving file #{path}"
content_type = case File.extname(path) send_data "HTTP/1.1 200 OK\r\nContent-Type: #{_content_type(path)}\r\nContent-Length: #{File.size path}\r\n\r\n"
stream_file_data(path).callback { close_connection_after_writing }
end

def _content_type(path)
case File.extname(path)
when '.css' then 'text/css' when '.css' then 'text/css'
when '.js' then 'application/ecmascript' when '.js' then 'application/ecmascript'
when '.gif' then 'image/gif' when '.gif' then 'image/gif'
when '.jpeg', '.jpg' then 'image/jpeg' when '.jpeg', '.jpg' then 'image/jpeg'
when '.png' then 'image/png' when '.png' then 'image/png'
else; 'text/plain' else; 'text/plain'
end end
send_data "HTTP/1.1 200 OK\r\nContent-Type: #{content_type}\r\nContent-Length: #{File.size path}\r\n\r\n" end
stream_file_data(path).callback { close_connection_after_writing }
def _livereload_js_file
File.expand_path("../../../../js/livereload.js", __FILE__)
end end


end end
Expand Down
11 changes: 6 additions & 5 deletions spec/lib/guard/livereload/reactor_spec.rb
Expand Up @@ -2,28 +2,29 @@


describe Guard::LiveReload::Reactor do describe Guard::LiveReload::Reactor do
let(:paths) { %w[stylesheets/layout.css stylesheets/style.css] } let(:paths) { %w[stylesheets/layout.css stylesheets/style.css] }
before { Guard::UI.stub(:info) }


describe "#reload_browser(paths = [])" do describe "#reload_browser(paths = [])" do
it "displays a message" do it "displays a message" do
Guard::UI.should_receive(:info).with("Reloading browser: stylesheets/layout.css stylesheets/style.css") expect(Guard::UI).to receive(:info).with("Reloading browser: stylesheets/layout.css stylesheets/style.css")
new_live_reactor.reload_browser(paths) new_live_reactor.reload_browser(paths)
end end


it "each web socket receives send with data containing default options for each path modified" do it "each web socket receives send with data containing default options for each path modified" do
reactor = new_live_reactor reactor = new_live_reactor
paths.each do |path| paths.each do |path|
reactor.web_sockets.each do |ws| reactor.web_sockets.each do |ws|
ws.should_receive(:send).with(MultiJson.encode(['refresh', { :path => "#{Dir.pwd}/#{path}", :apply_js_live => true, :apply_css_live => true }])) expect(ws).to receive(:send).with(MultiJson.encode(['refresh', path: "#{Dir.pwd}/#{path}", apply_js_live: true, apply_css_live: true]))
end end
end end
reactor.reload_browser(paths) reactor.reload_browser(paths)
end end


it "each web socket receives send with data containing custom options for each path modified" do it "each web socket receives send with data containing custom options for each path modified" do
reactor = new_live_reactor(:apply_css_live => false, :apply_js_live => false) reactor = new_live_reactor(apply_css_live: false, apply_js_live: false)
paths.each do |path| paths.each do |path|
reactor.web_sockets.each do |ws| reactor.web_sockets.each do |ws|
ws.should_receive(:send).with(MultiJson.encode(['refresh', { :path => "#{Dir.pwd}/#{path}", :apply_js_live => false, :apply_css_live => false }])) expect(ws).to receive(:send).with(MultiJson.encode(['refresh', path: "#{Dir.pwd}/#{path}", apply_js_live: false, apply_css_live: false]))
end end
end end
reactor.reload_browser(paths) reactor.reload_browser(paths)
Expand All @@ -33,5 +34,5 @@
end end


def new_live_reactor(options = {}) def new_live_reactor(options = {})
Guard::LiveReload::Reactor.new({ :api_version => '1.6', :host => '0.0.0.0', :port => '35729', :apply_js_live => true, :apply_css_live => true, :grace_period => 0 }.merge(options)) Guard::LiveReload::Reactor.new({ api_version: '1.6', host: '0.0.0.0', port: '35729', apply_js_live: true, apply_css_live: true, grace_period: 0 }.merge(options))
end end

0 comments on commit ea244f3

Please sign in to comment.