innate 2009.04
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +2981 -0
- data/COPYING +18 -0
- data/MANIFEST +127 -0
- data/README.md +563 -0
- data/Rakefile +35 -0
- data/example/app/retro_games.rb +60 -0
- data/example/app/todo/layout/default.xhtml +11 -0
- data/example/app/todo/spec/todo.rb +63 -0
- data/example/app/todo/start.rb +51 -0
- data/example/app/todo/view/index.xhtml +39 -0
- data/example/app/whywiki_erb/layout/wiki.html.erb +15 -0
- data/example/app/whywiki_erb/spec/wiki.rb +19 -0
- data/example/app/whywiki_erb/start.rb +42 -0
- data/example/app/whywiki_erb/view/edit.erb +6 -0
- data/example/app/whywiki_erb/view/index.erb +12 -0
- data/example/custom_middleware.rb +35 -0
- data/example/hello.rb +11 -0
- data/example/howto_spec.rb +35 -0
- data/example/link.rb +27 -0
- data/example/provides.rb +31 -0
- data/example/session.rb +38 -0
- data/innate.gemspec +29 -0
- data/lib/innate.rb +269 -0
- data/lib/innate/action.rb +150 -0
- data/lib/innate/adapter.rb +76 -0
- data/lib/innate/cache.rb +134 -0
- data/lib/innate/cache/api.rb +128 -0
- data/lib/innate/cache/drb.rb +58 -0
- data/lib/innate/cache/file_based.rb +41 -0
- data/lib/innate/cache/marshal.rb +17 -0
- data/lib/innate/cache/memory.rb +22 -0
- data/lib/innate/cache/yaml.rb +17 -0
- data/lib/innate/current.rb +37 -0
- data/lib/innate/dynamap.rb +96 -0
- data/lib/innate/helper.rb +183 -0
- data/lib/innate/helper/aspect.rb +124 -0
- data/lib/innate/helper/cgi.rb +54 -0
- data/lib/innate/helper/flash.rb +36 -0
- data/lib/innate/helper/link.rb +94 -0
- data/lib/innate/helper/redirect.rb +85 -0
- data/lib/innate/helper/render.rb +87 -0
- data/lib/innate/helper/send_file.rb +26 -0
- data/lib/innate/log.rb +20 -0
- data/lib/innate/log/color_formatter.rb +43 -0
- data/lib/innate/log/hub.rb +73 -0
- data/lib/innate/middleware_compiler.rb +65 -0
- data/lib/innate/mock.rb +49 -0
- data/lib/innate/node.rb +1025 -0
- data/lib/innate/options.rb +37 -0
- data/lib/innate/options/dsl.rb +202 -0
- data/lib/innate/options/stub.rb +7 -0
- data/lib/innate/request.rb +141 -0
- data/lib/innate/response.rb +23 -0
- data/lib/innate/route.rb +110 -0
- data/lib/innate/session.rb +121 -0
- data/lib/innate/session/flash.rb +94 -0
- data/lib/innate/spec.rb +23 -0
- data/lib/innate/state.rb +27 -0
- data/lib/innate/state/accessor.rb +130 -0
- data/lib/innate/state/fiber.rb +74 -0
- data/lib/innate/state/thread.rb +47 -0
- data/lib/innate/traited.rb +85 -0
- data/lib/innate/trinity.rb +18 -0
- data/lib/innate/version.rb +3 -0
- data/lib/innate/view.rb +60 -0
- data/lib/innate/view/erb.rb +15 -0
- data/lib/innate/view/etanni.rb +36 -0
- data/lib/innate/view/none.rb +9 -0
- data/spec/example/app/retro_games.rb +30 -0
- data/spec/example/hello.rb +13 -0
- data/spec/example/link.rb +25 -0
- data/spec/example/provides.rb +16 -0
- data/spec/example/session.rb +22 -0
- data/spec/helper.rb +10 -0
- data/spec/innate/action/layout.rb +107 -0
- data/spec/innate/action/layout/file_layout.xhtml +1 -0
- data/spec/innate/cache/common.rb +47 -0
- data/spec/innate/cache/marshal.rb +5 -0
- data/spec/innate/cache/memory.rb +5 -0
- data/spec/innate/cache/yaml.rb +5 -0
- data/spec/innate/dynamap.rb +22 -0
- data/spec/innate/helper.rb +86 -0
- data/spec/innate/helper/aspect.rb +75 -0
- data/spec/innate/helper/cgi.rb +37 -0
- data/spec/innate/helper/flash.rb +118 -0
- data/spec/innate/helper/link.rb +139 -0
- data/spec/innate/helper/redirect.rb +160 -0
- data/spec/innate/helper/render.rb +133 -0
- data/spec/innate/helper/send_file.rb +21 -0
- data/spec/innate/helper/view/aspect_hello.xhtml +1 -0
- data/spec/innate/helper/view/locals.xhtml +1 -0
- data/spec/innate/helper/view/loop.xhtml +4 -0
- data/spec/innate/helper/view/num.xhtml +1 -0
- data/spec/innate/helper/view/partial.xhtml +1 -0
- data/spec/innate/helper/view/recursive.xhtml +7 -0
- data/spec/innate/mock.rb +84 -0
- data/spec/innate/node/mapping.rb +37 -0
- data/spec/innate/node/node.rb +134 -0
- data/spec/innate/node/resolve.rb +82 -0
- data/spec/innate/node/view/another_layout/another_layout.xhtml +3 -0
- data/spec/innate/node/view/bar.xhtml +1 -0
- data/spec/innate/node/view/foo.html.xhtml +1 -0
- data/spec/innate/node/view/only_view.xhtml +1 -0
- data/spec/innate/node/view/with_layout.xhtml +1 -0
- data/spec/innate/node/wrap_action_call.rb +83 -0
- data/spec/innate/options.rb +115 -0
- data/spec/innate/parameter.rb +154 -0
- data/spec/innate/provides.rb +99 -0
- data/spec/innate/provides/list.html.xhtml +1 -0
- data/spec/innate/provides/list.txt.xhtml +1 -0
- data/spec/innate/request.rb +77 -0
- data/spec/innate/route.rb +135 -0
- data/spec/innate/session.rb +54 -0
- data/spec/innate/state/fiber.rb +58 -0
- data/spec/innate/state/thread.rb +40 -0
- data/spec/innate/traited.rb +55 -0
- data/tasks/bacon.rake +66 -0
- data/tasks/changelog.rake +18 -0
- data/tasks/gem.rake +22 -0
- data/tasks/gem_installer.rake +76 -0
- data/tasks/grancher.rake +12 -0
- data/tasks/install_dependencies.rake +4 -0
- data/tasks/manifest.rake +4 -0
- data/tasks/rcov.rake +19 -0
- data/tasks/release.rake +51 -0
- data/tasks/reversion.rake +8 -0
- data/tasks/setup.rake +28 -0
- metadata +181 -0
data/Rakefile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/clean'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'time'
|
5
|
+
require 'date'
|
6
|
+
|
7
|
+
PROJECT_SPECS = FileList['spec/{innate,example}/**/*.rb'].exclude('common.rb')
|
8
|
+
PROJECT_MODULE = 'Innate'
|
9
|
+
PROJECT_README = 'README.md'
|
10
|
+
|
11
|
+
GEMSPEC = Gem::Specification.new{|s|
|
12
|
+
s.name = 'innate'
|
13
|
+
s.author = "Michael 'manveru' Fellinger"
|
14
|
+
s.summary = "Powerful web-framework wrapper for Rack."
|
15
|
+
s.description = "Simple, straight-forward base for web-frameworks."
|
16
|
+
s.email = 'm.fellinger@gmail.com'
|
17
|
+
s.homepage = 'http://github.com/manveru/innate'
|
18
|
+
s.platform = Gem::Platform::RUBY
|
19
|
+
s.version = (ENV['PROJECT_VERSION'] || Date.today.strftime("%Y.%m.%d"))
|
20
|
+
s.files = `git ls-files`.split("\n").sort
|
21
|
+
s.has_rdoc = true
|
22
|
+
s.require_path = 'lib'
|
23
|
+
s.rubyforge_project = "innate"
|
24
|
+
|
25
|
+
# s.add_runtime_dependency('rack', '>= 0.9.1') # lies!
|
26
|
+
# s.add_development_dependency('bacon', '>= 1.0')
|
27
|
+
# s.add_development_dependency('json', '~> 1.1.3')
|
28
|
+
# s.add_development_dependency('rack-test', '>= 0.1.0')
|
29
|
+
}
|
30
|
+
|
31
|
+
Dir['tasks/*.rake'].each{|f| import(f) }
|
32
|
+
|
33
|
+
task :default => [:bacon]
|
34
|
+
|
35
|
+
CLEAN.include('')
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'innate'
|
2
|
+
require 'yaml/store'
|
3
|
+
|
4
|
+
STORE = YAML::Store.new('games.yaml')
|
5
|
+
|
6
|
+
def STORE.[](key) transaction{|s| super } end
|
7
|
+
def STORE.[]=(key, value) transaction{|s| super } end
|
8
|
+
def STORE.each(&block)
|
9
|
+
YAML.load_file('games.yaml').sort_by{|k,v| -v }.each(&block)
|
10
|
+
end
|
11
|
+
|
12
|
+
STORE['Pacman'] = 1
|
13
|
+
|
14
|
+
class Games
|
15
|
+
Innate.node('/')
|
16
|
+
|
17
|
+
def index
|
18
|
+
TEMPLATE
|
19
|
+
end
|
20
|
+
|
21
|
+
def create
|
22
|
+
STORE[request[:name]] ||= 0 if request.post?
|
23
|
+
|
24
|
+
redirect_referrer
|
25
|
+
end
|
26
|
+
|
27
|
+
def vote(name)
|
28
|
+
STORE[name] += 1
|
29
|
+
|
30
|
+
redirect_referrer
|
31
|
+
end
|
32
|
+
|
33
|
+
TEMPLATE = <<-'T'.strip
|
34
|
+
<?xml version='1.0' encoding='utf-8' ?>
|
35
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
36
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
37
|
+
<html>
|
38
|
+
<head>
|
39
|
+
<title>Top Retro Games</title>
|
40
|
+
</head>
|
41
|
+
<body>
|
42
|
+
<h1>Vote on your favorite Retro Game</h1>
|
43
|
+
<form action="#{ r(:create) }" method="post">
|
44
|
+
<input type="text" name="name" />
|
45
|
+
<input type="submit" value="Add" />
|
46
|
+
</form>
|
47
|
+
<ol>
|
48
|
+
<?r STORE.each do |name, votes| ?>
|
49
|
+
<li>
|
50
|
+
#{ a("Vote", r(:vote, u(name))) }
|
51
|
+
#{ h "%5d => %s" % [votes, name] }
|
52
|
+
</li>
|
53
|
+
<?r end ?>
|
54
|
+
</ol>
|
55
|
+
</body>
|
56
|
+
</html>
|
57
|
+
T
|
58
|
+
end
|
59
|
+
|
60
|
+
Innate.start
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<?xml version='1.0' encoding='utf-8' ?>
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
+
<html>
|
4
|
+
<head>
|
5
|
+
<title>Innate TodoList</title>
|
6
|
+
</head>
|
7
|
+
<body>
|
8
|
+
<h1>Organize your life and learn Innate</h1>
|
9
|
+
#{ @content }
|
10
|
+
</body>
|
11
|
+
</html>
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'innate/spec'
|
2
|
+
|
3
|
+
FileUtils.rm_f('todo.pstore')
|
4
|
+
|
5
|
+
require 'start'
|
6
|
+
require 'hpricot'
|
7
|
+
|
8
|
+
describe Todo do
|
9
|
+
behaves_like :mock, :multipart
|
10
|
+
|
11
|
+
it 'starts out without tasks' do
|
12
|
+
doc = Hpricot(get('/').body)
|
13
|
+
doc.at(:table).inner_text.strip.should.be.empty
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'adds a task and redirects back' do
|
17
|
+
got = post('/create', multipart('title' => 'first task'))
|
18
|
+
got.status.should == 302
|
19
|
+
got['Location'].should == 'http://example.org/'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'shows the task as pending' do
|
23
|
+
doc = Hpricot(get('/').body)
|
24
|
+
doc.at('td/input[@name=title]')['value'].should == 'first task'
|
25
|
+
doc.at('td/input[@name=done]')['checked'].should.be.nil
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'updates the task title and redirects back' do
|
29
|
+
got = post('/update', multipart('id' => 'first task', 'title' => 'wash dishes'))
|
30
|
+
got.status.should == 302
|
31
|
+
got['Location'].should == 'http://example.org/'
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'shows the changed task title' do
|
35
|
+
doc = Hpricot(get('/').body)
|
36
|
+
doc.at('td/input[@name=title]')['value'].should == 'wash dishes'
|
37
|
+
doc.at('td/input[@name=done]')['checked'].should.be.nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'marks the task as done and redirects back' do
|
41
|
+
mp = multipart('id' => 'wash dishes', 'title' => 'wash dishes', 'done' => 'on')
|
42
|
+
got = post('/update', mp)
|
43
|
+
got.status.should == 302
|
44
|
+
got['Location'].should == 'http://example.org/'
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'shows the task as done' do
|
48
|
+
doc = Hpricot(get('/').body)
|
49
|
+
doc.at('td/input[@name=title]')['value'].should == 'wash dishes'
|
50
|
+
doc.at('td/input[@name=done]')['checked'].should == 'checked'
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'deletes the task and redirects back' do
|
54
|
+
got = post('/delete', multipart('id' => 'wash dishes'))
|
55
|
+
got.status.should == 302
|
56
|
+
got['Location'].should == 'http://example.org/'
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'shows no tasks' do
|
60
|
+
doc = Hpricot(get('/').body)
|
61
|
+
doc.at(:table).inner_text.strip.should.be.empty
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'innate'
|
3
|
+
require 'pstore'
|
4
|
+
|
5
|
+
LIST = PStore.new('todo.pstore')
|
6
|
+
|
7
|
+
class Todo
|
8
|
+
Innate.node '/'
|
9
|
+
layout 'default'
|
10
|
+
|
11
|
+
def index
|
12
|
+
@list = sync{|list| list.roots.map{|key| [key, list[key]] }}
|
13
|
+
end
|
14
|
+
|
15
|
+
def create
|
16
|
+
redirect_referer unless request.post? and title = request[:title]
|
17
|
+
title.strip!
|
18
|
+
|
19
|
+
sync{ LIST[title] = false } unless title.empty?
|
20
|
+
redirect_referer
|
21
|
+
end
|
22
|
+
|
23
|
+
def update
|
24
|
+
id, title, done = request[:id, :title, :done]
|
25
|
+
redirect_referer unless request.post? and id and title
|
26
|
+
done = !!done
|
27
|
+
title.strip!
|
28
|
+
|
29
|
+
if id == title
|
30
|
+
sync{ LIST[id] = done }
|
31
|
+
elsif title != ''
|
32
|
+
sync{ LIST.delete(id); LIST[title] = done }
|
33
|
+
end
|
34
|
+
|
35
|
+
redirect_referer
|
36
|
+
end
|
37
|
+
|
38
|
+
def delete
|
39
|
+
redirect_referer unless request.post? and id = request[:id]
|
40
|
+
sync{ LIST.delete(id) }
|
41
|
+
redirect_referer
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def sync
|
47
|
+
Innate.sync{ LIST.transaction{ yield(LIST) }}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
Innate.start
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<form method="post" action="#{ r :create }">
|
2
|
+
<fieldset>
|
3
|
+
<legend>Create new task</legend>
|
4
|
+
|
5
|
+
<label for="form_title">Title:</label>
|
6
|
+
<input id="form_title" type="text" name="title" />
|
7
|
+
|
8
|
+
<input type="submit" value="Create" />
|
9
|
+
</fieldset>
|
10
|
+
</form>
|
11
|
+
|
12
|
+
<table>
|
13
|
+
<?r @list.each do |title, done| ?>
|
14
|
+
<tr>
|
15
|
+
<form method="post" action="#{ r :update }">
|
16
|
+
<input type="hidden" name="id" value="#{ h title }" />
|
17
|
+
<td>
|
18
|
+
<input type="text" name="title" value="#{ h title }" />
|
19
|
+
</td>
|
20
|
+
<td>
|
21
|
+
<?r if done ?>
|
22
|
+
<input type="checkbox" name="done" checked="checked" />
|
23
|
+
<?r else ?>
|
24
|
+
<input type="checkbox" name="done" />
|
25
|
+
<?r end ?>
|
26
|
+
</td>
|
27
|
+
<td>
|
28
|
+
<input type="submit" value="Update" />
|
29
|
+
</td>
|
30
|
+
</form>
|
31
|
+
<form method="post" action="#{ r :delete }">
|
32
|
+
<input type="hidden" name="id" value="#{ h title }" />
|
33
|
+
<td>
|
34
|
+
<input type="submit" value="Delete" />
|
35
|
+
</td>
|
36
|
+
</form>
|
37
|
+
</tr>
|
38
|
+
<?r end ?>
|
39
|
+
</table>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<?xml version='1.0' encoding='utf-8' ?>
|
2
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
+
<html>
|
4
|
+
<head>
|
5
|
+
<title>MicroWiki <%= h @page %></title>
|
6
|
+
<style type="text/css">
|
7
|
+
a.exists{ color: #00f; }
|
8
|
+
a.missing{ color: #f00; }
|
9
|
+
textarea{ width: 90%; height: 20em; }
|
10
|
+
</style>
|
11
|
+
</head>
|
12
|
+
<body>
|
13
|
+
<%= @content %>
|
14
|
+
</body>
|
15
|
+
</html>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'innate'
|
2
|
+
require 'innate/spec'
|
3
|
+
require 'yaml/store'
|
4
|
+
|
5
|
+
base = File.join(File.dirname(__FILE__), '..')
|
6
|
+
DB = YAML::Store.new(db_file = "#{base}/spec/wiki.yaml")
|
7
|
+
|
8
|
+
require "start"
|
9
|
+
|
10
|
+
Innate.config.app.root = base
|
11
|
+
|
12
|
+
describe 'Wiki' do
|
13
|
+
it 'should have index page' do
|
14
|
+
page = Innate::Mock.get('/')
|
15
|
+
page.body.should == ''
|
16
|
+
end
|
17
|
+
|
18
|
+
FileUtils.rm_f(db_file)
|
19
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# The minimal _why wiki in Innate with ERB
|
2
|
+
|
3
|
+
%w[rubygems innate erb maruku yaml/store].each{|l| require(l) }
|
4
|
+
|
5
|
+
DB = YAML::Store.new('wiki.yaml') unless defined?(DB)
|
6
|
+
|
7
|
+
class Wiki
|
8
|
+
Innate.node '/'
|
9
|
+
layout 'wiki'
|
10
|
+
provide :html, :engine => :ERB
|
11
|
+
|
12
|
+
def index(page = 'Home')
|
13
|
+
@page = page
|
14
|
+
@text = 'foo'
|
15
|
+
sync{
|
16
|
+
@text = DB[page].to_s.dup
|
17
|
+
@text.gsub!(/\[\[(.*?)\]\]/) do
|
18
|
+
%(<a href="#{r($1)}" class="#{DB[$1] ? 'exists' : 'missing'}">#{h($1)}</a>)
|
19
|
+
end
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def edit(page)
|
24
|
+
@page = page
|
25
|
+
@text = sync{ DB[page].to_s }
|
26
|
+
end
|
27
|
+
|
28
|
+
def save
|
29
|
+
page, text = request[:page, :text]
|
30
|
+
sync{ DB[page] = text } if request.post? and page and text
|
31
|
+
|
32
|
+
redirect(r(page))
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def sync
|
38
|
+
Innate::STATE.sync{ DB.transaction{ yield }}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Innate.start
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<% unless @page == 'Home' %>
|
2
|
+
<%= a('< Home', :Home) %>
|
3
|
+
<% end %>
|
4
|
+
|
5
|
+
<h1><%= h @page %></h1>
|
6
|
+
|
7
|
+
<% if @text.empty? %>
|
8
|
+
<%= a("Create #@page", :edit, @page) %>
|
9
|
+
<% else %>
|
10
|
+
<%= a("Edit #@page", :edit, @page) %>
|
11
|
+
<%= Maruku.new(@text).to_html %>
|
12
|
+
<% end %>
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'innate'
|
3
|
+
|
4
|
+
class Demo
|
5
|
+
Innate.node '/'
|
6
|
+
|
7
|
+
def index
|
8
|
+
'Hello, World!'
|
9
|
+
end
|
10
|
+
|
11
|
+
def empty
|
12
|
+
response.status = 405
|
13
|
+
''
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Innate.start do |mw|
|
18
|
+
# Makes sure all requests and responses conform to Rack protocol
|
19
|
+
mw.use Rack::Lint
|
20
|
+
|
21
|
+
# Avoid showing empty failure pages, give information when it happens.
|
22
|
+
mw.use Rack::ShowStatus
|
23
|
+
|
24
|
+
# Catch exceptions inside Innate and give nice status info
|
25
|
+
mw.use Rack::ShowExceptions
|
26
|
+
|
27
|
+
# Log access
|
28
|
+
mw.use Rack::CommonLogger
|
29
|
+
|
30
|
+
# Reload modified files before request
|
31
|
+
mw.use Rack::Reloader
|
32
|
+
|
33
|
+
# Start up the application
|
34
|
+
mw.innate
|
35
|
+
end
|
data/example/hello.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'innate'
|
3
|
+
|
4
|
+
class SpecMe
|
5
|
+
Innate.node '/'
|
6
|
+
|
7
|
+
def index
|
8
|
+
"I should be at /"
|
9
|
+
end
|
10
|
+
|
11
|
+
def foo
|
12
|
+
response['Content-Type'] = 'text/css'
|
13
|
+
"I should be at /foo"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'innate/spec'
|
18
|
+
|
19
|
+
describe 'An example spec' do
|
20
|
+
behaves_like :mock
|
21
|
+
|
22
|
+
should 'respond to /' do
|
23
|
+
got = get('/')
|
24
|
+
got.status.should == 200
|
25
|
+
got.body.should == "I should be at /"
|
26
|
+
got['Content-Type'].should == 'text/html'
|
27
|
+
end
|
28
|
+
|
29
|
+
should 'respond to /foo' do
|
30
|
+
got = get('/foo')
|
31
|
+
got.status.should == 200
|
32
|
+
got.body.should == "I should be at /foo"
|
33
|
+
got['Content-Type'].should == 'text/css'
|
34
|
+
end
|
35
|
+
end
|