nitro 0.21.2 → 0.22.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 +121 -0
- data/README +9 -3
- data/doc/RELEASES +86 -1
- data/lib/nitro.rb +1 -1
- data/lib/nitro/adapter/cgi.rb +4 -1
- data/lib/nitro/adapter/scgi.rb +2 -0
- data/lib/nitro/adapter/webrick.rb +1 -1
- data/lib/nitro/caching/output.rb +6 -5
- data/lib/nitro/compiler.rb +8 -3
- data/lib/nitro/dispatcher.rb +2 -2
- data/lib/nitro/dispatcher/nice.rb +1 -1
- data/lib/nitro/element.rb +19 -2
- data/lib/nitro/mixin/markup.rb +2 -2
- data/lib/nitro/mixin/pager.rb +80 -25
- data/lib/nitro/mixin/rss.rb +5 -2
- data/lib/nitro/render.rb +9 -0
- data/lib/nitro/request.rb +93 -6
- data/lib/nitro/response.rb +4 -0
- data/lib/nitro/server.rb +24 -10
- data/lib/nitro/server/runner.rb +15 -10
- data/lib/nitro/service/xmlrpc.rb +1 -0
- data/lib/nitro/test.rb +5 -0
- data/lib/nitro/test/assertions.rb +171 -0
- data/lib/nitro/{testing → test}/context.rb +0 -0
- data/lib/nitro/test/testcase.rb +66 -0
- data/proto/public/error.xhtml +5 -2
- data/proto/public/settings.xhtml +2 -0
- data/proto/script/runner +20 -0
- data/test/nitro/tc_controller.rb +3 -3
- data/test/nitro/tc_controller_aspect.rb +29 -0
- data/test/nitro/tc_dispatcher.rb +2 -1
- data/test/nitro/tc_element.rb +9 -0
- data/test/nitro/tc_request.rb +38 -0
- metadata +13 -13
- data/lib/nitro/mail.rb +0 -270
- data/lib/nitro/template.rb +0 -202
- data/lib/nitro/testing.rb +0 -2
- data/lib/nitro/testing/assertions.rb +0 -100
- data/lib/nitro/testing/testcase.rb +0 -51
- data/test/nitro/tc_mail.rb +0 -97
- data/test/nitro/tc_template.rb +0 -32
data/lib/nitro/server/runner.rb
CHANGED
@@ -21,7 +21,7 @@ module Nitro
|
|
21
21
|
|
22
22
|
class Runner
|
23
23
|
|
24
|
-
#
|
24
|
+
# The adapter used.
|
25
25
|
|
26
26
|
setting :adapter, :default => :webrick, :doc => 'The web adapter'
|
27
27
|
|
@@ -43,8 +43,8 @@ class Runner
|
|
43
43
|
#
|
44
44
|
# The default mode is :debug
|
45
45
|
|
46
|
-
|
47
|
-
|
46
|
+
setting :mode, :default => :debug, :doc => 'The execution mode'
|
47
|
+
|
48
48
|
# :start, :stop, :restart
|
49
49
|
|
50
50
|
attr_accessor :action
|
@@ -69,7 +69,6 @@ class Runner
|
|
69
69
|
# parameters to setup the application.
|
70
70
|
|
71
71
|
def setup_options
|
72
|
-
@mode ||= :debug
|
73
72
|
@action ||= :start
|
74
73
|
@server ||= :webrick
|
75
74
|
@daemon = false
|
@@ -77,7 +76,11 @@ class Runner
|
|
77
76
|
|
78
77
|
# Setup from environment
|
79
78
|
|
80
|
-
|
79
|
+
if mode = ENV['NITRO_MODE']
|
80
|
+
self.class.mode = mode.to_sym
|
81
|
+
else
|
82
|
+
self.class.mode ||= :debug
|
83
|
+
end
|
81
84
|
|
82
85
|
# Setup from command line arguments.
|
83
86
|
|
@@ -104,15 +107,15 @@ class Runner
|
|
104
107
|
end
|
105
108
|
|
106
109
|
opts.on('-D', '--debug', 'Run application in debug mode.') do
|
107
|
-
|
110
|
+
self.class.mode = :debug
|
108
111
|
end
|
109
112
|
|
110
113
|
opts.on('-T', '--stage', 'Run application in stage mode.') do
|
111
|
-
|
114
|
+
self.class.mode = :stage
|
112
115
|
end
|
113
116
|
|
114
117
|
opts.on('-L', '--live', 'Run application in live mode.') do
|
115
|
-
|
118
|
+
self.class.mode = :live
|
116
119
|
end
|
117
120
|
|
118
121
|
opts.on('-w', '--webrick', 'Use a webrick server [default].') do
|
@@ -182,7 +185,7 @@ class Runner
|
|
182
185
|
# using the passed configuration parameters.
|
183
186
|
|
184
187
|
def setup_mode
|
185
|
-
case
|
188
|
+
case self.class.mode
|
186
189
|
when :debug
|
187
190
|
setup_debug
|
188
191
|
|
@@ -270,7 +273,7 @@ class Runner
|
|
270
273
|
|
271
274
|
@server ||= Runner.adapter
|
272
275
|
|
273
|
-
puts "\n==> Listening at #{server.address}:#{server.port}. (#{
|
276
|
+
puts "\n==> Listening at #{server.address}:#{server.port}. (#{self.class.mode} mode)\n\n"
|
274
277
|
|
275
278
|
case @server
|
276
279
|
when :webrick
|
@@ -348,6 +351,8 @@ class Runner
|
|
348
351
|
|
349
352
|
end
|
350
353
|
|
354
|
+
Run = Runner
|
355
|
+
|
351
356
|
end
|
352
357
|
|
353
358
|
# * George Moschovitis <gm@navel.gr>
|
data/lib/nitro/service/xmlrpc.rb
CHANGED
data/lib/nitro/test.rb
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'test/unit/assertions'
|
3
|
+
require 'rexml/document'
|
4
|
+
|
5
|
+
module Test::Unit::Assertions
|
6
|
+
|
7
|
+
STATUS_MAP = {
|
8
|
+
:success => 200,
|
9
|
+
:ok => 200,
|
10
|
+
:redirect => 307
|
11
|
+
}
|
12
|
+
|
13
|
+
# :section: General assertions.
|
14
|
+
|
15
|
+
# Check the status of the response.
|
16
|
+
|
17
|
+
def assert_response(options = {})
|
18
|
+
unless options.is_a? Hash
|
19
|
+
options = { :status => options }
|
20
|
+
end
|
21
|
+
msg = options[:msg]
|
22
|
+
if status = options.fetch(:status, :success)
|
23
|
+
status = STATUS_MAP[status] if STATUS_MAP.has_key?(status)
|
24
|
+
assert_status(status, msg)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def assert_status(status, msg)
|
29
|
+
msg = format_msg("Status not '#{status}'", msg)
|
30
|
+
assert_block(msg) { @context.status == status }
|
31
|
+
end
|
32
|
+
|
33
|
+
#--
|
34
|
+
# Compile some helpers.
|
35
|
+
#++
|
36
|
+
|
37
|
+
for m in [:get, :post, :put, :delete, :head]
|
38
|
+
eval %{
|
39
|
+
def assert_#{m}(uri, headers = {}, params = {}, session = nil)
|
40
|
+
#{m}(uri, headers, params, session)
|
41
|
+
assert_response :success
|
42
|
+
end
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def assert_output(options = {})
|
47
|
+
msg = options[:msg]
|
48
|
+
if re = options[:match] || options[:contains]
|
49
|
+
assert_output_match(re, msg)
|
50
|
+
end
|
51
|
+
if re = options[:no_match] || options[:contains_no]
|
52
|
+
assert_output_not_match(re, msg)
|
53
|
+
end
|
54
|
+
if content_type = options[:content_type]
|
55
|
+
assert_content_type(content_type, msg)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def assert_output_match(re, msg)
|
60
|
+
msg = format_msg("Rendered output does not match '#{re.source}'", msg)
|
61
|
+
assert_block(msg) { @context.body =~ Regexp.new(re) }
|
62
|
+
end
|
63
|
+
alias_method :assert_output_contains, :assert_output_match
|
64
|
+
|
65
|
+
def assert_output_not_match(re, msg)
|
66
|
+
msg = format_msg("Rendered output matches '#{re.source}'", msg)
|
67
|
+
assert_block(msg) { @context.out =~ Regexp.new(re) }
|
68
|
+
end
|
69
|
+
alias_method :assert_output_contains_not, :assert_output_match
|
70
|
+
|
71
|
+
def assert_content_type(ctype, msg)
|
72
|
+
msg = format_msg("Content type is not '#{ctype}' as expected", msg)
|
73
|
+
assert_block(msg) { @context.content_type == ctype }
|
74
|
+
end
|
75
|
+
|
76
|
+
# :section: Session related assertions.
|
77
|
+
|
78
|
+
def assert_session(options = {})
|
79
|
+
msg = options[:msg]
|
80
|
+
if key = options[:has]
|
81
|
+
assert_session_has(key, msg)
|
82
|
+
end
|
83
|
+
if key = options[:has_no] || options[:no]
|
84
|
+
assert_session_has_no(key, msg)
|
85
|
+
end
|
86
|
+
if key = options[:key] and value = options[:value]
|
87
|
+
assert_session_equal(key, value, msg)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def assert_session_has(key, msg = nil)
|
92
|
+
msg = format_msg("Object '#{key}' not found in session", msg)
|
93
|
+
assert_block(msg) { @context.session[key] }
|
94
|
+
end
|
95
|
+
|
96
|
+
def assert_session_has_no(key, msg = nil)
|
97
|
+
msg = format_msg("Unexpected object '#{key}' found in session", msg)
|
98
|
+
assert_block(msg) { !@context.session[key] }
|
99
|
+
end
|
100
|
+
|
101
|
+
def assert_session_equal(key, value, msg = nil)
|
102
|
+
msg = format_msg("The value of session object '#{key}' is '#{@context.session[key]}' but was expected '#{value}'", msg)
|
103
|
+
assert_block(msg) { @context.session[key] == value }
|
104
|
+
end
|
105
|
+
|
106
|
+
# :section: Cookies related assertions.
|
107
|
+
|
108
|
+
def assert_cookie(options = {})
|
109
|
+
msg = options[:msg]
|
110
|
+
if key = options[:has]
|
111
|
+
assert_cookie_has(key, msg)
|
112
|
+
end
|
113
|
+
if key = options[:has_no] || options[:no]
|
114
|
+
assert_cookie_has_no(key, msg)
|
115
|
+
end
|
116
|
+
if key = options[:key] and value = options[:value]
|
117
|
+
assert_cookie_equal(key, value, msg)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def assert_cookie_has(name, msg = nil)
|
122
|
+
msg = format_msg("Cookie '#{name}' not found", msg)
|
123
|
+
assert_block(msg) { @context.response_cookie(name) }
|
124
|
+
end
|
125
|
+
|
126
|
+
def assert_cookie_has_no(name, msg = nil)
|
127
|
+
msg = format_msg("Unexpected cookie '#{name}' found", msg)
|
128
|
+
assert_block(msg) { !@context.response_cookie(name) }
|
129
|
+
end
|
130
|
+
|
131
|
+
def assert_cookie_equal(name, value, msg = nil)
|
132
|
+
unless cookie = @context.response_cookie(name)
|
133
|
+
msg = format_msg("Cookie '#{name}' not found", msg)
|
134
|
+
assert_block(msg) { false }
|
135
|
+
end
|
136
|
+
msg = format_msg("The value of cookie '#{name}' is '#{cookie.value}' but was expected '#{value}'", msg)
|
137
|
+
assert_block(msg) { cookie.value == value }
|
138
|
+
end
|
139
|
+
|
140
|
+
# :section: Template related assertions.
|
141
|
+
|
142
|
+
# :section: Redirection assertions.
|
143
|
+
|
144
|
+
def assert_redirected(options = {})
|
145
|
+
msg = options[:msg]
|
146
|
+
|
147
|
+
msg = format_msg("No redirection (status = #{@context.status})", msg)
|
148
|
+
assert_block(msg) { @context.redirect? }
|
149
|
+
|
150
|
+
if to = options[:to]
|
151
|
+
msg = format_msg("Not redirected to '#{to}'", msg)
|
152
|
+
assert_block(msg) { @context.response_headers['location'] == "http://#{to}" }
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def assert_not_redirected(options = {})
|
157
|
+
msg = options[:msg]
|
158
|
+
msg = format_msg("Unexpected redirection (location = '#{@context.response_headers['location']}')", msg)
|
159
|
+
assert_block(msg) { !@context.redirect? }
|
160
|
+
end
|
161
|
+
|
162
|
+
# :section: Utility methods
|
163
|
+
|
164
|
+
def format_msg(message, extra) # :nodoc:
|
165
|
+
extra += ', ' if extra
|
166
|
+
return "#{extra}#{message}"
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
# * George Moschovitis <gm@navel.gr>
|
File without changes
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'test/unit/assertions'
|
3
|
+
require 'rexml/document'
|
4
|
+
|
5
|
+
require 'glue'
|
6
|
+
require 'nitro/test/context'
|
7
|
+
|
8
|
+
module Test::Unit
|
9
|
+
|
10
|
+
class TestCase
|
11
|
+
include Nitro
|
12
|
+
|
13
|
+
def controller(klass)
|
14
|
+
@server = Server.run(klass)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Send a request to the controller. Alternatively you can use
|
18
|
+
# the request method helpers (get, post, ...)
|
19
|
+
#
|
20
|
+
# === Options
|
21
|
+
#
|
22
|
+
# :uri, :method, :headers/:env, :params, :session
|
23
|
+
|
24
|
+
def process(options = {})
|
25
|
+
unless options.is_a? Hash
|
26
|
+
options = { :uri => options.to_s }
|
27
|
+
end
|
28
|
+
|
29
|
+
uri = options[:uri]
|
30
|
+
uri = "/#{uri}" unless uri =~ /^\//
|
31
|
+
|
32
|
+
context = @context = Context.new(@server)
|
33
|
+
|
34
|
+
context.params = options[:params] || {}
|
35
|
+
context.headers = options[:headers] || options[:env] || {}
|
36
|
+
context.headers['REQUEST_URI'] = uri
|
37
|
+
context.headers['REQUEST_METHOD'] = options[:method].to_s.upcase
|
38
|
+
context.cookies = options[:cookies]
|
39
|
+
context.session = options[:session] if options[:session]
|
40
|
+
|
41
|
+
context.render(context.path)
|
42
|
+
|
43
|
+
return context.body
|
44
|
+
end
|
45
|
+
|
46
|
+
#--
|
47
|
+
# Compile some helpers.
|
48
|
+
#++
|
49
|
+
|
50
|
+
for m in [:get, :post, :put, :delete, :head]
|
51
|
+
eval %{
|
52
|
+
def #{m}(options = {})
|
53
|
+
unless options.is_a? Hash
|
54
|
+
options = { :uri => options.to_s }
|
55
|
+
end
|
56
|
+
options[:method] = :#{m}
|
57
|
+
process(options)
|
58
|
+
end
|
59
|
+
}
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
# * George Moschovitis <gm@navel.gr>
|
data/proto/public/error.xhtml
CHANGED
@@ -31,6 +31,8 @@
|
|
31
31
|
<body>
|
32
32
|
<h1>Error</h1>
|
33
33
|
|
34
|
+
<?r if Run.mode == :debug ?>
|
35
|
+
|
34
36
|
<?r for error, path in @context.rendering_errors ?>
|
35
37
|
<div class="path"><strong>Path:</strong> #{path}</div>
|
36
38
|
<div class="error"><strong>#{error.to_s}</strong></div>
|
@@ -41,7 +43,7 @@
|
|
41
43
|
<?r
|
42
44
|
extract = error.source_extract.split("\n")
|
43
45
|
extract.each_with_index do |line, idx|
|
44
|
-
line =
|
46
|
+
line = sanitize(line)
|
45
47
|
if 4 == idx
|
46
48
|
?>
|
47
49
|
<div style="background: #eee">#{line}</div>
|
@@ -74,8 +76,9 @@
|
|
74
76
|
<div id="session" style="display: none">
|
75
77
|
<p><strong>Values:</strong> #{session.inspect}</p>
|
76
78
|
</div>
|
77
|
-
|
79
|
+
|
78
80
|
<br /><br />
|
79
81
|
Powered by <a href="http://www.nitrohq.com">Nitro</a> version #{Nitro::Version}
|
82
|
+
<?r end ?>
|
80
83
|
</body>
|
81
84
|
</html>
|
data/proto/public/settings.xhtml
CHANGED
@@ -39,6 +39,7 @@
|
|
39
39
|
</style>
|
40
40
|
</head>
|
41
41
|
<body>
|
42
|
+
<?r if Run.mode == :debug ?>
|
42
43
|
<h1>Settings</h1>
|
43
44
|
|
44
45
|
<table width="100%">
|
@@ -60,5 +61,6 @@
|
|
60
61
|
|
61
62
|
<br /><br />
|
62
63
|
Powered by <a href="http://www.nitrohq.com">Nitro</a> version #{Nitro::Version}
|
64
|
+
<?r end ?>
|
63
65
|
</body>
|
64
66
|
</html>
|
data/proto/script/runner
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
ARGV.options do |opts|
|
6
|
+
opts.banner = "Usage: #{File.basename($0)} 'puts Person[1].name' [options]"
|
7
|
+
opts.separator ''
|
8
|
+
opts.on('-h', '--help', 'Show this help message.') { puts opts; exit }
|
9
|
+
opts.parse!
|
10
|
+
end
|
11
|
+
|
12
|
+
code = ARGV.shift
|
13
|
+
|
14
|
+
$NITRO_NO_INVOKE = true
|
15
|
+
$:.unshift File.join(File.dirname(__FILE__), '..')
|
16
|
+
$:.unshift '/home/gmosx/public/glue/lib', '/home/gmosx/public/og/lib', '/home/gmosx/public/nitro/lib'
|
17
|
+
require 'rubygems'
|
18
|
+
require 'run.rb'
|
19
|
+
|
20
|
+
eval(code)
|
data/test/nitro/tc_controller.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
$:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
|
2
2
|
|
3
|
+
$NITRO_NO_ENVIRONMENT = true
|
4
|
+
|
3
5
|
require 'test/unit'
|
4
6
|
require 'ostruct'
|
5
7
|
|
6
8
|
require 'glue'
|
7
9
|
require 'glue/logger'
|
8
|
-
require 'nitro
|
9
|
-
require 'nitro/dispatcher'
|
10
|
-
require 'nitro/controller'
|
10
|
+
require 'nitro'
|
11
11
|
|
12
12
|
class TC_Controller < Test::Unit::TestCase # :nodoc: all
|
13
13
|
include Nitro
|
@@ -0,0 +1,29 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', '..', 'lib')
|
2
|
+
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
require 'nitro/controller'
|
6
|
+
|
7
|
+
class TestControllerAspect < Test::Unit::TestCase # :nodoc: all
|
8
|
+
include Nitro
|
9
|
+
|
10
|
+
class TestController < Controller
|
11
|
+
attr_reader :aflag, :tflag
|
12
|
+
|
13
|
+
post "@aflag = 25", :on => :list
|
14
|
+
|
15
|
+
def list
|
16
|
+
@aflag = 3
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_aspect
|
21
|
+
ctx = Context.new(Server.new)
|
22
|
+
ctx.instance_variable_set '@session', {}
|
23
|
+
c = TestController.new(ctx)
|
24
|
+
c.list_action
|
25
|
+
|
26
|
+
assert_equal 25, c.aflag
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|