nitro 0.10.0 → 0.11.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/AUTHORS +4 -1
- data/ChangeLog +290 -7
- data/README +3 -3
- data/RELEASES +94 -0
- data/Rakefile +7 -7
- data/benchmark/og/bench.rb +11 -10
- data/{ChangeLog.1 → doc/ChangeLog.1} +0 -0
- data/doc/apache.txt +9 -0
- data/doc/architecture.txt +1 -27
- data/doc/bugs.txt +11 -4
- data/doc/config.txt +22 -0
- data/doc/og_config.txt +35 -0
- data/doc/og_tutorial.txt +595 -0
- data/doc/tutorial.txt +22 -0
- data/examples/blog/conf/apache.conf +30 -0
- data/examples/blog/conf/lhttpd.conf +2 -2
- data/examples/blog/lib/blog/controller.rb +11 -2
- data/examples/blog/log/apache.error_log +5528 -0
- data/examples/blog/root/fcgi.rb +1 -1
- data/examples/blog/run.rb +9 -3
- data/examples/flash/run.rb +2 -2
- data/examples/no_xsl_blog/conf/apache.conf +30 -0
- data/examples/no_xsl_blog/conf/lhttpd.conf +1 -1
- data/examples/no_xsl_blog/lib/blog/controller.rb +2 -2
- data/examples/no_xsl_blog/log/apache.error_log +68 -0
- data/examples/no_xsl_blog/root/fcgi.rb +2 -2
- data/examples/no_xsl_blog/run.rb +3 -3
- data/examples/og/run.rb +1 -1
- data/examples/tiny/conf/apache.conf +29 -4
- data/examples/tiny/conf/lhttpd.conf +1 -1
- data/examples/tiny/log/apache.error_log +30 -0
- data/examples/tiny/root/fcgi.rb +2 -2
- data/examples/tiny/root/index.xhtml +1 -1
- data/examples/tiny/run.rb +3 -2
- data/examples/wee_style/run.rb +7 -9
- data/examples/why_wiki/README +5 -0
- data/examples/why_wiki/run.rb +57 -0
- data/examples/why_wiki/wiki.yml +6 -0
- data/examples/wiki.yml +1 -0
- data/lib/glue/array.rb +14 -33
- data/lib/glue/hash.rb +32 -53
- data/lib/glue/pool.rb +9 -12
- data/lib/glue/property.rb +31 -9
- data/lib/nitro.rb +30 -8
- data/lib/nitro/adapters/cgi.rb +23 -3
- data/lib/nitro/adapters/webrick.rb +9 -3
- data/lib/nitro/builders/form.rb +21 -13
- data/lib/nitro/builders/rss.rb +20 -9
- data/lib/nitro/builders/table.rb +69 -10
- data/lib/nitro/builders/xhtml.rb +13 -4
- data/lib/nitro/component.rb +15 -0
- data/lib/nitro/conf.rb +4 -3
- data/lib/nitro/context.rb +22 -14
- data/lib/nitro/controller.rb +63 -5
- data/lib/nitro/dispatcher.rb +11 -6
- data/lib/nitro/output.rb +28 -0
- data/lib/nitro/render.rb +78 -59
- data/lib/nitro/request.rb +5 -1
- data/lib/nitro/runner.rb +20 -6
- data/lib/nitro/session.rb +89 -18
- data/lib/nitro/session/drb.rb +31 -0
- data/lib/nitro/session/drbserver.rb +71 -0
- data/lib/nitro/session/memory.rb +13 -0
- data/lib/nitro/simple.rb +7 -0
- data/lib/nitro/ui/date-select.rb +2 -5
- data/lib/nitro/ui/pager.rb +4 -4
- data/lib/nitro/ui/tabs.rb +2 -4
- data/lib/nitro/uri.rb +7 -4
- data/lib/og.rb +20 -12
- data/lib/og/adapter.rb +40 -13
- data/lib/og/adapters/filesys.rb +121 -0
- data/lib/og/adapters/mysql.rb +10 -5
- data/lib/og/adapters/oracle.rb +374 -0
- data/lib/og/adapters/psql.rb +10 -23
- data/lib/og/adapters/sqlite.rb +3 -3
- data/lib/og/backend.rb +2 -2
- data/lib/og/connection.rb +6 -6
- data/lib/og/database.rb +5 -5
- data/lib/og/enchant.rb +6 -2
- data/lib/og/meta.rb +56 -26
- data/lib/og/mock.rb +1 -1
- data/lib/og/typemacros.rb +23 -0
- data/lib/parts/content.rb +4 -10
- data/test/nitro/adapters/tc_cgi.rb +1 -1
- data/test/nitro/builders/tc_rss.rb +1 -1
- data/test/nitro/builders/tc_table.rb +30 -0
- data/test/nitro/tc_context.rb +4 -0
- data/test/nitro/tc_controller.rb +9 -2
- data/test/og/tc_filesys.rb +83 -0
- data/test/og/tc_meta.rb +55 -0
- data/test/tc_og.rb +115 -36
- data/vendor/README +11 -5
- data/vendor/breakpoint.rb +35 -38
- data/vendor/breakpoint_client.rb +119 -80
- data/vendor/composite_sexp_processor.rb +43 -0
- data/vendor/parse_tree.rb +745 -0
- data/vendor/sexp_processor.rb +453 -0
- metadata +34 -7
- data/examples/no_xsl_blog/conf/app.conf.rb +0 -47
data/lib/nitro/output.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# * George Moschovitis <gm@navel.gr>
|
2
|
+
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
+
# $Id: output.rb 267 2005-02-28 14:52:41Z gmosx $
|
4
|
+
|
5
|
+
require 'nitro/builders/xml'
|
6
|
+
require 'nitro/builders/xhtml'
|
7
|
+
require 'nitro/builders/rss'
|
8
|
+
require 'nitro/builders/form'
|
9
|
+
require 'nitro/builders/table'
|
10
|
+
|
11
|
+
module N
|
12
|
+
|
13
|
+
# The output buffer string. This buffer integrates
|
14
|
+
# the programmatic rendering support (XhtmlBuilder)
|
15
|
+
# and the various builders required by the application.
|
16
|
+
#--
|
17
|
+
# TODO: Implement a FAST string (maybe in C)
|
18
|
+
#++
|
19
|
+
|
20
|
+
class OutputBuffer < String
|
21
|
+
include XmlBuilderMixin
|
22
|
+
include XhtmlBuilderMixin
|
23
|
+
include RssBuilderMixin
|
24
|
+
include FormBuilderMixin
|
25
|
+
include TableBuilderMixin
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/lib/nitro/render.rb
CHANGED
@@ -2,6 +2,10 @@
|
|
2
2
|
# (c) 2004-2005 Navel, all rights reserved.
|
3
3
|
# $Id$
|
4
4
|
|
5
|
+
require 'sync'
|
6
|
+
|
7
|
+
require 'nitro'
|
8
|
+
|
5
9
|
require 'glue/attribute'
|
6
10
|
require 'glue/misc'
|
7
11
|
require 'glue/object'
|
@@ -19,6 +23,8 @@ class RenderExit < Exception; end
|
|
19
23
|
|
20
24
|
module Rendering
|
21
25
|
|
26
|
+
@@sync = Sync.new
|
27
|
+
|
22
28
|
# The default template name (no extension).
|
23
29
|
|
24
30
|
mattr_accessor :default_template, 'index'
|
@@ -84,80 +90,85 @@ module Rendering
|
|
84
90
|
# Compile a controller action.
|
85
91
|
|
86
92
|
def self.compile_action(klass, action, base)
|
87
|
-
|
93
|
+
@@sync.synchronize do
|
94
|
+
dummy, api, action = action.to_s.split('__')
|
88
95
|
|
89
|
-
|
96
|
+
# This is not a controller action.
|
90
97
|
|
91
|
-
|
98
|
+
return false unless action
|
92
99
|
|
93
|
-
|
100
|
+
Logger.debug "Compiling action '#{base}/#{action}'" if $DBG
|
94
101
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
}
|
100
|
-
|
101
|
-
# call 'before' filter chain.
|
102
|
-
|
103
|
-
if klass.respond_to?(:before_filters)
|
104
|
-
code << %{
|
105
|
-
#{klass.gen_filters_call_code(klass.before_filters)}
|
102
|
+
valid = false
|
103
|
+
|
104
|
+
code = %{
|
105
|
+
def __#{api}__#{action}
|
106
106
|
}
|
107
|
-
|
107
|
+
|
108
|
+
# call 'before' filter chain.
|
109
|
+
|
110
|
+
if klass.respond_to?(:before_filters)
|
111
|
+
code << %{
|
112
|
+
#{klass.gen_filters_call_code(klass.before_filters)}
|
113
|
+
}
|
114
|
+
end
|
108
115
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
#{
|
115
|
-
|
116
|
-
|
116
|
+
# call the action
|
117
|
+
|
118
|
+
if klass.action_methods.include?(action)
|
119
|
+
valid = true
|
120
|
+
|
121
|
+
args = klass.action_method_arguments(action).map { |a| "@#{a} = @context['#{a}']" }
|
122
|
+
|
123
|
+
code << %{
|
124
|
+
#{action}(#{args.join(',')});
|
125
|
+
}
|
126
|
+
end
|
117
127
|
|
118
|
-
|
128
|
+
# call the programmatically generated template if exists.
|
119
129
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
130
|
+
if klass.action_methods.include?("#{action}__#{api}")
|
131
|
+
valid = true
|
132
|
+
code << %{
|
133
|
+
return unless #{action}__#{api}();
|
134
|
+
}
|
135
|
+
end
|
136
|
+
|
137
|
+
# call the template if exists.
|
138
|
+
|
139
|
+
if template = template_for_action(base, action)
|
140
|
+
valid = true
|
141
|
+
code << %{
|
142
|
+
return unless __#{api}__#{action}__template();
|
143
|
+
}
|
144
|
+
end
|
135
145
|
|
136
|
-
|
137
|
-
|
146
|
+
# raise "Invalid action '#{action}' for '#{klass}'!" unless valid
|
147
|
+
return false unless valid
|
138
148
|
|
139
|
-
|
149
|
+
# call 'after' filter chain.
|
140
150
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
end
|
146
|
-
|
147
|
-
code << %{
|
148
|
-
redirect_referer if @out.empty?
|
151
|
+
if klass.respond_to?(:after_filters)
|
152
|
+
code << %{
|
153
|
+
#{klass.gen_filters_call_code(klass.after_filters)}
|
154
|
+
}
|
149
155
|
end
|
150
|
-
|
151
|
-
|
152
|
-
if template
|
156
|
+
|
153
157
|
code << %{
|
154
|
-
|
155
|
-
#{transform_template(template, Rendering.shader)}
|
158
|
+
redirect_referer if @out.empty?
|
156
159
|
end
|
157
160
|
}
|
158
|
-
|
161
|
+
|
162
|
+
if template
|
163
|
+
code << %{
|
164
|
+
def __#{api}__#{action}__template
|
165
|
+
#{transform_template(template, Rendering.shader)}
|
166
|
+
end
|
167
|
+
}
|
168
|
+
end
|
159
169
|
|
160
|
-
|
170
|
+
klass.class_eval(code)
|
171
|
+
end
|
161
172
|
|
162
173
|
return true
|
163
174
|
end
|
@@ -198,7 +209,7 @@ module Render
|
|
198
209
|
@out = context.out
|
199
210
|
@base = base
|
200
211
|
end
|
201
|
-
|
212
|
+
|
202
213
|
# Renders the action denoted by path. The path
|
203
214
|
# is resolved by the dispatcher to get the correct
|
204
215
|
# controller.
|
@@ -233,6 +244,8 @@ module Render
|
|
233
244
|
@out << '(error)'
|
234
245
|
end
|
235
246
|
|
247
|
+
private
|
248
|
+
|
236
249
|
# Send a redirect response.
|
237
250
|
|
238
251
|
def redirect(url, status = 303)
|
@@ -267,6 +280,12 @@ module Render
|
|
267
280
|
@context.session
|
268
281
|
end
|
269
282
|
|
283
|
+
# Convenience method to access the output buffer.
|
284
|
+
|
285
|
+
def o
|
286
|
+
@out
|
287
|
+
end
|
288
|
+
|
270
289
|
end
|
271
290
|
|
272
291
|
end
|
data/lib/nitro/request.rb
CHANGED
@@ -55,6 +55,10 @@ module Request
|
|
55
55
|
uri ? uri.split('?').first : ''
|
56
56
|
end
|
57
57
|
|
58
|
+
def path_info
|
59
|
+
@headers['PATH_INFO']
|
60
|
+
end
|
61
|
+
|
58
62
|
# The request query string.
|
59
63
|
|
60
64
|
def query_string
|
@@ -71,7 +75,7 @@ module Request
|
|
71
75
|
# clickstream there is no referer, set "/" by default.
|
72
76
|
|
73
77
|
def referer
|
74
|
-
return @headers['
|
78
|
+
return @headers['HTTP_REFERER'] || '/'
|
75
79
|
end
|
76
80
|
|
77
81
|
# The remote IP address. REMOTE_ADDR is the standard
|
data/lib/nitro/runner.rb
CHANGED
@@ -110,6 +110,11 @@ class Runner
|
|
110
110
|
Logger.set(Logger.new('log/app.log'))
|
111
111
|
end
|
112
112
|
|
113
|
+
opts.on('-a', '--apache', 'Use an apache server.') do
|
114
|
+
@server = :apache
|
115
|
+
Logger.set(Logger.new('log/app.log'))
|
116
|
+
end
|
117
|
+
|
113
118
|
opts.on('-C', '--console', 'Start a console attached to an instance of the application.') do
|
114
119
|
if RUBY_PLATFORM =~ /mswin32/
|
115
120
|
irb_name = 'irb.bat'
|
@@ -122,11 +127,6 @@ class Runner
|
|
122
127
|
exit
|
123
128
|
end
|
124
129
|
|
125
|
-
opts.on('-l', '--lhttpd', 'Use a lighttpd server.') do
|
126
|
-
@server = :lhttpd
|
127
|
-
Logger.set(Logger.new('log/app.log'))
|
128
|
-
end
|
129
|
-
|
130
130
|
opts.on_tail('-v', '--version', 'Show version.') do
|
131
131
|
puts "Nitro #{Nitro::Version}"
|
132
132
|
exit
|
@@ -205,8 +205,9 @@ class Runner
|
|
205
205
|
case @action
|
206
206
|
when :start
|
207
207
|
|
208
|
-
|
208
|
+
puts "\n==> Application listening at #{conf.host}:#{conf.port}.\n\n"
|
209
209
|
|
210
|
+
case @server
|
210
211
|
when :webrick
|
211
212
|
require 'nitro/adapters/webrick'
|
212
213
|
Webrick.start(conf)
|
@@ -214,10 +215,23 @@ class Runner
|
|
214
215
|
when :lhttpd
|
215
216
|
require 'nitro/adapters/fastcgi'
|
216
217
|
`lighttpd -f conf/lhttpd.conf`
|
218
|
+
|
219
|
+
when :apache
|
220
|
+
require 'nitro/adapters/fastcgi'
|
221
|
+
`apachectl -d #{Dir.pwd} -f conf/apache.conf -k start`
|
217
222
|
end
|
218
223
|
|
219
224
|
when :stop
|
220
225
|
|
226
|
+
case @server
|
227
|
+
when :webrick
|
228
|
+
|
229
|
+
when :lhttpd
|
230
|
+
|
231
|
+
when :apache
|
232
|
+
`apachectl -d #{Dir.pwd} -f conf/apache.conf -k stop`
|
233
|
+
end
|
234
|
+
|
221
235
|
end
|
222
236
|
end
|
223
237
|
|
data/lib/nitro/session.rb
CHANGED
@@ -5,19 +5,19 @@
|
|
5
5
|
require 'md5'
|
6
6
|
require 'webrick'
|
7
7
|
|
8
|
+
require 'glue/hash'
|
8
9
|
require 'glue/attribute'
|
9
|
-
|
10
10
|
require 'nitro/cookie'
|
11
11
|
|
12
12
|
module N
|
13
13
|
|
14
14
|
# A web application session.
|
15
15
|
#
|
16
|
-
# State is a neccessary evil but session variables
|
17
|
-
# be avoided as much as possible. Session state
|
18
|
-
# distributed to many servers so avoid
|
19
|
-
# objects in session variables, only
|
20
|
-
# integer/strings.
|
16
|
+
# State is a neccessary evil but session variables
|
17
|
+
# should be avoided as much as possible. Session state
|
18
|
+
# is typically distributed to many servers so avoid
|
19
|
+
# storing complete objects in session variables, only
|
20
|
+
# store oids and small integer/strings.
|
21
21
|
#
|
22
22
|
# The session should be persistable to survive server
|
23
23
|
# shutdowns.
|
@@ -32,42 +32,99 @@ class Session < Hash
|
|
32
32
|
|
33
33
|
cattr_accessor :cookie_name, 'nsid'
|
34
34
|
|
35
|
-
# The sessions
|
36
|
-
|
37
|
-
cattr_accessor :manager; @@manager = {}
|
35
|
+
# The sessions store. By default sessions are
|
36
|
+
# stored in memory.
|
38
37
|
|
39
|
-
|
38
|
+
cattr_accessor :store; @@store = N::SafeHash.new
|
40
39
|
|
41
|
-
|
40
|
+
# Set the session store. The following options are
|
41
|
+
# available:
|
42
|
+
#
|
43
|
+
# * :memory [default]
|
44
|
+
# * :drb
|
45
|
+
# * :memcached (not available yet)
|
46
|
+
# * :og (not available yet)
|
47
|
+
# * :file (not available yet)
|
48
|
+
|
49
|
+
def self.store_type=(store_type)
|
50
|
+
require "nitro/session/#{store_type}"
|
51
|
+
end
|
42
52
|
|
53
|
+
# Lookup the session in the store by using the session
|
54
|
+
# cookie value as a key. If the session does not exist
|
55
|
+
# creates a new session, inserts it in the store and
|
56
|
+
# appends a new session cookie in the response.
|
57
|
+
|
43
58
|
def self.lookup(context)
|
44
|
-
if
|
45
|
-
session =
|
59
|
+
if session_id = context.cookies[Session.cookie_name]
|
60
|
+
session = Session.store[session_id]
|
46
61
|
end
|
47
62
|
|
48
63
|
unless session
|
64
|
+
# Create new session.
|
49
65
|
session = Session.new(context)
|
50
|
-
context.add_cookie(
|
51
|
-
|
66
|
+
context.add_cookie(
|
67
|
+
Cookie.new(Session.cookie_name, session.session_id)
|
68
|
+
)
|
69
|
+
Session.store[session.session_id] = session
|
70
|
+
else
|
71
|
+
# Access ('touch') the existing session.
|
72
|
+
session.touch!
|
52
73
|
end
|
53
74
|
|
54
75
|
return session
|
55
76
|
end
|
56
77
|
|
78
|
+
# The unique id of this session.
|
79
|
+
|
80
|
+
attr_reader :session_id
|
81
|
+
|
82
|
+
# The time this session was created.
|
83
|
+
|
84
|
+
attr_reader :ctime
|
85
|
+
alias_method :create_time, :ctime
|
86
|
+
|
87
|
+
# The time this session was last modified.
|
88
|
+
|
89
|
+
attr_accessor :mtime
|
90
|
+
alias_method :modify_time, :mtime
|
91
|
+
|
92
|
+
# The time this session was last accessed.
|
93
|
+
|
94
|
+
attr_accessor :atime
|
95
|
+
alias_method :access_time, :mtime
|
96
|
+
|
57
97
|
# Create the session for the given context.
|
58
98
|
|
59
99
|
def initialize(context = nil)
|
60
100
|
@session_id = create_id
|
101
|
+
@ctime = @mtime = @atime = Time.now
|
102
|
+
end
|
103
|
+
|
104
|
+
# Like the unix touch command, upadtes
|
105
|
+
# the atime to now.
|
106
|
+
|
107
|
+
def touch!
|
108
|
+
@atime = Time.now
|
61
109
|
end
|
62
110
|
|
111
|
+
# Synchronize the session store, by
|
112
|
+
# restoring this session. Especially useful
|
113
|
+
# in distributed and/or multiprocess setups.
|
114
|
+
|
115
|
+
def sync
|
116
|
+
Session.store[@session_id] = self
|
117
|
+
end
|
118
|
+
alias_method :restore, :sync
|
119
|
+
|
63
120
|
protected
|
64
121
|
|
65
122
|
# Calculates a unique id.
|
66
123
|
#
|
67
124
|
# The session id must be unique, a monotonically
|
68
|
-
# increasing function like time is appropriate.
|
69
|
-
# may produce equal ids? add a prefix
|
70
|
-
# hackers from creating session_ids.
|
125
|
+
# increasing function like time is appropriate.
|
126
|
+
# Random may produce equal ids? add a prefix
|
127
|
+
# (SALT) to stop hackers from creating session_ids.
|
71
128
|
|
72
129
|
def create_id
|
73
130
|
now = Time.now
|
@@ -81,4 +138,18 @@ protected
|
|
81
138
|
|
82
139
|
end
|
83
140
|
|
141
|
+
# Abstract class for a session store manager.
|
142
|
+
|
143
|
+
class SessionStore
|
144
|
+
def []=(sid, session)
|
145
|
+
end
|
146
|
+
|
147
|
+
def [](sid)
|
148
|
+
end
|
149
|
+
|
150
|
+
def delete(sid)
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
84
155
|
end
|