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
data/README
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= Nitro 0.
|
1
|
+
= Nitro 0.30.0 README
|
2
2
|
|
3
3
|
Nitro provides everything you need to develop professional Web
|
4
4
|
applications using Ruby and Javascript.
|
@@ -325,14 +325,14 @@ doc/RELEASES
|
|
325
325
|
|
326
326
|
The latest version of Nitro can be found at
|
327
327
|
|
328
|
-
* http://www.
|
328
|
+
* http://www.nitroproject.org
|
329
329
|
|
330
330
|
|
331
331
|
== Documentation
|
332
332
|
|
333
333
|
Documentation for Nitro can be found at
|
334
334
|
|
335
|
-
* http://www.
|
335
|
+
* http://www.nitroproject.org
|
336
336
|
|
337
337
|
Don't forget to read the file doc/RELEASES for usefull
|
338
338
|
documentation bits. Also, have a look at the test cases in
|
@@ -344,7 +344,7 @@ the test directory for examples of usage.
|
|
344
344
|
A number of videos that demonstrate Nitro in practical usage
|
345
345
|
are available here:
|
346
346
|
|
347
|
-
http://www.
|
347
|
+
http://www.nitroproject.org/view/Videos
|
348
348
|
|
349
349
|
|
350
350
|
== Requirements
|
@@ -549,7 +549,7 @@ http://rubyforge.org/mailman/listinfo/nitro-general
|
|
549
549
|
Copyright (c) 2004-2006, George 'gmosx' Moschovitis (http://www.gmosx.com)
|
550
550
|
Copyright (c) 2004-2006, Navel Ltd (http://www.navel.gr)
|
551
551
|
|
552
|
-
Nitro (http://www.
|
552
|
+
Nitro (http://www.nitroproject.org) is copyrighted free software
|
553
553
|
created and maintained by George Moschovitis (mailto:gm@navel.gr)
|
554
554
|
and released under the standard BSD Licence. For details consult
|
555
555
|
the file LICENCE.
|
data/doc/AUTHORS
CHANGED
@@ -50,6 +50,12 @@ IDEAS, ADDITIONAL CODING, SUPPORT:
|
|
50
50
|
* TRANS <transfire@gmail.com>
|
51
51
|
Small bug fixes, patches.
|
52
52
|
|
53
|
+
* Kashia Buch <kashia@vfemail.net>
|
54
|
+
Patches, documentation.
|
55
|
+
|
56
|
+
* Massimo Maria Ghisalberti
|
57
|
+
Patches.
|
58
|
+
|
53
59
|
* Dan Yoder <dan@zeraweb.com>
|
54
60
|
Original 'Elements' implementation, bug reports.
|
55
61
|
|
data/doc/RELEASES
CHANGED
@@ -1,3 +1,160 @@
|
|
1
|
+
== Version 0.30.0
|
2
|
+
|
3
|
+
Another pragmatic release. The Nitro development team worked over
|
4
|
+
the submitted tickets and provided many bug fixes. More over, there
|
5
|
+
are many small improvements along the codebase and as always
|
6
|
+
we could not resist adding some cool new features.
|
7
|
+
|
8
|
+
Special thanks fly to Bryan Sotto for making this release
|
9
|
+
possible!
|
10
|
+
|
11
|
+
Most notable chages:
|
12
|
+
|
13
|
+
* Nitro allows fine grained customization of the compiler
|
14
|
+
tranformation pipeline per controller or even per action.
|
15
|
+
Here come some examples:
|
16
|
+
|
17
|
+
class MyController
|
18
|
+
ann :self, :transformation_pipeline => [MyTransformer, AnotherXForm]
|
19
|
+
|
20
|
+
...
|
21
|
+
|
22
|
+
def my_action
|
23
|
+
...
|
24
|
+
end
|
25
|
+
ann :my_action, :transformation_pipeline => Compiler.transformation_pipeline.dup.shift(CustomXForm)
|
26
|
+
|
27
|
+
...
|
28
|
+
end
|
29
|
+
|
30
|
+
* Nitro automates integration testing by means of the new
|
31
|
+
session VCR feature that allows for easy proxy based
|
32
|
+
functional testing. A typicall session goes like this:
|
33
|
+
|
34
|
+
Start your app with:
|
35
|
+
|
36
|
+
ruby run.rb --record myfile
|
37
|
+
|
38
|
+
Then use your web browser to 'perform' your testing session.
|
39
|
+
You can used multiple browsers, concurrent users and hit all
|
40
|
+
the pages in your app. At the end, just stop the server.
|
41
|
+
|
42
|
+
In order to perform regression testing against this recorded
|
43
|
+
session just restart the server in playback mode:
|
44
|
+
|
45
|
+
ruby run.rb --playback myfile
|
46
|
+
|
47
|
+
Nitro automatically plays back the recorded session and logs
|
48
|
+
any errors or Exceptions.
|
49
|
+
|
50
|
+
* Better Global variable implementation works better with
|
51
|
+
distributed stores (Drb, Memcached). Notice the new
|
52
|
+
Global.init and Global[:key].update { |v| } methods.
|
53
|
+
|
54
|
+
* Improved the Router implementation. One notable addition
|
55
|
+
is support for global router initialization:
|
56
|
+
|
57
|
+
Router.rules = [
|
58
|
+
{ :match => /~(.*)/, :controller => IdController, :action => :view, :params => [:name] }
|
59
|
+
]
|
60
|
+
|
61
|
+
* Cleaned up glue by removing files duplicating functionality
|
62
|
+
allready available in Facets. Moreover, we moved several
|
63
|
+
generally useful files and methods from Glue to Facets.
|
64
|
+
|
65
|
+
* Replaced the old RSSHelper with the new FeedHelper. The new
|
66
|
+
implementation provides support for RSS, Atom, OPML. The
|
67
|
+
FeedHelper is backwards compatible with the old helper but
|
68
|
+
provides even more features.
|
69
|
+
|
70
|
+
class MyController
|
71
|
+
helper :feed
|
72
|
+
end
|
73
|
+
|
74
|
+
* Added Og query by example support. Query the database for an
|
75
|
+
entity that matches the example. The example is a hash
|
76
|
+
populated with the property values to search for.
|
77
|
+
|
78
|
+
The provided property values are joined with AND to build
|
79
|
+
the actual query.
|
80
|
+
|
81
|
+
Article.query_by_example :title => 'IBM%', :hits => 2
|
82
|
+
Article.find_with_properties :title => 'IBM%', :hits => 2
|
83
|
+
|
84
|
+
* Added type casting support for Og aggregations and
|
85
|
+
calculations.
|
86
|
+
|
87
|
+
* Greatly improved the configuration system. One noteable
|
88
|
+
(and extremely useful) new feature is that you can now
|
89
|
+
customize classes before they are even defined:
|
90
|
+
|
91
|
+
|
92
|
+
Configuration.User.crypt_salt = 'HELLO'
|
93
|
+
require 'users'
|
94
|
+
|
95
|
+
in users.rb:
|
96
|
+
|
97
|
+
class User
|
98
|
+
setting :crypt_salt, :default => 'DF', :doc => 'The crypt salt'
|
99
|
+
end
|
100
|
+
|
101
|
+
* Calculate rendering level in actions to allow for conditional
|
102
|
+
rendering in top level actions or sub-actions. Some helpers
|
103
|
+
are also provided:
|
104
|
+
|
105
|
+
def myaction
|
106
|
+
if request.is_top_level?
|
107
|
+
...
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
* Introduced an alternative more sophisticated (yet intuitive)
|
112
|
+
form builder. While this new helper is still under construction,
|
113
|
+
it is already very useful. Here come some examples:
|
114
|
+
|
115
|
+
<!-- entity backed form -->
|
116
|
+
|
117
|
+
<div id="myform">
|
118
|
+
#{form :object => @owner, :action => :save_profile do |f|
|
119
|
+
f.property :name, :editable => false
|
120
|
+
f.property :password
|
121
|
+
f.br
|
122
|
+
f.submit 'Update'
|
123
|
+
end}
|
124
|
+
</div>
|
125
|
+
|
126
|
+
<!-- form with virtual method (:multipart),
|
127
|
+
special controls (:select_file) -->
|
128
|
+
|
129
|
+
<div id="myform">
|
130
|
+
#{form :method => :multipart do |f|
|
131
|
+
f.p {
|
132
|
+
f.label 'Select the new icon filename'
|
133
|
+
f.select_file :file, :label => 'Select icon'
|
134
|
+
}
|
135
|
+
f.p {
|
136
|
+
f.submit 'Change'
|
137
|
+
}
|
138
|
+
end}
|
139
|
+
</div>
|
140
|
+
|
141
|
+
* More flexible Script generator, the developer can use most of
|
142
|
+
its features without a Client subclass.
|
143
|
+
|
144
|
+
* Reimplemented session garbage collection.
|
145
|
+
|
146
|
+
* Added many more RDoc comments to the source code.
|
147
|
+
|
148
|
+
* Many, many bug fixes.
|
149
|
+
|
150
|
+
* Updated to latest Facets, Scriptaculous, Prototype.
|
151
|
+
|
152
|
+
|
153
|
+
Please note that the project home page has been moved to:
|
154
|
+
|
155
|
+
http://www.nitroproject.org
|
156
|
+
|
157
|
+
|
1
158
|
== Version 0.29.0
|
2
159
|
|
3
160
|
A bold step towards maturity. Great care was taken to
|
@@ -1098,7 +1255,7 @@ Another superb release! State of the art AJAX/Javascript support,
|
|
1098
1255
|
Wee components / programmatic renderer integration, a beginners
|
1099
1256
|
tutorial, self documenting configuration and many important bug
|
1100
1257
|
fixes. Don't forget to check out our new community site at
|
1101
|
-
http://www.
|
1258
|
+
http://www.nitroproject.org
|
1102
1259
|
|
1103
1260
|
Some notable changes:
|
1104
1261
|
|
@@ -1297,7 +1454,7 @@ Some notable changes:
|
|
1297
1454
|
|
1298
1455
|
* This is surely the most request feature: Nitro Step by Step
|
1299
1456
|
by James Britt, a beginers guide to Nitro. Available in the
|
1300
|
-
brand-new, Nitro-powered, www.
|
1457
|
+
brand-new, Nitro-powered, www.nitroproject.org Community wiki.
|
1301
1458
|
|
1302
1459
|
* New examples: The totaly recoded and ultra cool ajax example,
|
1303
1460
|
a Wee/Nitro example and the new Hello world example.
|
data/lib/glue/sweeper.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'facets/more/aspects'
|
2
2
|
|
3
3
|
module Glue
|
4
4
|
|
@@ -12,7 +12,7 @@ module Glue
|
|
12
12
|
#++
|
13
13
|
|
14
14
|
module Sweeper
|
15
|
-
include
|
15
|
+
include ::Aspects
|
16
16
|
|
17
17
|
before "sweep_affected(:insert)", :on => :og_insert
|
18
18
|
before "sweep_affected(:update)", :on => :og_update
|
data/lib/glue/webfile.rb
CHANGED
@@ -5,6 +5,20 @@ require 'facet/inheritor'
|
|
5
5
|
module Glue
|
6
6
|
|
7
7
|
# A Web File.
|
8
|
+
#
|
9
|
+
# You can customize the path where the uploaded file will be
|
10
|
+
# by defining a webfile_path class method *before* the property:
|
11
|
+
#
|
12
|
+
# class Icon
|
13
|
+
# def self.webfile_path request, name
|
14
|
+
# File.join(Uploads.public_root, request.user.name, 'icon.png')
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# property :file, WebFile, :magick => { :small => '64x64', :medium => '96x96' }
|
18
|
+
# end
|
19
|
+
#--
|
20
|
+
# TODO: webfile_path customization sucks, should be improved!
|
21
|
+
#++
|
8
22
|
|
9
23
|
class WebFile
|
10
24
|
|
@@ -65,7 +79,6 @@ class WebFile
|
|
65
79
|
def #{name}_from_request(request)
|
66
80
|
param = request['#{name}']
|
67
81
|
}
|
68
|
-
|
69
82
|
if base.respond_to? :webfile_path
|
70
83
|
code << %{
|
71
84
|
path = #{base}.webfile_path(request, '#{name}')
|
data/lib/nitro.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# = Nitro
|
2
2
|
#
|
3
|
-
# Copyright (c) 2004-
|
4
|
-
# Copyright (c) 2004-
|
3
|
+
# Copyright (c) 2004-2006, George Moschovitis (http://www.gmosx.com)
|
4
|
+
# Copyright (c) 2004-2006, Navel Ltd (http://www.navel.gr)
|
5
5
|
#
|
6
|
-
# Nitro (http://www.
|
6
|
+
# Nitro (http://www.nitroproject.org) is copyrighted free software
|
7
7
|
# created and maintained by George Moschovitis (mailto:gm@navel.gr)
|
8
8
|
# and released under the standard BSD Licence. For details
|
9
9
|
# consult the file doc/LICENCE.
|
@@ -16,7 +16,7 @@ module Nitro
|
|
16
16
|
|
17
17
|
# The version.
|
18
18
|
|
19
|
-
Version = '0.
|
19
|
+
Version = '0.30.0'
|
20
20
|
|
21
21
|
# Library path.
|
22
22
|
|
@@ -39,6 +39,7 @@ end
|
|
39
39
|
# gmosx: leave them here.
|
40
40
|
#++
|
41
41
|
|
42
|
+
require 'nitro/global'
|
42
43
|
require 'nitro/context'
|
43
44
|
require 'nitro/controller'
|
44
45
|
require 'nitro/dispatcher'
|
@@ -95,11 +96,7 @@ module Nitro
|
|
95
96
|
|
96
97
|
end
|
97
98
|
|
98
|
-
|
99
|
-
# temporal store, will be moved to the actuall cache in
|
100
|
-
# Server.start
|
101
|
-
|
102
|
-
$global = $application = {}
|
99
|
+
$global = $application = Global
|
103
100
|
|
104
101
|
end
|
105
102
|
|
@@ -138,59 +138,53 @@ class MongrelAdapter < ::Mongrel::HttpHandler
|
|
138
138
|
unless handle_file(req, res)
|
139
139
|
path = req.path_info
|
140
140
|
|
141
|
-
|
142
|
-
|
143
|
-
context = Context.new(@server)
|
141
|
+
begin
|
142
|
+
context = Context.new(@server)
|
144
143
|
|
145
|
-
|
144
|
+
context.in = StringIO.new(req.body || "")
|
146
145
|
|
147
|
-
|
148
|
-
|
149
|
-
|
146
|
+
context.headers = {}
|
147
|
+
req.params.each { |h, v|
|
148
|
+
if h =~ /\AHTTP_(.*)\Z/
|
150
149
|
context.headers[$1.gsub("_", "-")] = v
|
151
150
|
end
|
152
151
|
context.headers[h] = v
|
153
|
-
|
154
|
-
|
152
|
+
}
|
153
|
+
# context.headers.update(req.meta_vars)
|
155
154
|
|
156
|
-
|
155
|
+
context.headers['REQUEST_URI'] = context.headers['SCRIPT_NAME']
|
157
156
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
157
|
+
if context.headers['PATH_INFO'].blank?
|
158
|
+
context.headers['REQUEST_URI'] = '/'
|
159
|
+
else
|
160
|
+
context.headers['REQUEST_URI'] = '/' + context.headers['PATH_INFO']
|
161
|
+
end
|
163
162
|
|
164
|
-
|
165
|
-
#context.headers['REQUEST_URI'].slice!(/http:\/\/(.*?)\//)
|
166
|
-
# context.headers['REQUEST_URI'] << '/'
|
163
|
+
# gmosx: make compatible with fastcgi.
|
167
164
|
|
168
|
-
|
169
|
-
|
165
|
+
context.headers['REQUEST_URI'].slice!(/http:\/\/(.*?)\//)
|
166
|
+
context.headers['REQUEST_URI'] = '/' + context.headers['REQUEST_URI']
|
170
167
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
headers = context.response_headers
|
183
|
-
headers["Content-length"] = context.out.size
|
184
|
-
headers.each { |h,v| res.socket << "#{h}: #{v}\r\n" }
|
185
|
-
res.socket << "\r\n"
|
186
|
-
|
187
|
-
# TODO handle setting cookies
|
188
|
-
res.socket << context.out
|
189
|
-
|
190
|
-
context.close
|
191
|
-
ensure
|
192
|
-
Og.manager.put_store if defined?(Og) and Og.respond_to?(:manager)
|
168
|
+
Cgi.parse_params(context)
|
169
|
+
Cgi.parse_cookies(context)
|
170
|
+
|
171
|
+
context.render(path)
|
172
|
+
|
173
|
+
res.socket << "HTTP/1.1 #{context.status.to_s} "
|
174
|
+
|
175
|
+
if STATUS_CODES.has_key? context.status
|
176
|
+
res.socket << STATUS_CODES[context.status]
|
177
|
+
else
|
178
|
+
res.socket << "Unknown Status Code"
|
193
179
|
end
|
180
|
+
res.socket << "\r\n"
|
181
|
+
|
182
|
+
res.socket << Cgi.response_headers(context)
|
183
|
+
res.socket << context.out
|
184
|
+
|
185
|
+
context.close
|
186
|
+
ensure
|
187
|
+
Og.manager.put_store if defined?(Og) and Og.respond_to?(:manager) and Og.manager
|
194
188
|
end
|
195
189
|
end
|
196
190
|
end
|
@@ -218,4 +212,3 @@ end
|
|
218
212
|
|
219
213
|
# * Joshua Hoke
|
220
214
|
# * George Moschovitis <gm@navel.gr>
|
221
|
-
|
data/lib/nitro/adapter/scgi.rb
CHANGED
@@ -168,7 +168,7 @@ module SCGI # :nodoc: all
|
|
168
168
|
Nitro::Cgi.process(@server, cgi, cgi.stdinput, cgi.stdoutput)
|
169
169
|
#end
|
170
170
|
ensure
|
171
|
-
Og.manager.put_store if defined?(Og) and Og.respond_to?(:manager)
|
171
|
+
Og.manager.put_store if defined?(Og) and Og.respond_to?(:manager) and Og.manager
|
172
172
|
end
|
173
173
|
end
|
174
174
|
|
@@ -32,6 +32,7 @@ class Webrick
|
|
32
32
|
end
|
33
33
|
|
34
34
|
webrick_options = server.options.dup
|
35
|
+
|
35
36
|
require 'webrick/https' if webrick_options[:SSLEnable]
|
36
37
|
|
37
38
|
webrick_options.update(
|
@@ -43,6 +44,10 @@ class Webrick
|
|
43
44
|
[wblog, WEBrick::AccessLog::REFERER_LOG_FORMAT]
|
44
45
|
]
|
45
46
|
)
|
47
|
+
|
48
|
+
enable_record_mode($record_session_filename) if $record_session_filename
|
49
|
+
enable_playback_mode($playback_session_filename) if $playback_session_filename
|
50
|
+
|
46
51
|
@webrick = WEBrick::HTTPServer.new(webrick_options)
|
47
52
|
|
48
53
|
trap('INT') { stop }
|
@@ -65,6 +70,75 @@ class Webrick
|
|
65
70
|
|
66
71
|
def initialize_webrick(server)
|
67
72
|
end
|
73
|
+
|
74
|
+
# Enables session recording. The recorded data can be used
|
75
|
+
# for automatic app testing by means of the playback mode.
|
76
|
+
|
77
|
+
def enable_record_mode(filename = 'session.yaml')
|
78
|
+
Logger.info "Recording application server session to '#{filename}'."
|
79
|
+
|
80
|
+
require 'facets/core/file/self/create'
|
81
|
+
|
82
|
+
$record_session = []
|
83
|
+
$last_record_time = Time.now
|
84
|
+
|
85
|
+
Nitro::WebrickAdapter.class_eval %{
|
86
|
+
def do_GET(req, res)
|
87
|
+
record_context(req, res)
|
88
|
+
handle(req, res)
|
89
|
+
end
|
90
|
+
alias_method :do_POST, :do_GET
|
91
|
+
|
92
|
+
def record_context(req, res)
|
93
|
+
delta = Time.now - $last_record_time
|
94
|
+
$last_record_time = Time.now
|
95
|
+
$record_session << [delta, req, res]
|
96
|
+
end
|
97
|
+
}
|
98
|
+
|
99
|
+
at_exit do
|
100
|
+
File.create(filename, YAML.dump($record_session))
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Playback a recorded session. Typically used for testing.
|
105
|
+
|
106
|
+
def enable_playback_mode(filename = 'session.yaml')
|
107
|
+
Logger.info "Playing back application server session from '#{filename}'."
|
108
|
+
|
109
|
+
$playback_session = YAML.load_file(filename)
|
110
|
+
$playback_exception_count = 0
|
111
|
+
|
112
|
+
WEBrick::HTTPServer.class_eval %{
|
113
|
+
def start(&block)
|
114
|
+
run(nil)
|
115
|
+
end
|
116
|
+
|
117
|
+
def run(sock)
|
118
|
+
while true
|
119
|
+
delta, req, res = $playback_session.shift
|
120
|
+
|
121
|
+
if delta
|
122
|
+
sleep(delta)
|
123
|
+
begin
|
124
|
+
service(req, res)
|
125
|
+
rescue Object => ex
|
126
|
+
$playback_exception_count += 1
|
127
|
+
p '---', ex
|
128
|
+
end
|
129
|
+
else
|
130
|
+
return
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
}
|
135
|
+
|
136
|
+
at_exit do
|
137
|
+
puts "\n\n"
|
138
|
+
puts "Playback raised #$playback_exception_count exceptions.\n"
|
139
|
+
puts "\n"
|
140
|
+
end
|
141
|
+
end
|
68
142
|
|
69
143
|
end
|
70
144
|
|
@@ -127,39 +201,37 @@ class WebrickAdapter < WEBrick::HTTPServlet::AbstractServlet
|
|
127
201
|
unless handle_file(req, res)
|
128
202
|
path = req.request_uri.path
|
129
203
|
|
130
|
-
|
131
|
-
|
132
|
-
path = req.request_uri.path
|
204
|
+
begin
|
205
|
+
path = req.request_uri.path
|
133
206
|
|
134
|
-
|
207
|
+
context = Context.new(@server)
|
135
208
|
|
136
|
-
|
209
|
+
context.in = StringIO.new(req.body || "")
|
137
210
|
|
138
|
-
|
139
|
-
|
140
|
-
|
211
|
+
context.headers = {}
|
212
|
+
req.header.each { |h, v| context.headers[h.upcase] = v.first }
|
213
|
+
context.headers.update(req.meta_vars)
|
141
214
|
|
142
|
-
|
215
|
+
# gmosx: make compatible with fastcgi.
|
143
216
|
|
144
|
-
|
145
|
-
|
217
|
+
context.headers['REQUEST_URI'].slice!(/http:\/\/(.*?)\//)
|
218
|
+
context.headers['REQUEST_URI'] = '/' + context.headers['REQUEST_URI']
|
146
219
|
|
147
|
-
|
148
|
-
|
220
|
+
Cgi.parse_params(context)
|
221
|
+
Cgi.parse_cookies(context)
|
149
222
|
|
150
|
-
|
223
|
+
context.render(path)
|
151
224
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
225
|
+
res.status = context.status
|
226
|
+
res.instance_variable_set(:@header, context.response_headers || {})
|
227
|
+
res.instance_variable_set(:@cookies, context.response_cookies || {})
|
228
|
+
res.body = context.out
|
229
|
+
res.chunked = true if context.out.is_a?(IO) and context["SERVER_PROTOCOL"] == "HTTP/1.1"
|
157
230
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
end
|
231
|
+
context.close
|
232
|
+
ensure
|
233
|
+
$autoreload_dirty = false
|
234
|
+
Og.manager.put_store if defined?(Og) and Og.respond_to?(:manager) and Og.manager
|
163
235
|
end
|
164
236
|
end
|
165
237
|
end
|