Skip to content

Commit

Permalink
Added documentation, checks, and tests for Rack::Utils::Context
Browse files Browse the repository at this point in the history
  • Loading branch information
scytrin committed Jun 7, 2008
1 parent 78ad4da commit 1990057
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 5 deletions.
39 changes: 34 additions & 5 deletions lib/rack/utils.rb
Expand Up @@ -71,17 +71,46 @@ def escape_html(string)
end
module_function :escape_html

# The recommended manner in which to implement a contexting application
# is to define a method #context in which a new Context is instantiated.
#
# As a Context is a glorified block, it is highly recommended that you
# define the contextual block within the application's operational scope.
# This would typically the application as you're place into Rack's stack.
#
# class MyObject
# ...
# def context app
# Rack::Utils::Context.new app do |env|
# do_stuff
# response = app.call(env)
# do_more_stuff
# end
# end
# ...
# end
#
# mobj = MyObject.new
# app = mobj.context other_app
# Rack::Handler::Mongrel.new app
class Context < Proc
alias_method :old_inspect, :inspect
attr_reader :for, :app
def initialize app_f=nil, app_r=nil
@for, @app = app_f, app_r
def initialize app_f, app_r
raise 'running context not provided' unless app_f
raise 'running context does not respond to #context' unless app_f.respond_to? :context
raise 'application context not provided' unless app_r
raise 'application context does not respond to #call' unless app_r.respond_to? :call
@for = app_f
@app = app_r
end
alias_method :old_inspect, :inspect
def inspect
"#{old_inspect} ==> #{@for.inspect} ==> #{@app.inspect}"
end
def context app
self.dup.instance_eval{@app=app; self}
def context app_r
raise 'new application context not provided' unless app_r
raise 'new application context does not respond to #call' unless app_r.respond_to? :call
@for.context app_r
end
def pretty_print pp
pp.text old_inspect
Expand Down
83 changes: 83 additions & 0 deletions test/spec_rack_utils.rb
@@ -1,4 +1,8 @@
require 'test/spec'

require 'rack/utils'
require 'rack/lint'
require 'rack/mock'

context "Rack::Utils" do
specify "should escape correctly" do
Expand Down Expand Up @@ -67,3 +71,82 @@
h.to_hash.should.be.instance_of Hash
end
end

context "Rack::Utils::Context" do
test_app1 = Object.new
def test_app1.context app
Rack::Utils::Context.new self, app do |env|
p app
app.call env
end
end
test_app2 = Object.new
def test_app2.context env; end
test_app3 = Object.new
test_target1 = proc{|e| e.to_s+' world' }
test_target2 = proc{|e| e.to_i+2 }
test_target3 = proc{|e| nil }
test_target4 = proc{|e| [200,{'Content-Type'=>'text/plain'},['']] }
test_target5 = Object.new

specify "should perform checks on both arguments" do
lambda { Rack::Utils::Context.new(nil, nil){} }.should.raise
lambda { Rack::Utils::Context.new(test_app1, nil){} }.should.raise
lambda { Rack::Utils::Context.new(nil, test_target1){} }.should.raise
lambda { Rack::Utils::Context.new(test_app1, test_target1){} }.should.not.raise
lambda { Rack::Utils::Context.new(test_app3, test_target1){} }.should.raise
lambda { Rack::Utils::Context.new(test_app1, test_target5){} }.should.raise
lambda { test_app1.context(nil){} }.should.raise
lambda { test_app1.context(test_target1){} }.should.not.raise
lambda { test_app1.context(test_target5){} }.should.raise
end

specify "should set context correctly" do
c1 = Rack::Utils::Context.new(test_app1, test_target1){}
c1.for.should.equal test_app1
c1.app.should.equal test_target1
c2 = Rack::Utils::Context.new(test_app1, test_target2){}
c2.for.should.equal test_app1
c2.app.should.equal test_target2
c3 = Rack::Utils::Context.new(test_app2, test_target3){}
c3.for.should.equal test_app2
c3.app.should.equal test_target3
c4 = Rack::Utils::Context.new(test_app2, test_target4){}
c4.for.should.equal test_app2
c4.app.should.equal test_target4
end

specify "should alter app on recontexting" do
c1 = Rack::Utils::Context.new(test_app1, test_target1){}
c1.for.should.equal test_app1
c1.app.should.equal test_target1
c2 = c1.context(test_target2)
c2.for.should.equal test_app1
c2.app.should.not.equal test_target1
c2.app.should.equal test_target2
c3 = c2.context(test_target3)
c3.for.should.equal test_app1
c3.app.should.not.equal test_target2
c3.app.should.equal test_target3
c4 = c3.context(test_target4)
c4.for.should.equal test_app1
c4.app.should.not.equal test_target3
c4.app.should.equal test_target4
end

specify "should run different apps" do
c1 = test_app1.context(test_target1)
c2 = c1.context test_target2
c3 = c2.context test_target3
c4 = c3.context test_target4
a4 = Rack::Lint.new c4
r1 = c1.call('hello')
r1.should.equal 'hello world'
r2 = c2.call(2)
r2.should.equal 4
r3 = c3.call(:misc_symbol)
r3.should.be.nil
r4 = Rack::MockRequest.new(a4).get('/')
r4.status.should.be 200
end
end

0 comments on commit 1990057

Please sign in to comment.