guard-livereload 2.4.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,5 +1,21 @@
1
1
  require "bundler/gem_tasks"
2
2
 
3
- require 'rspec/core/rake_task'
4
- RSpec::Core::RakeTask.new(:spec)
5
- task :default => :spec
3
+ require "rspec/core/rake_task"
4
+
5
+ def ci?
6
+ ENV["CI"] == "true"
7
+ end
8
+
9
+ RSpec::Core::RakeTask.new(:spec) do |t|
10
+ t.verbose = ci?
11
+ end
12
+
13
+ default_tasks = [:spec]
14
+
15
+ unless ci?
16
+ require "rubocop/rake_task"
17
+ RuboCop::RakeTask.new(:rubocop)
18
+ default_tasks << :rubocop
19
+ end
20
+
21
+ task default: default_tasks
@@ -4,24 +4,23 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'guard/livereload/version'
5
5
 
6
6
  Gem::Specification.new do |s|
7
- s.name = "guard-livereload"
7
+ s.name = 'guard-livereload'
8
8
  s.version = Guard::LiveReloadVersion::VERSION
9
9
  s.author = 'Thibaud Guillaume-Gentil'
10
10
  s.email = 'thibaud@thibaud.me'
11
11
  s.summary = 'Guard plugin for livereload'
12
12
  s.description = "Guard::LiveReload automatically reloads your browser when 'view' files are modified."
13
13
  s.homepage = 'https://rubygems.org/gems/guard-livereload'
14
- s.license = "MIT"
14
+ s.license = 'MIT'
15
15
 
16
16
  s.files = `git ls-files`.split($/)
17
17
  s.test_files = s.files.grep(%r{^spec/})
18
18
  s.require_path = 'lib'
19
19
 
20
20
  s.add_dependency 'guard', '~> 2.8'
21
+ s.add_dependency 'guard-compat', '~> 1.0'
21
22
  s.add_dependency 'em-websocket', '~> 0.5'
22
23
  s.add_dependency 'multi_json', '~> 1.8'
23
24
 
24
25
  s.add_development_dependency 'bundler', '>= 1.3.5'
25
- s.add_development_dependency 'rake'
26
- s.add_development_dependency 'rspec'
27
26
  end
@@ -1,3 +1,4 @@
1
+ // <%= "guard-livereload options: #{options.inspect}" %>
1
2
  (function() {
2
3
  var __customevents = {}, __protocol = {}, __connector = {}, __timer = {}, __options = {}, __reloader = {}, __livereload = {}, __less = {}, __startup = {};
3
4
 
@@ -732,9 +733,9 @@
732
733
  return this.waitUntilCssLoads(clone, function() {
733
734
  var additionalWaitingTime;
734
735
  if (/AppleWebKit/.test(navigator.userAgent)) {
735
- additionalWaitingTime = 5;
736
+ additionalWaitingTime = <%= options[:js_apple_webkit_extra_wait_time] || 5 %>;
736
737
  } else {
737
- additionalWaitingTime = 200;
738
+ additionalWaitingTime = <%= options[:js_default_extra_wait_time] || 200 %>;
738
739
  }
739
740
  return _this.Timer.start(additionalWaitingTime, function() {
740
741
  var _ref;
@@ -1052,4 +1053,4 @@
1052
1053
  CustomEvents.bind(document, 'LiveReloadShutDown', function() {
1053
1054
  return LiveReload.shutDown();
1054
1055
  });
1055
- })();
1056
+ })();
@@ -1,22 +1,28 @@
1
- require 'guard'
2
- require 'guard/plugin'
1
+ require 'guard/compat/plugin'
3
2
 
4
3
  module Guard
5
4
  class LiveReload < Plugin
6
5
  require 'guard/livereload/websocket'
7
6
  require 'guard/livereload/reactor'
7
+ require 'guard/livereload/snippet'
8
8
 
9
9
  attr_accessor :reactor, :options
10
10
 
11
11
  def initialize(options = {})
12
12
  super
13
+
14
+ js_path = File.expand_path('../../../js/livereload.js.erb', __FILE__)
13
15
  @options = {
14
16
  host: '0.0.0.0',
15
17
  port: '35729',
16
18
  apply_css_live: true,
17
19
  override_url: false,
18
- grace_period: 0
20
+ grace_period: 0,
21
+ js_template: js_path
19
22
  }.merge(options)
23
+
24
+ js_path = @options[:js_template]
25
+ @options[:livereload_js_path] = Snippet.new(js_path, @options).path
20
26
  end
21
27
 
22
28
  def start
@@ -31,6 +37,5 @@ module Guard
31
37
  sleep options[:grace_period]
32
38
  reactor.reload_browser(paths)
33
39
  end
34
-
35
40
  end
36
41
  end
@@ -18,19 +18,19 @@ module Guard
18
18
 
19
19
  def reload_browser(paths = [])
20
20
  msg = "Reloading browser: #{paths.join(' ')}"
21
- UI.info msg
21
+ Compat::UI.info msg
22
22
  if options[:notify]
23
- Notifier.notify(msg, title: 'Reloading browser', image: :success)
23
+ Compat::UI.notify(msg, title: 'Reloading browser', image: :success)
24
24
  end
25
25
 
26
26
  paths.each do |path|
27
27
  data = _data(path)
28
- UI.debug(data)
28
+ Compat::UI.debug(data)
29
29
  web_sockets.each { |ws| ws.send(MultiJson.encode(data)) }
30
30
  end
31
31
  end
32
32
 
33
- private
33
+ private
34
34
 
35
35
  def _data(path)
36
36
  data = {
@@ -45,20 +45,26 @@ module Guard
45
45
  end
46
46
 
47
47
  def _start_reactor
48
- EventMachine.epoll
48
+ EventMachine.epoll if EventMachine.epoll?
49
+ EventMachine.kqueue if EventMachine.kqueue?
49
50
  EventMachine.run do
50
- EventMachine.start_server(options[:host], options[:port], WebSocket, {}) do |ws|
51
+ EventMachine.start_server(
52
+ options[:host],
53
+ options[:port],
54
+ WebSocket,
55
+ options
56
+ ) do |ws|
51
57
  ws.onopen { _connect(ws) }
52
58
  ws.onclose { _disconnect(ws) }
53
59
  ws.onmessage { |msg| _print_message(msg) }
54
60
  end
55
- UI.info "LiveReload is waiting for a browser to connect."
61
+ Compat::UI.info 'LiveReload is waiting for a browser to connect.'
56
62
  end
57
63
  end
58
64
 
59
65
  def _connect(ws)
60
66
  @connections_count += 1
61
- UI.info "Browser connected." if connections_count == 1
67
+ Compat::UI.info 'Browser connected.' if connections_count == 1
62
68
 
63
69
  ws.send MultiJson.encode(
64
70
  command: 'hello',
@@ -67,8 +73,8 @@ module Guard
67
73
  )
68
74
  @web_sockets << ws
69
75
  rescue
70
- UI.error $!
71
- UI.error $!.backtrace
76
+ Compat::UI.error $!
77
+ Compat::UI.error $!.backtrace
72
78
  end
73
79
 
74
80
  def _disconnect(ws)
@@ -77,9 +83,8 @@ module Guard
77
83
 
78
84
  def _print_message(message)
79
85
  message = MultiJson.decode(message)
80
- UI.info "Browser URL: #{message['url']}" if message['command'] == 'url'
86
+ Compat::UI.info "Browser URL: #{message['url']}" if message['command'] == 'url'
81
87
  end
82
-
83
88
  end
84
89
  end
85
90
  end
@@ -0,0 +1,23 @@
1
+ require 'erb'
2
+ require 'tempfile'
3
+
4
+ require 'guard/compat/plugin'
5
+
6
+ module Guard
7
+ class LiveReload < Plugin
8
+ class Snippet
9
+ attr_reader :path
10
+ attr_reader :options
11
+
12
+ def initialize(template, options)
13
+ @options = options # for ERB context
14
+ tmpfile = Tempfile.new('livereload.js')
15
+ source = IO.read(template)
16
+ data = ERB.new(source).result(binding)
17
+ tmpfile.write(data)
18
+ tmpfile.close
19
+ @path = tmpfile.path
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,8 +1,38 @@
1
1
  guard 'livereload' do
2
- watch(%r{app/views/.+\.(erb|haml|slim)$})
2
+ extensions = {
3
+ css: :css,
4
+ scss: :css,
5
+ sass: :css,
6
+ js: :js,
7
+ coffee: :js,
8
+ html: :html,
9
+ png: :png,
10
+ gif: :gif,
11
+ jpg: :jpg,
12
+ jpeg: :jpeg,
13
+ # less: :less, # uncomment if you want LESS stylesheets done in browser
14
+ }
15
+
16
+ rails_view_exts = %w(erb haml slim)
17
+
18
+ # file types LiveReload may optimize refresh for
19
+ compiled_exts = extensions.values.uniq
20
+ watch(%r{public/.+\.(#{compiled_exts * '|'})})
21
+
22
+ extensions.each do |ext, type|
23
+ watch(%r{
24
+ (?:app|vendor)
25
+ (?:/assets/\w+/(?<path>[^.]+) # path+base without extension
26
+ (?<ext>\.#{ext})) # matching extension (must be first encountered)
27
+ (?:\.\w+|$) # other extensions
28
+ }x) do |m|
29
+ path = m[1]
30
+ "/assets/#{path}.#{type}"
31
+ end
32
+ end
33
+
34
+ # file needing a full reload of the page anyway
35
+ watch(%r{app/views/.+\.(#{rails_view_exts * '|'})$})
3
36
  watch(%r{app/helpers/.+\.rb})
4
- watch(%r{public/.+\.(css|js|html)})
5
37
  watch(%r{config/locales/.+\.yml})
6
- # Rails Assets Pipeline
7
- watch(%r{(app|vendor)(/assets/\w+/(.+\.(css|js|html|png|jpg))).*}) { |m| "/assets/#{m[3]}" }
8
38
  end
@@ -1,5 +1,5 @@
1
1
  module Guard
2
2
  module LiveReloadVersion
3
- VERSION = '2.4.0'
3
+ VERSION = '2.5.0'
4
4
  end
5
5
  end
@@ -6,6 +6,10 @@ require 'uri'
6
6
  module Guard
7
7
  class LiveReload
8
8
  class WebSocket < EventMachine::WebSocket::Connection
9
+ def initialize(options)
10
+ @livereload_js_path = options[:livereload_js_path]
11
+ super
12
+ end
9
13
 
10
14
  def dispatch(data)
11
15
  parser = Http::Parser.new
@@ -14,14 +18,9 @@ module Guard
14
18
  request_path = '.' + URI.parse(parser.request_url).path
15
19
  request_path += '/index.html' if File.directory? request_path
16
20
  if parser.http_method != 'GET' || parser.upgrade?
17
- super #pass the request to websocket
18
- elsif request_path == './livereload.js'
19
- _serve_file(_livereload_js_file)
20
- elsif File.readable?(request_path) && !File.directory?(request_path)
21
- _serve_file(request_path)
21
+ super # pass the request to websocket
22
22
  else
23
- send_data("HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 13\r\n\r\n404 Not Found")
24
- close_connection_after_writing
23
+ _serve(request_path)
25
24
  end
26
25
  end
27
26
 
@@ -29,7 +28,15 @@ module Guard
29
28
 
30
29
  def _serve_file(path)
31
30
  UI.debug "Serving file #{path}"
32
- send_data "HTTP/1.1 200 OK\r\nContent-Type: #{_content_type(path)}\r\nContent-Length: #{File.size path}\r\n\r\n"
31
+
32
+ data = [
33
+ 'HTTP/1.1 200 OK',
34
+ 'Content-Type: %s',
35
+ 'Content-Length: %s',
36
+ '',
37
+ '']
38
+ data = format(data * "\r\n", _content_type(path), File.size(path))
39
+ send_data(data)
33
40
  stream_file_data(path).callback { close_connection_after_writing }
34
41
  end
35
42
 
@@ -45,10 +52,20 @@ module Guard
45
52
  end
46
53
  end
47
54
 
48
- def _livereload_js_file
49
- File.expand_path("../../../../js/livereload.js", __FILE__)
55
+ def _livereload_js_path
56
+ @livereload_js_path
50
57
  end
51
58
 
59
+ def _serve(path)
60
+ return _serve_file(_livereload_js_path) if path == './livereload.js'
61
+ return _serve_file(path) if _readable_file(path)
62
+ send_data("HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: 13\r\n\r\n404 Not Found")
63
+ close_connection_after_writing
64
+ end
65
+
66
+ def _readable_file(path)
67
+ File.readable?(path) && !File.directory?(path)
68
+ end
52
69
  end
53
70
  end
54
71
  end
@@ -1,28 +1,32 @@
1
- require 'spec_helper'
2
-
3
- describe Guard::LiveReload::Reactor do
1
+ RSpec.describe Guard::LiveReload::Reactor do
4
2
  let(:paths) { %w[stylesheets/layout.css stylesheets/style.css] }
5
- before { allow(Guard::UI).to receive(:info) }
6
3
 
7
- describe "#reload_browser(paths = [])" do
8
- it "displays a message" do
9
- expect(Guard::UI).to receive(:info).
4
+ before do
5
+ allow(Guard::Compat::UI).to receive(:info)
6
+ allow(Guard::Compat::UI).to receive(:debug)
7
+ allow(Guard::Compat::UI).to receive(:error)
8
+ allow(Guard::Compat::UI).to receive(:warning)
9
+ end
10
+
11
+ describe '#reload_browser(paths = [])' do
12
+ it 'displays a message' do
13
+ expect(Guard::Compat::UI).to receive(:info).
10
14
  with('Reloading browser: stylesheets/layout.css stylesheets/style.css')
11
15
  new_live_reactor.reload_browser(paths)
12
16
  end
13
17
 
14
18
  it 'by default does not send notification' do
15
- expect(::Guard::Notifier).to_not receive(:notify)
19
+ expect(Guard::Compat::UI).to_not receive(:notify)
16
20
  new_live_reactor.reload_browser(paths)
17
21
  end
18
22
 
19
23
  it 'optionally pushes notification' do
20
- expect(::Guard::Notifier).to receive(:notify).
24
+ expect(Guard::Compat::UI).to receive(:notify).
21
25
  with(kind_of(String), have_key(:title))
22
26
  new_live_reactor(notify: true).reload_browser(paths)
23
27
  end
24
28
 
25
- it "each web socket receives send with data containing default options for each path modified" do
29
+ it 'each web socket receives send with data containing default options for each path modified' do
26
30
  reactor = new_live_reactor
27
31
  paths.each do |path|
28
32
  reactor.web_sockets.each do |ws|
@@ -32,7 +36,7 @@ describe Guard::LiveReload::Reactor do
32
36
  reactor.reload_browser(paths)
33
37
  end
34
38
 
35
- it "each web socket receives send with data containing custom options for each path modified" do
39
+ it 'each web socket receives send with data containing custom options for each path modified' do
36
40
  reactor = new_live_reactor(apply_css_live: false, apply_js_live: false)
37
41
  paths.each do |path|
38
42
  reactor.web_sockets.each do |ws|
@@ -43,20 +47,20 @@ describe Guard::LiveReload::Reactor do
43
47
  end
44
48
  end
45
49
 
46
- describe "#_connect(ws)" do
50
+ describe '#_connect(ws)' do
47
51
  let(:ws) { double.as_null_object }
48
52
  let(:reactor) { new_live_reactor }
49
53
 
50
- it "displays a message once" do
51
- expect(Guard::UI).to receive(:info).with("Browser connected.").once
54
+ it 'displays a message once' do
55
+ expect(Guard::Compat::UI).to receive(:info).with('Browser connected.').once
52
56
  reactor.send(:_connect, ws)
53
57
  reactor.send(:_connect, ws)
54
58
  end
55
59
 
56
- it "increments the connection count" do
57
- expect {
60
+ it 'increments the connection count' do
61
+ expect do
58
62
  reactor.send(:_connect, ws)
59
- }.to change { reactor.connections_count }.from(0).to 1
63
+ end.to change { reactor.connections_count }.from(0).to 1
60
64
  end
61
65
  end
62
66
 
@@ -0,0 +1,45 @@
1
+ RSpec.describe Guard::LiveReload::Snippet do
2
+ let(:options) { { foo: :bar } }
3
+
4
+ let(:template) { '/foo/livereload.js.erb' }
5
+ let(:contents) { '// <%= options[:foo] %>' }
6
+
7
+ subject { described_class.new(template, options) }
8
+
9
+ let(:tmpfile) { instance_double(Tempfile) }
10
+
11
+ before do
12
+ allow(File).to receive(:expand_path) do |*args|
13
+ fail "stub called for File.expand_path(#{args.map(&:inspect) * ','})"
14
+ end
15
+
16
+ allow(IO).to receive(:read) do |*args|
17
+ fail "stub called for IO.read(#{args.map(&:inspect) * ','})"
18
+ end
19
+
20
+ allow(IO).to receive(:read).with(template).and_return(contents)
21
+
22
+ allow(Tempfile).to receive(:new).and_return(tmpfile)
23
+ allow(tmpfile).to receive(:path).and_return('/tmp/livereload-123')
24
+ allow(tmpfile).to receive(:write)
25
+ allow(tmpfile).to receive(:close)
26
+ end
27
+
28
+ describe '#initialize' do
29
+ it 'evaluates the js snippet file' do
30
+ expect(tmpfile).to receive(:write).with('// bar')
31
+ subject
32
+ end
33
+
34
+ it 'closes the tmpfile' do
35
+ expect(tmpfile).to receive(:close)
36
+ subject
37
+ end
38
+ end
39
+
40
+ describe '#path' do
41
+ it 'is set to a tmpfile with the ERB result' do
42
+ expect(subject.path).to eq '/tmp/livereload-123'
43
+ end
44
+ end
45
+ end