rjspotter-innate 2009.06.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS +10 -0
- data/CHANGELOG +3261 -0
- data/COPYING +18 -0
- data/MANIFEST +127 -0
- data/README.md +563 -0
- data/Rakefile +39 -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 +41 -0
- data/lib/innate.rb +269 -0
- data/lib/innate/action.rb +137 -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 +44 -0
- data/lib/innate/cache/marshal.rb +20 -0
- data/lib/innate/cache/memory.rb +21 -0
- data/lib/innate/cache/yaml.rb +20 -0
- data/lib/innate/current.rb +35 -0
- data/lib/innate/dynamap.rb +96 -0
- data/lib/innate/helper.rb +185 -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 +152 -0
- data/lib/innate/helper/send_file.rb +26 -0
- data/lib/innate/log.rb +20 -0
- data/lib/innate/log/color_formatter.rb +49 -0
- data/lib/innate/log/hub.rb +77 -0
- data/lib/innate/middleware_compiler.rb +65 -0
- data/lib/innate/mock.rb +49 -0
- data/lib/innate/node.rb +1029 -0
- data/lib/innate/options.rb +37 -0
- data/lib/innate/options/dsl.rb +205 -0
- data/lib/innate/options/stub.rb +7 -0
- data/lib/innate/request.rb +141 -0
- data/lib/innate/response.rb +24 -0
- data/lib/innate/route.rb +114 -0
- data/lib/innate/session.rb +133 -0
- data/lib/innate/session/flash.rb +94 -0
- data/lib/innate/spec.rb +1 -0
- data/lib/innate/spec/bacon.rb +28 -0
- data/lib/innate/state.rb +26 -0
- data/lib/innate/state/accessor.rb +130 -0
- data/lib/innate/traited.rb +90 -0
- data/lib/innate/trinity.rb +18 -0
- data/lib/innate/version.rb +3 -0
- data/lib/innate/view.rb +97 -0
- data/lib/innate/view/erb.rb +14 -0
- data/lib/innate/view/etanni.rb +33 -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 +121 -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 +115 -0
- data/spec/innate/helper/link.rb +139 -0
- data/spec/innate/helper/redirect.rb +171 -0
- data/spec/innate/helper/render.rb +165 -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/modes.rb +61 -0
- data/spec/innate/node/mapping.rb +37 -0
- data/spec/innate/node/node.rb +135 -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 +123 -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 +79 -0
- data/spec/innate/route.rb +135 -0
- data/spec/innate/session.rb +58 -0
- data/spec/innate/traited.rb +55 -0
- data/tasks/authors.rake +30 -0
- data/tasks/bacon.rake +66 -0
- data/tasks/changelog.rake +18 -0
- data/tasks/gem.rake +22 -0
- data/tasks/gem_setup.rake +99 -0
- data/tasks/grancher.rake +12 -0
- data/tasks/manifest.rake +4 -0
- data/tasks/rcov.rake +19 -0
- data/tasks/release.rake +53 -0
- data/tasks/reversion.rake +8 -0
- data/tasks/setup.rake +6 -0
- data/tasks/ycov.rake +84 -0
- metadata +218 -0
data/example/link.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'innate'
|
2
|
+
|
3
|
+
class Linking
|
4
|
+
Innate.node '/'
|
5
|
+
|
6
|
+
def index
|
7
|
+
"Index links to " + a('Help?', :help)
|
8
|
+
end
|
9
|
+
|
10
|
+
def help
|
11
|
+
"Help links to " + Different.a('A Different Node', :another)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Different
|
16
|
+
Innate.node '/link_to'
|
17
|
+
|
18
|
+
def another
|
19
|
+
a('Another links even deeper', 'and/deeper')
|
20
|
+
end
|
21
|
+
|
22
|
+
def and__deeper
|
23
|
+
Linking.a('Back to Linking Node', :index)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
Innate.start
|
data/example/provides.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'innate'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
ARTICLES = {
|
6
|
+
'hello' => {
|
7
|
+
:author => 'manveru',
|
8
|
+
:title => 'Hello, World!',
|
9
|
+
:text => 'Some text'
|
10
|
+
}
|
11
|
+
}
|
12
|
+
|
13
|
+
class BlogArticles
|
14
|
+
Innate.node('/')
|
15
|
+
|
16
|
+
# provide a content representation for requests to /<action>.yaml
|
17
|
+
# If you request `/list.yaml`, you will get the `ARTICLES object serialized
|
18
|
+
# to YAML.
|
19
|
+
provide(:yaml, :type => 'text/yaml'){|action, value| value.to_yaml }
|
20
|
+
|
21
|
+
# Since there will always be an `html` representation (the default), you have
|
22
|
+
# to take care of it. If you simply want to return an empty page, use following.
|
23
|
+
provide(:html){|action, value| '' }
|
24
|
+
|
25
|
+
# The return value of this method is the `value` in the provides above.
|
26
|
+
def list
|
27
|
+
return ARTICLES
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Innate.start
|
data/example/session.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'innate'
|
2
|
+
|
3
|
+
class Hello
|
4
|
+
Innate.node '/'
|
5
|
+
|
6
|
+
TEMPLATE = '
|
7
|
+
<html>
|
8
|
+
<head>
|
9
|
+
<title>Session example</title>
|
10
|
+
</head>
|
11
|
+
<body>
|
12
|
+
<h1>Session example</h1>
|
13
|
+
<p>
|
14
|
+
Value is: #{ session[:value] }<br />
|
15
|
+
#{ a :increment }<br />
|
16
|
+
#{ a :decrement }
|
17
|
+
</p>
|
18
|
+
</body>
|
19
|
+
</html>
|
20
|
+
'.strip
|
21
|
+
|
22
|
+
def index
|
23
|
+
session[:value] = 0
|
24
|
+
TEMPLATE
|
25
|
+
end
|
26
|
+
|
27
|
+
def increment
|
28
|
+
session[:value] = session[:value].to_i + 1
|
29
|
+
TEMPLATE
|
30
|
+
end
|
31
|
+
|
32
|
+
def decrement
|
33
|
+
session[:value] = session[:value].to_i - 1
|
34
|
+
TEMPLATE
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
Innate.start
|
data/innate.gemspec
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{innate}
|
5
|
+
s.version = "2009.06.29"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Michael 'manveru' Fellinger"]
|
9
|
+
s.date = %q{2009-06-30}
|
10
|
+
s.description = %q{Simple, straight-forward base for web-frameworks.}
|
11
|
+
s.email = %q{m.fellinger@gmail.com}
|
12
|
+
s.files = ["AUTHORS", "CHANGELOG", "COPYING", "MANIFEST", "README.md", "Rakefile", "example/app/retro_games.rb", "example/app/todo/layout/default.xhtml", "example/app/todo/spec/todo.rb", "example/app/todo/start.rb", "example/app/todo/view/index.xhtml", "example/app/whywiki_erb/layout/wiki.html.erb", "example/app/whywiki_erb/spec/wiki.rb", "example/app/whywiki_erb/start.rb", "example/app/whywiki_erb/view/edit.erb", "example/app/whywiki_erb/view/index.erb", "example/custom_middleware.rb", "example/hello.rb", "example/howto_spec.rb", "example/link.rb", "example/provides.rb", "example/session.rb", "innate.gemspec", "lib/innate.rb", "lib/innate/action.rb", "lib/innate/adapter.rb", "lib/innate/cache.rb", "lib/innate/cache/api.rb", "lib/innate/cache/drb.rb", "lib/innate/cache/file_based.rb", "lib/innate/cache/marshal.rb", "lib/innate/cache/memory.rb", "lib/innate/cache/yaml.rb", "lib/innate/current.rb", "lib/innate/dynamap.rb", "lib/innate/helper.rb", "lib/innate/helper/aspect.rb", "lib/innate/helper/cgi.rb", "lib/innate/helper/flash.rb", "lib/innate/helper/link.rb", "lib/innate/helper/redirect.rb", "lib/innate/helper/render.rb", "lib/innate/helper/send_file.rb", "lib/innate/log.rb", "lib/innate/log/color_formatter.rb", "lib/innate/log/hub.rb", "lib/innate/middleware_compiler.rb", "lib/innate/mock.rb", "lib/innate/node.rb", "lib/innate/options.rb", "lib/innate/options/dsl.rb", "lib/innate/options/stub.rb", "lib/innate/request.rb", "lib/innate/response.rb", "lib/innate/route.rb", "lib/innate/session.rb", "lib/innate/session/flash.rb", "lib/innate/spec.rb", "lib/innate/spec/bacon.rb", "lib/innate/state.rb", "lib/innate/state/accessor.rb", "lib/innate/traited.rb", "lib/innate/trinity.rb", "lib/innate/version.rb", "lib/innate/view.rb", "lib/innate/view/erb.rb", "lib/innate/view/etanni.rb", "lib/innate/view/none.rb", "spec/example/app/retro_games.rb", "spec/example/hello.rb", "spec/example/link.rb", "spec/example/provides.rb", "spec/example/session.rb", "spec/helper.rb", "spec/innate/action/layout.rb", "spec/innate/action/layout/file_layout.xhtml", "spec/innate/cache/common.rb", "spec/innate/cache/marshal.rb", "spec/innate/cache/memory.rb", "spec/innate/cache/yaml.rb", "spec/innate/dynamap.rb", "spec/innate/helper.rb", "spec/innate/helper/aspect.rb", "spec/innate/helper/cgi.rb", "spec/innate/helper/flash.rb", "spec/innate/helper/link.rb", "spec/innate/helper/redirect.rb", "spec/innate/helper/render.rb", "spec/innate/helper/send_file.rb", "spec/innate/helper/view/aspect_hello.xhtml", "spec/innate/helper/view/locals.xhtml", "spec/innate/helper/view/loop.xhtml", "spec/innate/helper/view/num.xhtml", "spec/innate/helper/view/partial.xhtml", "spec/innate/helper/view/recursive.xhtml", "spec/innate/mock.rb", "spec/innate/modes.rb", "spec/innate/node/mapping.rb", "spec/innate/node/node.rb", "spec/innate/node/resolve.rb", "spec/innate/node/view/another_layout/another_layout.xhtml", "spec/innate/node/view/bar.xhtml", "spec/innate/node/view/foo.html.xhtml", "spec/innate/node/view/only_view.xhtml", "spec/innate/node/view/with_layout.xhtml", "spec/innate/node/wrap_action_call.rb", "spec/innate/options.rb", "spec/innate/parameter.rb", "spec/innate/provides.rb", "spec/innate/provides/list.html.xhtml", "spec/innate/provides/list.txt.xhtml", "spec/innate/request.rb", "spec/innate/route.rb", "spec/innate/session.rb", "spec/innate/traited.rb", "tasks/authors.rake", "tasks/bacon.rake", "tasks/changelog.rake", "tasks/gem.rake", "tasks/gem_setup.rake", "tasks/grancher.rake", "tasks/manifest.rake", "tasks/rcov.rake", "tasks/release.rake", "tasks/reversion.rake", "tasks/setup.rake", "tasks/ycov.rake"]
|
13
|
+
s.has_rdoc = true
|
14
|
+
s.homepage = %q{http://github.com/manveru/innate}
|
15
|
+
s.require_paths = ["lib"]
|
16
|
+
s.rubyforge_project = %q{innate}
|
17
|
+
s.rubygems_version = %q{1.3.1}
|
18
|
+
s.summary = %q{Powerful web-framework wrapper for Rack.}
|
19
|
+
|
20
|
+
if s.respond_to? :specification_version then
|
21
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
22
|
+
s.specification_version = 2
|
23
|
+
|
24
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
25
|
+
s.add_runtime_dependency(%q<rack>, ["~> 1.0.0"])
|
26
|
+
s.add_development_dependency(%q<bacon>, [">= 1.1.0"])
|
27
|
+
s.add_development_dependency(%q<json>, ["~> 1.1.6"])
|
28
|
+
s.add_development_dependency(%q<rack-test>, [">= 0.3.0"])
|
29
|
+
else
|
30
|
+
s.add_dependency(%q<rack>, ["~> 1.0.0"])
|
31
|
+
s.add_dependency(%q<bacon>, [">= 1.1.0"])
|
32
|
+
s.add_dependency(%q<json>, ["~> 1.1.6"])
|
33
|
+
s.add_dependency(%q<rack-test>, [">= 0.3.0"])
|
34
|
+
end
|
35
|
+
else
|
36
|
+
s.add_dependency(%q<rack>, ["~> 1.0.0"])
|
37
|
+
s.add_dependency(%q<bacon>, [">= 1.1.0"])
|
38
|
+
s.add_dependency(%q<json>, ["~> 1.1.6"])
|
39
|
+
s.add_dependency(%q<rack-test>, [">= 0.3.0"])
|
40
|
+
end
|
41
|
+
end
|
data/lib/innate.rb
ADDED
@@ -0,0 +1,269 @@
|
|
1
|
+
# What can be done with fewer assumptions is done in vain with more.
|
2
|
+
# -- William of Ockham (ca. 1285-1349)
|
3
|
+
#
|
4
|
+
# Name-space of Innate, just about everything goes in here.
|
5
|
+
#
|
6
|
+
# The only exception is Logger::ColorFormatter.
|
7
|
+
#
|
8
|
+
module Innate
|
9
|
+
ROOT = File.expand_path(File.dirname(__FILE__))
|
10
|
+
|
11
|
+
unless $LOAD_PATH.any?{|lp| File.expand_path(lp) == ROOT }
|
12
|
+
$LOAD_PATH.unshift(ROOT)
|
13
|
+
end
|
14
|
+
|
15
|
+
# stdlib
|
16
|
+
require 'digest/sha1'
|
17
|
+
require 'digest/sha2'
|
18
|
+
require 'find'
|
19
|
+
require 'ipaddr'
|
20
|
+
require 'logger'
|
21
|
+
require 'pathname'
|
22
|
+
require 'pp'
|
23
|
+
require 'set'
|
24
|
+
require 'socket'
|
25
|
+
require 'uri'
|
26
|
+
|
27
|
+
# 3rd party
|
28
|
+
require 'rack'
|
29
|
+
|
30
|
+
# innate core
|
31
|
+
require 'innate/version'
|
32
|
+
require 'innate/traited'
|
33
|
+
require 'innate/trinity'
|
34
|
+
require 'innate/middleware_compiler'
|
35
|
+
require 'innate/options/dsl'
|
36
|
+
require 'innate/options/stub'
|
37
|
+
require 'innate/dynamap'
|
38
|
+
|
39
|
+
# innate full
|
40
|
+
require 'innate/cache'
|
41
|
+
require 'innate/node'
|
42
|
+
require 'innate/options'
|
43
|
+
require 'innate/log'
|
44
|
+
require 'innate/state'
|
45
|
+
require 'innate/current'
|
46
|
+
require 'innate/mock'
|
47
|
+
require 'innate/adapter'
|
48
|
+
require 'innate/action'
|
49
|
+
require 'innate/helper'
|
50
|
+
require 'innate/view'
|
51
|
+
require 'innate/session'
|
52
|
+
require 'innate/session/flash'
|
53
|
+
require 'innate/route'
|
54
|
+
|
55
|
+
extend Trinity
|
56
|
+
|
57
|
+
# Contains all the module functions for Innate, we keep them in a module so
|
58
|
+
# Ramaze can simply use them as well.
|
59
|
+
module SingletonMethods
|
60
|
+
PROXY_OPTIONS = { :port => 'adapter.port', :host => 'adapter.host',
|
61
|
+
:adapter => 'adapter.handler' }
|
62
|
+
# The method that starts the whole business.
|
63
|
+
#
|
64
|
+
# Call Innate.start after you defined your application.
|
65
|
+
#
|
66
|
+
# Usually, this is a blocking call and will not return until the adapter
|
67
|
+
# has finished, which usually happens when you kill the application or hit
|
68
|
+
# ^C.
|
69
|
+
#
|
70
|
+
# We do return if options.started is true, which indicates that all you
|
71
|
+
# wanted to do is setup the environment and update options.
|
72
|
+
#
|
73
|
+
# @example usage
|
74
|
+
#
|
75
|
+
# # passing options
|
76
|
+
# Innate.start :adapter => :mongrel, :mode => :live
|
77
|
+
#
|
78
|
+
# # defining custom middleware
|
79
|
+
# Innate.start do |m|
|
80
|
+
# m.innate
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# @return [nil] if options.started is true
|
84
|
+
# @yield [MiddlewareCompiler]
|
85
|
+
# @param [Proc] block will be passed to {middleware!}
|
86
|
+
#
|
87
|
+
# @option param :host [String] ('0.0.0.0')
|
88
|
+
# IP address or hostname that we respond to - 0.0.0.0 for all
|
89
|
+
# @option param :port [Fixnum] (7000)
|
90
|
+
# Port for the server
|
91
|
+
# @option param :started [boolean] (false)
|
92
|
+
# Indicate that calls Innate::start will be ignored
|
93
|
+
# @option param :adapter [Symbol] (:webrick)
|
94
|
+
# Web server to run on
|
95
|
+
# @option param :setup [Array] ([Innate::Cache, Innate::Node])
|
96
|
+
# Will send ::setup to each element during Innate::start
|
97
|
+
# @option param :header [Hash] ({'Content-Type' => 'text/html'})
|
98
|
+
# Headers that will be merged into the response before Node::call
|
99
|
+
# @option param :trap [String] ('SIGINT')
|
100
|
+
# Trap this signal to issue shutdown, nil/false to disable trap
|
101
|
+
# @option param :state [Symbol] (:Fiber)
|
102
|
+
# Keep state in Thread or Fiber, fall back to Thread if Fiber not available
|
103
|
+
# @option param :mode [Symbol] (:dev)
|
104
|
+
# Indicates which default middleware to use, (:dev|:live)
|
105
|
+
def start(given_options = {}, &block)
|
106
|
+
root = given_options.delete(:root)
|
107
|
+
file = given_options.delete(:file)
|
108
|
+
|
109
|
+
found_root = go_figure_root(caller, :root => root, :file => file)
|
110
|
+
Innate.options.roots = [*found_root] if found_root
|
111
|
+
|
112
|
+
# Convert some top-level option keys to the internal ones that we use.
|
113
|
+
PROXY_OPTIONS.each{|k,v| given_options[v] = given_options.delete(k) }
|
114
|
+
given_options.delete_if{|k,v| v.nil? }
|
115
|
+
|
116
|
+
# Merge the user's given options into our existing set, which contains defaults.
|
117
|
+
options.merge!(given_options)
|
118
|
+
|
119
|
+
setup_dependencies
|
120
|
+
middleware!(options.mode, &block) if block_given?
|
121
|
+
|
122
|
+
return if options.started
|
123
|
+
options.started = true
|
124
|
+
|
125
|
+
signal = options.trap
|
126
|
+
trap(signal){ stop(10) } if signal
|
127
|
+
|
128
|
+
start!
|
129
|
+
end
|
130
|
+
|
131
|
+
def start!(mode = options[:mode])
|
132
|
+
Adapter.start(middleware(mode))
|
133
|
+
end
|
134
|
+
|
135
|
+
def stop(wait = 3)
|
136
|
+
Log.info("Shutdown within #{wait} seconds")
|
137
|
+
Timeout.timeout(wait){ teardown_dependencies }
|
138
|
+
Timeout.timeout(wait){ exit }
|
139
|
+
ensure
|
140
|
+
exit!
|
141
|
+
end
|
142
|
+
|
143
|
+
def setup_dependencies
|
144
|
+
options[:setup].each{|obj| obj.setup if obj.respond_to?(:setup) }
|
145
|
+
end
|
146
|
+
|
147
|
+
def teardown_dependencies
|
148
|
+
options[:setup].each{|obj| obj.teardown if obj.respond_to?(:teardown) }
|
149
|
+
end
|
150
|
+
|
151
|
+
# Treat Innate like a rack application, pass the rack +env+ and optionally
|
152
|
+
# the +mode+ the application runs in.
|
153
|
+
#
|
154
|
+
# @param [Hash] env rack env
|
155
|
+
# @param [Symbol] mode indicates the mode of the application
|
156
|
+
# @default mode options.mode
|
157
|
+
# @return [Array] with [body, header, status]
|
158
|
+
# @author manveru
|
159
|
+
def call(env, mode = options[:mode])
|
160
|
+
middleware(mode).call(env)
|
161
|
+
end
|
162
|
+
|
163
|
+
def middleware(mode = options[:mode], &block)
|
164
|
+
options[:middleware_compiler].build(mode, &block)
|
165
|
+
end
|
166
|
+
|
167
|
+
def middleware!(mode = options[:mode], &block)
|
168
|
+
options[:middleware_compiler].build!(mode, &block)
|
169
|
+
end
|
170
|
+
|
171
|
+
def middleware_recompile(mode = options[:mode])
|
172
|
+
options[:middleware_compiler]::COMPILED[mode].compile!
|
173
|
+
end
|
174
|
+
|
175
|
+
# @example Innate can be started by:
|
176
|
+
#
|
177
|
+
# Innate.start :file => __FILE__
|
178
|
+
# Innate.start :root => File.dirname(__FILE__)
|
179
|
+
#
|
180
|
+
# Either setting will surpress the warning that might show up on startup
|
181
|
+
# and tells you it couldn't find an explicit root.
|
182
|
+
#
|
183
|
+
# In case these options are not passed we will try to figure out a file named
|
184
|
+
# `start.rb` in the process' working directory and assume it's a valid point.
|
185
|
+
def go_figure_root(backtrace, options)
|
186
|
+
if root = options[:root]
|
187
|
+
root
|
188
|
+
elsif file = options[:file]
|
189
|
+
File.dirname(file)
|
190
|
+
elsif File.file?('start.rb')
|
191
|
+
Dir.pwd
|
192
|
+
else
|
193
|
+
root = File.dirname(backtrace[0][/^(.*?):\d+/, 1])
|
194
|
+
Log.warn "No explicit root folder found, assuming it is #{root}"
|
195
|
+
root
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
extend SingletonMethods
|
201
|
+
|
202
|
+
# This sets up the default modes.
|
203
|
+
# The Proc to use is determined by the value of options.mode.
|
204
|
+
# The Proc value is passed to setup_middleware if no block is given to
|
205
|
+
# Innate::start.
|
206
|
+
#
|
207
|
+
# A quick overview over the middleware used here:
|
208
|
+
#
|
209
|
+
# * Rack::CommonLogger
|
210
|
+
# Logs a line in Apache common log format or <tt>rack.errors</tt>.
|
211
|
+
#
|
212
|
+
# * Rack::ShowExceptions
|
213
|
+
# Catches all exceptions raised from the app it wraps. It shows a useful
|
214
|
+
# backtrace with the sourcefile and clickable context, the whole Rack
|
215
|
+
# environment and the request data.
|
216
|
+
# Be careful when you use this on public-facing sites as it could reveal
|
217
|
+
# information helpful to attackers.
|
218
|
+
#
|
219
|
+
# * Rack::ShowStatus
|
220
|
+
# Catches all empty responses the app it wraps and replaces them with a
|
221
|
+
# site explaining the error.
|
222
|
+
# Additional details can be put into <tt>rack.showstatus.detail</tt> and
|
223
|
+
# will be shown as HTML. If such details exist, the error page is always
|
224
|
+
# rendered, even if the reply was not empty.
|
225
|
+
#
|
226
|
+
# * Rack::ConditionalGet
|
227
|
+
# Middleware that enables conditional GET using If-None-Match and
|
228
|
+
# If-Modified-Since. The application should set either or both of the
|
229
|
+
# Last-Modified or Etag response headers according to RFC 2616. When
|
230
|
+
# either of the conditions is met, the response body is set to be zero
|
231
|
+
# length and the response status is set to 304 Not Modified.
|
232
|
+
#
|
233
|
+
# * Rack::Head
|
234
|
+
# Removes the body of the response for HEAD requests.
|
235
|
+
#
|
236
|
+
# * Rack::Reloader
|
237
|
+
# Pure ruby source reloader, runs on every request with a configurable
|
238
|
+
# cooldown period.
|
239
|
+
#
|
240
|
+
# * Rack::Lint
|
241
|
+
# Rack::Lint validates your application and the requests and responses
|
242
|
+
# according to the Rack spec.
|
243
|
+
#
|
244
|
+
# Note that `m.innate` takes away most of the boring part and leaves it up to
|
245
|
+
# you to select your middleware in your application.
|
246
|
+
#
|
247
|
+
# `m.innate` expands to:
|
248
|
+
#
|
249
|
+
# use Rack::Cascade.new([
|
250
|
+
# Rack::File.new('public'),
|
251
|
+
# Innate::Current.new(
|
252
|
+
# Rack::Cascade.new([
|
253
|
+
# Innate::Rewrite.new(Innate::DynaMap),
|
254
|
+
# Innate::Route.new(Innate::DynaMap)])))
|
255
|
+
#
|
256
|
+
# @see Rack::MiddlewareCompiler
|
257
|
+
middleware :dev do |m|
|
258
|
+
m.apps(Rack::Lint, Rack::Head, Rack::ContentLength, Rack::CommonLogger,
|
259
|
+
Rack::ShowExceptions, Rack::ShowStatus, Rack::ConditionalGet)
|
260
|
+
m.use(Rack::Reloader, 2)
|
261
|
+
m.innate
|
262
|
+
end
|
263
|
+
|
264
|
+
middleware :live do |m|
|
265
|
+
m.apps(Rack::Head, Rack::ContentLength, Rack::CommonLogger,
|
266
|
+
Rack::ShowStatus, Rack::ConditionalGet)
|
267
|
+
m.innate
|
268
|
+
end
|
269
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module Innate
|
2
|
+
ACTION_MEMBERS = [ :node, :instance, :method, :params, :method_value, :view,
|
3
|
+
:view_value, :layout, :wish, :options, :variables, :engine, :path ]
|
4
|
+
|
5
|
+
class Action < Struct.new(*ACTION_MEMBERS)
|
6
|
+
# Create a new Action instance.
|
7
|
+
# Note that the default cannot be a constant as assigning the value objects
|
8
|
+
# to the struct would modify them and might lead to bugs due to persisting
|
9
|
+
# action contents.
|
10
|
+
#
|
11
|
+
# @param [Hash, #to_hash] hash used to seed new Action instance
|
12
|
+
# @return [Action] action with the given defaults from hash
|
13
|
+
# @api stable
|
14
|
+
# @author manveru
|
15
|
+
def self.create(hash = {})
|
16
|
+
default = {:options => {}, :variables => {}, :params => []}
|
17
|
+
new(*default.merge(hash.to_hash).values_at(*ACTION_MEMBERS))
|
18
|
+
end
|
19
|
+
|
20
|
+
def merge!(hash)
|
21
|
+
hash.each_pair{|key, value| send("#{key}=", value) }
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
# Call the Action instance, will insert itself temporarily into
|
26
|
+
# Current.actions during the render operation so even in nested calls one
|
27
|
+
# can still access all other Action instances.
|
28
|
+
# Will initialize the assigned node and call Action#render
|
29
|
+
#
|
30
|
+
# @return [String] The rendition of all nested calls
|
31
|
+
# @see Action#render Node#action_found
|
32
|
+
# @api stable
|
33
|
+
# @author manveru
|
34
|
+
def call
|
35
|
+
Current.actions ? wrap_in_current{ render } : render
|
36
|
+
end
|
37
|
+
|
38
|
+
# @return [Binding] binding of the instance for this Action
|
39
|
+
# @see Node#binding
|
40
|
+
# @api stable
|
41
|
+
# @author manveru
|
42
|
+
def binding
|
43
|
+
instance.binding
|
44
|
+
end
|
45
|
+
|
46
|
+
# Copy the instance variable names and values from given
|
47
|
+
# from_action#instance into the Action#variables of the action this method
|
48
|
+
# is called on.
|
49
|
+
#
|
50
|
+
# @param [Action #instance] from_action
|
51
|
+
# @return [Action] from_action
|
52
|
+
# @see Action#wrap_in_layout
|
53
|
+
# @api unstable
|
54
|
+
# @author manveru
|
55
|
+
def sync_variables(from_action)
|
56
|
+
instance = from_action.instance
|
57
|
+
|
58
|
+
instance.instance_variables.each{|iv|
|
59
|
+
iv_value = instance.instance_variable_get(iv)
|
60
|
+
iv_name = iv.to_s[1..-1]
|
61
|
+
self.variables[iv_name.to_sym] = iv_value
|
62
|
+
}
|
63
|
+
|
64
|
+
from_action
|
65
|
+
end
|
66
|
+
|
67
|
+
# Copy Action#variables as instance variables into the given object.
|
68
|
+
# Defaults to copying the variables to self.
|
69
|
+
#
|
70
|
+
# @param [Object #instance_variable_set] object
|
71
|
+
# @return [NilClass] there is no indication of failure or success
|
72
|
+
# @see Action#render
|
73
|
+
# @author manveru
|
74
|
+
def copy_variables(object)
|
75
|
+
self.variables.each do |iv, value|
|
76
|
+
object.instance_variable_set("@#{iv}", value)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def render
|
81
|
+
self.instance = node.new
|
82
|
+
self.variables[:content] ||= nil
|
83
|
+
|
84
|
+
instance.wrap_action_call(self) do
|
85
|
+
copy_variables(self.instance) # this might need another position
|
86
|
+
self.method_value = instance.__send__(method, *params) if method
|
87
|
+
self.view_value = View.read(view) if view
|
88
|
+
|
89
|
+
body, content_type = wrap_in_layout{
|
90
|
+
engine.call(self, view_value || method_value || '') }
|
91
|
+
options[:content_type] ||= content_type if content_type
|
92
|
+
body
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def wrap_in_layout
|
97
|
+
return yield unless layout
|
98
|
+
|
99
|
+
action = dup
|
100
|
+
action.view, action.method = layout_view_or_method(*layout)
|
101
|
+
action.params = []
|
102
|
+
action.layout = nil
|
103
|
+
action.view_value = nil
|
104
|
+
action.sync_variables(self)
|
105
|
+
body, content_type = yield
|
106
|
+
action.sync_variables(self)
|
107
|
+
action.variables[:content] = body
|
108
|
+
return action.call, content_type
|
109
|
+
end
|
110
|
+
|
111
|
+
def layout_view_or_method(name, arg)
|
112
|
+
[:layout, :view].include?(name) ? [arg, nil] : [nil, arg]
|
113
|
+
end
|
114
|
+
|
115
|
+
def wrap_in_current
|
116
|
+
Current.actions << self
|
117
|
+
yield
|
118
|
+
ensure
|
119
|
+
Current.actions.delete(self)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Try to figure out a sane name for current action.
|
123
|
+
def name
|
124
|
+
File.basename((method || view).to_s).split('.').first
|
125
|
+
end
|
126
|
+
|
127
|
+
# Path to this action, including params, with the mapping of the current
|
128
|
+
# controller prepended.
|
129
|
+
def full_path
|
130
|
+
File.join(node.mapping, path)
|
131
|
+
end
|
132
|
+
|
133
|
+
def valid?
|
134
|
+
node.needs_method? ? (method && view) : (method || view)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|