From 1960a80a092417032b14d89778f60f6a491ac7fa Mon Sep 17 00:00:00 2001 From: Cezary Baginski Date: Sun, 18 Oct 2015 23:52:01 +0200 Subject: [PATCH 1/2] allow custom js file (including ERB syntax) --- README.md | 1 + js/{livereload.js => livereload.js.erb} | 3 +- lib/guard/livereload.rb | 9 +++- lib/guard/livereload/reactor.rb | 7 ++- lib/guard/livereload/snippet.rb | 23 +++++++++ lib/guard/livereload/websocket.rb | 11 +++-- spec/lib/guard/livereload/snippet_spec.rb | 45 ++++++++++++++++++ spec/lib/guard/livereload_spec.rb | 58 +++++++++++++++++++++-- 8 files changed, 148 insertions(+), 9 deletions(-) rename js/{livereload.js => livereload.js.erb} (99%) create mode 100644 lib/guard/livereload/snippet.rb create mode 100644 spec/lib/guard/livereload/snippet_spec.rb diff --git a/README.md b/README.md index 7fd65dd..2e8bcb7 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ port: '12345' # default '35729' apply_css_live: false # default true override_url: false # default false grace_period: 0.5 # default 0 (seconds) +js_template: './my_livereload.js.erb' # default is livereload.js.erb from gem ``` `notify` uses Guard's [system notifications](https://github.com/guard/guard/wiki/System-notifications). diff --git a/js/livereload.js b/js/livereload.js.erb similarity index 99% rename from js/livereload.js rename to js/livereload.js.erb index 1fa691b..46f0566 100644 --- a/js/livereload.js +++ b/js/livereload.js.erb @@ -1,3 +1,4 @@ +// <%= "guard-livereload options: #{options.inspect}" %> (function() { var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __options = {}, __reloader = {}, __livereload = {}, __less = {}, __startup = {}; @@ -1052,4 +1053,4 @@ CustomEvents.bind(document, 'LiveReloadShutDown', function() { return LiveReload.shutDown(); }); - })(); \ No newline at end of file + })(); diff --git a/lib/guard/livereload.rb b/lib/guard/livereload.rb index 449ae06..d8a55a7 100644 --- a/lib/guard/livereload.rb +++ b/lib/guard/livereload.rb @@ -4,18 +4,25 @@ module Guard class LiveReload < Plugin require 'guard/livereload/websocket' require 'guard/livereload/reactor' + require 'guard/livereload/snippet' attr_accessor :reactor, :options def initialize(options = {}) super + + js_path = File.expand_path('../../../js/livereload.js.erb', __FILE__) @options = { host: '0.0.0.0', port: '35729', apply_css_live: true, override_url: false, - grace_period: 0 + grace_period: 0, + js_template: js_path }.merge(options) + + js_path = @options[:js_template] + @options[:livereload_js_path] = Snippet.new(js_path, @options).path end def start diff --git a/lib/guard/livereload/reactor.rb b/lib/guard/livereload/reactor.rb index 659be47..1a3e1cc 100644 --- a/lib/guard/livereload/reactor.rb +++ b/lib/guard/livereload/reactor.rb @@ -48,7 +48,12 @@ def _start_reactor EventMachine.epoll if EventMachine.epoll? EventMachine.kqueue if EventMachine.kqueue? EventMachine.run do - EventMachine.start_server(options[:host], options[:port], WebSocket, {}) do |ws| + EventMachine.start_server( + options[:host], + options[:port], + WebSocket, + options + ) do |ws| ws.onopen { _connect(ws) } ws.onclose { _disconnect(ws) } ws.onmessage { |msg| _print_message(msg) } diff --git a/lib/guard/livereload/snippet.rb b/lib/guard/livereload/snippet.rb new file mode 100644 index 0000000..108dbee --- /dev/null +++ b/lib/guard/livereload/snippet.rb @@ -0,0 +1,23 @@ +require 'erb' +require 'tempfile' + +require 'guard/compat/plugin' + +module Guard + class LiveReload < Plugin + class Snippet + attr_reader :path + attr_reader :options + + def initialize(template, options) + @options = options # for ERB context + tmpfile = Tempfile.new('livereload.js') + source = IO.read(template) + data = ERB.new(source).result(binding) + tmpfile.write(data) + tmpfile.close + @path = tmpfile.path + end + end + end +end diff --git a/lib/guard/livereload/websocket.rb b/lib/guard/livereload/websocket.rb index 620e2e6..38d1766 100644 --- a/lib/guard/livereload/websocket.rb +++ b/lib/guard/livereload/websocket.rb @@ -6,6 +6,11 @@ module Guard class LiveReload class WebSocket < EventMachine::WebSocket::Connection + def initialize(options) + @livereload_js_path = options[:livereload_js_path] + super + end + def dispatch(data) parser = Http::Parser.new parser << data @@ -47,12 +52,12 @@ def _content_type(path) end end - def _livereload_js_file - File.expand_path('../../../../js/livereload.js', __FILE__) + def _livereload_js_path + @livereload_js_path end def _serve(path) - return _serve_file(_livereload_js_file) if path == './livereload.js' + return _serve_file(_livereload_js_path) if path == './livereload.js' return _serve_file(path) if _readable_file(path) 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 diff --git a/spec/lib/guard/livereload/snippet_spec.rb b/spec/lib/guard/livereload/snippet_spec.rb new file mode 100644 index 0000000..66db77a --- /dev/null +++ b/spec/lib/guard/livereload/snippet_spec.rb @@ -0,0 +1,45 @@ +RSpec.describe Guard::LiveReload::Snippet do + let(:options) { { foo: :bar } } + + let(:template) { '/foo/livereload.js.erb' } + let(:contents) { '// <%= options[:foo] %>' } + + subject { described_class.new(template, options) } + + let(:tmpfile) { instance_double(Tempfile) } + + before do + allow(File).to receive(:expand_path) do |*args| + fail "stub called for File.expand_path(#{args.map(&:inspect) * ','})" + end + + allow(IO).to receive(:read) do |*args| + fail "stub called for IO.read(#{args.map(&:inspect) * ','})" + end + + allow(IO).to receive(:read).with(template).and_return(contents) + + allow(Tempfile).to receive(:new).and_return(tmpfile) + allow(tmpfile).to receive(:path).and_return('/tmp/livereload-123') + allow(tmpfile).to receive(:write) + allow(tmpfile).to receive(:close) + end + + describe '#initialize' do + it 'evaluates the js snippet file' do + expect(tmpfile).to receive(:write).with('// bar') + subject + end + + it 'closes the tmpfile' do + expect(tmpfile).to receive(:close) + subject + end + end + + describe '#path' do + it 'is set to a tmpfile with the ERB result' do + expect(subject.path).to eq '/tmp/livereload-123' + end + end +end diff --git a/spec/lib/guard/livereload_spec.rb b/spec/lib/guard/livereload_spec.rb index efbdbba..4a09ad0 100644 --- a/spec/lib/guard/livereload_spec.rb +++ b/spec/lib/guard/livereload_spec.rb @@ -3,7 +3,23 @@ RSpec.describe Guard::LiveReload do let(:plugin) { Guard::LiveReload.new } let(:reactor) { double(Guard::LiveReload::Reactor) } - before { allow(plugin).to receive(:reactor) { reactor } } + + let(:tmp_path) { '/tmp/livereload-123' } + let(:snippet) { instance_double(Guard::LiveReload::Snippet, path: tmp_path) } + + before do + allow(File).to receive(:expand_path) do |*args| + fail "stub called for File.expand_path(#{args.map(&:inspect) * ','})" + end + + allow(File).to receive(:expand_path). + with('../../../js/livereload.js.erb', anything). + and_return('/foo/js/livereload.js.erb') + + allow(Guard::LiveReload::Snippet).to receive(:new).and_return(snippet) + + allow(plugin).to receive(:reactor) { reactor } + end describe '#initialize' do describe ':host option' do @@ -65,6 +81,38 @@ expect(plugin.options[:grace_period]).to eq 0.5 end end + + describe ':js_template option' do + subject { described_class.new(*args) } + + context 'when no value is provided' do + let(:args) { [] } + + it 'is set to full path to default JS' do + expect(subject.options[:js_template]).to eq '/foo/js/livereload.js.erb' + end + + it 'evalutes the default snippet' do + expect(Guard::LiveReload::Snippet).to receive(:new). + with('/foo/js/livereload.js.erb', anything).and_return(snippet) + subject + end + end + + context 'with a custom path' do + let(:args) { [js_template: 'foo/bar.js.erb'] } + + it 'is set to the given JS' do + expect(subject.options[:js_template]).to eq 'foo/bar.js.erb' + end + + it 'evalutes the provided snippet' do + expect(Guard::LiveReload::Snippet).to receive(:new). + with('foo/bar.js.erb', anything).and_return(snippet) + subject + end + end + end end describe '#start' do @@ -75,7 +123,9 @@ port: '35729', apply_css_live: true, override_url: false, - grace_period: 0 + grace_period: 0, + js_template: '/foo/js/livereload.js.erb', + livereload_js_path: '/tmp/livereload-123' ) plugin.start end @@ -87,7 +137,9 @@ port: '12345', apply_css_live: false, override_url: true, - grace_period: 1 + grace_period: 1, + js_template: '/foo/js/livereload.js.erb', + livereload_js_path: '/tmp/livereload-123' ) plugin.start end From cbd86a6b7af01b315372f3fd7e0df5f1f18fd39c Mon Sep 17 00:00:00 2001 From: Cezary Baginski Date: Mon, 19 Oct 2015 00:20:38 +0200 Subject: [PATCH 2/2] allow setting additionalWaitingTime in Guardfile See issue #123 for more info about the workaround --- README.md | 7 +++++++ js/livereload.js.erb | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2e8bcb7..2ab1cc9 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,13 @@ grace_period: 0.5 # default 0 (seconds) js_template: './my_livereload.js.erb' # default is livereload.js.erb from gem ``` +Additional custom JS template options (see livereload.js.erb for details): +``` ruby +js_apple_webkit_extra_wait_time: 50 # default is 5 (see issue #123) +js_default_extra_wait_time: 100 # default is 200 +``` + + `notify` uses Guard's [system notifications](https://github.com/guard/guard/wiki/System-notifications). See [LiveReload configuration doc](https://github.com/mockko/livereload/blob/master/README-old.md) from version 1.x for more info about other options. diff --git a/js/livereload.js.erb b/js/livereload.js.erb index 46f0566..12ac9cc 100644 --- a/js/livereload.js.erb +++ b/js/livereload.js.erb @@ -733,9 +733,9 @@ return this.waitUntilCssLoads(clone, function() { var additionalWaitingTime; if (/AppleWebKit/.test(navigator.userAgent)) { - additionalWaitingTime = 5; + additionalWaitingTime = <%= options[:js_apple_webkit_extra_wait_time] || 5 %>; } else { - additionalWaitingTime = 200; + additionalWaitingTime = <%= options[:js_default_extra_wait_time] || 200 %>; } return _this.Timer.start(additionalWaitingTime, function() { var _ref;