nitro 0.23.0 → 0.24.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 +350 -0
- data/INSTALL +2 -2
- data/ProjectInfo +61 -0
- data/README +5 -4
- data/Rakefile +5 -4
- data/bin/nitrogen +3 -1
- data/doc/AUTHORS +27 -3
- data/doc/RELEASES +193 -0
- data/doc/lhttpd.txt +4 -0
- data/lib/nitro.rb +1 -1
- data/lib/nitro/adapter/cgi.rb +6 -321
- data/lib/nitro/adapter/fastcgi.rb +2 -14
- data/lib/nitro/adapter/scgi.rb +237 -71
- data/lib/nitro/adapter/webrick.rb +25 -7
- data/lib/nitro/caching.rb +1 -0
- data/lib/nitro/cgi.rb +296 -0
- data/lib/nitro/{cookie.rb → cgi/cookie.rb} +0 -0
- data/lib/nitro/cgi/http.rb +62 -0
- data/lib/nitro/{request.rb → cgi/request.rb} +4 -1
- data/lib/nitro/{response.rb → cgi/response.rb} +0 -0
- data/lib/nitro/cgi/stream.rb +43 -0
- data/lib/nitro/cgi/utils.rb +38 -0
- data/lib/nitro/compiler.rb +23 -11
- data/lib/nitro/compiler/css.rb +8 -0
- data/lib/nitro/compiler/morphing.rb +66 -0
- data/lib/nitro/context.rb +21 -30
- data/lib/nitro/controller.rb +23 -100
- data/lib/nitro/dispatcher.rb +18 -8
- data/lib/nitro/element.rb +6 -2
- data/lib/nitro/flash.rb +2 -2
- data/lib/nitro/mixin/buffer.rb +2 -2
- data/lib/nitro/mixin/form.rb +204 -93
- data/lib/nitro/mixin/javascript.rb +170 -11
- data/lib/nitro/mixin/markup.rb +1 -0
- data/lib/nitro/mixin/pager.rb +7 -4
- data/lib/nitro/mixin/rss.rb +2 -0
- data/lib/nitro/mixin/table.rb +23 -6
- data/lib/nitro/mixin/xhtml.rb +2 -2
- data/lib/nitro/render.rb +19 -5
- data/lib/nitro/scaffold.rb +12 -6
- data/lib/nitro/server.rb +4 -6
- data/lib/nitro/server/runner.rb +2 -2
- data/lib/nitro/session.rb +8 -1
- data/lib/nitro/session/file.rb +40 -0
- data/lib/part/admin.rb +2 -0
- data/lib/part/admin/controller.rb +7 -3
- data/lib/part/admin/skin.rb +8 -1
- data/lib/part/admin/template/index.xhtml +39 -1
- data/proto/public/error.xhtml +5 -3
- data/proto/public/js/behaviour.js +254 -254
- data/proto/public/js/controls.js +427 -165
- data/proto/public/js/dragdrop.js +255 -276
- data/proto/public/js/effects.js +476 -277
- data/proto/public/js/prototype.js +561 -127
- data/proto/public/js/scaffold.js +74 -0
- data/proto/public/js/scriptaculous.js +44 -0
- data/proto/public/js/util.js +548 -0
- data/proto/public/scaffold/list.xhtml +4 -1
- data/proto/scgi.rb +333 -0
- data/script/scgi_ctl +221 -0
- data/script/scgi_service +120 -0
- data/test/nitro/adapter/raw_post1.bin +0 -0
- data/test/nitro/{tc_cookie.rb → cgi/tc_cookie.rb} +1 -1
- data/test/nitro/{tc_request.rb → cgi/tc_request.rb} +1 -1
- data/test/nitro/mixin/tc_xhtml.rb +1 -1
- data/test/nitro/{adapter/tc_cgi.rb → tc_cgi.rb} +12 -12
- data/test/nitro/tc_controller.rb +9 -5
- metadata +159 -169
- data/benchmark/bench.rb +0 -5
- data/benchmark/simple-webrick-n-200.txt +0 -44
- data/benchmark/static-webrick-n-200.txt +0 -43
- data/benchmark/tiny-lhttpd-n-200-c-5.txt +0 -43
- data/benchmark/tiny-webrick-n-200-c-5.txt +0 -44
- data/benchmark/tiny-webrick-n-200.txt +0 -44
- data/benchmark/tiny2-webrick-n-200.txt +0 -44
- data/examples/README +0 -7
@@ -28,11 +28,15 @@ private
|
|
28
28
|
def behaviour(id, js)
|
29
29
|
@_behaviours ||= []
|
30
30
|
@_behaviours << [id, js]
|
31
|
+
return nil
|
31
32
|
end
|
32
33
|
|
33
34
|
# :section: prototype.js
|
34
35
|
|
35
36
|
def live_request(id, options = {})
|
37
|
+
__append_script_file__ 'js/behaviour.js'
|
38
|
+
__append_script_file__ 'js/prototype.js'
|
39
|
+
|
36
40
|
if href = options.delete(:href)
|
37
41
|
behaviour "##{id}", %{
|
38
42
|
el.onclick = function() {
|
@@ -48,6 +52,7 @@ private
|
|
48
52
|
}
|
49
53
|
}
|
50
54
|
end
|
55
|
+
return nil
|
51
56
|
end
|
52
57
|
alias_method :live, :live_request
|
53
58
|
alias_method :async, :live_request
|
@@ -57,8 +62,13 @@ private
|
|
57
62
|
# Make the element dragable.
|
58
63
|
|
59
64
|
def draggable(id, options = {})
|
60
|
-
|
61
|
-
|
65
|
+
__append_script_file__ 'js/behaviour.js'
|
66
|
+
__append_script_file__ 'js/prototype.js'
|
67
|
+
__append_script_file__ 'js/effects.js'
|
68
|
+
__append_script_file__ 'js/dragdrop.js'
|
69
|
+
|
70
|
+
__append_script__ "\nnew Draggable('#{id}', #{hash_to_js(options)});"
|
71
|
+
return nil
|
62
72
|
end
|
63
73
|
|
64
74
|
# :section: script.aculo.us controls.js
|
@@ -68,8 +78,13 @@ private
|
|
68
78
|
def auto_complete(id, options = {})
|
69
79
|
update = options[:update] || "#{id}_auto_complete"
|
70
80
|
url = options[:url] || "#{id}_auto_complete"
|
71
|
-
|
72
|
-
|
81
|
+
|
82
|
+
__append_script_file__ 'js/behaviour.js'
|
83
|
+
__append_script_file__ 'js/prototype.js'
|
84
|
+
__append_script_file__ 'js/effects.js'
|
85
|
+
__append_script_file__ 'js/controls.js'
|
86
|
+
|
87
|
+
__append_script__ "\nnew Ajax.Autocompleter('#{id}', '#{update}', '#{url}');"
|
73
88
|
|
74
89
|
# Turn off the browser's autocomplete functionality to avoid
|
75
90
|
# interference.
|
@@ -77,18 +92,127 @@ private
|
|
77
92
|
behaviour "##{id}", %{
|
78
93
|
el.autocomplete = 'off';
|
79
94
|
}
|
95
|
+
return nil
|
96
|
+
end
|
97
|
+
|
98
|
+
# :section: styling.
|
99
|
+
|
100
|
+
# Style border.
|
101
|
+
|
102
|
+
def style_border
|
103
|
+
end
|
104
|
+
|
105
|
+
# Round element corners using the nifty corners technique.
|
106
|
+
|
107
|
+
def round_corners(id, options = {})
|
108
|
+
o = {
|
109
|
+
:bg => '#fff',
|
110
|
+
:fg => '#ccc',
|
111
|
+
}.update(options)
|
112
|
+
|
113
|
+
__append_script_file__ 'js/prototype.js'
|
114
|
+
__append_script_file__ 'js/round.js'
|
115
|
+
|
116
|
+
__append_script__ %{
|
117
|
+
Box.round('#{id}', '#{o[:fg]}', '#{o[:bg]}');
|
118
|
+
}
|
119
|
+
|
120
|
+
__append_css__ %{
|
121
|
+
.rtop,.rbottom{display:block}
|
122
|
+
.rtop *,.rbottom *{display:block;height: 1px;overflow: hidden}
|
123
|
+
.r1{margin: 0 5px}
|
124
|
+
.r2{margin: 0 3px}
|
125
|
+
.r3{margin: 0 2px}
|
126
|
+
.r4{margin: 0 1px;height: 2px}
|
127
|
+
}
|
128
|
+
|
129
|
+
return nil
|
130
|
+
end
|
131
|
+
|
132
|
+
# Generalized border decoration.
|
133
|
+
|
134
|
+
def decorate_borders(options = {})
|
135
|
+
o = {
|
136
|
+
:bg => '#fff',
|
137
|
+
:fg => '#ccc',
|
138
|
+
:klass => 'w'
|
139
|
+
}.update(options)
|
140
|
+
|
141
|
+
klass = o[:klass]
|
142
|
+
|
143
|
+
__append_script_file__ 'js/prototype.js'
|
144
|
+
__append_script_file__ 'js/styler.js'
|
145
|
+
|
146
|
+
__append_script__ %{
|
147
|
+
decorateBorders('#{klass}');
|
148
|
+
}
|
149
|
+
|
150
|
+
__append_css__ %{
|
151
|
+
.#{klass}t {
|
152
|
+
background: #{o[:bg]};
|
153
|
+
background-image: url(m/#{klass}t.gif);
|
154
|
+
background-repeat: repeat-x;
|
155
|
+
background-position: top;
|
156
|
+
}
|
157
|
+
.#{klass}r {
|
158
|
+
background-image: url(m/#{klass}r.gif);
|
159
|
+
background-repeat: repeat-y;
|
160
|
+
background-position: right;
|
161
|
+
}
|
162
|
+
.#{klass}b {
|
163
|
+
background-image: url(m/#{klass}b.gif);
|
164
|
+
background-repeat: repeat-x;
|
165
|
+
background-position: bottom;
|
166
|
+
}
|
167
|
+
.#{klass}l {
|
168
|
+
background-image: url(m/#{klass}l.gif);
|
169
|
+
background-repeat: repeat-y;
|
170
|
+
background-position: left;
|
171
|
+
}
|
172
|
+
.#{klass}tl {
|
173
|
+
background-image: url(m/#{klass}tl.gif);
|
174
|
+
background-repeat: no-repeat;
|
175
|
+
background-position: top left;
|
176
|
+
}
|
177
|
+
.#{klass}tr {
|
178
|
+
background-image: url(m/#{klass}tr.gif);
|
179
|
+
background-repeat: no-repeat;
|
180
|
+
background-position: top right;
|
181
|
+
}
|
182
|
+
.#{klass}bl {
|
183
|
+
background-image: url(m/#{klass}bl.gif);
|
184
|
+
background-repeat: no-repeat;
|
185
|
+
background-position: bottom left;
|
186
|
+
}
|
187
|
+
.#{klass}br {
|
188
|
+
background-image: url(m/#{klass}br.gif);
|
189
|
+
background-repeat: no-repeat;
|
190
|
+
background-position: bottom right;
|
191
|
+
}
|
192
|
+
.#{klass}c {
|
193
|
+
padding: 25px;
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
return nil
|
80
198
|
end
|
81
199
|
|
82
200
|
# :section: general javascript helpers.
|
83
201
|
|
84
202
|
# Include external javascript file.
|
85
203
|
|
86
|
-
def include_script(files
|
87
|
-
|
204
|
+
def include_script(*files)
|
205
|
+
return if @_script_files.nil? and files.empty?
|
88
206
|
|
89
|
-
|
90
|
-
|
91
|
-
|
207
|
+
code = ''
|
208
|
+
|
209
|
+
for file in files
|
210
|
+
code << %|<script src="#{file}" type="text/javascript">//</script>\n|
|
211
|
+
end if files
|
212
|
+
|
213
|
+
for file in @_script_files
|
214
|
+
code << %|<script src="#{file}" type="text/javascript">//</script>\n|
|
215
|
+
end if @_script_files
|
92
216
|
|
93
217
|
return code
|
94
218
|
end
|
@@ -105,12 +229,20 @@ private
|
|
105
229
|
'{' + options.map {|k, v| "#{k}:#{v}"}.join(', ') + '}'
|
106
230
|
end
|
107
231
|
|
232
|
+
# Emits the aggregated css.
|
233
|
+
|
234
|
+
def emit_css
|
235
|
+
return unless @_css
|
236
|
+
%{<style>#{@_css.join("\n")}</style>}
|
237
|
+
end
|
238
|
+
alias_method :helper_css, :emit_css
|
239
|
+
|
108
240
|
# Emits the aggregated helper javascript.
|
109
241
|
#--
|
110
242
|
# FIXME: refactor this!
|
111
243
|
#++
|
112
244
|
|
113
|
-
def
|
245
|
+
def emit_script
|
114
246
|
code = %|<script type="text/javascript">\n|
|
115
247
|
unless @_behaviours.empty?
|
116
248
|
code << %|var _behaviours = {\n|
|
@@ -125,11 +257,38 @@ private
|
|
125
257
|
|
|
126
258
|
end
|
127
259
|
code << %|
|
128
|
-
|
260
|
+
#{@_script.join("\n")}
|
261
|
+
| if @_script
|
262
|
+
code << %|
|
129
263
|
</script>
|
130
264
|
|
|
131
265
|
end
|
266
|
+
alias_method :helper_script, :emit_script
|
267
|
+
|
268
|
+
# ...
|
132
269
|
|
270
|
+
def js_distance_of_time_in_words(time)
|
271
|
+
time = time.utc.strftime("%a, %d %b %Y %H:%M:%S GMT")
|
272
|
+
%|<span class="human_time" title="#{time}">#{time}</span>|
|
273
|
+
end
|
274
|
+
|
275
|
+
# :section: internal helpers.
|
276
|
+
|
277
|
+
def __append_script_file__(file)
|
278
|
+
@_script_files ||= []
|
279
|
+
@_script_files << file unless @_script_files.include?(file)
|
280
|
+
end
|
281
|
+
|
282
|
+
def __append_script__(script)
|
283
|
+
@_script ||= []
|
284
|
+
@_script << script unless @_script.include?(script)
|
285
|
+
end
|
286
|
+
|
287
|
+
def __append_css__(css)
|
288
|
+
@_css ||= []
|
289
|
+
@_css << css unless @_css.include?(css)
|
290
|
+
end
|
291
|
+
|
133
292
|
end
|
134
293
|
|
135
294
|
end
|
data/lib/nitro/mixin/markup.rb
CHANGED
data/lib/nitro/mixin/pager.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'glue/uri'
|
2
2
|
require 'glue/configuration'
|
3
3
|
|
4
|
+
require 'og/collection'
|
5
|
+
|
4
6
|
module Nitro
|
5
7
|
|
6
8
|
# Displays a collection of entitities in multiple pages.
|
@@ -258,24 +260,25 @@ private
|
|
258
260
|
|
259
261
|
def paginate(items, options = {})
|
260
262
|
per_page = options.delete(:per_page) || Pager.per_page
|
261
|
-
|
263
|
+
pager_key = options.delete(:pager_key) || Pager.key
|
264
|
+
|
262
265
|
case items
|
263
266
|
when Array
|
264
267
|
items = items.dup
|
265
|
-
pager = Pager.new(request, per_page, items.size,
|
268
|
+
pager = Pager.new(request, per_page, items.size, pager_key)
|
266
269
|
items = items.slice(pager.offset, pager.per_page)
|
267
270
|
return items, pager
|
268
271
|
|
269
272
|
when Og::Collection
|
270
273
|
collection = items
|
271
|
-
pager = Pager.new(request, per_page, collection.count,
|
274
|
+
pager = Pager.new(request, per_page, collection.count, pager_key)
|
272
275
|
options.update(pager.limit)
|
273
276
|
items = collection.reload(options)
|
274
277
|
return items, pager
|
275
278
|
|
276
279
|
when Class
|
277
280
|
klass = items
|
278
|
-
pager = Pager.new(request, per_page, klass.count(options),
|
281
|
+
pager = Pager.new(request, per_page, klass.count(options), pager_key)
|
279
282
|
options.update(pager.limit)
|
280
283
|
items = klass.all(options)
|
281
284
|
return items, pager
|
data/lib/nitro/mixin/rss.rb
CHANGED
@@ -32,6 +32,7 @@ module RssMixin
|
|
32
32
|
|
33
33
|
def build_rss_09(objects, options = {})
|
34
34
|
c = {
|
35
|
+
:title => 'Syndication',
|
35
36
|
:description => 'Syndication'
|
36
37
|
}.update(options)
|
37
38
|
|
@@ -40,6 +41,7 @@ module RssMixin
|
|
40
41
|
raise "Option ':base' cannot be infered!" unless c[:base]
|
41
42
|
|
42
43
|
channel = RSS::Rss::Channel.new
|
44
|
+
channel.title = c[:title]
|
43
45
|
channel.description = c[:description]
|
44
46
|
channel.link = c[:link] if c[:link]
|
45
47
|
|
data/lib/nitro/mixin/table.rb
CHANGED
@@ -8,11 +8,11 @@ module Nitro
|
|
8
8
|
#
|
9
9
|
# <?r
|
10
10
|
# users = User.all.map { |u| [u.name, u.first_name, u.last_name, u.email] }
|
11
|
-
#
|
11
|
+
# headers = ['Username', 'First name', 'Last name', 'Email']
|
12
12
|
# ?>
|
13
13
|
#
|
14
14
|
# <div class="custom-table-class">
|
15
|
-
# #{table
|
15
|
+
# #{table :values => users, :headers => header}
|
16
16
|
# </div>
|
17
17
|
#--
|
18
18
|
# TODO: sorting, thead/tbody/legend etc, verbose...
|
@@ -32,7 +32,25 @@ module TableMixin
|
|
32
32
|
|
33
33
|
str = '<table'
|
34
34
|
str << %| id="#{c[:id]}"| if c[:id]
|
35
|
-
str << '
|
35
|
+
str << '>'
|
36
|
+
|
37
|
+
str << table_rows(options)
|
38
|
+
|
39
|
+
str << '</table>'
|
40
|
+
end
|
41
|
+
alias_method :build_table, :table
|
42
|
+
|
43
|
+
# [+options+]
|
44
|
+
# A hash of options.
|
45
|
+
#
|
46
|
+
# :id = id of the component.
|
47
|
+
# :headers = an array of the header values
|
48
|
+
# :values = an array of arrays.
|
49
|
+
|
50
|
+
def table_rows(options)
|
51
|
+
c = options
|
52
|
+
|
53
|
+
str = '<tr>'
|
36
54
|
|
37
55
|
for h in c[:headers]
|
38
56
|
str << %|<th>#{h}</th>|
|
@@ -40,6 +58,8 @@ module TableMixin
|
|
40
58
|
|
41
59
|
str << "</tr>"
|
42
60
|
|
61
|
+
items = c[:values] || c[:items] || c[:rows]
|
62
|
+
|
43
63
|
for row in c[:values]
|
44
64
|
str << "<tr>"
|
45
65
|
|
@@ -50,11 +70,8 @@ module TableMixin
|
|
50
70
|
str << "</tr>"
|
51
71
|
end
|
52
72
|
|
53
|
-
str << "</table>"
|
54
|
-
|
55
73
|
return str
|
56
74
|
end
|
57
|
-
alias_method :build_table, :table
|
58
75
|
|
59
76
|
end
|
60
77
|
|
data/lib/nitro/mixin/xhtml.rb
CHANGED
@@ -90,7 +90,7 @@ private
|
|
90
90
|
#{options(:labels_values => (1..31).to_a, :selected => date.day)}
|
91
91
|
</select>
|
92
92
|
<select id="#{name}.month" name="#{name}.month">
|
93
|
-
#{options(:labels => Date::MONTHNAMES, :values => (1..12).to_a, :selected => (date.month
|
93
|
+
#{options(:labels => Date::MONTHNAMES, :values => (1..12).to_a, :selected => (date.month))}
|
94
94
|
</select>
|
95
95
|
<select id="#{name}.year" name="#{name}.year">
|
96
96
|
#{options(:labels_values => ((Time.now.year-10)..(Time.now.year+10)).to_a, :selected => date.year)}
|
@@ -129,7 +129,7 @@ private
|
|
129
129
|
:scrollbars => false,
|
130
130
|
}.merge(options)
|
131
131
|
|
132
|
-
poptions = (o[:resizable] ? 'resizable=yes' : 'resizable=no')
|
132
|
+
poptions = (o[:resizable] ? 'resizable=yes,' : 'resizable=no,')
|
133
133
|
poptions << (o[:scrollbars] ? 'scrollbars=yes' : 'scrollbars=no')
|
134
134
|
|
135
135
|
url = o[:url] || o[:uri]
|
data/lib/nitro/render.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'singleton'
|
2
2
|
require 'sync'
|
3
|
+
require 'stringio'
|
3
4
|
|
4
|
-
require 'nano/string/blank
|
5
|
+
require 'nano/string/blank'
|
5
6
|
|
6
7
|
require 'glue/attribute'
|
7
8
|
require 'glue/settings'
|
@@ -21,7 +22,7 @@ module Nitro
|
|
21
22
|
|
22
23
|
class ActionExit < Exception; end
|
23
24
|
|
24
|
-
# Raise or
|
25
|
+
# Raise or Throw this exception to stop rendering altogether.
|
25
26
|
# Typically called by redirects.
|
26
27
|
|
27
28
|
class RenderExit < Exception; end
|
@@ -121,10 +122,10 @@ module Render
|
|
121
122
|
if self.class == klass
|
122
123
|
self.send(action)
|
123
124
|
else
|
124
|
-
klass.new(
|
125
|
+
klass.new(@context, base).send(action)
|
125
126
|
end
|
126
127
|
|
127
|
-
rescue RenderExit => e
|
128
|
+
rescue RenderExit, ActionExit => e
|
128
129
|
|
129
130
|
# Just stop rendering.
|
130
131
|
# For example called by redirects.
|
@@ -140,6 +141,19 @@ module Render
|
|
140
141
|
|
141
142
|
private
|
142
143
|
|
144
|
+
# Helper method to exit the current action, typically used
|
145
|
+
# to skip the template.
|
146
|
+
|
147
|
+
def exit
|
148
|
+
raise ActionExit.new
|
149
|
+
end
|
150
|
+
|
151
|
+
# Flush the IO object if we are in streaming mode.
|
152
|
+
|
153
|
+
def flush
|
154
|
+
@out.flush if @out.is_a?(IO)
|
155
|
+
end
|
156
|
+
|
143
157
|
# Send a redirect response.
|
144
158
|
#
|
145
159
|
# If the url starts with '/' it is considered absolute, else
|
@@ -197,7 +211,7 @@ private
|
|
197
211
|
|
198
212
|
def render_template(filename)
|
199
213
|
filename = "#{filename}.xhtml" unless filename =~ /\.xhtml$/
|
200
|
-
template = File.read("#{
|
214
|
+
template = File.read("#{template_root}/#{filename}")
|
201
215
|
Template.process_template(template, '@out', binding)
|
202
216
|
end
|
203
217
|
|