nitro 0.29.0 → 0.30.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 +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
@@ -8,7 +8,7 @@ module Nitro
|
|
8
8
|
|
9
9
|
module ScriptCompiler
|
10
10
|
extend JavascriptHelper
|
11
|
-
|
11
|
+
|
12
12
|
def self.transform(text, compiler)
|
13
13
|
begin
|
14
14
|
client = constant("#{compiler.controller}::Client")
|
@@ -21,9 +21,11 @@ module ScriptCompiler
|
|
21
21
|
client = client.new
|
22
22
|
|
23
23
|
functions = {}
|
24
|
+
params = {}
|
24
25
|
|
25
|
-
text.scan(/__nc_(.*)\(\)/) do |match|
|
26
|
+
text.scan(/__nc_(.*)\((.*)\)/) do |match|
|
26
27
|
functions[match.first] = true
|
28
|
+
params[match.last] = true
|
27
29
|
end
|
28
30
|
|
29
31
|
script = ''
|
@@ -38,13 +40,13 @@ module ScriptCompiler
|
|
38
40
|
|
39
41
|
function_code = client.buffer
|
40
42
|
|
41
|
-
# if the client action
|
43
|
+
# if the client action returns a String append it to
|
42
44
|
# the function code.
|
43
45
|
|
44
46
|
function_code << ret if ret.is_a?(String)
|
45
47
|
|
46
48
|
script << %{
|
47
|
-
function __nc_#{fun}() {
|
49
|
+
function __nc_#{fun}(params) {
|
48
50
|
#{function_code}
|
49
51
|
}
|
50
52
|
}
|
@@ -53,51 +55,57 @@ module ScriptCompiler
|
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
58
|
+
end
|
59
|
+
|
60
|
+
# Inject css in the head tag.
|
61
|
+
|
62
|
+
if css_buffer = compiler.shared[:css_buffer]
|
63
|
+
text.sub!(/<\/head>/) do |match|
|
64
|
+
%{
|
65
|
+
<style>
|
66
|
+
#{css_buffer}
|
67
|
+
</style>
|
68
|
+
</head>
|
69
|
+
}
|
67
70
|
end
|
71
|
+
end
|
68
72
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
73
|
+
# Inject required javascript files in the head tag.
|
74
|
+
|
75
|
+
required_files = Javascript.required_files
|
76
|
+
if crf = compiler.shared[:js_required_files]
|
77
|
+
required_files.concat(crf.keys)
|
78
|
+
end
|
79
|
+
|
80
|
+
unless required_files.empty?
|
81
|
+
text.sub!(/<\/head>/) do |match|
|
82
|
+
%{
|
83
|
+
#{include_script *required_files}
|
84
|
+
</head>
|
85
|
+
}
|
78
86
|
end
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
87
|
+
end
|
88
|
+
|
89
|
+
# Inject javascript just before the end of the
|
90
|
+
# template.
|
91
|
+
#--
|
92
|
+
# gmosx: injection happens at the end, so that the DOM
|
93
|
+
# tree is created. Dunno if this is valid xhtml though.
|
94
|
+
#++
|
86
95
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
end
|
96
|
+
js_buffer = compiler.shared[:js_buffer]
|
97
|
+
|
98
|
+
if script or js_buffer
|
99
|
+
text.sub!(/<\/body>/) do |match|
|
100
|
+
%{
|
101
|
+
<script type="text/javascript">
|
102
|
+
#{script}
|
103
|
+
#{js_buffer}
|
104
|
+
</script>
|
105
|
+
</body>
|
106
|
+
}
|
99
107
|
end
|
100
|
-
end
|
108
|
+
end
|
101
109
|
|
102
110
|
return text
|
103
111
|
end
|
@@ -1,12 +1,13 @@
|
|
1
1
|
module Nitro
|
2
|
-
|
3
|
-
#
|
2
|
+
|
3
|
+
# A compiler transformation pipeline stage that compresses
|
4
|
+
# the generated xhtml code.
|
4
5
|
|
5
6
|
class Squeeze
|
6
7
|
|
7
8
|
# Compresses the inline xhtml. Does not touch the ruby code.
|
8
9
|
|
9
|
-
def self.transform(text)
|
10
|
+
def self.transform(text, compiler = nil)
|
10
11
|
return text.gsub(/\@out \<\< \%\^(.*?)\^/m) do |match|
|
11
12
|
c = $1.gsub(/^(\s*)/m, '').squeeze(" \t").tr("\n", '').tr("\t", ' ')
|
12
13
|
"@out << %{#{c}}"
|
data/lib/nitro/compiler/xslt.rb
CHANGED
@@ -4,10 +4,12 @@ require 'xml/xslt'
|
|
4
4
|
|
5
5
|
module Nitro
|
6
6
|
|
7
|
-
#
|
7
|
+
# Pre-applies an XSL transformation to the template file to
|
8
|
+
# generate the final template file. Due to preproccessing, the
|
9
|
+
# transformation comes for free.
|
8
10
|
|
9
11
|
class XSLTransform
|
10
|
-
|
12
|
+
@@sync = Sync.new
|
11
13
|
|
12
14
|
class << self
|
13
15
|
|
@@ -34,8 +36,7 @@ class XSLTransform
|
|
34
36
|
|
35
37
|
# Transform the given xml.
|
36
38
|
|
37
|
-
def transform(text)
|
38
|
-
|
39
|
+
def transform(text, compiler = nil)
|
39
40
|
parse_xsl()
|
40
41
|
@xslt.xml = text
|
41
42
|
hash += @name
|
@@ -43,8 +44,8 @@ class XSLTransform
|
|
43
44
|
process_next(hash, xslt.serve)
|
44
45
|
end
|
45
46
|
|
46
|
-
|
47
|
-
|
47
|
+
private
|
48
|
+
|
48
49
|
# Parse the xsl.
|
49
50
|
|
50
51
|
def parse_xsl
|
data/lib/nitro/context.rb
CHANGED
@@ -2,10 +2,13 @@ require 'forwardable'
|
|
2
2
|
|
3
3
|
require 'facet/kernel/assign_with'
|
4
4
|
|
5
|
+
require 'glue/cache/memory'
|
6
|
+
|
5
7
|
require 'nitro/cgi'
|
6
8
|
require 'nitro/cgi/request'
|
7
9
|
require 'nitro/cgi/response'
|
8
10
|
require 'nitro/render'
|
11
|
+
require 'nitro/global'
|
9
12
|
require 'nitro/session'
|
10
13
|
|
11
14
|
module Nitro
|
@@ -16,17 +19,14 @@ module Nitro
|
|
16
19
|
#
|
17
20
|
# The Context object can be accessed by the context, request or
|
18
21
|
# response aliases. You can use the alias that makes sense
|
19
|
-
# every time.
|
22
|
+
# every time. This means inside an action request, response and
|
23
|
+
# context all point to the same object.
|
20
24
|
|
21
25
|
class Context
|
22
26
|
include Request
|
23
27
|
include Response
|
24
28
|
include Render
|
25
29
|
|
26
|
-
# The cache/store used to back global variables.
|
27
|
-
|
28
|
-
setting :global_cache_class, :default => ($NITRO_GLOBAL_CACHE_CLASS || MemoryCache), :doc => 'The store used to back global variables'
|
29
|
-
|
30
30
|
# The configuration parameters.
|
31
31
|
|
32
32
|
attr_accessor :conf
|
@@ -42,7 +42,15 @@ class Context
|
|
42
42
|
|
43
43
|
attr_accessor :dispatcher
|
44
44
|
|
45
|
+
# The rendering level. An action may include sub-actions,
|
46
|
+
# each time the action is called, the level is increased,
|
47
|
+
# when the action returns the level decreases. The first
|
48
|
+
# action, called top level action has a level of 1.
|
49
|
+
|
50
|
+
attr_accessor :level
|
51
|
+
|
45
52
|
def initialize(conf)
|
53
|
+
@level = 0
|
46
54
|
@conf = conf
|
47
55
|
@dispatcher = @conf.dispatcher
|
48
56
|
@context = self
|
@@ -57,6 +65,17 @@ class Context
|
|
57
65
|
@out ||= OutputBuffer.new
|
58
66
|
end
|
59
67
|
|
68
|
+
|
69
|
+
# Don't sync session. This method may be needed in low level
|
70
|
+
# hacks with the session code. For example if you updade an
|
71
|
+
# entity (managed) object that is cached in the session, you
|
72
|
+
# may dissable the syncing to avoid resetting the old value
|
73
|
+
# after the sync.
|
74
|
+
|
75
|
+
def no_sync!
|
76
|
+
@no_sync = true
|
77
|
+
end
|
78
|
+
|
60
79
|
# Close the context, should be called at the
|
61
80
|
# end of the HTTP request handling code.
|
62
81
|
|
@@ -67,12 +86,14 @@ class Context
|
|
67
86
|
@session[:FLASH].clean
|
68
87
|
end
|
69
88
|
|
70
|
-
# INVESTIGATE: is this needed?
|
71
|
-
@session.sync
|
89
|
+
# INVESTIGATE: is this needed?
|
90
|
+
@session.sync unless @no_sync
|
72
91
|
end
|
73
92
|
end
|
74
93
|
alias_method :finish, :close
|
75
94
|
|
95
|
+
# The accomulated output for the current context (ie the
|
96
|
+
# current request).
|
76
97
|
#--
|
77
98
|
# FIXME: still something more elegant/efficient.
|
78
99
|
#++
|
@@ -97,7 +118,7 @@ class Context
|
|
97
118
|
# these variables can reside outside of the process.
|
98
119
|
|
99
120
|
def global
|
100
|
-
return
|
121
|
+
return Global
|
101
122
|
end
|
102
123
|
alias_method :application, :global
|
103
124
|
|
@@ -132,18 +153,16 @@ class Context
|
|
132
153
|
alias_method :populate, :fill
|
133
154
|
alias_method :assign, :fill
|
134
155
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
def_delegators :@context, :controller, :request, :response, :session, :out
|
156
|
+
# Is the current action the top level action? The level
|
157
|
+
# of the top action is 1.
|
158
|
+
|
159
|
+
def is_top_level?
|
160
|
+
@level == 1
|
161
|
+
end
|
162
|
+
alias_method :is_top?, :is_top_level?
|
163
|
+
alias_method :in_top_level?, :is_top_level?
|
164
|
+
alias_method :top_level?, :is_top_level?
|
165
|
+
|
147
166
|
end
|
148
167
|
|
149
168
|
end
|
data/lib/nitro/controller.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'facet/annotation'
|
2
2
|
require 'facet/inheritor'
|
3
|
+
require 'facets/more/aspects'
|
3
4
|
|
4
|
-
require 'glue/aspects'
|
5
5
|
require 'glue/markup'
|
6
6
|
|
7
7
|
require 'nitro'
|
@@ -37,12 +37,13 @@ module Nitro
|
|
37
37
|
|
38
38
|
|
39
39
|
module Publishable
|
40
|
+
|
40
41
|
def self.included(base)
|
41
42
|
super
|
42
43
|
|
43
44
|
base.module_eval do
|
44
45
|
include Render
|
45
|
-
include
|
46
|
+
include ::Aspects
|
46
47
|
include Flashing
|
47
48
|
include Helpers
|
48
49
|
end
|
@@ -154,6 +155,13 @@ module Publishable
|
|
154
155
|
@template_root.reverse!
|
155
156
|
end
|
156
157
|
alias_method :mount, :mount_at
|
158
|
+
|
159
|
+
# Returns the path where this controller is mounted.
|
160
|
+
|
161
|
+
def mount_path
|
162
|
+
@mount_path
|
163
|
+
end
|
164
|
+
alias_method :mount_point, :mount_path
|
157
165
|
end
|
158
166
|
end
|
159
167
|
|
@@ -170,10 +178,21 @@ private
|
|
170
178
|
@context.cookies
|
171
179
|
end
|
172
180
|
|
181
|
+
# Send the cookie to the response stream.
|
182
|
+
|
173
183
|
def send_cookie(name, value = nil)
|
174
184
|
@context.add_cookie(name, value)
|
175
185
|
end
|
176
186
|
|
187
|
+
# Delete the cookie by setting the expire time to now and
|
188
|
+
# clearing the value.
|
189
|
+
|
190
|
+
def delete_cookie(name)
|
191
|
+
cookie = Cookie.new(name, '')
|
192
|
+
cookie.expires = Time.now
|
193
|
+
@context.add_cookie(cookie)
|
194
|
+
end
|
195
|
+
|
177
196
|
# Encode controller, action, params into a valid url.
|
178
197
|
# Automatically respects nice urls and routing.
|
179
198
|
#
|
@@ -210,10 +229,10 @@ private
|
|
210
229
|
controller = args.shift
|
211
230
|
action = args.shift.to_sym
|
212
231
|
|
213
|
-
url = "
|
232
|
+
url = "#{controller.mount_path}/#{action}"
|
214
233
|
|
215
234
|
unless args.empty?
|
216
|
-
if controller.
|
235
|
+
if controller.respond_to_action_or_template? action
|
217
236
|
param_count = controller.instance_method(action).arity
|
218
237
|
if param_count != 0
|
219
238
|
param_count.times do
|
@@ -262,7 +281,7 @@ class Controller
|
|
262
281
|
def self.mounted(path)
|
263
282
|
# Resolve aspects.
|
264
283
|
|
265
|
-
|
284
|
+
::Aspects.include_advice_modules(self)
|
266
285
|
|
267
286
|
# The scaffolding code is compiled after the mount, so
|
268
287
|
# that template roots are finalized.
|
data/lib/nitro/dispatcher.rb
CHANGED
@@ -74,6 +74,7 @@ class Dispatcher
|
|
74
74
|
|
75
75
|
# Customize the class for mounting at the given path.
|
76
76
|
#--
|
77
|
+
# gmosx, TODO: path should include trailing '/'
|
77
78
|
# gmosx, TODO: should actually create an instance, thus
|
78
79
|
# allowing mounting the same controller to multiple
|
79
80
|
# paths, plus simplifying the code. This instance will
|
@@ -81,7 +82,6 @@ class Dispatcher
|
|
81
82
|
#++
|
82
83
|
|
83
84
|
klass.mount_at(path)
|
84
|
-
|
85
85
|
klass.mounted(path) if klass.respond_to?(:mounted)
|
86
86
|
end
|
87
87
|
|
@@ -112,16 +112,23 @@ class Dispatcher
|
|
112
112
|
|
113
113
|
# Update the routes. Typically called after a new
|
114
114
|
# Controller is mounted.
|
115
|
+
#
|
116
|
+
# === Example of routing through annotations
|
117
|
+
#
|
118
|
+
# def view_user
|
119
|
+
# "params: #{request[:id]} and #{request[:mode]}"
|
120
|
+
# end
|
121
|
+
# ann :view_user, :route => [ /user_(\d*)_(*?)\.html/, :id, :mode ]
|
115
122
|
|
116
123
|
def update_routes
|
117
|
-
|
124
|
+
init_routes()
|
118
125
|
|
119
126
|
@controllers.each do |base, c|
|
120
127
|
base = '' if base == '/'
|
121
128
|
for m in c.action_methods
|
122
129
|
m = m.to_sym
|
123
130
|
if route = c.ann(m).route and (!route.nil?)
|
124
|
-
add_route(route.first, c, m, route.last)
|
131
|
+
add_route(route.first, :controller => c, :action => m, :params => route.last)
|
125
132
|
end
|
126
133
|
end
|
127
134
|
end
|
@@ -156,8 +163,9 @@ class Dispatcher
|
|
156
163
|
|
157
164
|
klass, action, params = decode_route(path)
|
158
165
|
if klass
|
159
|
-
context.params.update(params)
|
160
|
-
|
166
|
+
context.params.update(params) if params
|
167
|
+
# gmosx, FIXME/OPTIMIZE: no annotation for mount point!!
|
168
|
+
return klass, "#{action}_action", klass.mount_path
|
161
169
|
end
|
162
170
|
|
163
171
|
parts = path.split('/')
|
data/lib/nitro/global.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'glue/cache/memory'
|
2
|
+
|
3
|
+
# Global scoped variables. This is backed by a Cache store.
|
4
|
+
|
5
|
+
class Global
|
6
|
+
|
7
|
+
# The address of the store.
|
8
|
+
|
9
|
+
setting :cache_address, :default => '127.0.0.1', :doc => 'The address of the store'
|
10
|
+
|
11
|
+
# The port of the store.
|
12
|
+
|
13
|
+
setting :cache_port, :default => 9079, :doc => 'The port of the store'
|
14
|
+
|
15
|
+
# The cache store that backs global variables.
|
16
|
+
|
17
|
+
setting :cache, :default => ::Glue::MemoryCache.new, :doc => 'The cache store that backs global variables'
|
18
|
+
|
19
|
+
class << self
|
20
|
+
|
21
|
+
# Initialize a global value once.
|
22
|
+
|
23
|
+
def init(key, value)
|
24
|
+
unless Global[key]
|
25
|
+
Global[key] = value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def set(key, value)
|
30
|
+
Global.cache[key] = value
|
31
|
+
end
|
32
|
+
alias_method :[]=, :set
|
33
|
+
|
34
|
+
def get(key)
|
35
|
+
return Global.cache[key]
|
36
|
+
end
|
37
|
+
alias_method :[], :get
|
38
|
+
|
39
|
+
# If block is given it acts as an update methods,
|
40
|
+
# that transparently handles distributed stores.
|
41
|
+
#
|
42
|
+
# Global.update(:USERS) do |users|
|
43
|
+
# users << 'gmosx'
|
44
|
+
# end
|
45
|
+
|
46
|
+
def update(key)
|
47
|
+
if block_given?
|
48
|
+
# update, also handles distributed stores.
|
49
|
+
val = Global.cache[key]
|
50
|
+
yield val
|
51
|
+
Global.cache[key] = val
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def delete(key)
|
56
|
+
Global.cache.delete(key)
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
# * George Moschovitis <gm@navel.gr>
|