nitro 0.20.0 → 0.21.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +752 -543
- data/INSTALL +38 -38
- data/README +264 -225
- data/Rakefile +48 -49
- data/bin/nitro +3 -3
- data/bin/nitrogen +6 -6
- data/doc/AUTHORS +10 -10
- data/doc/CHANGELOG.1 +1939 -1939
- data/doc/CHANGELOG.2 +954 -954
- data/doc/LICENSE +3 -3
- data/doc/MIGRATION +28 -0
- data/doc/RELEASES +814 -643
- data/doc/config.txt +5 -5
- data/install.rb +7 -17
- data/lib/nitro.rb +38 -9
- data/lib/nitro/adapter/cgi.rb +311 -312
- data/lib/nitro/adapter/fastcgi.rb +18 -25
- data/lib/nitro/adapter/webrick.rb +128 -137
- data/lib/nitro/adapter/wee.rb +51 -0
- data/lib/nitro/caching.rb +20 -20
- data/lib/nitro/caching/actions.rb +43 -43
- data/lib/nitro/caching/fragments.rb +46 -46
- data/lib/nitro/caching/invalidation.rb +11 -11
- data/lib/nitro/caching/output.rb +65 -65
- data/lib/nitro/caching/stores.rb +67 -67
- data/lib/nitro/compiler.rb +262 -0
- data/lib/nitro/compiler/elements.rb +0 -0
- data/lib/nitro/compiler/errors.rb +65 -0
- data/lib/nitro/compiler/localization.rb +25 -0
- data/lib/nitro/compiler/markup.rb +19 -0
- data/lib/nitro/compiler/shaders.rb +206 -0
- data/lib/nitro/compiler/squeeze.rb +20 -0
- data/lib/nitro/compiler/xslt.rb +61 -0
- data/lib/nitro/context.rb +87 -88
- data/lib/nitro/controller.rb +151 -158
- data/lib/nitro/cookie.rb +34 -34
- data/lib/nitro/dispatcher.rb +195 -186
- data/lib/nitro/element.rb +132 -126
- data/lib/nitro/element/java_script.rb +6 -6
- data/lib/nitro/flash.rb +66 -66
- data/lib/nitro/mail.rb +192 -192
- data/lib/nitro/mixin/buffer.rb +66 -0
- data/lib/nitro/mixin/debug.rb +16 -16
- data/lib/nitro/mixin/form.rb +88 -0
- data/lib/nitro/mixin/helper.rb +2 -2
- data/lib/nitro/mixin/javascript.rb +108 -108
- data/lib/nitro/mixin/markup.rb +144 -0
- data/lib/nitro/mixin/pager.rb +202 -202
- data/lib/nitro/mixin/rss.rb +67 -0
- data/lib/nitro/mixin/table.rb +63 -0
- data/lib/nitro/mixin/xhtml.rb +75 -0
- data/lib/nitro/mixin/xml.rb +124 -0
- data/lib/nitro/render.rb +183 -359
- data/lib/nitro/request.rb +140 -140
- data/lib/nitro/response.rb +27 -27
- data/lib/nitro/routing.rb +21 -21
- data/lib/nitro/scaffold.rb +124 -118
- data/lib/nitro/server.rb +117 -80
- data/lib/nitro/server/runner.rb +341 -0
- data/lib/nitro/service.rb +12 -12
- data/lib/nitro/service/xmlrpc.rb +22 -22
- data/lib/nitro/session.rb +122 -120
- data/lib/nitro/session/drb.rb +9 -9
- data/lib/nitro/session/drbserver.rb +34 -34
- data/lib/nitro/template.rb +171 -155
- data/lib/nitro/testing/assertions.rb +90 -90
- data/lib/nitro/testing/context.rb +16 -16
- data/lib/nitro/testing/testcase.rb +34 -34
- data/proto/conf/lhttpd.conf +9 -9
- data/proto/public/error.xhtml +75 -75
- data/proto/public/index.xhtml +18 -18
- data/proto/public/js/behaviour.js +65 -65
- data/proto/public/js/controls.js +1 -1
- data/proto/public/js/prototype.js +3 -3
- data/proto/public/settings.xhtml +61 -61
- data/proto/run.rb +1 -5
- data/test/nitro/adapter/raw_post1.bin +0 -0
- data/test/nitro/adapter/tc_cgi.rb +57 -57
- data/test/nitro/adapter/tc_webrick.rb +4 -4
- data/test/nitro/mixin/tc_pager.rb +25 -25
- data/test/nitro/mixin/tc_rss.rb +24 -0
- data/test/nitro/mixin/tc_table.rb +31 -0
- data/test/nitro/mixin/tc_xhtml.rb +13 -0
- data/test/nitro/tc_caching.rb +10 -10
- data/test/nitro/tc_context.rb +8 -8
- data/test/nitro/tc_controller.rb +48 -48
- data/test/nitro/tc_cookie.rb +6 -6
- data/test/nitro/tc_dispatcher.rb +64 -64
- data/test/nitro/tc_element.rb +27 -27
- data/test/nitro/tc_flash.rb +31 -31
- data/test/nitro/tc_mail.rb +63 -63
- data/test/nitro/tc_server.rb +26 -26
- data/test/nitro/tc_session.rb +9 -9
- data/test/nitro/tc_template.rb +19 -19
- data/test/public/blog/list.xhtml +1 -1
- metadata +31 -37
- data/lib/nitro/buffering.rb +0 -45
- data/lib/nitro/builder/form.rb +0 -104
- data/lib/nitro/builder/rss.rb +0 -104
- data/lib/nitro/builder/table.rb +0 -80
- data/lib/nitro/builder/xhtml.rb +0 -132
- data/lib/nitro/builder/xml.rb +0 -131
- data/lib/nitro/conf.rb +0 -36
- data/lib/nitro/environment.rb +0 -21
- data/lib/nitro/errors.rb +0 -69
- data/lib/nitro/localization.rb +0 -153
- data/lib/nitro/markup.rb +0 -147
- data/lib/nitro/output.rb +0 -24
- data/lib/nitro/runner.rb +0 -348
- data/lib/nitro/shaders.rb +0 -206
- data/test/nitro/builder/tc_rss.rb +0 -23
- data/test/nitro/builder/tc_table.rb +0 -30
- data/test/nitro/builder/tc_xhtml.rb +0 -39
- data/test/nitro/builder/tc_xml.rb +0 -56
- data/test/nitro/tc_localization.rb +0 -49
data/lib/nitro/controller.rb
CHANGED
@@ -6,71 +6,72 @@ require 'nitro/render'
|
|
6
6
|
require 'nitro/scaffold'
|
7
7
|
require 'nitro/caching'
|
8
8
|
require 'nitro/flash'
|
9
|
+
require 'nitro/mixin/markup'
|
9
10
|
|
10
11
|
module Nitro
|
11
12
|
|
12
13
|
# Encapsulates metadata that describe an action
|
13
14
|
# parameter.
|
14
15
|
#
|
15
|
-
#
|
16
|
-
#
|
16
|
+
# [+default+]
|
17
|
+
# The default value.
|
17
18
|
#
|
18
|
-
#
|
19
|
-
#
|
19
|
+
# [+format+]
|
20
|
+
# The expected format.
|
20
21
|
#
|
21
|
-
#
|
22
|
-
#
|
22
|
+
# [+required+]
|
23
|
+
# Is this parameter required?
|
23
24
|
|
24
25
|
unless const_defined? :ActionParam
|
25
|
-
|
26
|
+
ActionParam = Struct.new(:default, :format, :required)
|
26
27
|
end
|
27
28
|
|
28
29
|
# Encapsulates metadata that describe an action.
|
29
30
|
|
30
31
|
class ActionMeta < Hash
|
31
32
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
33
|
+
# The arguments of the given method.
|
34
|
+
|
35
|
+
attr_accessor :params
|
36
|
+
|
37
|
+
# Initialize the metadata.
|
38
|
+
|
39
|
+
def initialize(options)
|
40
|
+
@params = {}
|
41
|
+
update(options)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Update the metadata.
|
45
|
+
#
|
46
|
+
# [+options+]
|
47
|
+
# A hash containing the metadata. Options with Symbol
|
48
|
+
# keys are considered metadata, options with
|
49
|
+
# String keys are the named parameters for the action.
|
50
|
+
|
51
|
+
def update(options)
|
52
|
+
options.each do |k, v|
|
53
|
+
case k
|
54
|
+
when String
|
55
|
+
# A key of type String denotes a parameter.
|
56
|
+
case v
|
57
|
+
when Regexp
|
58
|
+
@params[k] = ActionParam.new(nil, v, nil)
|
59
|
+
when ActionParam
|
60
|
+
@params[k] = v
|
61
|
+
else
|
62
|
+
if v == :required
|
63
|
+
@params[k] = ActionParam.new(nil, nil, true)
|
64
|
+
else
|
65
|
+
@params[k] = ActionParam.new(v, nil, nil)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
when Symbol
|
69
|
+
self[k] = v
|
70
|
+
else
|
71
|
+
raise TypeError.new('The keys must be either Symbols or Strings.')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
74
75
|
|
75
76
|
end
|
76
77
|
|
@@ -79,103 +80,94 @@ end
|
|
79
80
|
# interface.
|
80
81
|
|
81
82
|
module Publishable
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
if Rendering.compile_action(self.class, action)
|
171
|
-
send(action, *args)
|
172
|
-
else
|
173
|
-
super
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
end
|
83
|
+
def self.append_features(base)
|
84
|
+
|
85
|
+
base.module_eval do
|
86
|
+
include Render
|
87
|
+
include Glue::Aspects
|
88
|
+
include Flashing
|
89
|
+
include Glue::Helpers
|
90
|
+
|
91
|
+
class << self
|
92
|
+
attr_accessor :template_root
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# Define metadata for an action. This is a helper
|
97
|
+
# macro.
|
98
|
+
|
99
|
+
base.module_eval do
|
100
|
+
def self.action(name, options)
|
101
|
+
if meta = action_metadata[name]
|
102
|
+
meta.update(options)
|
103
|
+
else
|
104
|
+
action_metadata[name] = ActionMeta.new(options)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Aliases an action
|
110
|
+
#--
|
111
|
+
# gmosx, FIXME: better implementation needed.
|
112
|
+
#++
|
113
|
+
|
114
|
+
base.module_eval do
|
115
|
+
def self.alias_action(new, old)
|
116
|
+
alias_method new, old
|
117
|
+
md = action_metadata[old] || ActionMetadata.new
|
118
|
+
md[:view] = old
|
119
|
+
action_metadata[new] = md
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Return the 'action' methods for this Controller.
|
124
|
+
# Some dangerous methods from ancestors are removed.
|
125
|
+
# All private methods are ignored.
|
126
|
+
|
127
|
+
base.module_eval do
|
128
|
+
def self.action_methods
|
129
|
+
classes = self.ancestors.reject do |a|
|
130
|
+
[Object, Kernel, Render, Controller, Caching].include?(a)
|
131
|
+
end
|
132
|
+
|
133
|
+
classes.delete(PP::ObjectMixin) if defined?(PP::ObjectMixin)
|
134
|
+
|
135
|
+
methods = classes.inject([]) do |action_methods, klass|
|
136
|
+
action_methods + klass.public_instance_methods(false)
|
137
|
+
end
|
138
|
+
|
139
|
+
# gmosx: add the default action (leave this?)
|
140
|
+
# methods << 'index'
|
141
|
+
|
142
|
+
return methods
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# A hash containing metadata for the action
|
147
|
+
# methods.
|
148
|
+
|
149
|
+
base.module_eval do
|
150
|
+
def self.action_metadata
|
151
|
+
# FIXME: improve this.
|
152
|
+
@action_metadata ||= {}
|
153
|
+
@action_metadata
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Use the method_missing hook to compile the actions
|
158
|
+
# for this controller.
|
159
|
+
|
160
|
+
base.module_eval do
|
161
|
+
def method_missing(action, *args)
|
162
|
+
if Compiler.new.compile(self.class, action)
|
163
|
+
send(action, *args)
|
164
|
+
else
|
165
|
+
super
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
179
171
|
end
|
180
172
|
|
181
173
|
# The Controller part in the MVC paradigm. The controller's
|
@@ -183,18 +175,19 @@ end
|
|
183
175
|
# contains the Publishable mixin and additional helper mixins.
|
184
176
|
|
185
177
|
class Controller
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
178
|
+
include Publishable
|
179
|
+
include Scaffolding
|
180
|
+
include Caching
|
181
|
+
include Markup
|
182
|
+
|
183
|
+
# The default action.
|
184
|
+
=begin
|
185
|
+
def index
|
186
|
+
print %{
|
187
|
+
This is the placeholder action is provided as a default for #{self.class.name}.<br />
|
188
|
+
You probably want to <b>implement your custom action</b> here.
|
189
|
+
}
|
190
|
+
end
|
198
191
|
=end
|
199
192
|
end
|
200
193
|
|
data/lib/nitro/cookie.rb
CHANGED
@@ -3,40 +3,40 @@ module Nitro
|
|
3
3
|
# Encapsulates a HTTP Cookie.
|
4
4
|
|
5
5
|
class Cookie
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
6
|
+
attr_reader :name
|
7
|
+
attr_accessor :value, :version
|
8
|
+
attr_accessor :domain, :path, :secure
|
9
|
+
attr_accessor :comment, :max_age
|
10
|
+
|
11
|
+
def initialize(name, value)
|
12
|
+
@name = name
|
13
|
+
@value = value
|
14
|
+
@version = 0 # Netscape Cookie
|
15
|
+
@path = '/' # gmosx: KEEP this!
|
16
|
+
@domain = @secure = @comment = @max_age =
|
17
|
+
@expires = @comment_url = @discard = @port = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def expires=(t)
|
21
|
+
@expires = t && (t.is_a?(Time) ? t.httpdate : t.to_s)
|
22
|
+
end
|
23
|
+
|
24
|
+
def expires
|
25
|
+
@expires && Time.parse(@expires)
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
ret = ""
|
30
|
+
ret << @name << "=" << @value
|
31
|
+
ret << "; " << "Version=" << @version.to_s if @version > 0
|
32
|
+
ret << "; " << "Domain=" << @domain if @domain
|
33
|
+
ret << "; " << "Expires=" << @expires if @expires
|
34
|
+
ret << "; " << "Max-Age=" << @max_age.to_s if @max_age
|
35
|
+
ret << "; " << "Comment=" << @comment if @comment
|
36
|
+
ret << "; " << "Path=" << @path if @path
|
37
|
+
ret << "; " << "Secure" if @secure
|
38
|
+
ret
|
39
|
+
end
|
40
40
|
|
41
41
|
end
|
42
42
|
|
data/lib/nitro/dispatcher.rb
CHANGED
@@ -10,192 +10,201 @@ module Nitro
|
|
10
10
|
|
11
11
|
class Dispatcher
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
13
|
+
include Router
|
14
|
+
|
15
|
+
# The map.
|
16
|
+
|
17
|
+
setting :map, :default => { '/' => SimpleController }, :doc => 'The controller map'
|
18
|
+
|
19
|
+
unless const_defined? :ROOT
|
20
|
+
ROOT = '/'
|
21
|
+
end
|
22
|
+
|
23
|
+
# The public root directory. The files in this
|
24
|
+
# directory are published by the web server.
|
25
|
+
|
26
|
+
attr_accessor :public_root
|
27
|
+
|
28
|
+
# The template root directory. By default this points to the
|
29
|
+
# public root directory to allow for PHP/JSP/ASP style
|
30
|
+
# programming. But you should probably change this to
|
31
|
+
# another directory for extra security.
|
32
|
+
|
33
|
+
attr_accessor :template_root
|
34
|
+
|
35
|
+
# The controllers map.
|
36
|
+
|
37
|
+
attr_accessor :controllers
|
38
|
+
|
39
|
+
# Create a new Dispatcher.
|
40
|
+
#
|
41
|
+
# Input:
|
42
|
+
#
|
43
|
+
# [+controllers+]
|
44
|
+
# Either a hash of controller mappings or a single
|
45
|
+
# controller that gets mapped to :root.
|
46
|
+
|
47
|
+
def initialize(controllers = nil)
|
48
|
+
@public_root = 'public'
|
49
|
+
@template_root = @public_root
|
50
|
+
|
51
|
+
if controllers and controllers.is_a?(Class) and controllers.ancestors.include?(Controller)
|
52
|
+
controllers = { '/' => controllers }
|
53
|
+
else
|
54
|
+
controllers ||= { '/' => SimpleController }
|
55
|
+
end
|
56
|
+
|
57
|
+
mount(controllers)
|
58
|
+
end
|
59
|
+
|
60
|
+
# A published object is exposed through a REST interface.
|
61
|
+
# Only the public non standard methods of the object are
|
62
|
+
# accessible. Published objects implement the Controller
|
63
|
+
# part of MVC.
|
64
|
+
#
|
65
|
+
# Process the given hash and mount the
|
66
|
+
# defined classes (controllers).
|
67
|
+
#
|
68
|
+
# Input:
|
69
|
+
#
|
70
|
+
# [+controllers+]
|
71
|
+
# A hash representing the mapping of
|
72
|
+
# mount points to controllers.
|
73
|
+
#
|
74
|
+
# === Examples
|
75
|
+
#
|
76
|
+
# disp.mount(
|
77
|
+
# '/' => MainController, # mounts /
|
78
|
+
# '/users' => UsersController # mounts /users
|
79
|
+
# )
|
80
|
+
# disp.publish '/' => MainController
|
81
|
+
|
82
|
+
def add_controller(controllers)
|
83
|
+
for path, c in controllers
|
84
|
+
unless (c.ancestors.include?(Controller) or c.ancestors.include?(Publishable))
|
85
|
+
c.send :include, Publishable
|
86
|
+
end
|
87
|
+
|
88
|
+
auto_mixin(c)
|
89
|
+
|
90
|
+
# Try to setup a template_root if none is defined:
|
91
|
+
|
92
|
+
unless c.template_root
|
93
|
+
c.template_root = "#{Template.root}#{path}".gsub(/\/$/, '')
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
(@controllers ||= {}).update(controllers)
|
98
|
+
|
99
|
+
update_routes()
|
100
|
+
end
|
101
|
+
alias_method :mount, :add_controller
|
102
|
+
alias_method :publish, :add_controller
|
103
|
+
alias_method :map=, :add_controller
|
104
|
+
|
105
|
+
# Call this method to automatically include helpers in the
|
106
|
+
# Controllers. For each Controller 'XxxController' the
|
107
|
+
# default helper 'Helper' and the auto mixin
|
108
|
+
# 'XxxControllerMixin' (if it exists) are included.
|
109
|
+
|
110
|
+
def auto_mixin(c)
|
111
|
+
c.helper(Helper)
|
112
|
+
|
113
|
+
begin
|
114
|
+
if helper = Module.by_name("#{c}Mixin")
|
115
|
+
c.helper(helper)
|
116
|
+
end
|
117
|
+
rescue NameError
|
118
|
+
# The auto helper is not defined.
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Update the routes. Typically called after a new
|
123
|
+
# Controller is mounted.
|
124
|
+
|
125
|
+
def update_routes
|
126
|
+
@routes = []
|
127
|
+
@controllers.each do |base, c|
|
128
|
+
base = '' if base == '/'
|
129
|
+
c.action_metadata.each do |action, meta|
|
130
|
+
if route = meta[:route]
|
131
|
+
@routes << [route, "#{base}/#{action}", *meta.params.keys]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Processes the path and dispatches to the corresponding
|
138
|
+
# controller/action pair.
|
139
|
+
# The base returned contains a trailing '/'.
|
140
|
+
#
|
141
|
+
# [+path+]
|
142
|
+
# The path to dispatch.
|
143
|
+
#
|
144
|
+
# [:context]
|
145
|
+
# The dispatching context.
|
146
|
+
#--
|
147
|
+
# FIXME: this is a critical method that should be optimized
|
148
|
+
# watch out for excessive String creation.
|
149
|
+
#++
|
150
|
+
|
151
|
+
def dispatch(path, context = nil)
|
152
|
+
path = route(path, context)
|
153
|
+
|
154
|
+
parts = path.split('/')
|
155
|
+
parts.shift
|
156
|
+
|
157
|
+
case parts.size
|
158
|
+
when 0
|
159
|
+
# / -> root.index
|
160
|
+
base = '/'
|
161
|
+
klass = controller_class_for(base)
|
162
|
+
action = 'index'
|
163
|
+
|
164
|
+
when 1
|
165
|
+
base = "/#{parts[0]}"
|
166
|
+
if klass = controller_class_for(base)
|
167
|
+
# controller/ -> controller.index
|
168
|
+
action = 'index'
|
169
|
+
else
|
170
|
+
# action/ -> root.action
|
171
|
+
base = '/'
|
172
|
+
klass = controller_class_for(base)
|
173
|
+
action = parts[0]
|
174
|
+
end
|
175
|
+
|
176
|
+
else
|
177
|
+
base = "/#{parts[0]}"
|
178
|
+
if klass = controller_class_for(base)
|
179
|
+
# controller/action -> controller.action
|
180
|
+
parts.shift
|
181
|
+
action = parts.join('__')
|
182
|
+
else
|
183
|
+
# action/ -> root.action
|
184
|
+
base = '/'
|
185
|
+
klass = controller_class_for(base)
|
186
|
+
action = parts.join('__')
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
return klass, "#{action}_action", base
|
191
|
+
end
|
192
|
+
alias_method :split_path, :dispatch
|
193
|
+
|
194
|
+
# Get the controller for the given key.
|
195
|
+
# Also handles reloading of controllers.
|
196
|
+
|
197
|
+
def controller_class_for(key)
|
198
|
+
klass = @controllers[key]
|
199
|
+
|
200
|
+
if klass and Compiler.reload
|
201
|
+
klass.instance_methods.grep(/(action$)|(template$)/).each do |m|
|
202
|
+
klass.send(:remove_method, m) rescue nil
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
return klass
|
207
|
+
end
|
199
208
|
|
200
209
|
end
|
201
210
|
|