From 86d636ec0a2923fa28493b497e77321bff0a33c0 Mon Sep 17 00:00:00 2001 From: Cezary Baginski Date: Fri, 18 Mar 2016 18:20:30 +0100 Subject: [PATCH] guarantee sleep for :grace_period [fix #114] --- Gemfile | 2 + lib/guard/livereload.rb | 3 +- lib/guard/livereload/guaranteed_sleep.rb | 14 ++++ .../guard/livereload/guaranteed_sleep_spec.rb | 64 +++++++++++++++++++ spec/lib/guard/livereload_spec.rb | 12 +++- 5 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 lib/guard/livereload/guaranteed_sleep.rb create mode 100644 spec/lib/guard/livereload/guaranteed_sleep_spec.rb diff --git a/Gemfile b/Gemfile index 2216fd1..0600883 100644 --- a/Gemfile +++ b/Gemfile @@ -7,10 +7,12 @@ group :development do gem "guard-rspec", require: false gem "guard-rubocop", require: false gem "hound-tools", '~> 0.0.4', require: false + gem 'timecop' end group :test do gem "coveralls", require: false gem "rake", require: false gem 'rspec', '~> 3.1' + gem 'timecop' end diff --git a/lib/guard/livereload.rb b/lib/guard/livereload.rb index 1ca1153..bcd1aa5 100644 --- a/lib/guard/livereload.rb +++ b/lib/guard/livereload.rb @@ -5,6 +5,7 @@ class LiveReload < Plugin require 'guard/livereload/websocket' require 'guard/livereload/reactor' require 'guard/livereload/snippet' + require 'guard/livereload/guaranteed_sleep' attr_accessor :reactor, :options @@ -37,7 +38,7 @@ def stop end def run_on_modifications(paths) - sleep options[:grace_period] + GuaranteedSleep.new.sleep(options[:grace_period]) reactor.reload_browser(paths) end end diff --git a/lib/guard/livereload/guaranteed_sleep.rb b/lib/guard/livereload/guaranteed_sleep.rb new file mode 100644 index 0000000..29e0f2a --- /dev/null +++ b/lib/guard/livereload/guaranteed_sleep.rb @@ -0,0 +1,14 @@ +require 'guard/compat/plugin' + +module Guard + class LiveReload < Plugin + class GuaranteedSleep + def sleep(seconds) + deadline = Time.now + seconds + while (remaining = deadline - Time.now) > 0 + Kernel.sleep(remaining) + end + end + end + end +end diff --git a/spec/lib/guard/livereload/guaranteed_sleep_spec.rb b/spec/lib/guard/livereload/guaranteed_sleep_spec.rb new file mode 100644 index 0000000..b344851 --- /dev/null +++ b/spec/lib/guard/livereload/guaranteed_sleep_spec.rb @@ -0,0 +1,64 @@ +require 'guard/compat/test/helper' + +require 'timecop' + +RSpec.describe Guard::LiveReload::GuaranteedSleep do + let(:start_time) { Time.local(2006, 3, 18, 2, 0) } + + let(:implementation) { Kernel } + + around do |example| + Timecop.freeze(start_time) do + example.run + end + end + + describe '.sleep' do + before do + @interruptions = interruptions + allow(implementation).to receive(:sleep) do |time| + t = (@interruptions > 0 ? (time.to_f / 2) : time) + @interruptions -= 1 + Timecop.travel(Time.now + t) + t + end + end + + context 'with 0' do + let(:interruptions) { 0 } + + it 'never sleeps' do + subject.sleep(0) + expect(implementation).to_not receive(:sleep) + expect(Time.now).to be_within(0.05).of(start_time) + end + end + + context 'when never interrupted' do + let(:interruptions) { 0 } + + it 'waits before reloading the browser' do + subject.sleep(5) + expect(Time.now).to be_within(0.1).of(start_time + 5) + end + end + + context 'when interrupted once' do + let(:interruptions) { 1 } + + it 'waits before reloading the browser' do + subject.sleep(5) + expect(Time.now).to be_within(0.1).of(start_time + 5) + end + end + + context 'when interrupted many times' do + let(:interruptions) { 3 } + + it 'waits before reloading the browser' do + subject.sleep(5) + expect(Time.now).to be_within(0.1).of(start_time + 5) + end + end + end +end diff --git a/spec/lib/guard/livereload_spec.rb b/spec/lib/guard/livereload_spec.rb index 4a09ad0..aa2f96d 100644 --- a/spec/lib/guard/livereload_spec.rb +++ b/spec/lib/guard/livereload_spec.rb @@ -153,14 +153,22 @@ end describe '#run_on_modifications' do + let(:sleeper) { instance_double(Guard::LiveReload::GuaranteedSleep) } + + before do + allow(reactor).to receive(:reload_browser) + allow(Guard::LiveReload::GuaranteedSleep).to receive(:new).and_return(sleeper) + allow(sleeper).to receive(:sleep) + end + it 'reloads browser' do expect(reactor).to receive(:reload_browser).with(['foo']) plugin.run_on_modifications(['foo']) end - it 'can wait 0.5 seconds before reloading the browser' do + it 'waits given time before reloading the browser' do expect(reactor).to receive(:reload_browser).with(['foo']) - expect(plugin).to receive(:sleep).with(0.5) + allow(sleeper).to receive(:sleep).with(0.5) plugin.options[:grace_period] = 0.5 plugin.run_on_modifications(['foo']) end