nitro 0.20.0 → 0.21.0
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 +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
|
|