manveru-innate 2009.02.06
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/CHANGELOG +1409 -0
- data/COPYING +18 -0
- data/MANIFEST +100 -0
- data/README.md +485 -0
- data/Rakefile +139 -0
- data/example/app/retro_games.rb +57 -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 +45 -0
- data/example/app/whywiki_erb/view/edit.html.erb +6 -0
- data/example/app/whywiki_erb/view/index.html.erb +10 -0
- data/example/custom_middleware.rb +43 -0
- data/example/error_handling.rb +31 -0
- data/example/hello.rb +12 -0
- data/example/howto_spec.rb +60 -0
- data/example/link.rb +35 -0
- data/example/providing_hash.rb +46 -0
- data/example/session.rb +42 -0
- data/innate.gemspec +118 -0
- data/lib/innate.rb +191 -0
- data/lib/innate/action.rb +156 -0
- data/lib/innate/adapter.rb +89 -0
- data/lib/innate/cache.rb +117 -0
- data/lib/innate/cache/api.rb +106 -0
- data/lib/innate/cache/drb.rb +58 -0
- data/lib/innate/cache/file_based.rb +39 -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/core_compatibility/basic_object.rb +9 -0
- data/lib/innate/core_compatibility/string.rb +3 -0
- data/lib/innate/current.rb +37 -0
- data/lib/innate/dynamap.rb +81 -0
- data/lib/innate/helper.rb +195 -0
- data/lib/innate/helper/aspect.rb +62 -0
- data/lib/innate/helper/cgi.rb +39 -0
- data/lib/innate/helper/flash.rb +36 -0
- data/lib/innate/helper/link.rb +55 -0
- data/lib/innate/helper/partial.rb +90 -0
- data/lib/innate/helper/redirect.rb +85 -0
- data/lib/innate/helper/send_file.rb +18 -0
- data/lib/innate/log.rb +23 -0
- data/lib/innate/log/color_formatter.rb +43 -0
- data/lib/innate/log/hub.rb +72 -0
- data/lib/innate/mock.rb +49 -0
- data/lib/innate/node.rb +471 -0
- data/lib/innate/options.rb +91 -0
- data/lib/innate/options/dsl.rb +155 -0
- data/lib/innate/request.rb +165 -0
- data/lib/innate/response.rb +18 -0
- data/lib/innate/route.rb +109 -0
- data/lib/innate/session.rb +104 -0
- data/lib/innate/session/flash.rb +94 -0
- data/lib/innate/setup.rb +23 -0
- data/lib/innate/spec.rb +42 -0
- data/lib/innate/state.rb +22 -0
- data/lib/innate/state/accessor.rb +130 -0
- data/lib/innate/state/fiber.rb +68 -0
- data/lib/innate/state/thread.rb +39 -0
- data/lib/innate/traited.rb +20 -0
- data/lib/innate/trinity.rb +22 -0
- data/lib/innate/version.rb +3 -0
- data/lib/innate/view.rb +67 -0
- data/lib/innate/view/erb.rb +17 -0
- data/lib/innate/view/none.rb +9 -0
- data/lib/rack/middleware_compiler.rb +62 -0
- data/lib/rack/reloader.rb +192 -0
- data/spec/example/hello.rb +14 -0
- data/spec/example/link.rb +29 -0
- data/spec/helper.rb +2 -0
- data/spec/innate/cache/common.rb +45 -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 +66 -0
- data/spec/innate/helper/aspect.rb +80 -0
- data/spec/innate/helper/cgi.rb +37 -0
- data/spec/innate/helper/flash.rb +148 -0
- data/spec/innate/helper/link.rb +82 -0
- data/spec/innate/helper/partial.rb +66 -0
- data/spec/innate/helper/redirect.rb +148 -0
- data/spec/innate/helper/send_file.rb +21 -0
- data/spec/innate/helper/view/aspect_hello.erb +1 -0
- data/spec/innate/helper/view/locals.erb +1 -0
- data/spec/innate/helper/view/loop.erb +4 -0
- data/spec/innate/helper/view/num.erb +1 -0
- data/spec/innate/helper/view/partial.erb +1 -0
- data/spec/innate/helper/view/recursive.erb +8 -0
- data/spec/innate/mock.rb +84 -0
- data/spec/innate/node.rb +180 -0
- data/spec/innate/node/bar.html +1 -0
- data/spec/innate/node/foo.html.erb +1 -0
- data/spec/innate/node/with_layout.erb +3 -0
- data/spec/innate/options.rb +90 -0
- data/spec/innate/parameter.rb +154 -0
- data/spec/innate/request.rb +73 -0
- data/spec/innate/route.rb +129 -0
- data/spec/innate/session.rb +59 -0
- data/spec/innate/traited.rb +55 -0
- metadata +160 -0
data/example/link.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'innate'
|
2
|
+
|
3
|
+
class Linking
|
4
|
+
include Innate::Node
|
5
|
+
map '/'
|
6
|
+
|
7
|
+
def index
|
8
|
+
"simple link<br />" +
|
9
|
+
a('Help?', :help)
|
10
|
+
end
|
11
|
+
|
12
|
+
def new
|
13
|
+
"Something new!"
|
14
|
+
end
|
15
|
+
|
16
|
+
def help
|
17
|
+
"You have help<br />" +
|
18
|
+
Different.a('A Different Node', :another)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class Different
|
23
|
+
include Innate::Node
|
24
|
+
map '/link_to'
|
25
|
+
|
26
|
+
def another
|
27
|
+
a('Even deeper', 'and/deeper')
|
28
|
+
end
|
29
|
+
|
30
|
+
def and__deeper
|
31
|
+
Linking.a('Back to Linking Node', :index)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
Innate.start
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'innate'
|
2
|
+
|
3
|
+
# This demonstrates how to obtain different content types from the return value
|
4
|
+
# of action methods.
|
5
|
+
#
|
6
|
+
# Try following requests:
|
7
|
+
# /set/foo/bar
|
8
|
+
# /set/duh/duf
|
9
|
+
#
|
10
|
+
# /index.json
|
11
|
+
# /index.yaml
|
12
|
+
#
|
13
|
+
# /get/foo.json
|
14
|
+
# /get/foo.yaml
|
15
|
+
#
|
16
|
+
# Note that this functionality is quite experimental, but by strategically
|
17
|
+
# placing ressources in actions it may be possible to achieve interesting
|
18
|
+
# effects and interoperability with JavaScript at a low cost.
|
19
|
+
#
|
20
|
+
# TODO:
|
21
|
+
# * parsing requests based on the content-type, but that's much less
|
22
|
+
# straight-forward and would require some kind of convention?
|
23
|
+
|
24
|
+
class Dict
|
25
|
+
include Innate::Node
|
26
|
+
map '/'
|
27
|
+
|
28
|
+
DICT = {}
|
29
|
+
|
30
|
+
# /get/foo || /get/foo.json || /get/foo.yaml
|
31
|
+
def get(key)
|
32
|
+
{key => DICT[key]}
|
33
|
+
end
|
34
|
+
|
35
|
+
# /set/foo/bar || /set/foo/bar.json || /set/foo/bar.yaml
|
36
|
+
def set(key, value)
|
37
|
+
{key => (DICT[key] = value)}
|
38
|
+
end
|
39
|
+
|
40
|
+
# /index.json || /.json || /index.yaml || /.yaml
|
41
|
+
def index
|
42
|
+
DICT
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
Innate.start
|
data/example/session.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'innate'
|
2
|
+
|
3
|
+
class Hello
|
4
|
+
include Innate::Node
|
5
|
+
map '/'
|
6
|
+
|
7
|
+
helper :link, :cgi
|
8
|
+
|
9
|
+
provide :html => :haml
|
10
|
+
|
11
|
+
TEMPLATE = '
|
12
|
+
!!! XML
|
13
|
+
!!!
|
14
|
+
%html
|
15
|
+
%head
|
16
|
+
%title Session example
|
17
|
+
%body
|
18
|
+
%h1 Session example
|
19
|
+
= "Value is #{session[:value]}"
|
20
|
+
%br/
|
21
|
+
= a :increment
|
22
|
+
%br/
|
23
|
+
= a :decrement
|
24
|
+
'.strip
|
25
|
+
|
26
|
+
def index
|
27
|
+
session[:value] = 0
|
28
|
+
TEMPLATE
|
29
|
+
end
|
30
|
+
|
31
|
+
def increment
|
32
|
+
session[:value] += 1 if session[:value]
|
33
|
+
TEMPLATE
|
34
|
+
end
|
35
|
+
|
36
|
+
def decrement
|
37
|
+
session[:value] -= 1 if session[:value]
|
38
|
+
TEMPLATE
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
Innate.start
|
data/innate.gemspec
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "innate"
|
3
|
+
s.version = "2009.02.06"
|
4
|
+
|
5
|
+
s.summary = "Powerful web-framework wrapper for Rack."
|
6
|
+
s.description = "Simple, straight-forward, base for web-frameworks."
|
7
|
+
s.platform = "ruby"
|
8
|
+
s.has_rdoc = true
|
9
|
+
s.author = "Michael 'manveru' Fellinger"
|
10
|
+
s.email = "m.fellinger@gmail.com"
|
11
|
+
s.homepage = "http://github.com/manveru/innate"
|
12
|
+
s.require_path = "lib"
|
13
|
+
|
14
|
+
s.add_dependency('rack', '>= 0.4.0')
|
15
|
+
|
16
|
+
s.files = [
|
17
|
+
"CHANGELOG",
|
18
|
+
"COPYING",
|
19
|
+
"MANIFEST",
|
20
|
+
"README.md",
|
21
|
+
"Rakefile",
|
22
|
+
"example/app/retro_games.rb",
|
23
|
+
"example/app/whywiki_erb/layout/wiki.html.erb",
|
24
|
+
"example/app/whywiki_erb/spec/wiki.rb",
|
25
|
+
"example/app/whywiki_erb/start.rb",
|
26
|
+
"example/app/whywiki_erb/view/edit.html.erb",
|
27
|
+
"example/app/whywiki_erb/view/index.html.erb",
|
28
|
+
"example/custom_middleware.rb",
|
29
|
+
"example/error_handling.rb",
|
30
|
+
"example/hello.rb",
|
31
|
+
"example/howto_spec.rb",
|
32
|
+
"example/link.rb",
|
33
|
+
"example/providing_hash.rb",
|
34
|
+
"example/session.rb",
|
35
|
+
"innate.gemspec",
|
36
|
+
"lib/innate.rb",
|
37
|
+
"lib/innate/action.rb",
|
38
|
+
"lib/innate/adapter.rb",
|
39
|
+
"lib/innate/cache.rb",
|
40
|
+
"lib/innate/cache/api.rb",
|
41
|
+
"lib/innate/cache/drb.rb",
|
42
|
+
"lib/innate/cache/file_based.rb",
|
43
|
+
"lib/innate/cache/marshal.rb",
|
44
|
+
"lib/innate/cache/memory.rb",
|
45
|
+
"lib/innate/cache/yaml.rb",
|
46
|
+
"lib/innate/core_compatibility/basic_object.rb",
|
47
|
+
"lib/innate/core_compatibility/string.rb",
|
48
|
+
"lib/innate/current.rb",
|
49
|
+
"lib/innate/dynamap.rb",
|
50
|
+
"lib/innate/helper.rb",
|
51
|
+
"lib/innate/helper/aspect.rb",
|
52
|
+
"lib/innate/helper/cgi.rb",
|
53
|
+
"lib/innate/helper/flash.rb",
|
54
|
+
"lib/innate/helper/link.rb",
|
55
|
+
"lib/innate/helper/partial.rb",
|
56
|
+
"lib/innate/helper/redirect.rb",
|
57
|
+
"lib/innate/helper/send_file.rb",
|
58
|
+
"lib/innate/log.rb",
|
59
|
+
"lib/innate/log/color_formatter.rb",
|
60
|
+
"lib/innate/log/hub.rb",
|
61
|
+
"lib/innate/mock.rb",
|
62
|
+
"lib/innate/node.rb",
|
63
|
+
"lib/innate/options.rb",
|
64
|
+
"lib/innate/options/dsl.rb",
|
65
|
+
"lib/innate/request.rb",
|
66
|
+
"lib/innate/response.rb",
|
67
|
+
"lib/innate/route.rb",
|
68
|
+
"lib/innate/session.rb",
|
69
|
+
"lib/innate/session/flash.rb",
|
70
|
+
"lib/innate/setup.rb",
|
71
|
+
"lib/innate/spec.rb",
|
72
|
+
"lib/innate/state.rb",
|
73
|
+
"lib/innate/state/accessor.rb",
|
74
|
+
"lib/innate/state/fiber.rb",
|
75
|
+
"lib/innate/state/thread.rb",
|
76
|
+
"lib/innate/traited.rb",
|
77
|
+
"lib/innate/trinity.rb",
|
78
|
+
"lib/innate/version.rb",
|
79
|
+
"lib/innate/view.rb",
|
80
|
+
"lib/innate/view/erb.rb",
|
81
|
+
"lib/innate/view/none.rb",
|
82
|
+
"lib/rack/middleware_compiler.rb",
|
83
|
+
"lib/rack/reloader.rb",
|
84
|
+
"spec/example/hello.rb",
|
85
|
+
"spec/example/link.rb",
|
86
|
+
"spec/helper.rb",
|
87
|
+
"spec/innate/cache/common.rb",
|
88
|
+
"spec/innate/cache/marshal.rb",
|
89
|
+
"spec/innate/cache/memory.rb",
|
90
|
+
"spec/innate/cache/yaml.rb",
|
91
|
+
"spec/innate/dynamap.rb",
|
92
|
+
"spec/innate/helper.rb",
|
93
|
+
"spec/innate/helper/aspect.rb",
|
94
|
+
"spec/innate/helper/cgi.rb",
|
95
|
+
"spec/innate/helper/flash.rb",
|
96
|
+
"spec/innate/helper/link.rb",
|
97
|
+
"spec/innate/helper/partial.rb",
|
98
|
+
"spec/innate/helper/redirect.rb",
|
99
|
+
"spec/innate/helper/send_file.rb",
|
100
|
+
"spec/innate/helper/view/aspect_hello.erb",
|
101
|
+
"spec/innate/helper/view/locals.erb",
|
102
|
+
"spec/innate/helper/view/loop.erb",
|
103
|
+
"spec/innate/helper/view/num.erb",
|
104
|
+
"spec/innate/helper/view/partial.erb",
|
105
|
+
"spec/innate/helper/view/recursive.erb",
|
106
|
+
"spec/innate/mock.rb",
|
107
|
+
"spec/innate/node.rb",
|
108
|
+
"spec/innate/node/bar.html",
|
109
|
+
"spec/innate/node/foo.html.erb",
|
110
|
+
"spec/innate/node/with_layout.erb",
|
111
|
+
"spec/innate/options.rb",
|
112
|
+
"spec/innate/parameter.rb",
|
113
|
+
"spec/innate/request.rb",
|
114
|
+
"spec/innate/route.rb",
|
115
|
+
"spec/innate/session.rb",
|
116
|
+
"spec/innate/traited.rb"
|
117
|
+
]
|
118
|
+
end
|
data/lib/innate.rb
ADDED
@@ -0,0 +1,191 @@
|
|
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
|
+
# Exceptions are:
|
7
|
+
#
|
8
|
+
# * Logger::ColorFormatter
|
9
|
+
# * In 1.8, we define ::BasicObject
|
10
|
+
# * In 1.9, we define ::String#each
|
11
|
+
#
|
12
|
+
module Innate
|
13
|
+
ROOT = File.expand_path(File.dirname(__FILE__))
|
14
|
+
|
15
|
+
unless $LOAD_PATH.any?{|lp| File.expand_path(lp) == ROOT }
|
16
|
+
$LOAD_PATH.unshift(ROOT)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# stdlib
|
21
|
+
require 'pp'
|
22
|
+
require 'set'
|
23
|
+
require 'pathname'
|
24
|
+
require 'digest/sha1'
|
25
|
+
require 'ipaddr'
|
26
|
+
require 'socket'
|
27
|
+
require 'logger'
|
28
|
+
require 'uri'
|
29
|
+
|
30
|
+
# 3rd party
|
31
|
+
require 'rack'
|
32
|
+
|
33
|
+
# innate core patches
|
34
|
+
require 'innate/core_compatibility/string'
|
35
|
+
require 'innate/core_compatibility/basic_object'
|
36
|
+
|
37
|
+
# innate core
|
38
|
+
require 'innate/version'
|
39
|
+
require 'innate/traited'
|
40
|
+
require 'innate/cache'
|
41
|
+
require 'innate/node'
|
42
|
+
require 'innate/options'
|
43
|
+
require 'innate/log'
|
44
|
+
require 'innate/state'
|
45
|
+
require 'innate/trinity'
|
46
|
+
require 'innate/current'
|
47
|
+
require 'innate/mock'
|
48
|
+
require 'innate/adapter'
|
49
|
+
require 'innate/action'
|
50
|
+
require 'innate/helper'
|
51
|
+
require 'innate/view'
|
52
|
+
require 'innate/session'
|
53
|
+
require 'innate/session/flash'
|
54
|
+
require 'innate/dynamap'
|
55
|
+
require 'innate/route'
|
56
|
+
|
57
|
+
require 'rack/reloader'
|
58
|
+
require 'rack/middleware_compiler'
|
59
|
+
|
60
|
+
module Innate
|
61
|
+
extend Trinity
|
62
|
+
|
63
|
+
# Note that `m.innate` takes away most of the boring part and leaves it up to
|
64
|
+
# you to select your middleware in your application.
|
65
|
+
#
|
66
|
+
# This expands to:
|
67
|
+
#
|
68
|
+
# use Rack::ShowExceptions
|
69
|
+
# use Rack::RouteExceptions
|
70
|
+
# use Rack::ShowStatus
|
71
|
+
# use Rack::Reloader
|
72
|
+
# use Rack::Cascade.new([
|
73
|
+
# Rack::File.new('public'),
|
74
|
+
# Innate::Current.new(
|
75
|
+
# Rack::Cascade.new([
|
76
|
+
# Innate::Rewrite.new(Innate::DynaMap),
|
77
|
+
# Innate::Route.new(Innate::DynaMap)])))
|
78
|
+
DEFAULT_MIDDLEWARE = lambda{|m|
|
79
|
+
m.use Rack::CommonLogger # usually fast, depending on the output
|
80
|
+
m.use Rack::ShowExceptions # fast
|
81
|
+
# m.use Rack::RouteExceptions # fast, use when you have custom error pages.
|
82
|
+
m.use Rack::ShowStatus # fast
|
83
|
+
m.use Rack::Reloader # reasonably fast depending on settings
|
84
|
+
# m.use Rack::Lint # slow, use only while developing
|
85
|
+
|
86
|
+
m.innate
|
87
|
+
}
|
88
|
+
|
89
|
+
module_function
|
90
|
+
|
91
|
+
def start(parameter = {}, &block)
|
92
|
+
setup_dependencies
|
93
|
+
setup_middleware(&block)
|
94
|
+
|
95
|
+
options[:app][:root] = go_figure_root(parameter, caller)
|
96
|
+
parameter.reject!{|k, v| [:root, :file].include?(k) }
|
97
|
+
options.merge!(parameter)
|
98
|
+
|
99
|
+
return if options.started
|
100
|
+
options.started = true
|
101
|
+
|
102
|
+
trap(options[:trap]){ stop(10) } if options[:trap]
|
103
|
+
|
104
|
+
start!(options)
|
105
|
+
end
|
106
|
+
|
107
|
+
def start!(options = Innate.options)
|
108
|
+
Adapter.start(middleware(:innate), options)
|
109
|
+
end
|
110
|
+
|
111
|
+
def stop(wait = 3)
|
112
|
+
Log.info("Shutdown Innate within #{wait} seconds")
|
113
|
+
Timeout.timeout(wait){ exit }
|
114
|
+
ensure
|
115
|
+
exit!
|
116
|
+
end
|
117
|
+
|
118
|
+
def middleware(name, &block)
|
119
|
+
Rack::MiddlewareCompiler.build(name, &block)
|
120
|
+
end
|
121
|
+
|
122
|
+
def middleware!(name, &block)
|
123
|
+
Rack::MiddlewareCompiler.build!(name, &block)
|
124
|
+
end
|
125
|
+
|
126
|
+
def setup_dependencies
|
127
|
+
options[:setup].each{|obj| obj.setup }
|
128
|
+
end
|
129
|
+
|
130
|
+
# Set the default middleware for applications.
|
131
|
+
def setup_middleware(&block)
|
132
|
+
middleware(:innate, &(block || DEFAULT_MIDDLEWARE))
|
133
|
+
end
|
134
|
+
|
135
|
+
# Pass the +env+ to this method and it will be sent to the appropriate
|
136
|
+
# middleware called +mw+.
|
137
|
+
# Tries to avoid recursion.
|
138
|
+
|
139
|
+
def call(env, mw = :innate)
|
140
|
+
this_file = File.expand_path(__FILE__)
|
141
|
+
count = 0
|
142
|
+
caller_lines(caller){|f, l, m| count += 1 if f == this_file }
|
143
|
+
|
144
|
+
raise RuntimeError, "Recursive loop in Innate::call" if count > 10
|
145
|
+
|
146
|
+
middleware(mw).call(env)
|
147
|
+
end
|
148
|
+
|
149
|
+
# Innate can be started by:
|
150
|
+
#
|
151
|
+
# Innate.start :file => __FILE__
|
152
|
+
# Innate.start :root => '/path/to/here'
|
153
|
+
#
|
154
|
+
# In case these options are not passed we will try to figure out a file named
|
155
|
+
# `start.rb` in the backtrace and use the directory it resides in.
|
156
|
+
#
|
157
|
+
# TODO: better documentation and nice defaults, don't want to rely on a
|
158
|
+
# filename, bad mojo.
|
159
|
+
|
160
|
+
def go_figure_root(options, backtrace)
|
161
|
+
if o_file = options[:file]
|
162
|
+
return File.dirname(o_file)
|
163
|
+
elsif root = options[:root]
|
164
|
+
return root
|
165
|
+
end
|
166
|
+
|
167
|
+
pwd = Dir.pwd
|
168
|
+
|
169
|
+
return pwd if File.file?(File.join(pwd, 'start.rb'))
|
170
|
+
|
171
|
+
caller_lines(backtrace) do |file, line, method|
|
172
|
+
dir, file = File.split(File.expand_path(file))
|
173
|
+
return dir if file == "start.rb"
|
174
|
+
end
|
175
|
+
|
176
|
+
return nil
|
177
|
+
end
|
178
|
+
|
179
|
+
# yields +file+, +line+, +method+
|
180
|
+
def caller_lines(backtrace)
|
181
|
+
backtrace.each do |line|
|
182
|
+
if line =~ /^(.*?):(\d+):in `(.*)'$/
|
183
|
+
file, line, method = $1, $2.to_i, $3
|
184
|
+
elsif line =~ /^(.*?):(\d+)$/
|
185
|
+
file, line, method = $1, $2.to_i, nil
|
186
|
+
end
|
187
|
+
|
188
|
+
yield(File.expand_path(file), line, method) if file and File.file?(file)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
module Innate
|
2
|
+
ACTION_MEMBERS = [ :node, :method, :params, :view, :layout, :instance, :exts,
|
3
|
+
:wish, :options, :variables, :value, :view_value, :name ]
|
4
|
+
|
5
|
+
class Action < Struct.new(*ACTION_MEMBERS)
|
6
|
+
# Create a new Action instance.
|
7
|
+
#
|
8
|
+
# @param [Hash, #values_at] hash used to seed new Action instance
|
9
|
+
# @return [Action] action with the given defaults from hash
|
10
|
+
# @author manveru
|
11
|
+
def self.create(hash = {})
|
12
|
+
new(*hash.values_at(*ACTION_MEMBERS))
|
13
|
+
end
|
14
|
+
|
15
|
+
# Call the Action instance, will insert itself temporarily into Current.actions during the render operation so even in nested calls one can still access all other Action instances.
|
16
|
+
# Will initialize the assigned node and call Action#render
|
17
|
+
#
|
18
|
+
# @return [String] The rendition of all nested calls
|
19
|
+
# @see Action#render Node#action_found
|
20
|
+
# @author manveru
|
21
|
+
def call
|
22
|
+
Current.actions << self
|
23
|
+
self.instance = node.new
|
24
|
+
self.variables[:content] ||= nil
|
25
|
+
render
|
26
|
+
ensure
|
27
|
+
Current.actions.delete(self)
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [Binding] binding of the instance for this Action
|
31
|
+
# @see Node#binding
|
32
|
+
# @author manveru
|
33
|
+
def binding
|
34
|
+
instance.binding
|
35
|
+
end
|
36
|
+
|
37
|
+
# Copy the instance variable names and values from given
|
38
|
+
# from_action#instance into the Action#variables of the action this method
|
39
|
+
# is called on.
|
40
|
+
#
|
41
|
+
# @param [Action #instance] from_action
|
42
|
+
# @return [Action] from_action
|
43
|
+
# @see Action#wrap_in_layout
|
44
|
+
# @author manveru
|
45
|
+
def sync_variables(from_action)
|
46
|
+
instance = from_action.instance
|
47
|
+
|
48
|
+
instance.instance_variables.each{|iv|
|
49
|
+
iv_value = instance.instance_variable_get(iv)
|
50
|
+
iv_name = iv.to_s[1..-1]
|
51
|
+
self.variables[iv_name.to_sym] = iv_value
|
52
|
+
}
|
53
|
+
|
54
|
+
from_action
|
55
|
+
end
|
56
|
+
|
57
|
+
# Copy Action#variables as instance variables into the given binding.
|
58
|
+
#
|
59
|
+
# This relies on Innate::STATE, so should be thread-safe and doesn't depend
|
60
|
+
# on Innate::Current::actions order.
|
61
|
+
# So we avoid nasty business with Objectspace#_id2ref which may not work on
|
62
|
+
# all ruby implementations and seems to cause other problems as well.
|
63
|
+
#
|
64
|
+
# @param [Binding #eval] binding
|
65
|
+
# @return [NilClass] there is no indication of failure or success
|
66
|
+
# @see View::ERB::render
|
67
|
+
# @author manveru
|
68
|
+
def copy_variables(binding = self.binding)
|
69
|
+
return unless variables.any?
|
70
|
+
|
71
|
+
STATE.sync do
|
72
|
+
STATE[:action_variables] = self.variables
|
73
|
+
|
74
|
+
binding.eval('
|
75
|
+
STATE[:action_variables].each do |iv, value|
|
76
|
+
instance_variable_set("@#{iv}", value)
|
77
|
+
end')
|
78
|
+
|
79
|
+
STATE[:action_variables] = nil
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def render
|
84
|
+
instance.wrap_action_call(self) do
|
85
|
+
self.value = instance.__send__(method, *params) if method
|
86
|
+
self.view_value = File.read(view) if view
|
87
|
+
end
|
88
|
+
|
89
|
+
content_type, body = send(Innate.options.action.wish[wish] || :as_html)
|
90
|
+
Current.response['Content-Type'] ||= content_type
|
91
|
+
|
92
|
+
body
|
93
|
+
end
|
94
|
+
|
95
|
+
# @return [Array] Content-Type and rendered action
|
96
|
+
# @see Action#render Action#wrap_in_layout
|
97
|
+
# @author manveru
|
98
|
+
def as_html
|
99
|
+
return 'text/html', wrap_in_layout{ fulfill_wish(view_value || value) }
|
100
|
+
end
|
101
|
+
|
102
|
+
# @return [Array] Content-Type and rendered action
|
103
|
+
# @see Action#render Action#wrap_in_layout
|
104
|
+
# @author manveru
|
105
|
+
def as_yaml
|
106
|
+
require 'yaml'
|
107
|
+
return 'text/yaml', (value || view_value).to_yaml
|
108
|
+
end
|
109
|
+
|
110
|
+
# @return [Array] Content-Type and rendered action
|
111
|
+
# @see Action#render Action#wrap_in_layout
|
112
|
+
# @author manveru
|
113
|
+
def as_json
|
114
|
+
require 'json'
|
115
|
+
return 'application/json', (value || view_value).to_json
|
116
|
+
end
|
117
|
+
|
118
|
+
# @param [String, #to_str] string to be rendered
|
119
|
+
# @return [String] The rendered result of the templating engine
|
120
|
+
# @raise [RuntimeError] if no suitable templating engine was found
|
121
|
+
# @see Action#as_html
|
122
|
+
# @author manveru
|
123
|
+
def fulfill_wish(string)
|
124
|
+
way = File.basename(view).gsub!(/.*?#{wish}\./, '') if view
|
125
|
+
way ||= node.provide[wish] || node.provide['html']
|
126
|
+
|
127
|
+
if way
|
128
|
+
# Rack::Mime.mime_type(".#{wish}", 'text/html')
|
129
|
+
View.get(way).render(self, string)
|
130
|
+
else
|
131
|
+
raise("No templating engine was found for %p" % way)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def wrap_in_layout
|
136
|
+
return yield unless layout
|
137
|
+
|
138
|
+
action = dup
|
139
|
+
action.view, action.method = layout_view_or_method(*layout)
|
140
|
+
action.layout = nil
|
141
|
+
action.sync_variables(self)
|
142
|
+
action.variables[:content] = yield
|
143
|
+
action.call
|
144
|
+
end
|
145
|
+
|
146
|
+
def layout_view_or_method(name, arg)
|
147
|
+
return arg, nil if name == :layout || name == :view
|
148
|
+
return nil, arg
|
149
|
+
end
|
150
|
+
|
151
|
+
#Try to figure out a sane name for current action.
|
152
|
+
def name
|
153
|
+
File.basename((method || view).to_s).split('.').first
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|