manveru-innate 2009.02.06

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. data/CHANGELOG +1409 -0
  2. data/COPYING +18 -0
  3. data/MANIFEST +100 -0
  4. data/README.md +485 -0
  5. data/Rakefile +139 -0
  6. data/example/app/retro_games.rb +57 -0
  7. data/example/app/whywiki_erb/layout/wiki.html.erb +15 -0
  8. data/example/app/whywiki_erb/spec/wiki.rb +19 -0
  9. data/example/app/whywiki_erb/start.rb +45 -0
  10. data/example/app/whywiki_erb/view/edit.html.erb +6 -0
  11. data/example/app/whywiki_erb/view/index.html.erb +10 -0
  12. data/example/custom_middleware.rb +43 -0
  13. data/example/error_handling.rb +31 -0
  14. data/example/hello.rb +12 -0
  15. data/example/howto_spec.rb +60 -0
  16. data/example/link.rb +35 -0
  17. data/example/providing_hash.rb +46 -0
  18. data/example/session.rb +42 -0
  19. data/innate.gemspec +118 -0
  20. data/lib/innate.rb +191 -0
  21. data/lib/innate/action.rb +156 -0
  22. data/lib/innate/adapter.rb +89 -0
  23. data/lib/innate/cache.rb +117 -0
  24. data/lib/innate/cache/api.rb +106 -0
  25. data/lib/innate/cache/drb.rb +58 -0
  26. data/lib/innate/cache/file_based.rb +39 -0
  27. data/lib/innate/cache/marshal.rb +17 -0
  28. data/lib/innate/cache/memory.rb +22 -0
  29. data/lib/innate/cache/yaml.rb +17 -0
  30. data/lib/innate/core_compatibility/basic_object.rb +9 -0
  31. data/lib/innate/core_compatibility/string.rb +3 -0
  32. data/lib/innate/current.rb +37 -0
  33. data/lib/innate/dynamap.rb +81 -0
  34. data/lib/innate/helper.rb +195 -0
  35. data/lib/innate/helper/aspect.rb +62 -0
  36. data/lib/innate/helper/cgi.rb +39 -0
  37. data/lib/innate/helper/flash.rb +36 -0
  38. data/lib/innate/helper/link.rb +55 -0
  39. data/lib/innate/helper/partial.rb +90 -0
  40. data/lib/innate/helper/redirect.rb +85 -0
  41. data/lib/innate/helper/send_file.rb +18 -0
  42. data/lib/innate/log.rb +23 -0
  43. data/lib/innate/log/color_formatter.rb +43 -0
  44. data/lib/innate/log/hub.rb +72 -0
  45. data/lib/innate/mock.rb +49 -0
  46. data/lib/innate/node.rb +471 -0
  47. data/lib/innate/options.rb +91 -0
  48. data/lib/innate/options/dsl.rb +155 -0
  49. data/lib/innate/request.rb +165 -0
  50. data/lib/innate/response.rb +18 -0
  51. data/lib/innate/route.rb +109 -0
  52. data/lib/innate/session.rb +104 -0
  53. data/lib/innate/session/flash.rb +94 -0
  54. data/lib/innate/setup.rb +23 -0
  55. data/lib/innate/spec.rb +42 -0
  56. data/lib/innate/state.rb +22 -0
  57. data/lib/innate/state/accessor.rb +130 -0
  58. data/lib/innate/state/fiber.rb +68 -0
  59. data/lib/innate/state/thread.rb +39 -0
  60. data/lib/innate/traited.rb +20 -0
  61. data/lib/innate/trinity.rb +22 -0
  62. data/lib/innate/version.rb +3 -0
  63. data/lib/innate/view.rb +67 -0
  64. data/lib/innate/view/erb.rb +17 -0
  65. data/lib/innate/view/none.rb +9 -0
  66. data/lib/rack/middleware_compiler.rb +62 -0
  67. data/lib/rack/reloader.rb +192 -0
  68. data/spec/example/hello.rb +14 -0
  69. data/spec/example/link.rb +29 -0
  70. data/spec/helper.rb +2 -0
  71. data/spec/innate/cache/common.rb +45 -0
  72. data/spec/innate/cache/marshal.rb +5 -0
  73. data/spec/innate/cache/memory.rb +5 -0
  74. data/spec/innate/cache/yaml.rb +5 -0
  75. data/spec/innate/dynamap.rb +22 -0
  76. data/spec/innate/helper.rb +66 -0
  77. data/spec/innate/helper/aspect.rb +80 -0
  78. data/spec/innate/helper/cgi.rb +37 -0
  79. data/spec/innate/helper/flash.rb +148 -0
  80. data/spec/innate/helper/link.rb +82 -0
  81. data/spec/innate/helper/partial.rb +66 -0
  82. data/spec/innate/helper/redirect.rb +148 -0
  83. data/spec/innate/helper/send_file.rb +21 -0
  84. data/spec/innate/helper/view/aspect_hello.erb +1 -0
  85. data/spec/innate/helper/view/locals.erb +1 -0
  86. data/spec/innate/helper/view/loop.erb +4 -0
  87. data/spec/innate/helper/view/num.erb +1 -0
  88. data/spec/innate/helper/view/partial.erb +1 -0
  89. data/spec/innate/helper/view/recursive.erb +8 -0
  90. data/spec/innate/mock.rb +84 -0
  91. data/spec/innate/node.rb +180 -0
  92. data/spec/innate/node/bar.html +1 -0
  93. data/spec/innate/node/foo.html.erb +1 -0
  94. data/spec/innate/node/with_layout.erb +3 -0
  95. data/spec/innate/options.rb +90 -0
  96. data/spec/innate/parameter.rb +154 -0
  97. data/spec/innate/request.rb +73 -0
  98. data/spec/innate/route.rb +129 -0
  99. data/spec/innate/session.rb +59 -0
  100. data/spec/innate/traited.rb +55 -0
  101. metadata +160 -0
data/Rakefile ADDED
@@ -0,0 +1,139 @@
1
+ require 'rake/rdoctask'
2
+ require 'rake/clean'
3
+ require 'time'
4
+ require 'date'
5
+ require 'pp'
6
+
7
+ INNATE_VERSION = Date.today.strftime("%Y.%m.%d")
8
+
9
+ task :default => [:spec]
10
+
11
+ CLEAN.include('*coverage*')
12
+
13
+ desc 'update lib/innate/version.rb'
14
+ task :reversion do
15
+ File.open('lib/innate/version.rb', 'w+') do |file|
16
+ file.puts('module Innate')
17
+ file.puts(' VERSION = %p' % INNATE_VERSION)
18
+ file.puts('end')
19
+ end
20
+ end
21
+
22
+ desc 'publish to github'
23
+ task :release => [:reversion, :gemspec] do
24
+ sh('git add MANIFEST CHANGELOG innate.gemspec lib/innate/version.rb')
25
+ puts "I added the relevant files, you can now run:", ''
26
+ puts "git commit -m 'Version #{INNATE_VERSION}'"
27
+ puts "git tag -m '#{INNATE_VERSION}'"
28
+ puts "git push"
29
+ puts
30
+ end
31
+
32
+ desc 'update manifest'
33
+ task :manifest do
34
+ File.open('MANIFEST', 'w+') do|manifest|
35
+ manifest.puts(`git ls-files`)
36
+ end
37
+ end
38
+
39
+ desc 'update changelog'
40
+ task :changelog do
41
+ File.open('CHANGELOG', 'w+') do |changelog|
42
+ `git log -z --abbrev-commit`.split("\0").each do |commit|
43
+ next if commit =~ /^Merge: \d*/
44
+ ref, author, time, _, title, _, message = commit.split("\n", 7)
45
+ ref = ref[/commit ([0-9a-f]+)/, 1]
46
+ author = author[/Author: (.*)/, 1].strip
47
+ time = Time.parse(time[/Date: (.*)/, 1]).utc
48
+ title.strip!
49
+
50
+ changelog.puts "[#{ref} | #{time}] #{author}"
51
+ changelog.puts '', " * #{title}"
52
+ changelog.puts '', message.rstrip if message
53
+ changelog.puts
54
+ end
55
+ end
56
+ end
57
+
58
+ desc 'generate gemspec'
59
+ task :gemspec => [:manifest, :changelog] do
60
+ manifest = File.read('MANIFEST').split("\n")
61
+ files = manifest.map{|file| " %p," % file }.join("\n")[0..-2]
62
+
63
+ gemspec = <<-GEMSPEC
64
+ Gem::Specification.new do |s|
65
+ s.name = "innate"
66
+ s.version = #{INNATE_VERSION.dump}
67
+
68
+ s.summary = "Powerful web-framework wrapper for Rack."
69
+ s.description = "Simple, straight-forward, base for web-frameworks."
70
+ s.platform = "ruby"
71
+ s.has_rdoc = true
72
+ s.author = "Michael 'manveru' Fellinger"
73
+ s.email = "m.fellinger@gmail.com"
74
+ s.homepage = "http://github.com/manveru/innate"
75
+ s.require_path = "lib"
76
+
77
+ s.add_dependency('rack', '>= 0.4.0')
78
+
79
+ s.files = [
80
+ #{files}
81
+ ]
82
+ end
83
+ GEMSPEC
84
+
85
+ File.open('innate.gemspec', 'w+'){|gs| gs.puts(gemspec) }
86
+ end
87
+
88
+ desc 'code coverage'
89
+ task :rcov => :clean do
90
+ specs = Dir['spec/innate/**/*.rb']
91
+ specs -= Dir['spec/innate/cache/common.rb']
92
+
93
+ # we ignore adapter as this has extensive specs in rack already.
94
+ ignore = %w[ gem rack bacon innate/adapter\.rb ]
95
+ ignore << 'fiber\.rb' if RUBY_VERSION < '1.9'
96
+
97
+ ignored = ignore.join(',')
98
+
99
+ cmd = "rcov --aggregate coverage.data --sort coverage -t --%s -x '#{ignored}' %s"
100
+
101
+ while spec = specs.shift
102
+ puts '', "Gather coverage for #{spec} ..."
103
+ html = specs.empty? ? 'html' : 'no-html'
104
+ sh(cmd % [html, spec])
105
+ end
106
+ end
107
+
108
+ desc 'Run all specs'
109
+ task :spec do
110
+ require 'open3'
111
+
112
+ specs = Dir['spec/{innate,example}/**/*.rb']
113
+ specs.delete_if{|f| f =~ /cache\/common\.rb/ }
114
+
115
+ total = specs.size
116
+ len = specs.sort.last.size
117
+ left_format = "%4d/%d: %-#{len + 11}s"
118
+
119
+ red, green = "\e[31m%s\e[0m", "\e[32m%s\e[0m"
120
+
121
+ specs.each_with_index do |spec, idx|
122
+ print(left_format % [idx + 1, total, spec])
123
+
124
+ Open3.popen3("#{RUBY} #{spec}") do |sin, sout, serr|
125
+ out = sout.read
126
+ err = serr.read
127
+
128
+ md = out.match(/(\d+) tests, (\d+) assertions, (\d+) failures, (\d+) errors/)
129
+ tests, assertions, failures, errors = all = md.captures.map{|c| c.to_i }
130
+
131
+ if failures + errors > 0
132
+ puts((red % "%5d tests, %d assertions, %d failures, %d errors") % all)
133
+ puts "", out, err, ""
134
+ else
135
+ puts((green % "%5d passed") % tests)
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,57 @@
1
+ require 'innate'
2
+ require 'yaml/store'
3
+
4
+ STORE = YAML::Store.new('games.yaml')
5
+
6
+ def STORE.[](key) transaction{|s| s[key] } end
7
+ def STORE.[]=(key, value) transaction{|s| s[key] = value } end
8
+ def STORE.each
9
+ YAML.load_file('games.yaml').sort_by{|k,v| -v }.each{|(k,v)| yield(k, v) }
10
+ end
11
+
12
+ class Games
13
+ include Innate::Node
14
+ map '/'
15
+ provide :html => :haml
16
+
17
+ def index
18
+ TEMPLATE
19
+ end
20
+
21
+ def create
22
+ if request.post?
23
+ name = request.params['name']
24
+ STORE[name] ||= 0
25
+ end
26
+
27
+ redirect_referrer
28
+ end
29
+
30
+ def vote(name)
31
+ STORE[url_decode name] += 1
32
+
33
+ redirect_referrer
34
+ end
35
+
36
+ TEMPLATE = <<-'T'.strip
37
+ !!! XML
38
+ !!!
39
+
40
+ %html
41
+ %head
42
+ %title Top Retro Games
43
+ %body
44
+ %h1 Vote on your favorite Retro Game
45
+ %form{:action => r(:create), :method => 'POST'}
46
+ %input{:type => 'text', :name => 'name'}
47
+ %input{:type => 'submit', :value => 'Add'}
48
+ %ol
49
+ - STORE.each do |name, votes|
50
+ %li
51
+ = Games.a("Vote", "/vote/#{u name}")
52
+ = h("%5d => %s" % [votes, name])
53
+ T
54
+
55
+ end
56
+
57
+ Innate.start
@@ -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,45 @@
1
+ # The minimal _why wiki in Innate
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
+ include Innate::Node
9
+ map '/'
10
+ provide :html => :erb
11
+ layout 'wiki'
12
+
13
+ def index(page = 'Home')
14
+ @page = page
15
+ @text = 'foo'
16
+ sync{
17
+ @text = DB[page].to_s.dup
18
+ @text.gsub!(/\[\[(.*?)\]\]/) do
19
+ %(<a href="#{r($1)}" class="#{DB[$1] ? 'exists' : 'missing'}">#{h($1)}</a>)
20
+ end
21
+ }
22
+ end
23
+
24
+ def edit(page)
25
+ @page = page
26
+ @text = sync{ DB[page].to_s }
27
+ end
28
+
29
+ def save
30
+ redirect_referrer unless request.post?
31
+
32
+ page, text = request[:page, :text]
33
+ sync{ DB[page] = text } if page and text
34
+
35
+ redirect(r(page))
36
+ end
37
+
38
+ private
39
+
40
+ def sync
41
+ Innate::STATE.sync{ DB.transaction{ yield }}
42
+ end
43
+ end
44
+
45
+ Innate.start :adapter => :mongrel
@@ -0,0 +1,6 @@
1
+ <a href="<%= r @page %>"><%= h "< #{@page}" %></a>
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,10 @@
1
+ <% unless @page == 'Home' %>
2
+ <a href="<%= r 'Home' %>">&lt; Home</a>
3
+ <% end %>
4
+ <h1><%= h @page %></h1>
5
+ <% if @text.empty? %>
6
+ <a href="<%= r :edit, @page %>"><%= h "Create #{@page}" %></a>
7
+ <% else %>
8
+ <a href="<%= r :edit, @page %>"><%= h "Edit #{@page}" %></a>
9
+ <%= Maruku.new(@text).to_html %>
10
+ <% end %>
@@ -0,0 +1,43 @@
1
+ require 'innate'
2
+
3
+ class Demo
4
+ include Innate::Node
5
+ map '/'
6
+
7
+ def index
8
+ 'Hello, World!'
9
+ end
10
+
11
+ def empty
12
+ response.status = 405
13
+ ''
14
+ end
15
+ end
16
+
17
+ # Make sure you do this before Innate.start, otherwise you have to use
18
+ # Innate.middleware! to force a rebuild in the MiddlewareCompiler.
19
+ Innate.middleware :innate do |mw|
20
+ # Makes sure all requests and responses conform to Rack protocol
21
+ mw.use Rack::Lint
22
+
23
+ # Avoid showing empty failure pages, give information when it happens.
24
+ mw.use Rack::ShowStatus
25
+
26
+ # Catch exceptions inside Innate and give nice status info
27
+ mw.use Rack::ShowExceptions
28
+
29
+ # Log access
30
+ mw.use Rack::CommonLogger
31
+
32
+ # Reload modified files before request
33
+ mw.use Rack::Reloader
34
+
35
+ # Initializes the Current objects: Request, Response, and Session
36
+ mw.use Innate::Current
37
+
38
+ # This will try to find a static file in /public first, and try DynaMap if
39
+ # Rack::File returns a 404 status.
40
+ mw.cascade Rack::File.new('public'), Innate::DynaMap
41
+ end
42
+
43
+ Innate.start
@@ -0,0 +1,31 @@
1
+ require 'innate'
2
+
3
+ class Flawed
4
+ include Innate::Node
5
+ map '/'
6
+
7
+ def index
8
+ raise ArgumentError, "No go"
9
+ end
10
+
11
+ def i_raise
12
+ 100 * "foo"
13
+ end
14
+ end
15
+
16
+ class Errors
17
+ include Innate::Node
18
+ map '/error'
19
+
20
+ def internal
21
+ path = request.env['rack.route_exceptions.path_info']
22
+ exception = request.env['rack.route_exceptions.exception']
23
+
24
+ format = "Oh my, you just went to %p, something went horribly wrong: %p"
25
+ format % [path, exception.message]
26
+ end
27
+ end
28
+
29
+ Rack::RouteExceptions.route(Exception, '/error/internal')
30
+
31
+ Innate.start
data/example/hello.rb ADDED
@@ -0,0 +1,12 @@
1
+ require 'innate'
2
+
3
+ class Hello
4
+ include Innate::Node
5
+ map '/'
6
+
7
+ def index
8
+ 'Hello, World!'
9
+ end
10
+ end
11
+
12
+ Innate.start
@@ -0,0 +1,60 @@
1
+ require 'innate'
2
+ require 'bacon'
3
+
4
+ class SpecMe
5
+ include Innate::Node
6
+ map '/'
7
+
8
+ def index
9
+ "I should be at /"
10
+ end
11
+
12
+ def foo
13
+ action.content_type = 'text/css'
14
+ "I should be at /foo"
15
+ end
16
+ end
17
+
18
+ class SpecMeToo
19
+ include Innate::Node
20
+ map '/too'
21
+
22
+ def index
23
+ "I should be at /too"
24
+ end
25
+
26
+ def foo
27
+ action.content_type = 'text/css'
28
+ "I should be at /too/foo"
29
+ end
30
+ end
31
+
32
+ Innate.setup_middleware
33
+
34
+ Bacon.summary_on_exit
35
+ Bacon.extend(Bacon::TestUnitOutput)
36
+
37
+ describe 'An example spec' do
38
+ def assert(url, body, content_type)
39
+ response = Innate::Mock.get(url)
40
+ response.status.should == 200
41
+ response.body.should == body
42
+ response.content_type.should == content_type
43
+ end
44
+
45
+ should 'respond to /' do
46
+ assert('/', "I should be at /", 'text/html')
47
+ end
48
+
49
+ should 'respond to /foo' do
50
+ assert('/foo', "I should be at /foo", 'text/css')
51
+ end
52
+
53
+ should 'respond to /too' do
54
+ assert('/too', "I should be at /too", 'text/html')
55
+ end
56
+
57
+ should 'respond to /too/foo' do
58
+ assert('/too/foo', "I should be at /too/foo", 'text/css')
59
+ end
60
+ end