innate 2009.04

Sign up to get free protection for your applications and to get access to all the features.
Files changed (128) hide show
  1. data/CHANGELOG +2981 -0
  2. data/COPYING +18 -0
  3. data/MANIFEST +127 -0
  4. data/README.md +563 -0
  5. data/Rakefile +35 -0
  6. data/example/app/retro_games.rb +60 -0
  7. data/example/app/todo/layout/default.xhtml +11 -0
  8. data/example/app/todo/spec/todo.rb +63 -0
  9. data/example/app/todo/start.rb +51 -0
  10. data/example/app/todo/view/index.xhtml +39 -0
  11. data/example/app/whywiki_erb/layout/wiki.html.erb +15 -0
  12. data/example/app/whywiki_erb/spec/wiki.rb +19 -0
  13. data/example/app/whywiki_erb/start.rb +42 -0
  14. data/example/app/whywiki_erb/view/edit.erb +6 -0
  15. data/example/app/whywiki_erb/view/index.erb +12 -0
  16. data/example/custom_middleware.rb +35 -0
  17. data/example/hello.rb +11 -0
  18. data/example/howto_spec.rb +35 -0
  19. data/example/link.rb +27 -0
  20. data/example/provides.rb +31 -0
  21. data/example/session.rb +38 -0
  22. data/innate.gemspec +29 -0
  23. data/lib/innate.rb +269 -0
  24. data/lib/innate/action.rb +150 -0
  25. data/lib/innate/adapter.rb +76 -0
  26. data/lib/innate/cache.rb +134 -0
  27. data/lib/innate/cache/api.rb +128 -0
  28. data/lib/innate/cache/drb.rb +58 -0
  29. data/lib/innate/cache/file_based.rb +41 -0
  30. data/lib/innate/cache/marshal.rb +17 -0
  31. data/lib/innate/cache/memory.rb +22 -0
  32. data/lib/innate/cache/yaml.rb +17 -0
  33. data/lib/innate/current.rb +37 -0
  34. data/lib/innate/dynamap.rb +96 -0
  35. data/lib/innate/helper.rb +183 -0
  36. data/lib/innate/helper/aspect.rb +124 -0
  37. data/lib/innate/helper/cgi.rb +54 -0
  38. data/lib/innate/helper/flash.rb +36 -0
  39. data/lib/innate/helper/link.rb +94 -0
  40. data/lib/innate/helper/redirect.rb +85 -0
  41. data/lib/innate/helper/render.rb +87 -0
  42. data/lib/innate/helper/send_file.rb +26 -0
  43. data/lib/innate/log.rb +20 -0
  44. data/lib/innate/log/color_formatter.rb +43 -0
  45. data/lib/innate/log/hub.rb +73 -0
  46. data/lib/innate/middleware_compiler.rb +65 -0
  47. data/lib/innate/mock.rb +49 -0
  48. data/lib/innate/node.rb +1025 -0
  49. data/lib/innate/options.rb +37 -0
  50. data/lib/innate/options/dsl.rb +202 -0
  51. data/lib/innate/options/stub.rb +7 -0
  52. data/lib/innate/request.rb +141 -0
  53. data/lib/innate/response.rb +23 -0
  54. data/lib/innate/route.rb +110 -0
  55. data/lib/innate/session.rb +121 -0
  56. data/lib/innate/session/flash.rb +94 -0
  57. data/lib/innate/spec.rb +23 -0
  58. data/lib/innate/state.rb +27 -0
  59. data/lib/innate/state/accessor.rb +130 -0
  60. data/lib/innate/state/fiber.rb +74 -0
  61. data/lib/innate/state/thread.rb +47 -0
  62. data/lib/innate/traited.rb +85 -0
  63. data/lib/innate/trinity.rb +18 -0
  64. data/lib/innate/version.rb +3 -0
  65. data/lib/innate/view.rb +60 -0
  66. data/lib/innate/view/erb.rb +15 -0
  67. data/lib/innate/view/etanni.rb +36 -0
  68. data/lib/innate/view/none.rb +9 -0
  69. data/spec/example/app/retro_games.rb +30 -0
  70. data/spec/example/hello.rb +13 -0
  71. data/spec/example/link.rb +25 -0
  72. data/spec/example/provides.rb +16 -0
  73. data/spec/example/session.rb +22 -0
  74. data/spec/helper.rb +10 -0
  75. data/spec/innate/action/layout.rb +107 -0
  76. data/spec/innate/action/layout/file_layout.xhtml +1 -0
  77. data/spec/innate/cache/common.rb +47 -0
  78. data/spec/innate/cache/marshal.rb +5 -0
  79. data/spec/innate/cache/memory.rb +5 -0
  80. data/spec/innate/cache/yaml.rb +5 -0
  81. data/spec/innate/dynamap.rb +22 -0
  82. data/spec/innate/helper.rb +86 -0
  83. data/spec/innate/helper/aspect.rb +75 -0
  84. data/spec/innate/helper/cgi.rb +37 -0
  85. data/spec/innate/helper/flash.rb +118 -0
  86. data/spec/innate/helper/link.rb +139 -0
  87. data/spec/innate/helper/redirect.rb +160 -0
  88. data/spec/innate/helper/render.rb +133 -0
  89. data/spec/innate/helper/send_file.rb +21 -0
  90. data/spec/innate/helper/view/aspect_hello.xhtml +1 -0
  91. data/spec/innate/helper/view/locals.xhtml +1 -0
  92. data/spec/innate/helper/view/loop.xhtml +4 -0
  93. data/spec/innate/helper/view/num.xhtml +1 -0
  94. data/spec/innate/helper/view/partial.xhtml +1 -0
  95. data/spec/innate/helper/view/recursive.xhtml +7 -0
  96. data/spec/innate/mock.rb +84 -0
  97. data/spec/innate/node/mapping.rb +37 -0
  98. data/spec/innate/node/node.rb +134 -0
  99. data/spec/innate/node/resolve.rb +82 -0
  100. data/spec/innate/node/view/another_layout/another_layout.xhtml +3 -0
  101. data/spec/innate/node/view/bar.xhtml +1 -0
  102. data/spec/innate/node/view/foo.html.xhtml +1 -0
  103. data/spec/innate/node/view/only_view.xhtml +1 -0
  104. data/spec/innate/node/view/with_layout.xhtml +1 -0
  105. data/spec/innate/node/wrap_action_call.rb +83 -0
  106. data/spec/innate/options.rb +115 -0
  107. data/spec/innate/parameter.rb +154 -0
  108. data/spec/innate/provides.rb +99 -0
  109. data/spec/innate/provides/list.html.xhtml +1 -0
  110. data/spec/innate/provides/list.txt.xhtml +1 -0
  111. data/spec/innate/request.rb +77 -0
  112. data/spec/innate/route.rb +135 -0
  113. data/spec/innate/session.rb +54 -0
  114. data/spec/innate/state/fiber.rb +58 -0
  115. data/spec/innate/state/thread.rb +40 -0
  116. data/spec/innate/traited.rb +55 -0
  117. data/tasks/bacon.rake +66 -0
  118. data/tasks/changelog.rake +18 -0
  119. data/tasks/gem.rake +22 -0
  120. data/tasks/gem_installer.rake +76 -0
  121. data/tasks/grancher.rake +12 -0
  122. data/tasks/install_dependencies.rake +4 -0
  123. data/tasks/manifest.rake +4 -0
  124. data/tasks/rcov.rake +19 -0
  125. data/tasks/release.rake +51 -0
  126. data/tasks/reversion.rake +8 -0
  127. data/tasks/setup.rake +28 -0
  128. metadata +181 -0
@@ -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,6 @@
1
+ <%= a("< #@page", @page) %>
2
+ <form method="post" action="<%= r :save %>">
3
+ <input type="hidden" name="page" value="<%= h @page %>" />
4
+ <textarea name="text"><%= @text %></textarea>
5
+ <input type="submit" value="Save" />
6
+ </form>
@@ -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
@@ -0,0 +1,11 @@
1
+ require 'innate'
2
+
3
+ class Hello
4
+ Innate.node '/'
5
+
6
+ def index
7
+ 'Hello, World!'
8
+ end
9
+ end
10
+
11
+ Innate.start
@@ -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