Compare commits

..

No commits in common. "master" and "fix-deadlocks-maybe" have entirely different histories.

20 changed files with 708 additions and 1173 deletions

2
.gitignore vendored
View File

@ -1,7 +1,5 @@
*.gem
.bundle
Gemfile.lock
gemfiles/*.lock
pkg/*
*.orig
tmp/

View File

@ -1,10 +0,0 @@
rvm:
- 1.9.3
- 2.0.0
branches:
only:
- master
gemfile:
- gemfiles/rails32.gemfile
- gemfiles/rails40.gemfile

View File

@ -1,7 +0,0 @@
appraise 'rails32' do
gem 'rails', '~> 3.2.0'
end
appraise 'rails40' do
gem 'rails', '~> 4.0.0'
end

View File

@ -1,7 +1,7 @@
# A sample Guardfile
# More info at https://github.com/guard/guard#readme
guard 'rspec', :cli => '-c' do
guard 'rspec', :version => 2, :cli => '-c' do
watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
watch('spec/spec_helper.rb') { "spec" }

19
LICENSE
View File

@ -1,19 +0,0 @@
Copyright © 2012 John Bintz
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the “Software”), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,75 +1,50 @@
# Rack::LiveReload
_This fork is deprecated: Go check out https://github.com/onesupercoder/rack-livereload instead._
<a href="http://travis-ci.org/johnbintz/rack-livereload"><img src="https://secure.travis-ci.org/johnbintz/rack-livereload.png" /></a>
[![Code Climate](https://codeclimate.com/github/johnbintz/rack-livereload.png)](https://codeclimate.com/github/johnbintz/rack-livereload)
Hey, you've got [LiveReload](http://livereload.com/) in my [Rack](http://rack.rubyforge.org/)!
Hey, you've got [LiveReload](http://www.livereload.com/) in my [Rack](http://rack.rubyforge.org/)!
No need for browser extensions anymore! Just plug it in your middleware stack and go!
Even supports browsers without WebSockets!
Use this with [guard-livereload](http://github.com/guard/guard-livereload) for maximum fun!
## Installation
## Install
`gem install rack-livereload`
## Using in...
### Rails
Add the gem to your Gemfile.
```ruby
gem "rack-livereload", group: :development
```
Then add the middleware to your Rails middleware stack by editing your `config/environments/development.rb`.
```ruby
# config/environments/development.rb
In `config/environments/development.rb`:
``` ruby
MyApp::Application.configure do
# Add Rack::LiveReload to the bottom of the middleware stack with the default options:
config.middleware.insert_after ActionDispatch::Static, Rack::LiveReload
config.middleware.insert_before(Rack::Lock, Rack::LiveReload)
# or, if you're using better_errors:
config.middleware.insert_before Rack::Lock, Rack::LiveReload
# ...or, change some options...
# ...
config.middleware.insert_before(
Rack::Lock, Rack::LiveReload,
:min_delay => 500,
:max_delay => 10000,
:port => 56789,
:host => 'myhost.cool.wow',
:ignore => [ %r{dont/modify\.html$} ]
)
end
```
#### Tweaking the options
```ruby
# Specifying Rack::LiveReload options.
config.middleware.use(Rack::LiveReload,
min_delay : 500, # default 1000
max_delay : 10_000, # default 60_000
live_reload_port : 56789, # default 35729
host : 'myhost.cool.wow',
ignore : [ %r{dont/modify\.html$} ]
)
```
In addition, Rack::LiveReload's position within middleware stack can be
specified by inserting it relative to an exsiting middleware via
`insert_before` or `insert_after`. See the [Rails on Rack: Adding a
Middleware](http://guides.rubyonrails.org/rails_on_rack.html#adding-a-middleware)
section for more detail.
### Sinatra / config.ru
### config.ru/Sinatra
``` ruby
require 'rack-livereload'
use Rack::LiveReload
# ...or...
use Rack::LiveReload, min_delay: 500, ...
use Rack::LiveReload, :min_delay => 500, ...
```
## How it works
The necessary `script` tag to bring in a copy of [livereload.js](https://github.com/livereload/livereload-js) is
injected right after the opening `head` tag in any `text/html` pages that come through. The `script` tag is built in
injected right before the closing `head` tag in any `text/html` pages that come through. The `script` tag is built in
such a way that the `HTTP_HOST` is used as the LiveReload host, so you can connect from external machines (say, to
`mycomputer:3000` instead of `localhost:3000`) and as long as the LiveReload port is accessible from the external machine,
you'll connect and be LiveReloading away!
@ -91,15 +66,17 @@ your browser doesn't need it. The SWF WebSocket implementor won't be loaded unle
WebSockets support or if you force it in the middleware stack:
``` ruby
use Rack::LiveReload, force_swf: true
use Rack::LiveReload, :force_swf => true
```
If you don't want any of the web-sockets-js code included at all, use the `no_swf` option:
``` ruby
use Rack::LiveReload, no_swf: true
use Rack::LiveReload, :no_swf => true
```
Once more browsers support WebSockets than don't, this option will be reversed and you'll have
to explicitly include the Flash shim.
As usual, super-alpha!

View File

@ -1,6 +1,4 @@
require "bundler/gem_tasks"
require 'bundler/setup'
require 'appraisal'
desc 'Update livereload.js'
task :update_livereload_js do

View File

@ -1,7 +0,0 @@
# This file was generated by Appraisal
source "http://rubygems.org"
gem "rails", "~> 3.2.0"
gemspec :path=>"../"

View File

@ -1,7 +0,0 @@
# This file was generated by Appraisal
source "http://rubygems.org"
gem "rails", "~> 4.0.0"
gemspec :path=>"../"

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
require "rack/livereload"
class Rack::LiveReload
VERSION = '0.3.16'
VERSION = '0.3.5'
end

View File

@ -1,15 +1,46 @@
require 'erb'
require 'rack/livereload/processing_skip_analyzer'
require 'rack/livereload/body_processor'
module Rack
class LiveReload
LIVERELOAD_JS_PATH = '/__rack/livereload.js'
LIVERELOAD_LOCAL_URI = 'http://localhost:35729/livereload.js'
BAD_USER_AGENTS = [ %r{MSIE} ]
attr_reader :app
def initialize(app, options = {})
@app, @options = app, options
end
def use_vendored?
return @use_vendored if @use_vendored
if @options[:source]
@use_vendored = (@options[:source] == :vendored)
else
require 'net/http'
require 'uri'
uri = URI.parse(LIVERELOAD_LOCAL_URI)
http = Net::HTTP.new(uri.host, uri.port)
http.read_timeout = 1
begin
http.send_request('GET', uri.path)
@use_vendored = false
rescue Timeout::Error, Errno::ECONNREFUSED, EOFError
@use_vendored = true
rescue => e
$stderr.puts e.inspect
raise e
end
end
@use_vendored
end
def call(env)
dup._call(env)
end
@ -20,23 +51,60 @@ module Rack
if path == '__rack' && ::File.file?(target = ::File.expand_path("../../../js/#{file}", __FILE__))
deliver_file(target)
else
status, headers, body = result = @app.call(env)
status, headers, body = @app.call(env)
return result if ProcessingSkipAnalyzer.skip_processing?(result, env, @options)
new_body = []
processor = BodyProcessor.new(body, @options)
processor.process!(env)
headers['Content-Length'] = processor.content_length.to_s
if processor.livereload_added
headers['X-Rack-LiveReload'] = '1'
body.each do |line|
new_body << line
end
[ status, headers, processor.new_body ]
body.close if body.respond_to?(:close)
if !ignored?(env['PATH_INFO']) && !bad_browser?(env['HTTP_USER_AGENT'])
if headers['Content-Type'] && headers['Content-Type'][%r{text/html}]
content_length = 0
new_body.each do |line|
if !headers['X-Rack-LiveReload'] && line['</head>']
host_to_use = (@options[:host] || env['HTTP_HOST'] || 'localhost').gsub(%r{:.*}, '')
if use_vendored?
src = LIVERELOAD_JS_PATH.dup + "?host=#{host_to_use}"
else
src = LIVERELOAD_LOCAL_URI.dup.gsub('localhost', host_to_use) + '?'
end
src << "&mindelay=#{@options[:min_delay]}" if @options[:min_delay]
src << "&maxdelay=#{@options[:max_delay]}" if @options[:max_delay]
src << "&port=#{@options[:port]}" if @options[:port]
template = ERB.new(::File.read(::File.expand_path('../../../skel/livereload.html.erb', __FILE__)))
line.gsub!('</head>', %{#{template.result(binding)}</head>})
headers["X-Rack-LiveReload"] = '1'
end
content_length += line.bytesize
end
headers['Content-Length'] = content_length.to_s
end
end
[ status, headers, new_body ]
end
end
def ignored?(path_info)
@options[:ignore] and @options[:ignore].any? { |filter| path_info[filter] }
end
def bad_browser?(user_agent)
BAD_USER_AGENTS.any? { |pattern| (user_agent || '')[pattern] }
end
private
def deliver_file(file)
type = case ::File.extname(file)
@ -48,6 +116,14 @@ module Rack
[ 200, { 'Content-Type' => type, 'Content-Length' => ::File.size(file).to_s }, [ ::File.read(file) ] ]
end
def force_swf?
@options[:force_swf]
end
def with_swf?
!@options[:no_swf]
end
end
end

View File

@ -1,116 +0,0 @@
require 'rack/livereload'
module Rack
class LiveReload
class BodyProcessor
LIVERELOAD_JS_PATH = '/__rack/livereload.js'
HEAD_TAG_REGEX = /<head>|<head[^(er)][^<]*>/
LIVERELOAD_PORT = 35729
attr_reader :content_length, :new_body, :livereload_added
def protocol
@options[:protocol] || "http"
end
def livereload_local_uri
"#{protocol}://localhost:#{@options[:live_reload_port]}/livereload.js"
end
def initialize(body, options)
@body, @options = body, options
@options[:live_reload_port] ||= LIVERELOAD_PORT
@processed = false
end
def force_swf?
@options[:force_swf]
end
def with_swf?
!@options[:no_swf]
end
def use_vendored?
return @use_vendored if @use_vendored
if @options[:source]
@use_vendored = (@options[:source] == :vendored)
else
require 'net/http'
require 'uri'
uri = URI.parse(livereload_local_uri)
http = Net::HTTP.new(uri.host, uri.port)
http.read_timeout = 1
begin
http.send_request('GET', uri.path)
@use_vendored = false
rescue ::Timeout::Error, Errno::ECONNREFUSED, EOFError, IOError
@use_vendored = true
rescue => e
$stderr.puts e.inspect
raise e
end
end
@use_vendored
end
def processed?
@processed
end
def process!(env)
@env = env
@body.close if @body.respond_to?(:close)
@new_body = [] ; @body.each { |line| @new_body << line.to_s }
@content_length = 0
@livereload_added = false
@new_body.each do |line|
if !@livereload_added && line['<head']
line.gsub!(HEAD_TAG_REGEX) { |match| %{#{match}#{template.result(binding)}} }
@livereload_added = true
end
@content_length += line.bytesize
@processed = true
end
end
def app_root
ENV['RAILS_RELATIVE_URL_ROOT'] || ''
end
def host_to_use
(@options[:host] || @env['HTTP_HOST'] || 'localhost').gsub(%r{:.*}, '')
end
def template
ERB.new(::File.read(::File.expand_path('../../../../skel/livereload.html.erb', __FILE__)))
end
def livereload_source
if use_vendored?
src = "#{app_root}#{LIVERELOAD_JS_PATH.dup}?host=#{host_to_use}"
else
src = livereload_local_uri.dup.gsub('localhost', host_to_use) + '?'
end
src << "&amp;mindelay=#{@options[:min_delay]}" if @options[:min_delay]
src << "&amp;maxdelay=#{@options[:max_delay]}" if @options[:max_delay]
src << "&amp;port=#{@options[:port]}" if @options[:port]
src
end
end
end
end

View File

@ -1,49 +0,0 @@
require 'rack/livereload'
module Rack
class LiveReload
class ProcessingSkipAnalyzer
BAD_USER_AGENTS = [ %r{MSIE} ]
def self.skip_processing?(result, env, options)
new(result, env, options).skip_processing?
end
def initialize(result, env, options)
@env, @options = env, options
@status, @headers, @body = result
end
def skip_processing?
!html? || chunked? || inline? || ignored? || bad_browser? || !get?
end
def chunked?
@headers['Transfer-Encoding'] == 'chunked'
end
def inline?
@headers['Content-Disposition'] =~ %r{^inline}
end
def ignored?
path = @env['QUERY_STRING'].empty? ? @env['PATH_INFO'] : "#{@env['PATH_INFO']}?#{@env['QUERY_STRING']}"
@options[:ignore] and @options[:ignore].any? { |filter| path[filter] }
end
def bad_browser?
BAD_USER_AGENTS.any? { |pattern| @env['HTTP_USER_AGENT'] =~ pattern }
end
def html?
@headers['Content-Type'] =~ %r{text/html}
end
def get?
@env['REQUEST_METHOD'] == 'GET'
end
end
end
end

View File

@ -8,7 +8,6 @@ Gem::Specification.new do |s|
s.authors = ["John Bintz"]
s.email = ["john@coswellproductions.com"]
s.homepage = ""
s.license = "MIT"
s.summary = %q{Insert LiveReload into your app easily as Rack middleware}
s.description = %q{Insert LiveReload into your app easily as Rack middleware}
@ -33,8 +32,7 @@ Gem::Specification.new do |s|
s.add_development_dependency "guard-cucumber"
s.add_development_dependency "guard-livereload"
s.add_development_dependency "webmock"
s.add_development_dependency "nokogiri", ("< 1.6" if RUBY_VERSION < "1.9") # Nokogiri >= 1.6 requires Ruby >= 1.9
s.add_development_dependency 'appraisal', '~> 0.4'
s.add_runtime_dependency "rack"
end

View File

@ -5,11 +5,8 @@
WEB_SOCKET_FORCE_FLASH = true;
<% end %>
</script>
<script type="text/javascript" src="<%= app_root %>/__rack/swfobject.js"></script>
<script type="text/javascript" src="<%= app_root %>/__rack/web_socket.js"></script>
<script type="text/javascript" src="/__rack/swfobject.js"></script>
<script type="text/javascript" src="/__rack/web_socket.js"></script>
<% end %>
<script type="text/javascript">
RACK_LIVERELOAD_PORT = <%= @options[:live_reload_port] %>;
</script>
<script type="text/javascript" src="<%= livereload_source %>"></script>
<script type="text/javascript" src="<%= src %>"></script>

View File

@ -1,200 +0,0 @@
require 'spec_helper'
require 'nokogiri'
describe Rack::LiveReload::BodyProcessor do
describe 'head tag regex' do
let(:regex) { described_class::HEAD_TAG_REGEX }
subject { regex }
it { should be_kind_of(Regexp) }
it 'only picks a valid <head> tag' do
regex.match("<head></head>").to_s.should eq('<head>')
regex.match("<head><title></title></head>").to_s.should eq('<head>')
regex.match("<head attribute='something'><title></title></head>").to_s.should eq("<head attribute='something'>")
end
it 'responds false when no head tag' do
regex.match("<header></header>").should be_falsey
end
end
let(:processor) { described_class.new(body, options) }
let(:body) { [ page_html ] }
let(:options) { {} }
let(:page_html) { '<head></head>' }
let(:processor_result) do
if !processor.processed?
processor.process!(env)
end
processor
end
subject { processor }
describe "livereload local uri" do
context 'does not exist' do
before do
stub_request(:any, 'localhost:35729/livereload.js').to_timeout
end
it { should use_vendored }
end
context 'exists' do
before do
stub_request(:any, 'localhost:35729/livereload.js')
end
it { should_not use_vendored }
end
context 'with custom port' do
let(:options) { {:live_reload_port => '12348'}}
context 'exists' do
before do
stub_request(:any, 'localhost:12348/livereload.js')
end
it { should_not use_vendored }
end
end
context 'specify vendored' do
let(:options) { { :source => :vendored } }
it { should use_vendored }
end
context 'specify LR' do
let(:options) { { :source => :livereload } }
it { should_not use_vendored }
end
end
context 'text/html' do
before do
processor.stubs(:use_vendored?).returns(true)
end
let(:host) { 'host' }
let(:env) { { 'HTTP_HOST' => host } }
let(:processed_body) { processor_result.new_body.join('') }
let(:length) { processor_result.content_length }
let(:page_html) { '<head></head>' }
context 'vendored' do
it 'should add the vendored livereload js script tag' do
processed_body.should include("script")
processed_body.should include(described_class::LIVERELOAD_JS_PATH)
length.to_s.should == processed_body.length.to_s
described_class::LIVERELOAD_JS_PATH.should_not include(host)
processed_body.should include('swfobject')
processed_body.should include('web_socket')
end
end
context 'at the top of the head tag' do
let(:page_html) { '<head attribute="attribute"><script type="text/javascript" insert="first"></script><script type="text/javascript" insert="before"></script></head>' }
let(:body_dom) { Nokogiri::XML(processed_body) }
it 'should add the livereload js script tag before all other script tags' do
body_dom.at_css("head")[:attribute].should == 'attribute'
body_dom.at_css("script:eq(5)")[:src].should include(described_class::LIVERELOAD_JS_PATH)
body_dom.at_css("script:last-child")[:insert].should == "before"
end
context 'when a relative URL root is specified' do
before do
ENV['RAILS_RELATIVE_URL_ROOT'] = '/a_relative_path'
end
it 'should prepend the relative path to the script src' do
body_dom.at_css("script:eq(5)")[:src].should match(%r{^/a_relative_path/})
end
end
end
describe "LIVERELOAD_PORT value" do
let(:options) { { :live_reload_port => 12345 }}
it "sets the variable at the top of the file" do
processed_body.should include 'RACK_LIVERELOAD_PORT = 12345'
end
end
context 'in header tags' do
let(:page_html) { "<header class='hero'><h1>Just a normal header tag</h1></header>" }
let(:body_dom) { Nokogiri::XML(processed_body) }
it 'should not add the livereload js' do
body_dom.at_css("header")[:class].should == 'hero'
body_dom.css('script').should be_empty
end
end
context 'not vendored' do
before do
processor.stubs(:use_vendored?).returns(false)
end
it 'should add the LR livereload js script tag' do
processed_body.should include("script")
processed_body.should include(processor.livereload_local_uri.gsub('localhost', 'host'))
end
end
context 'set options' do
let(:options) { { :host => new_host, :port => port, :min_delay => min_delay, :max_delay => max_delay } }
let(:min_delay) { 5 }
let(:max_delay) { 10 }
let(:port) { 23 }
let(:new_host) { 'myhost' }
it 'should add the livereload.js script tag' do
processed_body.should include("mindelay=#{min_delay}")
processed_body.should include("maxdelay=#{max_delay}")
processed_body.should include("port=#{port}")
processed_body.should include("host=#{new_host}")
end
end
context 'force flash' do
let(:options) { { :force_swf => true } }
it 'should not add the flash shim' do
processed_body.should include('WEB_SOCKET_FORCE_FLASH')
processed_body.should include('swfobject')
processed_body.should include('web_socket')
end
end
context 'no flash' do
let(:options) { { :no_swf => true } }
it 'should not add the flash shim' do
processed_body.should_not include('swfobject')
processed_body.should_not include('web_socket')
end
end
context 'no host at all' do
let(:env) { {} }
it 'should use localhost' do
processed_body.should include('localhost')
end
end
end
end

View File

@ -1,137 +0,0 @@
require 'spec_helper'
describe Rack::LiveReload::ProcessingSkipAnalyzer do
subject { described_class.new(result, env, options) }
let(:result) { [ status, headers, body ] }
let(:env) { { 'HTTP_USER_AGENT' => user_agent } }
let(:options) { {} }
let(:user_agent) { 'Firefox' }
let(:status) { 200 }
let(:headers) { {} }
let(:body) { [] }
describe '#skip_processing?' do
it "should skip processing" do
subject.skip_processing?.should be_truthy
end
end
describe '#ignored?' do
let(:options) { { :ignore => [ %r{file} ] } }
context 'path contains ignore pattern' do
let(:env) { { 'PATH_INFO' => '/this/file', 'QUERY_STRING' => '' } }
it { should be_ignored }
end
context 'root path' do
let(:env) { { 'PATH_INFO' => '/', 'QUERY_STRING' => '' } }
it { should_not be_ignored }
end
end
describe '#chunked?' do
context 'regular response' do
it { should_not be_chunked }
end
context 'chunked response' do
let(:headers) { { 'Transfer-Encoding' => 'chunked' } }
it { should be_chunked }
end
end
describe '#inline?' do
context 'inline disposition' do
let(:headers) { { 'Content-Disposition' => 'inline; filename=my_inlined_file' } }
it { should be_inline }
end
end
describe '#ignored?' do
let(:path_info) { 'path info' }
let(:query_string) { 'query_string' }
let(:env) { { 'PATH_INFO' => path_info, 'QUERY_STRING' => query_string } }
context 'no ignore set' do
it { should_not be_ignored }
end
context 'ignore set' do
let(:options) { { :ignore => [ %r{#{path_info}} ] } }
it { should be_ignored }
end
context 'ignore set including query_string' do
let(:options) { { :ignore => [ %r{#{path_info}\?#{query_string}} ] } }
it { should be_ignored }
end
end
describe '#bad_browser?' do
context 'Firefox' do
it { should_not be_bad_browser }
end
context 'BAD browser' do
let(:user_agent) { described_class::BAD_USER_AGENTS.first.source }
it { should be_bad_browser }
end
end
describe '#html?' do
context 'HTML content' do
let(:headers) { { 'Content-Type' => 'text/html' } }
it { should be_html }
end
context 'PDF content' do
let(:headers) { { 'Content-Type' => 'application/pdf' } }
it { should_not be_html }
end
end
describe '#get?' do
context 'GET request' do
let(:env) { { 'REQUEST_METHOD' => 'GET' } }
it { should be_get }
end
context 'PUT request' do
let(:env) { { 'REQUEST_METHOD' => 'PUT' } }
it { should_not be_get }
end
context 'POST request' do
let(:env) { { 'REQUEST_METHOD' => 'POST' } }
it { should_not be_get }
end
context 'DELETE request' do
let(:env) { { 'REQUEST_METHOD' => 'DELETE' } }
it { should_not be_get }
end
context 'PATCH request' do
let(:env) { { 'REQUEST_METHOD' => 'PATCH' } }
it { should_not be_get }
end
end
end

View File

@ -1,5 +1,4 @@
require 'spec_helper'
require 'nokogiri'
describe Rack::LiveReload do
let(:middleware) { described_class.new(app, options) }
@ -7,23 +6,196 @@ describe Rack::LiveReload do
subject { middleware }
it 'should be an app' do
middleware.app.should be == app
end
its(:app) { should == app }
let(:env) { {} }
let(:options) { {} }
describe described_class::LIVERELOAD_LOCAL_URI do
context 'does not exist' do
before do
stub_request(:any, 'localhost:35729/livereload.js').to_timeout
end
it { should use_vendored }
end
context 'exists' do
before do
stub_request(:any, 'localhost:35729/livereload.js')
end
it { should_not use_vendored }
end
context 'specify vendored' do
let(:options) { { :source => :vendored } }
it { should use_vendored }
end
context 'specify LR' do
let(:options) { { :source => :livereload } }
it { should_not use_vendored }
end
end
context 'not text/html' do
let(:ret) { [ 200, { 'Content-Type' => 'image/png' }, [ '<head></head>' ] ] }
before do
app.stubs(:call).with(env).returns(ret)
end
it 'should pass through' do
middleware.call(env).should == ret
end
end
context 'unknown Content-Type' do
let(:ret) { [ 200, {}, [ 'hey ho' ] ] }
before do
app.stubs(:call).with(env).returns(ret)
end
it 'should not break' do
middleware.call(env).should_not raise_error(NoMethodError, /You have a nil object/)
end
end
context 'text/html' do
before do
app.stubs(:call).with(env).returns([ 200, { 'Content-Type' => 'text/html', 'Content-Length' => 0 }, [ '<head></head>' ] ])
middleware.stubs(:use_vendored?).returns(true)
end
let(:host) { 'host' }
let(:env) { { 'HTTP_HOST' => host } }
let(:ret) { middleware._call(env) }
let(:body) { ret.last.join }
let(:length) { ret[1]['Content-Length'] }
context 'vendored' do
it 'should add the vendored livereload js script tag' do
body.should include("script")
body.should include(described_class::LIVERELOAD_JS_PATH)
length.should == body.length.to_s
described_class::LIVERELOAD_JS_PATH.should_not include(host)
body.should include('swfobject')
body.should include('web_socket')
end
end
context 'not vendored' do
before do
middleware.stubs(:use_vendored?).returns(false)
end
it 'should add the LR livereload js script tag' do
body.should include("script")
body.should include(described_class::LIVERELOAD_LOCAL_URI.gsub('localhost', 'host'))
end
end
context 'set options' do
let(:middleware) { described_class.new(app, :host => new_host, :port => port, :min_delay => min_delay, :max_delay => max_delay) }
let(:min_delay) { 5 }
let(:max_delay) { 10 }
let(:port) { 23 }
let(:new_host) { 'myhost' }
it 'should add the livereload.js script tag' do
body.should include("mindelay=#{min_delay}")
body.should include("maxdelay=#{max_delay}")
body.should include("port=#{port}")
body.should include("host=#{new_host}")
end
end
context 'force flash' do
let(:middleware) { described_class.new(app, :force_swf => true) }
it 'should not add the flash shim' do
body.should include('WEB_SOCKET_FORCE_FLASH')
body.should include('swfobject')
body.should include('web_socket')
end
end
context 'no flash' do
let(:middleware) { described_class.new(app, :no_swf => true) }
it 'should not add the flash shim' do
body.should_not include('swfobject')
body.should_not include('web_socket')
end
end
context 'no host at all' do
let(:env) { {} }
it 'should use localhost' do
body.should include('localhost')
end
end
context 'ignored' do
let(:options) { { :ignore => [ %r{file} ] } }
context 'not root' do
let(:env) { { 'PATH_INFO' => '/this/file' } }
it 'should have no change' do
body.should_not include('script')
end
end
context 'root' do
let(:env) { { 'PATH_INFO' => '/' } }
it 'should have script' do
body.should include('script')
end
end
end
end
context '/__rack/livereload.js' do
let(:env) { { 'PATH_INFO' => described_class::BodyProcessor::LIVERELOAD_JS_PATH } }
let(:env) { { 'PATH_INFO' => described_class::LIVERELOAD_JS_PATH } }
before do
middleware.expects(:deliver_file).returns(true)
end
it 'should return the js file' do
middleware._call(env).should be_truthy
middleware._call(env).should be_true
end
end
describe '#ignored?' do
let(:path_info) { 'path info' }
context 'no ignore set' do
it { should_not be_ignored(path_info) }
end
context 'ignore set' do
let(:options) { { :ignore => [ %r{#{path_info}} ] } }
it { should be_ignored(path_info) }
end
end
describe '#bad_browser?' do
let(:user_agent) { described_class::BAD_USER_AGENTS.first.source }
it { should be_bad_browser(user_agent) }
end
end

View File

@ -1,4 +1,4 @@
require 'mocha/api'
require 'mocha'
require 'webmock/rspec'
require 'rack-livereload'