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/ProjectInfo
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
TITLE : &title Nitro
|
4
4
|
NAME : &pkg nitro
|
5
|
-
VERSION : '0.
|
5
|
+
VERSION : '0.31.0'
|
6
6
|
STATUS : beta
|
7
7
|
|
8
8
|
AUTHOR : George Moschovitis
|
@@ -26,12 +26,12 @@ RUBYFORGE:
|
|
26
26
|
USERNAME: 'gmosx'
|
27
27
|
|
28
28
|
DEPENDENCIES:
|
29
|
-
- [ og, '= 0.
|
30
|
-
- [ gen, '= 0.
|
31
|
-
- [ glue, '= 0.
|
29
|
+
- [ og, '= 0.31.0' ]
|
30
|
+
- [ gen, '= 0.31.0' ]
|
31
|
+
- [ glue, '= 0.31.0' ]
|
32
32
|
- [ RedCloth, '= 3.0.3' ]
|
33
|
-
- [ ruby-breakpoint, '
|
34
|
-
- [ daemons, '
|
33
|
+
- [ ruby-breakpoint, '~> 0.5' ]
|
34
|
+
- [ daemons, '~> 0.4' ]
|
35
35
|
|
36
36
|
EXECUTABLES:
|
37
37
|
- nitro
|
data/bin/nitro
CHANGED
@@ -1,12 +1,105 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
3
|
+
require 'facets/more/consoleapp'
|
4
4
|
|
5
|
-
|
5
|
+
class NitroCommand < Console::Command
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
# :section: Commands
|
8
|
+
|
9
|
+
# The default action, starts the application. You can
|
10
|
+
# alternatively use the start/run aliases.
|
11
|
+
#
|
12
|
+
# === Examples
|
13
|
+
#
|
14
|
+
# $ nitro
|
15
|
+
# $ nitro start
|
16
|
+
# $ nitro run
|
17
|
+
|
18
|
+
def default
|
19
|
+
if f = application_file
|
20
|
+
$NITRO_NO_ENVIRONMENT = true
|
21
|
+
load 'run.rb'
|
22
|
+
else
|
23
|
+
puts 'No application found!'
|
24
|
+
# FIXME: better error mesage and/or show default app!
|
25
|
+
end
|
26
|
+
end
|
27
|
+
alias run default
|
28
|
+
alias start default
|
29
|
+
|
30
|
+
# Starts an IRB console attached to the web application.
|
31
|
+
|
32
|
+
def console
|
33
|
+
if RUBY_PLATFORM =~ /mswin32/
|
34
|
+
irb_name = 'irb.bat'
|
35
|
+
else
|
36
|
+
irb_name = 'irb'
|
37
|
+
end
|
38
|
+
|
39
|
+
ENV['NITRO_INVOKE'] = 'irb'
|
40
|
+
|
41
|
+
if f = application_file
|
42
|
+
ENV['NITRO_MODE'] = $DBG ? 'debug' : 'live'
|
43
|
+
exec "#{irb_name} -r #{f} -r irb/completion --noinspect"
|
44
|
+
end
|
45
|
+
|
46
|
+
exit
|
47
|
+
end
|
48
|
+
|
49
|
+
# Dump the version of Nitro.
|
50
|
+
|
51
|
+
def version
|
52
|
+
puts "Nitro 0.31.0"
|
53
|
+
end
|
54
|
+
|
55
|
+
# :section: Options
|
56
|
+
|
57
|
+
# Enable verbose mode.
|
58
|
+
|
59
|
+
def _v
|
60
|
+
$DBG = true
|
61
|
+
ENV['NITRO_MODE'] = 'debug'
|
62
|
+
end
|
63
|
+
alias _verbose _v
|
64
|
+
|
65
|
+
# Daemonize the server. Typically used with the Webrick
|
66
|
+
# adapter.
|
67
|
+
|
68
|
+
def _daemon
|
69
|
+
require 'daemons/daemonize'
|
70
|
+
|
71
|
+
pwd = Dir.pwd
|
72
|
+
Daemonize.daemonize(File.join(pwd, 'log/app.log'))
|
73
|
+
|
74
|
+
# Restore the original pwd (daemonize sets the
|
75
|
+
# pwd to '/').
|
76
|
+
Dir.chdir(pwd)
|
77
|
+
|
78
|
+
# Set the logger to a file (daemonize closes the
|
79
|
+
# std streams).
|
80
|
+
Logger.set(Logger.new('log/app.log'))
|
81
|
+
end
|
82
|
+
alias _daemonize _daemon
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
# Typical application main file names.
|
87
|
+
|
88
|
+
APPLICATION_FILES = %w{ run.rb start.rb conf.rb app.rb application.rb }
|
89
|
+
|
90
|
+
# Find out the application main file.
|
91
|
+
|
92
|
+
def application_file
|
93
|
+
for f in APPLICATION_FILES
|
94
|
+
if File.exist? f
|
95
|
+
return f
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
return false
|
100
|
+
end
|
12
101
|
end
|
102
|
+
|
103
|
+
NitroCommand.new.execute
|
104
|
+
|
105
|
+
# * George Moschovitis <gm@navel.gr>
|
data/doc/RELEASES
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
== Version 0.31.0
|
2
|
+
|
3
|
+
* Mongrel adapter updated to work with latest versions of Mongrel.
|
4
|
+
|
5
|
+
* Fixed a long-standing bug where the template root wasn't determined correctly (would result in blank pages).
|
6
|
+
|
7
|
+
* Added sendfile support.
|
8
|
+
|
9
|
+
* Fixed strip_path support. When this setting is set to a path, it will be stripped from urls. Given,
|
10
|
+
|
11
|
+
Router.strip_path = '/nitro-apps'
|
12
|
+
|
13
|
+
when the dispatcher gets a url like /nitro-apps/blog it will strip out /nitro-apps and resolve to the controller for /blog.
|
14
|
+
|
15
|
+
* Wee helper is removed.
|
16
|
+
|
17
|
+
* Updated Nitro start page with links to the examples.
|
18
|
+
|
1
19
|
== Version 0.30.0
|
2
20
|
|
3
21
|
Another pragmatic release. The Nitro development team worked over
|
data/lib/glue/sweeper.rb
CHANGED
@@ -12,22 +12,26 @@ 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
|
19
19
|
before "sweep_affected(:delete)", :on => :og_delete
|
20
20
|
|
21
|
+
# Expires (deletes) a cached page from the file system.
|
21
22
|
#--
|
22
23
|
# FIXME: replace with 'extend Nitro::Caching::Output' ?
|
24
|
+
# this way we wont have to sync the same code in two different
|
25
|
+
# places.
|
23
26
|
# If you change this method, don't forget the Caching::Output
|
24
27
|
# expire method.
|
25
28
|
#++
|
26
29
|
|
27
|
-
def self.expire(name)
|
30
|
+
def self.expire(name, klass)
|
28
31
|
begin
|
29
|
-
|
30
|
-
|
32
|
+
filename = "#{Server.public_root}/#{klass.ann.self.controller.mount_path}/#{name}".squeeze('/')
|
33
|
+
Logger.debug "Sweeper expired cache file '#{filename}'" if $DBG
|
34
|
+
FileUtils.rm_rf(filename)
|
31
35
|
rescue Object
|
32
36
|
# gmosx: is this the right thing to do?
|
33
37
|
end
|
@@ -53,7 +57,7 @@ private
|
|
53
57
|
#++
|
54
58
|
|
55
59
|
def expire_affected_output(name)
|
56
|
-
Sweeper.expire(name)
|
60
|
+
Sweeper.expire(name, self.class)
|
57
61
|
end
|
58
62
|
alias_method :expire_output, :expire_affected_output
|
59
63
|
|
data/lib/nitro.rb
CHANGED
@@ -16,7 +16,7 @@ module Nitro
|
|
16
16
|
|
17
17
|
# The version.
|
18
18
|
|
19
|
-
Version = '0.
|
19
|
+
Version = '0.31.0'
|
20
20
|
|
21
21
|
# Library path.
|
22
22
|
|
@@ -35,18 +35,6 @@ module Nitro
|
|
35
35
|
include Glue
|
36
36
|
end
|
37
37
|
|
38
|
-
#--
|
39
|
-
# gmosx: leave them here.
|
40
|
-
#++
|
41
|
-
|
42
|
-
require 'nitro/global'
|
43
|
-
require 'nitro/context'
|
44
|
-
require 'nitro/controller'
|
45
|
-
require 'nitro/dispatcher'
|
46
|
-
require 'nitro/render'
|
47
|
-
require 'nitro/server'
|
48
|
-
require 'nitro/part'
|
49
|
-
|
50
38
|
unless $NITRO_NO_ENVIRONMENT
|
51
39
|
# Setup up the proposed environment. You are free
|
52
40
|
# to skip this if you dont like it. Just set
|
@@ -68,6 +56,18 @@ unless $NITRO_NO_ENVIRONMENT
|
|
68
56
|
$LOAD_PATH.unshift 'lib'
|
69
57
|
end
|
70
58
|
|
59
|
+
#--
|
60
|
+
# gmosx: leave them here.
|
61
|
+
#++
|
62
|
+
|
63
|
+
require 'nitro/global'
|
64
|
+
require 'nitro/context'
|
65
|
+
require 'nitro/controller'
|
66
|
+
require 'nitro/dispatcher'
|
67
|
+
require 'nitro/render'
|
68
|
+
require 'nitro/server'
|
69
|
+
require 'nitro/part'
|
70
|
+
|
71
71
|
module Nitro
|
72
72
|
|
73
73
|
class << self
|
@@ -28,8 +28,7 @@ module Mongrel # :nodoc: all
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
31
|
-
|
32
|
-
|
31
|
+
|
33
32
|
module Nitro
|
34
33
|
|
35
34
|
class Mongrel
|
@@ -38,66 +37,53 @@ class Mongrel
|
|
38
37
|
attr_accessor :mongrel
|
39
38
|
|
40
39
|
# Start the Webrick adapter.
|
41
|
-
|
40
|
+
|
42
41
|
def start(server)
|
43
42
|
# TODO add logging.
|
44
43
|
|
45
|
-
|
44
|
+
mongrel_options = server.options.dup
|
46
45
|
|
47
|
-
|
46
|
+
mongrel_options.update(
|
48
47
|
:BindAddress => server.address,
|
49
48
|
:Port => server.port,
|
50
49
|
:DocumentRoot => server.public_root
|
51
50
|
)
|
51
|
+
|
52
52
|
@mongrel = ::Mongrel::HttpServer.new(mongrel_options[:BindAddress],
|
53
|
-
|
54
|
-
|
55
|
-
trap('INT') {
|
53
|
+
mongrel_options[:Port])
|
54
|
+
|
55
|
+
trap('INT') { exit } # works until you use breakpoint... why?
|
56
56
|
|
57
57
|
@mongrel.register('/', MongrelAdapter.new(server))
|
58
|
-
|
58
|
+
|
59
59
|
initialize_mongrel(server)
|
60
|
-
|
60
|
+
|
61
61
|
@mongrel.run
|
62
62
|
@mongrel_thread = @mongrel.acceptor
|
63
63
|
@mongrel_thread.join
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
# Stop the Mongrel adapter.
|
67
|
-
|
67
|
+
|
68
68
|
def stop
|
69
|
-
|
69
|
+
@mongrel_thread.kill
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
# Override this method to perform customized mongrel
|
73
73
|
# initialization.
|
74
74
|
|
75
75
|
def initialize_mongrel(server)
|
76
76
|
end
|
77
|
-
|
77
|
+
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
end
|
81
81
|
|
82
|
-
# A special handler for Xhtml files.
|
83
|
-
|
84
|
-
#class XhtmlFileHandler < WEBrick::HTTPServlet::DefaultFileHandler
|
85
|
-
# def do_GET(req, res)
|
86
|
-
# res['content-type'] = 'text/html'
|
87
|
-
# res.body = '<html><body>Permission denied</body></html>'
|
88
|
-
# end
|
89
|
-
#end
|
90
|
-
|
91
82
|
# A Mongrel Adapter for Nitro.
|
92
83
|
|
93
84
|
class MongrelAdapter < ::Mongrel::HttpHandler
|
94
85
|
attr_accessor :server
|
95
|
-
|
96
|
-
STATUS_CODES = {
|
97
|
-
"200" => "OK", "304" => "Not Modified",
|
98
|
-
"404" => "Not found", "500" => "Server Error"
|
99
|
-
}
|
100
|
-
|
86
|
+
|
101
87
|
def initialize(server)
|
102
88
|
@server = server
|
103
89
|
end
|
@@ -112,17 +98,11 @@ class MongrelAdapter < ::Mongrel::HttpHandler
|
|
112
98
|
begin
|
113
99
|
rewrite(req)
|
114
100
|
# TODO handle If-Modified-Since and add Last-Modified headers
|
115
|
-
filename = [@server.public_root, req.path_info].join("/")
|
116
|
-
ext = File.extname(filename)
|
117
|
-
content_type = ::Mongrel::DirHandler::MIME_TYPES[ext] || "text/plain"
|
101
|
+
filename = [@server.public_root, req.path_info].join("/").gsub(%r[//], '/')
|
118
102
|
File.open(filename, "rb") { |f|
|
119
103
|
# TODO check whether path circumvents public_root directory?
|
120
|
-
|
121
|
-
res.
|
122
|
-
res.socket << "Content-type: #{content_type}\r\n"
|
123
|
-
res.socket << "Content-length: #{size}\r\n"
|
124
|
-
res.socket << "\r\n"
|
125
|
-
res.socket << f.read # XXX inefficient for large files, may cause leaks
|
104
|
+
res.status = 200
|
105
|
+
res.body << f.read # XXX inefficient for large files, may cause leaks
|
126
106
|
}
|
127
107
|
return true
|
128
108
|
rescue Object => ex
|
@@ -141,47 +121,30 @@ class MongrelAdapter < ::Mongrel::HttpHandler
|
|
141
121
|
begin
|
142
122
|
context = Context.new(@server)
|
143
123
|
|
144
|
-
context.in =
|
124
|
+
context.in = if req.body.is_a? String
|
125
|
+
StringIO.new(req.body)
|
126
|
+
else
|
127
|
+
req.body
|
128
|
+
end
|
145
129
|
|
146
130
|
context.headers = {}
|
147
131
|
req.params.each { |h, v|
|
148
132
|
if h =~ /\AHTTP_(.*)\Z/
|
149
|
-
|
150
|
-
|
151
|
-
|
133
|
+
context.headers[$1.gsub("_", "-")] = v
|
134
|
+
end
|
135
|
+
context.headers[h] = v
|
152
136
|
}
|
153
|
-
# context.headers.update(req.meta_vars)
|
154
|
-
|
155
|
-
context.headers['REQUEST_URI'] = context.headers['SCRIPT_NAME']
|
156
|
-
|
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
|
162
|
-
|
163
|
-
# gmosx: make compatible with fastcgi.
|
164
|
-
|
165
|
-
context.headers['REQUEST_URI'].slice!(/http:\/\/(.*?)\//)
|
166
|
-
context.headers['REQUEST_URI'] = '/' + context.headers['REQUEST_URI']
|
167
137
|
|
168
138
|
Cgi.parse_params(context)
|
169
139
|
Cgi.parse_cookies(context)
|
170
140
|
|
171
141
|
context.render(path)
|
172
|
-
|
173
|
-
res.
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
res.socket << "Unknown Status Code"
|
179
|
-
end
|
180
|
-
res.socket << "\r\n"
|
181
|
-
|
182
|
-
res.socket << Cgi.response_headers(context)
|
183
|
-
res.socket << context.out
|
184
|
-
|
142
|
+
|
143
|
+
res.status = context.status
|
144
|
+
|
145
|
+
res.header.out << Cgi.response_headers(context)
|
146
|
+
res.body << context.out
|
147
|
+
|
185
148
|
context.close
|
186
149
|
ensure
|
187
150
|
Og.manager.put_store if defined?(Og) and Og.respond_to?(:manager) and Og.manager
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'nitro/cgi'
|
2
|
+
|
3
|
+
module Nitro
|
4
|
+
|
5
|
+
# The script adapter. Useful when running in console mode, or
|
6
|
+
# when creating scripts for cron jobs, testing and more. Allows
|
7
|
+
# you to programmatically 'drive' the web application.
|
8
|
+
|
9
|
+
class ScriptAdapter
|
10
|
+
|
11
|
+
# The last generated response.
|
12
|
+
|
13
|
+
attr_accessor :response
|
14
|
+
|
15
|
+
def initialize server
|
16
|
+
@server = server
|
17
|
+
end
|
18
|
+
|
19
|
+
# Perform a programmatic http request to the web app.
|
20
|
+
#
|
21
|
+
# === Examples
|
22
|
+
#
|
23
|
+
# app.get 'users/logout'
|
24
|
+
# app.post 'users/login', :params => { :name => 'gmosx', :password => 'pass' }
|
25
|
+
# app.post 'users/login?name=gmosx;password=pass
|
26
|
+
# app.post 'articles/view/1'
|
27
|
+
|
28
|
+
def handle uri, options = {}
|
29
|
+
context = Context.new(@server)
|
30
|
+
|
31
|
+
begin
|
32
|
+
context.params = options.fetch(:params, {})
|
33
|
+
context.headers = options.fetch(:headers, {})
|
34
|
+
|
35
|
+
context.headers['REQUEST_URI'] = uri
|
36
|
+
context.headers['REQUEST_METHOD'] = options.fetch(:method, :get)
|
37
|
+
context.headers['HTTP_COOKIE'] ||= options[:cookies]
|
38
|
+
|
39
|
+
Cgi.parse_params context
|
40
|
+
Cgi.parse_cookies context
|
41
|
+
|
42
|
+
context.render uri
|
43
|
+
|
44
|
+
context.close
|
45
|
+
ensure
|
46
|
+
$autoreload_dirty = false
|
47
|
+
Og.manager.put_store if defined?(Og) and Og.respond_to?(:manager) and Og.manager
|
48
|
+
end
|
49
|
+
|
50
|
+
@response = context
|
51
|
+
end
|
52
|
+
|
53
|
+
# Perform a programmatic http get request to the web app.
|
54
|
+
|
55
|
+
def get uri, options = {}
|
56
|
+
options[:method] = :get
|
57
|
+
handle uri, options
|
58
|
+
end
|
59
|
+
|
60
|
+
# Perform a programmatic http post request to the web app.
|
61
|
+
|
62
|
+
def post uri, options = {}
|
63
|
+
options[:method] = :post
|
64
|
+
handle uri, options
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
# * George Moschovitis <gm@navel.gr>
|