nitro 0.30.0 → 0.31.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/ProjectInfo +6 -6
- data/bin/nitro +100 -7
- data/doc/RELEASES +18 -0
- data/lib/glue/sweeper.rb +9 -5
- data/lib/nitro.rb +13 -13
- data/lib/nitro/adapter/console.rb +7 -0
- data/lib/nitro/adapter/mongrel.rb +34 -71
- data/lib/nitro/adapter/script.rb +71 -0
- data/lib/nitro/adapter/webrick.rb +0 -2
- data/lib/nitro/caching.rb +0 -1
- data/lib/nitro/caching/fragments.rb +2 -3
- data/lib/nitro/caching/output.rb +3 -4
- data/lib/nitro/cgi.rb +14 -0
- data/lib/nitro/cgi/request.rb +10 -9
- data/lib/nitro/cgi/sendfile.rb +45 -0
- data/lib/nitro/compiler.rb +1 -1
- data/lib/nitro/compiler/errors.rb +3 -3
- data/lib/nitro/context.rb +16 -1
- data/lib/nitro/controller.rb +60 -5
- data/lib/nitro/dispatcher.rb +2 -1
- data/lib/nitro/helper.rb +0 -2
- data/lib/nitro/helper/form/builder.rb +5 -1
- data/lib/nitro/helper/javascript.rb +1 -1
- data/lib/nitro/helper/pager.rb +19 -10
- data/lib/nitro/helper/table.rb +28 -3
- data/lib/nitro/helper/xhtml.rb +4 -3
- data/lib/nitro/part.rb +57 -2
- data/lib/nitro/render.rb +67 -28
- data/lib/nitro/router.rb +1 -0
- data/lib/nitro/scaffold.rb +141 -0
- data/lib/nitro/scaffolding.rb +17 -17
- data/lib/nitro/server/runner.rb +2 -9
- data/lib/nitro/session.rb +13 -5
- data/lib/nitro/test/testcase.rb +2 -0
- data/proto/run.rb +3 -1
- data/src/part/admin/controller.rb +2 -1
- data/src/part/admin/template/index.xhtml +2 -2
- data/test/nitro/tc_element.rb +13 -11
- data/test/nitro/tc_render.rb +1 -2
- metadata +186 -182
- data/bin/nitrogen +0 -5
- data/lib/nitro/helper/wee.rb +0 -57
data/lib/nitro/helper/pager.rb
CHANGED
@@ -24,6 +24,10 @@ class Pager
|
|
24
24
|
|
25
25
|
setting :key, :default => '_page', :doc => 'The request key'
|
26
26
|
|
27
|
+
# The nav link titles
|
28
|
+
|
29
|
+
setting :link_titles, :default => {:first => 'First', :previous => 'Previous', :last => 'Last', :next => 'Next'}, :doc => "Titles of pager links"
|
30
|
+
|
27
31
|
# The current page.
|
28
32
|
|
29
33
|
attr_accessor :page
|
@@ -40,10 +44,10 @@ class Pager
|
|
40
44
|
|
41
45
|
attr_accessor :total_count
|
42
46
|
|
43
|
-
def initialize(request, per_page, total_count, key = Pager.key)
|
47
|
+
def initialize(request, per_page, total_count, key = Pager.key, link_titles = Pager.link_titles)
|
44
48
|
raise 'per_page should be > 0' unless per_page > 0
|
45
49
|
|
46
|
-
@request, @key = request, key
|
50
|
+
@request, @key, @link_titles = request, key, link_titles
|
47
51
|
@page = request.query.fetch(key, 1).to_i
|
48
52
|
@per_page = per_page
|
49
53
|
set_count(total_count)
|
@@ -55,6 +59,10 @@ class Pager
|
|
55
59
|
@page_count = (@total_count.to_f / @per_page).ceil
|
56
60
|
end
|
57
61
|
|
62
|
+
def has_pages?
|
63
|
+
return @page_count > 1
|
64
|
+
end
|
65
|
+
|
58
66
|
# Return the first page index.
|
59
67
|
|
60
68
|
def first_page
|
@@ -188,17 +196,18 @@ class Pager
|
|
188
196
|
def navigation
|
189
197
|
nav = ""
|
190
198
|
|
199
|
+
return nav unless has_pages?
|
191
200
|
unless first_page?
|
192
201
|
nav << %{
|
193
|
-
<div class="first"><a href="#{first_page_href}"
|
194
|
-
<div class="previous"><a href="#{previous_page_href}"
|
202
|
+
<div class="first"><a href="#{first_page_href}">#{CGI.escapeHTML(@link_titles[:first])}</a></div>
|
203
|
+
<div class="previous"><a href="#{previous_page_href}">#{CGI.escapeHTML(@link_titles[:previous])}</a></div>
|
195
204
|
}
|
196
205
|
end
|
197
206
|
|
198
207
|
unless last_page?
|
199
208
|
nav << %{
|
200
|
-
<div class="last"><a href="#{last_page_href}"
|
201
|
-
<div class="next"><a href="#{next_page_href}"
|
209
|
+
<div class="last"><a href="#{last_page_href}">#{CGI.escapeHTML(@link_titles[:last])}</a></div>
|
210
|
+
<div class="next"><a href="#{next_page_href}">#{CGI.escapeHTML(@link_titles[:next])}</a></div>
|
202
211
|
}
|
203
212
|
end
|
204
213
|
|
@@ -270,24 +279,24 @@ private
|
|
270
279
|
def paginate(items, options = {})
|
271
280
|
per_page = options.delete(:per_page) || Pager.per_page
|
272
281
|
pager_key = options.delete(:pager_key) || Pager.key
|
273
|
-
|
282
|
+
pager_link_titles = Pager.link_titles.merge(options.delete(:pager_link_titles) || Pager.link_titles)
|
274
283
|
case items
|
275
284
|
when Array
|
276
285
|
items = items.dup
|
277
|
-
pager = Pager.new(request, per_page, items.size, pager_key)
|
286
|
+
pager = Pager.new(request, per_page, items.size, pager_key, pager_link_titles)
|
278
287
|
items = items.slice(pager.offset, pager.per_page) || []
|
279
288
|
return items, pager
|
280
289
|
|
281
290
|
when Og::Collection
|
282
291
|
collection = items
|
283
|
-
pager = Pager.new(request, per_page, collection.count, pager_key)
|
292
|
+
pager = Pager.new(request, per_page, collection.count, pager_key, pager_link_titles)
|
284
293
|
options.update(pager.limit)
|
285
294
|
items = collection.reload(options)
|
286
295
|
return items, pager
|
287
296
|
|
288
297
|
when Class
|
289
298
|
klass = items
|
290
|
-
pager = Pager.new(request, per_page, klass.count(options), pager_key)
|
299
|
+
pager = Pager.new(request, per_page, klass.count(options), pager_key, pager_link_titles)
|
291
300
|
options.update(pager.limit)
|
292
301
|
items = klass.all(options)
|
293
302
|
return items, pager
|
data/lib/nitro/helper/table.rb
CHANGED
@@ -111,7 +111,7 @@ module TableHelper
|
|
111
111
|
str << '>'
|
112
112
|
|
113
113
|
for value in row
|
114
|
-
str << %|<td>#{value}</td>|
|
114
|
+
str << %|<td>#{process(value)}</td>|
|
115
115
|
end
|
116
116
|
|
117
117
|
str << '</tr>'
|
@@ -131,7 +131,7 @@ module TableHelper
|
|
131
131
|
str << '>'
|
132
132
|
|
133
133
|
for value in row
|
134
|
-
str << %|<td>#{value}</td>|
|
134
|
+
str << %|<td>#{process(value)}</td>|
|
135
135
|
end
|
136
136
|
|
137
137
|
str << '</tr>'
|
@@ -159,6 +159,7 @@ module TableHelper
|
|
159
159
|
str << '<tr>'
|
160
160
|
|
161
161
|
options[:headers].each_with_index do |header, index|
|
162
|
+
header = process(header)
|
162
163
|
if (options[:order] && options[:order][:values] &&
|
163
164
|
options[:order][:values][index])
|
164
165
|
order_by = options[:order][:values][index]
|
@@ -233,7 +234,31 @@ module TableHelper
|
|
233
234
|
end
|
234
235
|
|
235
236
|
def create_tbody?(options)
|
236
|
-
options[:values][0][0].respond_to?(:to_ary)
|
237
|
+
options[:values][0].respond_to?(:to_ary) && options[:values][0][0].respond_to?(:to_ary)
|
238
|
+
end
|
239
|
+
|
240
|
+
# A simple hack to allow Localization-processing in the table-helper
|
241
|
+
# overwrite this method to make this happen
|
242
|
+
# Now you can just pass [[somestring]] to the tablehelper and it will
|
243
|
+
# be localized like the rest of the page.
|
244
|
+
# ATM it's only kicking in when the @lc is set.
|
245
|
+
#
|
246
|
+
# Example for the method:
|
247
|
+
# module Nitro
|
248
|
+
# module TableHelper
|
249
|
+
# def process(value)
|
250
|
+
# val = value.to_s.gsub(/\[\[(.*?)\]\]/){ @lc[$1] }
|
251
|
+
# return val == "" ? value : val
|
252
|
+
# end
|
253
|
+
# end
|
254
|
+
# end
|
255
|
+
|
256
|
+
def process(value)
|
257
|
+
if @lc
|
258
|
+
val = value.to_s.gsub(/\[\[(.*?)\]\]/){ @lc[$1] }
|
259
|
+
return val == "" ? value : val
|
260
|
+
end
|
261
|
+
return value
|
237
262
|
end
|
238
263
|
|
239
264
|
end
|
data/lib/nitro/helper/xhtml.rb
CHANGED
@@ -13,7 +13,7 @@ module XhtmlHelper
|
|
13
13
|
elsif obj.respond_to? :to_href
|
14
14
|
href = obj.to_href
|
15
15
|
else
|
16
|
-
href = "#{obj.class.name.pluralize.
|
16
|
+
href = "#{obj.class.name.pluralize.underscore}/#{obj.oid}"
|
17
17
|
end
|
18
18
|
|
19
19
|
if base
|
@@ -63,7 +63,8 @@ module XhtmlHelper
|
|
63
63
|
|
64
64
|
values = options[:values] || options[:labels_values] || (0...labels.size).to_a
|
65
65
|
|
66
|
-
selected =
|
66
|
+
selected = options[:selected]
|
67
|
+
selected = selected.to_s if selected
|
67
68
|
|
68
69
|
labels.each_with_index do |label, idx|
|
69
70
|
value = values[idx]
|
@@ -75,7 +76,7 @@ module XhtmlHelper
|
|
75
76
|
end
|
76
77
|
style = %{ style="#{style}"}
|
77
78
|
end
|
78
|
-
if value == selected
|
79
|
+
if value.to_s == selected
|
79
80
|
str << %|<option value="#{value}" selected="selected"#{style}>#{label}</option>|
|
80
81
|
else
|
81
82
|
str << %|<option value="#{value}"#{style}>#{label}</option>|
|
data/lib/nitro/part.rb
CHANGED
@@ -3,12 +3,67 @@ module Nitro
|
|
3
3
|
# A part is a module of reusable functionality encapsulated as
|
4
4
|
# a mini site/app. You can require (include) multiple parts in
|
5
5
|
# your application. A part is in essence a high level component.
|
6
|
-
|
6
|
+
#
|
7
|
+
# The directory structure of a part mirrors the structure
|
8
|
+
# of a typicall web application. By conventions we put the
|
9
|
+
# main directories of parts in a root directory called 'part'.
|
10
|
+
#
|
11
|
+
# Let's demonstrate the above with an example. Two parts are
|
12
|
+
# defined here. A user management part (users) and a CMS
|
13
|
+
# (content). A typical dir structure goes like this ($ is a
|
14
|
+
# directory in the load path, this means you can put parts in
|
15
|
+
# multiple places as long as the are in the load path):
|
16
|
+
#
|
17
|
+
# $/part # parts will be stored here.
|
18
|
+
#
|
19
|
+
# $/part/users.rb # helper file used to 'require' the part.
|
20
|
+
# $/part/users/public/
|
21
|
+
# $/part/users/controller.rb
|
22
|
+
# $/part/users/controller/xml.rb
|
23
|
+
# $/part/users/model/user.rb
|
24
|
+
# $/part/users/model/acl.rb
|
25
|
+
# $/part/users/template/login.xhtml
|
26
|
+
# $/part/users/template/form.xinc
|
27
|
+
# $/part/users/run.rb # starts an 'example' application for this part.
|
28
|
+
#
|
29
|
+
# $/part/content.rb
|
30
|
+
# $/part/content/controller.rb
|
31
|
+
# $/part/content/model.rb
|
32
|
+
# ...
|
33
|
+
#
|
34
|
+
# Given this direcotry structure you can 'require' a part
|
35
|
+
# like this:
|
36
|
+
#
|
37
|
+
# require 'part/users'
|
38
|
+
# require 'part/content'
|
39
|
+
#
|
40
|
+
# The helper files (for example the file part/users.rb) typically
|
41
|
+
# require the part files needed by default.
|
42
|
+
#
|
43
|
+
# The 'example' application start files (for example part/users/run.rb)
|
44
|
+
# are optional. If present, they start a small application that
|
45
|
+
# demonstrates the usage of the part. In the example app, the main
|
46
|
+
# part controller is mounted at the root ('/'). Typically, in
|
47
|
+
# your own applications, you will mount the controller as needed,
|
48
|
+
# (for example: 'users' => UsersController,
|
49
|
+
# 'blog' => 'ContentController')
|
50
|
+
#
|
51
|
+
# The files that reside in the public directory are typically
|
52
|
+
# copied by a code generator to your application public dir.
|
53
|
+
#
|
54
|
+
# Part controllers setup the template root stack to lookup
|
55
|
+
# templates in their local template dir (for example part/users/template)
|
56
|
+
# if a template is not found in the applications normal template
|
57
|
+
# root. In essence, by requiring a part a target application,
|
58
|
+
# 'inherits' its templates. If you want to customize (override)
|
59
|
+
# one template, just place a template with the same name in the
|
60
|
+
# respective directory in the application template root.
|
61
|
+
|
7
62
|
class Part
|
8
63
|
|
9
64
|
# Require (include) a part in the current application.
|
10
65
|
|
11
|
-
def self.require
|
66
|
+
def self.require name
|
12
67
|
Logger.debug "Requiring part '#{name}'." if $DBG
|
13
68
|
Kernel.require 'part/' + name + '/run.rb'
|
14
69
|
end
|
data/lib/nitro/render.rb
CHANGED
@@ -4,7 +4,6 @@ require 'stringio'
|
|
4
4
|
|
5
5
|
require 'facet/string/blank'
|
6
6
|
|
7
|
-
require 'glue/attribute'
|
8
7
|
require 'glue/settings'
|
9
8
|
require 'glue/template'
|
10
9
|
require 'glue/builder/xml'
|
@@ -16,24 +15,32 @@ require 'nitro/helper/buffer'
|
|
16
15
|
|
17
16
|
module Nitro
|
18
17
|
|
18
|
+
#--
|
19
19
|
# Raise or Throw this exception to stop the current action.
|
20
|
-
# Typically called to skip the template.
|
20
|
+
# Typically called to skip the template. This is considerered
|
21
|
+
# a low level tactic. Prefer to use the exit method.
|
22
|
+
#++
|
21
23
|
|
22
|
-
class ActionExit < Exception
|
24
|
+
class ActionExit < Exception # :nodoc: all
|
25
|
+
end
|
23
26
|
|
27
|
+
#--
|
24
28
|
# Raise or Throw this exception to stop rendering altogether.
|
25
29
|
# Typically called by redirects.
|
30
|
+
#++
|
26
31
|
|
27
|
-
class RenderExit < Exception
|
32
|
+
class RenderExit < Exception # :nodoc: all
|
33
|
+
end
|
28
34
|
|
35
|
+
#--
|
29
36
|
# The output buffer. The output of a contoller action is
|
30
37
|
# accumulated in this buffer before sending this to the client
|
31
38
|
# as a HTTP Response.
|
32
|
-
|
39
|
+
#
|
33
40
|
# TODO: Implement a FAST string (maybe in C)
|
34
41
|
#++
|
35
42
|
|
36
|
-
class OutputBuffer < String
|
43
|
+
class OutputBuffer < String # :nodoc: all
|
37
44
|
end
|
38
45
|
|
39
46
|
# The rendering mixin. This module is typically included in
|
@@ -81,12 +88,9 @@ module Render
|
|
81
88
|
|
82
89
|
attr_accessor :base
|
83
90
|
|
84
|
-
# The
|
85
|
-
#--
|
86
|
-
# gmosx: Needed for WEE. Will be deprecated.
|
87
|
-
#++
|
91
|
+
# The current controller class.
|
88
92
|
|
89
|
-
attr_accessor :
|
93
|
+
attr_accessor :controller
|
90
94
|
|
91
95
|
# Initialize the render.
|
92
96
|
#
|
@@ -94,9 +98,8 @@ module Render
|
|
94
98
|
# A parent render/controller acts as the context.
|
95
99
|
|
96
100
|
def initialize(context, base = nil)
|
97
|
-
@rendering_context = 0
|
98
101
|
@request = @response = @context = context
|
99
|
-
@
|
102
|
+
@base = base
|
100
103
|
@out = context.out
|
101
104
|
end
|
102
105
|
|
@@ -114,21 +117,23 @@ module Render
|
|
114
117
|
|
115
118
|
Logger.debug "Rendering '#{path}'." if $DBG
|
116
119
|
|
117
|
-
|
120
|
+
@controller, action, base = @context.dispatcher.dispatch(path, @context)
|
118
121
|
|
119
|
-
|
120
|
-
@context.content_type = klass.instance_variable_get('@content_type') || 'text/html'
|
122
|
+
raise 'No controller for action' unless @controller
|
121
123
|
|
122
|
-
|
124
|
+
# FIXME:
|
125
|
+
@context.content_type = @controller.instance_variable_get('@content_type') || 'text/html'
|
123
126
|
|
124
127
|
@context.level += 1
|
125
|
-
|
126
|
-
|
128
|
+
old_controller = Controller.replace_current(@controller)
|
129
|
+
|
130
|
+
if self.class == @controller
|
127
131
|
self.send(action)
|
128
132
|
else
|
129
|
-
|
133
|
+
@controller.new(@context, base).send(action)
|
130
134
|
end
|
131
135
|
|
136
|
+
Controller.replace_current(old_controller)
|
132
137
|
@context.level -= 1
|
133
138
|
|
134
139
|
rescue NoActionError => e1
|
@@ -142,6 +147,7 @@ module Render
|
|
142
147
|
rescue Exception, StandardError => e3
|
143
148
|
# More fault tolerant, only flags the erroneous box with
|
144
149
|
# error not the full page.
|
150
|
+
|
145
151
|
log_error(e3, path)
|
146
152
|
print '(error)'
|
147
153
|
end
|
@@ -149,13 +155,21 @@ module Render
|
|
149
155
|
private
|
150
156
|
|
151
157
|
# Helper method to exit the current action, typically used
|
152
|
-
# to skip the template.
|
158
|
+
# to skip the template rendering.
|
159
|
+
#
|
160
|
+
# === Example
|
161
|
+
#
|
162
|
+
# def my_action
|
163
|
+
# ...
|
164
|
+
# exit unless user.admin?
|
165
|
+
# end
|
153
166
|
|
154
167
|
def exit
|
155
168
|
raise ActionExit.new
|
156
169
|
end
|
157
170
|
|
158
|
-
# Flush the IO object if we are in streaming
|
171
|
+
# Flush the IO object (OutputBuffer) if we are in streaming
|
172
|
+
# mode.
|
159
173
|
|
160
174
|
def flush
|
161
175
|
@out.flush if @out.is_a?(IO)
|
@@ -168,9 +182,34 @@ private
|
|
168
182
|
# If the url starts with '/' it is considered absolute, else
|
169
183
|
# the url is considered relative to the current controller and
|
170
184
|
# the controller base is prepended.
|
185
|
+
#
|
186
|
+
# The parameters are passed to the R operator (encode_url)
|
187
|
+
# to actually build the url. So the following forms (among
|
188
|
+
# others) are allowed:
|
189
|
+
#
|
190
|
+
# redirect 'home/login'
|
191
|
+
# redirect ForaController, :post, :title, 'The title'
|
192
|
+
# redirect :welcome
|
193
|
+
# redirect article # => article.to_href
|
194
|
+
#
|
195
|
+
# You can also pass optional hash parameters at the end,
|
196
|
+
# for example:
|
197
|
+
#
|
198
|
+
# redirect :welcome, :status => 307
|
199
|
+
#
|
200
|
+
# The default redirect status is 303.
|
171
201
|
|
172
|
-
def redirect(
|
173
|
-
|
202
|
+
def redirect(*args)
|
203
|
+
if args.last.is_a? Hash
|
204
|
+
status = args.last.fetch(:status, 303)
|
205
|
+
else
|
206
|
+
status = 303
|
207
|
+
end
|
208
|
+
|
209
|
+
url = encode_url(*args)
|
210
|
+
|
211
|
+
# gmosx, THINK: this may be unnecessary!
|
212
|
+
|
174
213
|
unless url =~ /^http/
|
175
214
|
url = "#@base/#{url}" unless url =~ /^\//
|
176
215
|
url = "#{@context.host_url}/#{url.gsub(/^\//, '')}"
|
@@ -187,7 +226,7 @@ private
|
|
187
226
|
# Redirect to the referer.
|
188
227
|
|
189
228
|
def redirect_referer(postfix = nil, status = 303)
|
190
|
-
redirect
|
229
|
+
redirect "#{@context.referer}#{postfix}", :status => status
|
191
230
|
end
|
192
231
|
alias_method :redirect_to_referer, :redirect_referer
|
193
232
|
alias_method :redirect_referrer, :redirect_referer
|
@@ -196,7 +235,7 @@ private
|
|
196
235
|
# Redirect to home.
|
197
236
|
|
198
237
|
def redirect_home(status = 303)
|
199
|
-
redirect
|
238
|
+
redirect '/', :status => status
|
200
239
|
end
|
201
240
|
alias_method :redirect_to_home, :redirect_home
|
202
241
|
|
@@ -209,10 +248,10 @@ private
|
|
209
248
|
# === Example
|
210
249
|
#
|
211
250
|
# caller:
|
212
|
-
# color, type = call
|
251
|
+
# color, type = call 'utils/select_color'
|
213
252
|
#
|
214
253
|
# target:
|
215
|
-
# answer
|
254
|
+
# answer color, type
|
216
255
|
#--
|
217
256
|
# FIXME: dont use yet, you have to encode the branch to
|
218
257
|
# make this safe for use.
|