nitro 0.29.0 → 0.30.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +410 -0
- data/ProjectInfo +36 -44
- data/README +5 -5
- data/doc/AUTHORS +6 -0
- data/doc/RELEASES +159 -2
- data/lib/glue/sweeper.rb +2 -2
- data/lib/glue/webfile.rb +14 -1
- data/lib/nitro.rb +6 -9
- data/lib/nitro/adapter/mongrel.rb +36 -43
- data/lib/nitro/adapter/scgi.rb +1 -1
- data/lib/nitro/adapter/webrick.rb +96 -24
- data/lib/nitro/caching/actions.rb +2 -1
- data/lib/nitro/caching/fragments.rb +1 -8
- data/lib/nitro/caching/output.rb +14 -4
- data/lib/nitro/cgi.rb +19 -21
- data/lib/nitro/cgi/cookie.rb +5 -1
- data/lib/nitro/cgi/request.rb +20 -4
- data/lib/nitro/compiler.rb +74 -28
- data/lib/nitro/compiler/cleanup.rb +1 -1
- data/lib/nitro/compiler/elements.rb +1 -2
- data/lib/nitro/compiler/localization.rb +1 -1
- data/lib/nitro/compiler/markup.rb +1 -1
- data/lib/nitro/compiler/script.rb +52 -44
- data/lib/nitro/compiler/squeeze.rb +4 -3
- data/lib/nitro/compiler/xslt.rb +7 -6
- data/lib/nitro/context.rb +39 -20
- data/lib/nitro/controller.rb +24 -5
- data/lib/nitro/dispatcher.rb +13 -5
- data/lib/nitro/global.rb +63 -0
- data/lib/nitro/helper/feed.rb +432 -0
- data/lib/nitro/helper/form.rb +11 -3
- data/lib/nitro/helper/form/builder.rb +140 -0
- data/lib/nitro/helper/form/controls.rb +2 -1
- data/lib/nitro/helper/javascript.rb +6 -0
- data/lib/nitro/helper/javascript/morphing.rb +13 -6
- data/lib/nitro/helper/xhtml.rb +42 -6
- data/lib/nitro/helper/xml.rb +3 -0
- data/lib/nitro/part.rb +2 -2
- data/lib/nitro/render.rb +7 -2
- data/lib/nitro/router.rb +57 -16
- data/lib/nitro/scaffolding.rb +29 -20
- data/lib/nitro/server.rb +4 -10
- data/lib/nitro/server/drb.rb +1 -1
- data/lib/nitro/server/runner.rb +10 -0
- data/lib/nitro/session.rb +31 -12
- data/lib/nitro/session/drb.rb +13 -1
- data/lib/nitro/session/file.rb +1 -1
- data/lib/nitro/session/memcached.rb +1 -1
- data/lib/nitro/session/memory.rb +1 -1
- data/lib/nitro/session/og.rb +1 -1
- data/lib/nitro/test/testcase.rb +3 -0
- data/proto/public/error.xhtml +5 -5
- data/proto/public/js/controls.js +2 -2
- data/proto/public/js/dragdrop.js +320 -79
- data/proto/public/js/effects.js +200 -152
- data/proto/public/js/prototype.js +284 -63
- data/proto/public/js/scriptaculous.js +7 -5
- data/proto/public/js/unittest.js +11 -0
- data/proto/public/scaffold/advanced_search.xhtml +30 -0
- data/proto/public/scaffold/list.xhtml +8 -1
- data/proto/public/scaffold/search.xhtml +2 -1
- data/proto/script/scgi_service +1 -1
- data/src/part/admin/controller.rb +1 -1
- data/src/part/admin/skin.rb +1 -1
- data/test/nitro/CONFIG.rb +3 -0
- data/test/nitro/adapter/tc_webrick.rb +1 -1
- data/test/nitro/cgi/tc_cookie.rb +1 -1
- data/test/nitro/cgi/tc_request.rb +5 -5
- data/test/nitro/compiler/tc_client_morpher.rb +47 -0
- data/test/nitro/compiler/tc_compiler.rb +2 -0
- data/test/nitro/helper/tc_feed.rb +138 -0
- data/test/nitro/helper/tc_pager.rb +1 -1
- data/test/nitro/helper/tc_rss.rb +1 -1
- data/test/nitro/helper/tc_table.rb +1 -1
- data/test/nitro/helper/tc_xhtml.rb +1 -1
- data/test/nitro/tc_caching.rb +1 -1
- data/test/nitro/tc_cgi.rb +1 -1
- data/test/nitro/tc_context.rb +1 -1
- data/test/nitro/tc_controller.rb +31 -3
- data/test/nitro/tc_controller_aspect.rb +1 -1
- data/test/nitro/tc_dispatcher.rb +1 -1
- data/test/nitro/tc_element.rb +1 -1
- data/test/nitro/tc_flash.rb +1 -1
- data/test/nitro/tc_helper.rb +1 -1
- data/test/nitro/tc_render.rb +6 -6
- data/test/nitro/tc_router.rb +8 -4
- data/test/nitro/tc_server.rb +1 -3
- data/test/nitro/tc_session.rb +1 -3
- metadata +107 -104
- data/Rakefile +0 -232
- data/lib/nitro/adapter/acgi.rb +0 -237
- data/proto/public/Makefile.acgi +0 -40
- data/proto/public/acgi.c +0 -138
@@ -21,6 +21,8 @@ module Caching
|
|
21
21
|
|
22
22
|
module ClassMethods
|
23
23
|
|
24
|
+
# Cache the given actions.
|
25
|
+
|
24
26
|
def cache_action(*actions)
|
25
27
|
return unless caching_enabled?
|
26
28
|
|
@@ -49,7 +51,6 @@ module Caching
|
|
49
51
|
private
|
50
52
|
|
51
53
|
# Expire the cached fragment of the given actions.
|
52
|
-
#
|
53
54
|
#--
|
54
55
|
# FIXME: not very good implementation?
|
55
56
|
#++
|
@@ -17,14 +17,7 @@ module Caching
|
|
17
17
|
|
18
18
|
# The cache used to store the fragments.
|
19
19
|
|
20
|
-
setting :cache, :default =>
|
21
|
-
|
22
|
-
#--
|
23
|
-
# gmosx, FIXME: this is a hack, improve setting
|
24
|
-
# implementation.
|
25
|
-
#++
|
26
|
-
|
27
|
-
@@cache = Glue::MemoryCache.new
|
20
|
+
setting :cache, :default => Glue::MemoryCache.new, :doc => 'The cache used to store the fragments'
|
28
21
|
|
29
22
|
def self.get(name, options = {})
|
30
23
|
return @@cache.get(name, options)
|
data/lib/nitro/caching/output.rb
CHANGED
@@ -11,7 +11,8 @@ module Caching
|
|
11
11
|
# (Lighttpd, Apache, etc) for optimal performance.
|
12
12
|
#
|
13
13
|
# Nitro promotes coding your application in such a way as to
|
14
|
-
# allow for output caching to the greatest extend.
|
14
|
+
# allow for output caching to the greatest extend. Output
|
15
|
+
# caching *is your friend*.
|
15
16
|
#--
|
16
17
|
# gmosx, FIXME: Don't create excessive directories, use better
|
17
18
|
# rewrite rules to handle xxx.html files.
|
@@ -66,6 +67,9 @@ module Caching
|
|
66
67
|
end
|
67
68
|
end
|
68
69
|
|
70
|
+
# Explicitly expire the output cached under the given
|
71
|
+
# cache key. The cache key is typically the name of the
|
72
|
+
# top level action responsible for generating the page.
|
69
73
|
#--
|
70
74
|
# If you change this method, don't forget the CacheSweeper
|
71
75
|
# expire method.
|
@@ -73,14 +77,20 @@ module Caching
|
|
73
77
|
|
74
78
|
def expire_output(name)
|
75
79
|
begin
|
76
|
-
Logger.debug "Expirinig cache file '#{
|
77
|
-
FileUtils.rm_rf("#{
|
78
|
-
rescue Object
|
80
|
+
Logger.debug "Expirinig cache file '#{Server.public_root}/#{name}'" if $DBG
|
81
|
+
FileUtils.rm_rf("#{Server.public_root}/#{name}")
|
82
|
+
rescue Object => ex
|
79
83
|
# gmosx: is this the right thing to do?
|
80
84
|
end
|
81
85
|
end
|
82
86
|
alias_method :delete_output, :expire_output
|
83
87
|
|
88
|
+
# Is caching allowed for this action (page)? The default
|
89
|
+
# implementation does not cache post request or request
|
90
|
+
# with query parameters. You can work arround the second
|
91
|
+
# 'limitation' by cleverly using Nitro's implicit support
|
92
|
+
# for 'nice' urls.
|
93
|
+
|
84
94
|
def caching_allowed?
|
85
95
|
not (@request.post? or @request.uri =~ /\?/)
|
86
96
|
end
|
data/lib/nitro/cgi.rb
CHANGED
@@ -31,30 +31,28 @@ class Cgi
|
|
31
31
|
#--
|
32
32
|
# gmosx: only handle nitro requests.
|
33
33
|
#++
|
34
|
-
|
35
|
-
# gmosx: QUERY_STRING is sometimes not populated.
|
34
|
+
# gmosx: QUERY_STRING is sometimes not populated.
|
36
35
|
|
37
|
-
|
38
|
-
|
39
|
-
|
36
|
+
if context.query_string.empty? and context.uri =~ /\?/
|
37
|
+
context.headers['QUERY_STRING'] = context.uri.split('?').last
|
38
|
+
end
|
40
39
|
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
Cgi.parse_params(context)
|
41
|
+
Cgi.parse_cookies(context)
|
42
|
+
context.render(context.path)
|
44
43
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
end
|
55
|
-
else
|
56
|
-
out.print(context.out)
|
44
|
+
out.print(Cgi.response_headers(context))
|
45
|
+
|
46
|
+
if context.out.is_a?(IO)
|
47
|
+
begin
|
48
|
+
while buf = context.out.read(4096)
|
49
|
+
out.write(buf)
|
50
|
+
end
|
51
|
+
ensure
|
52
|
+
context.out.close
|
57
53
|
end
|
54
|
+
else
|
55
|
+
out.print(context.out)
|
58
56
|
end
|
59
57
|
|
60
58
|
$autoreload_dirty = false
|
@@ -116,7 +114,7 @@ class Cgi
|
|
116
114
|
if env['HTTP_COOKIE'] or env['COOKIE']
|
117
115
|
(env['HTTP_COOKIE'] or env['COOKIE']).split(/; /).each do |c|
|
118
116
|
key, val = c.split(/=/, 2)
|
119
|
-
|
117
|
+
val ||= ""
|
120
118
|
key = CGI.unescape(key)
|
121
119
|
val = val.split(/&/).collect{|v| CGI::unescape(v)}.join("\0")
|
122
120
|
|
data/lib/nitro/cgi/cookie.rb
CHANGED
@@ -18,14 +18,18 @@ class Cookie
|
|
18
18
|
@comment_url = @discard = @port = nil
|
19
19
|
end
|
20
20
|
|
21
|
+
# Set the cookie expiration.
|
22
|
+
|
21
23
|
def expires=(t)
|
22
24
|
@expires = t && (t.is_a?(Time) ? t.httpdate : t.to_s)
|
23
25
|
end
|
24
26
|
|
27
|
+
# When the cookie expires.
|
28
|
+
|
25
29
|
def expires
|
26
30
|
@expires && Time.parse(@expires)
|
27
31
|
end
|
28
|
-
|
32
|
+
|
29
33
|
def to_s
|
30
34
|
ret = ""
|
31
35
|
ret << @name << "=" << @value
|
data/lib/nitro/cgi/request.rb
CHANGED
@@ -26,6 +26,7 @@ module Request
|
|
26
26
|
# The request cookies.
|
27
27
|
|
28
28
|
attr_accessor :cookies
|
29
|
+
alias_method :cookie, :cookies
|
29
30
|
|
30
31
|
# The request protocol.
|
31
32
|
|
@@ -60,8 +61,8 @@ module Request
|
|
60
61
|
#
|
61
62
|
# === Examples
|
62
63
|
#
|
63
|
-
# www.
|
64
|
-
# www.
|
64
|
+
# www.nitroproject.org: request.domain # => 'nitroproject.org'
|
65
|
+
# www.nitroproject.co.uk: request.domain(2) # => 'nitroproject.co.uk'
|
65
66
|
|
66
67
|
def domain(tld_length = 1)
|
67
68
|
host.split('.').last(1 + tld_length).join('.')
|
@@ -71,7 +72,7 @@ module Request
|
|
71
72
|
#
|
72
73
|
# === Examples
|
73
74
|
#
|
74
|
-
# my.name.
|
75
|
+
# my.name.nitroproject.org: request.subdomains # => ['my', 'name']
|
75
76
|
|
76
77
|
def subdomains(tld_length = 1)
|
77
78
|
parts = host.split('.')
|
@@ -80,7 +81,7 @@ module Request
|
|
80
81
|
|
81
82
|
# The request query string.
|
82
83
|
#--
|
83
|
-
#
|
84
|
+
# gmosx, FIXME: handles some fcgi problems.
|
84
85
|
#++
|
85
86
|
|
86
87
|
def query_string
|
@@ -251,6 +252,20 @@ module Request
|
|
251
252
|
@params[param] = value
|
252
253
|
end
|
253
254
|
|
255
|
+
# Check if a boolean param (checkbox) is true.
|
256
|
+
|
257
|
+
def true?(param)
|
258
|
+
@params[param] == 'on'
|
259
|
+
end
|
260
|
+
alias_method :enabled?, :true?
|
261
|
+
alias_method :boolean, :true?
|
262
|
+
|
263
|
+
# Check if a boolean param (checkbox) is false.
|
264
|
+
|
265
|
+
def false?(param)
|
266
|
+
!true?(param)
|
267
|
+
end
|
268
|
+
|
254
269
|
# Fetch a parameter with default value.
|
255
270
|
|
256
271
|
def fetch(param, default = nil)
|
@@ -263,6 +278,7 @@ module Request
|
|
263
278
|
@params.has_key?(key)
|
264
279
|
end
|
265
280
|
alias_method :has_param?, :has_key?
|
281
|
+
alias_method :param?, :has_key?
|
266
282
|
end
|
267
283
|
|
268
284
|
end
|
data/lib/nitro/compiler.rb
CHANGED
@@ -40,6 +40,27 @@ class Compiler
|
|
40
40
|
|
41
41
|
setting :reload, :default => true, :doc => 'If true all code and templates are reloaded in each request'
|
42
42
|
|
43
|
+
|
44
|
+
# The default transformation pipeline. Nitro allows fine
|
45
|
+
# grained customization pipelines per controller or even per
|
46
|
+
# action. The Template transformation is added by default.
|
47
|
+
# Here come examples of pipeline customization:
|
48
|
+
#
|
49
|
+
# class MyController
|
50
|
+
# ann :self, :transformation_pipeline => [MyTransformer, AnotherXForm]
|
51
|
+
#
|
52
|
+
# ...
|
53
|
+
#
|
54
|
+
# def my_action
|
55
|
+
# ...
|
56
|
+
# end
|
57
|
+
# ann :my_action, :transformation_pipeline => Compiler.transformation_pipeline.dup.shift(CustomXForm)
|
58
|
+
#
|
59
|
+
# ...
|
60
|
+
# end
|
61
|
+
|
62
|
+
setting :transformation_pipeline, :default => [StaticInclude, Morphing, Elements, Markup, ScriptCompiler, Cleanup], :doc => 'The default transformation pipeline'
|
63
|
+
|
43
64
|
def initialize(controller = nil)
|
44
65
|
@controller = controller
|
45
66
|
@shared = {}
|
@@ -86,15 +107,34 @@ class Compiler
|
|
86
107
|
# The default transformation extracts the Ruby code from
|
87
108
|
# processing instructions, and uses the StaticInclude,
|
88
109
|
# Morphing, Elements and Markup compiler modules.
|
110
|
+
#
|
111
|
+
# The Template transformation stage is added by default.
|
112
|
+
#
|
113
|
+
# You can override this method or use aspects for really
|
114
|
+
# special transformation pipelines. Your imagination is the
|
115
|
+
# limit.
|
116
|
+
#--
|
117
|
+
# TODO: make Template stage pluggable.
|
118
|
+
# gmosx: This method is also called from the scaffolding
|
119
|
+
# code.
|
120
|
+
#++
|
89
121
|
|
90
|
-
def transform_template(template)
|
91
|
-
|
92
|
-
|
93
|
-
#
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
122
|
+
def transform_template(action, template)
|
123
|
+
# Check for an action specific transformation pipeline.
|
124
|
+
if (transformers = @controller.ann(action.to_sym).transformation_pipeline).nil?
|
125
|
+
# Check for a controller specific transformation pipeline.
|
126
|
+
if (transformers = @controller.ann.self.transformation_pipeline).nil?
|
127
|
+
# Use the default transformation pipeline.
|
128
|
+
transformers = Compiler.transformation_pipeline
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
transformers.each do |transformer|
|
133
|
+
template = transformer.transform(template, self)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Add Template transformation stage by default.
|
137
|
+
|
98
138
|
template = Template.transform(template)
|
99
139
|
end
|
100
140
|
|
@@ -109,7 +149,7 @@ class Compiler
|
|
109
149
|
|
110
150
|
code = %{
|
111
151
|
def #{action}_template
|
112
|
-
#{transform_template(template)}
|
152
|
+
#{transform_template(action, template)}
|
113
153
|
end
|
114
154
|
}
|
115
155
|
|
@@ -155,14 +195,19 @@ class Compiler
|
|
155
195
|
#++
|
156
196
|
|
157
197
|
def compile_action(action)
|
158
|
-
action = action.to_s.gsub(/_action$/, '')
|
198
|
+
action = @action = action.to_s.gsub(/_action$/, '')
|
159
199
|
|
160
200
|
return false unless action
|
161
201
|
|
162
202
|
Logger.debug "Compiling action '#@controller##{action}'" if $DBG
|
163
203
|
|
164
204
|
valid = false
|
165
|
-
|
205
|
+
|
206
|
+
#--
|
207
|
+
# FIXME: parent_action_name does not work as expected,
|
208
|
+
# if you include actions from other controllers!!
|
209
|
+
#++
|
210
|
+
|
166
211
|
code = %{
|
167
212
|
def #{action}_action
|
168
213
|
@parent_action_name = @action_name
|
@@ -171,7 +216,7 @@ class Compiler
|
|
171
216
|
|
172
217
|
# Inject the pre advices.
|
173
218
|
|
174
|
-
code <<
|
219
|
+
code << ::Aspects.gen_advice_code(action, @controller.advices, :pre)
|
175
220
|
|
176
221
|
# Call the action
|
177
222
|
|
@@ -187,16 +232,16 @@ class Compiler
|
|
187
232
|
|
188
233
|
# Try to resolve action parameters. Returns negative
|
189
234
|
# numbers for arbitrary parameters.
|
235
|
+
#--
|
236
|
+
# gmosx: This needs a better implementation. Better means
|
237
|
+
# cleaner and more optimized code.
|
238
|
+
#++
|
190
239
|
|
191
240
|
param_count = @controller.instance_method(action.to_sym).arity
|
192
241
|
|
193
242
|
if param_count != 0
|
194
|
-
if param_count > 0
|
195
|
-
code << "params = Array.new(#{param_count}, nil);"
|
196
|
-
else
|
197
|
-
code << "params = [];"
|
198
|
-
end
|
199
243
|
code << %{
|
244
|
+
params = []
|
200
245
|
unless context.query_string.blank?
|
201
246
|
all_params = context.query_string.split(/[&;]/)
|
202
247
|
is_hash = all_params.first.index('=')
|
@@ -208,9 +253,16 @@ class Compiler
|
|
208
253
|
end
|
209
254
|
code << %{
|
210
255
|
break if qs.index('=') and not is_hash
|
211
|
-
params
|
256
|
+
params << CGI.unescape(qs.split(/=/).last || "")
|
212
257
|
end
|
213
258
|
end
|
259
|
+
|
260
|
+
# Concatenate some extracted parameters.
|
261
|
+
params.concat(context.params.values)
|
262
|
+
|
263
|
+
# Fill the array with nils for the missing params.
|
264
|
+
(#{param_count} - params.size).times { params << nil }
|
265
|
+
|
214
266
|
action_return_value = #{action}(*params)
|
215
267
|
}
|
216
268
|
else
|
@@ -267,7 +319,7 @@ class Compiler
|
|
267
319
|
|
268
320
|
# Inject the post advices.
|
269
321
|
|
270
|
-
code <<
|
322
|
+
code << ::Aspects.gen_advice_code(action, @controller.advices, :post)
|
271
323
|
|
272
324
|
code << %{
|
273
325
|
@action_name = @parent_action_name
|
@@ -279,6 +331,8 @@ class Compiler
|
|
279
331
|
@controller.class_eval(code)
|
280
332
|
|
281
333
|
unless @controller.respond_to?("#{action}_template")
|
334
|
+
# If there is not method {action}_template in the controller
|
335
|
+
# search for a file template.
|
282
336
|
if template_path
|
283
337
|
compile_template(action, template_path)
|
284
338
|
end
|
@@ -297,15 +351,6 @@ class Compiler
|
|
297
351
|
# :section: Helper methods.
|
298
352
|
|
299
353
|
class << self
|
300
|
-
# Helper method for manipulating the template transformation
|
301
|
-
# pipeline.
|
302
|
-
|
303
|
-
def setup_transform_template(&block)
|
304
|
-
send :define_method, :transform_template, block
|
305
|
-
end
|
306
|
-
alias_method :setup_template_transform, :setup_transform_template
|
307
|
-
alias_method :setup_template_transformation, :setup_transform_template
|
308
|
-
|
309
354
|
# Typically used to precompile css templates.
|
310
355
|
|
311
356
|
def precompile(filename)
|
@@ -330,3 +375,4 @@ end
|
|
330
375
|
# * George Moschovitis <gm@navel.gr>
|
331
376
|
# * Chris Farmiloe <chris.farmiloe@farmiloe.com>
|
332
377
|
# * Rob Pitt <rob@motionpath.co.uk>
|
378
|
+
# * Jonas Pfenniger <zimba.tm@gmail.com>
|
@@ -80,7 +80,7 @@ class Elements # :nodoc: all
|
|
80
80
|
# name = name.demodulize
|
81
81
|
return false unless name =~ PREFIX_RE or name =~ CAPITALIZED_RE
|
82
82
|
|
83
|
-
name = name.gsub(
|
83
|
+
name = name.gsub(PREFIX_RE,'').camelize if name =~ PREFIX_RE
|
84
84
|
|
85
85
|
# First try to use Nitro::Element::xxx then ::xxx
|
86
86
|
|
@@ -95,7 +95,6 @@ class Elements # :nodoc: all
|
|
95
95
|
namespace = @compiler.controller.name
|
96
96
|
if /::/ =~ namespace
|
97
97
|
namespace = namespace.gsub( /::[a-zA-Z]+$/, "::#{name}" )
|
98
|
-
pp namespace
|
99
98
|
klass = Class.by_name(namespace)
|
100
99
|
end
|
101
100
|
rescue
|