nitro 0.7.0 → 0.8.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 +14 -4
- data/ChangeLog +192 -1
- data/README +50 -6
- data/RELEASES +60 -0
- data/Rakefile +1 -1
- data/bin/cluster.rb +2 -2
- data/bin/new_form.rb +1 -1
- data/examples/blog/config.rb +5 -4
- data/examples/blog/lib/blog.rb +56 -36
- data/examples/blog/root/comments.xhtml +5 -2
- data/examples/blog/root/entry_form.xhtml +7 -2
- data/examples/blog/root/login.xhtml +1 -1
- data/examples/blog/root/style.xsl +7 -0
- data/examples/og/mock_example.rb +6 -9
- data/examples/og/mysql_to_psql.rb +100 -0
- data/examples/og/run.rb +8 -17
- data/lib/glue.rb +7 -8
- data/lib/glue/array.rb +1 -1
- data/lib/glue/attribute.rb +86 -0
- data/lib/glue/cache.rb +1 -1
- data/lib/glue/hash.rb +1 -1
- data/lib/glue/inflector.rb +1 -1
- data/lib/glue/logger.rb +118 -18
- data/lib/glue/mixins.rb +1 -1
- data/lib/glue/number.rb +1 -1
- data/lib/glue/pool.rb +1 -1
- data/lib/glue/property.rb +48 -31
- data/lib/glue/string.rb +1 -1
- data/lib/glue/time.rb +2 -2
- data/lib/glue/validation.rb +400 -0
- data/lib/nitro/application.rb +6 -6
- data/lib/nitro/builders/form.rb +5 -5
- data/lib/nitro/builders/rss.rb +1 -1
- data/lib/nitro/builders/xhtml.rb +119 -0
- data/lib/nitro/builders/xml.rb +111 -0
- data/lib/nitro/config.rb +6 -6
- data/lib/nitro/events.rb +1 -1
- data/lib/nitro/html.rb +1 -1
- data/lib/nitro/markup.rb +15 -20
- data/lib/nitro/scaffold.rb +2 -2
- data/lib/nitro/server/appserver.rb +3 -3
- data/lib/nitro/server/cluster.rb +2 -2
- data/lib/nitro/server/dispatcher.rb +2 -2
- data/lib/nitro/server/filters/autologin.rb +1 -1
- data/lib/nitro/server/fragment.rb +2 -2
- data/lib/nitro/server/handlers.rb +2 -2
- data/lib/nitro/server/render.rb +17 -15
- data/lib/nitro/server/request.rb +6 -6
- data/lib/nitro/server/script.rb +2 -2
- data/lib/nitro/server/server.rb +2 -2
- data/lib/nitro/server/session.rb +6 -6
- data/lib/nitro/server/shaders.rb +2 -2
- data/lib/nitro/server/webrick.rb +1 -1
- data/lib/nitro/sitemap.rb +2 -2
- data/lib/nitro/uri.rb +1 -1
- data/lib/nitro/version.rb +7 -5
- data/lib/og.rb +95 -129
- data/lib/og/backend.rb +47 -46
- data/lib/og/backends/mysql.rb +64 -63
- data/lib/og/backends/psql.rb +73 -72
- data/lib/og/connection.rb +7 -8
- data/lib/og/enchant.rb +80 -0
- data/lib/og/meta.rb +21 -21
- data/lib/og/mock.rb +31 -88
- data/lib/og/version.rb +6 -5
- data/lib/parts/README +9 -0
- data/lib/parts/content.rb +23 -9
- data/test/glue/tc_attribute.rb +22 -0
- data/test/glue/tc_cache.rb +4 -6
- data/test/glue/tc_hash.rb +2 -2
- data/test/glue/tc_logger.rb +36 -0
- data/test/glue/tc_numbers.rb +2 -2
- data/test/glue/tc_property_mixins.rb +35 -4
- data/test/glue/tc_strings.rb +32 -32
- data/test/glue/tc_validation.rb +186 -0
- data/test/nitro/builders/tc_xhtml.rb +38 -0
- data/test/nitro/builders/tc_xml.rb +47 -0
- data/test/nitro/server/tc_request.rb +2 -2
- data/test/nitro/server/tc_session.rb +1 -1
- data/test/nitro/tc_sitemap.rb +1 -1
- data/test/nitro/ui/tc_pager.rb +1 -10
- data/test/tc_og.rb +3 -3
- data/vendor/blankslate.rb +53 -0
- data/vendor/extensions/_base.rb +153 -0
- data/vendor/extensions/_template.rb +36 -0
- data/vendor/extensions/all.rb +21 -0
- data/vendor/extensions/array.rb +68 -0
- data/vendor/extensions/binding.rb +224 -0
- data/vendor/extensions/class.rb +50 -0
- data/vendor/extensions/continuation.rb +71 -0
- data/vendor/extensions/enumerable.rb +250 -0
- data/vendor/extensions/hash.rb +23 -0
- data/vendor/extensions/io.rb +58 -0
- data/vendor/extensions/kernel.rb +42 -0
- data/vendor/extensions/module.rb +114 -0
- data/vendor/extensions/numeric.rb +230 -0
- data/vendor/extensions/object.rb +164 -0
- data/vendor/extensions/ostruct.rb +41 -0
- data/vendor/extensions/string.rb +316 -0
- data/vendor/extensions/symbol.rb +28 -0
- metadata +35 -13
- data/lib/glue/property.rb.old +0 -307
data/lib/nitro/server/cluster.rb
CHANGED
|
@@ -73,7 +73,7 @@ class Cluster < N::Application
|
|
|
73
73
|
begin
|
|
74
74
|
sdrb.server_sync(key, value)
|
|
75
75
|
rescue => ex
|
|
76
|
-
|
|
76
|
+
Logger.error "Server at #{uri} is down, removing from cluster"
|
|
77
77
|
cluster.delete(uri)
|
|
78
78
|
end
|
|
79
79
|
}
|
|
@@ -94,7 +94,7 @@ class Cluster < N::Application
|
|
|
94
94
|
begin
|
|
95
95
|
sdrb.server_sync(key, value) unless uri == server_uri
|
|
96
96
|
rescue => ex
|
|
97
|
-
|
|
97
|
+
Logger.error "Server at #{uri} is down, removing from cluster"
|
|
98
98
|
cluster.delete(uri)
|
|
99
99
|
end
|
|
100
100
|
}
|
|
@@ -22,8 +22,8 @@ module Dispatcher
|
|
|
22
22
|
render(request.request_uri.path, request, response, session)
|
|
23
23
|
response.body = @out
|
|
24
24
|
rescue Exception, StandardError => e
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
Logger.error "error while handling the request #{request.request_uri}"
|
|
26
|
+
Logger.error pp_exception(e)
|
|
27
27
|
|
|
28
28
|
if $error_page_url
|
|
29
29
|
# gmosx: SOS: TEST ME!
|
|
@@ -38,7 +38,7 @@ class AutoLoginFilter < N::ServerFilter
|
|
|
38
38
|
request.del_cookie($users_auth_cookie)
|
|
39
39
|
end
|
|
40
40
|
else
|
|
41
|
-
|
|
41
|
+
Logger.warn "Unknown user or wrong password in auth-cookie: #{cookie} from IP: #{request.remote_addr}"
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
end
|
|
@@ -28,8 +28,8 @@ module N
|
|
|
28
28
|
# - can run background cron scripts over the fragments (compression)
|
|
29
29
|
#
|
|
30
30
|
class Fragment
|
|
31
|
-
include
|
|
32
|
-
include
|
|
31
|
+
include N::Expirable
|
|
32
|
+
include N::LRUCache::Item
|
|
33
33
|
|
|
34
34
|
# precompiled flags for fragment key "customization"
|
|
35
35
|
|
|
@@ -50,7 +50,7 @@ class ScriptHandler < Handler
|
|
|
50
50
|
|
|
51
51
|
# cache the compiled page scripts to optimize future references.
|
|
52
52
|
# use a thread safe cache.
|
|
53
|
-
@@compiled_script_cache =
|
|
53
|
+
@@compiled_script_cache = N::SafeHash.new()
|
|
54
54
|
|
|
55
55
|
# dont allow 2 threads to compile the same script. In fact dont allow
|
|
56
56
|
# two threads to compile in parallel.
|
|
@@ -65,7 +65,7 @@ class ScriptHandler < Handler
|
|
|
65
65
|
if ::File.exists?("#$root_dir/#{path}")
|
|
66
66
|
return path
|
|
67
67
|
else
|
|
68
|
-
|
|
68
|
+
Logger.debug "OVERLOAD: '#{path}' -> 'p/#{path}'" if $DBG
|
|
69
69
|
return "p/#{path}"
|
|
70
70
|
end
|
|
71
71
|
end
|
data/lib/nitro/server/render.rb
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
#
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
# (c) 2004 Navel, all rights reserved.
|
|
1
|
+
# George Moschovitis <gm@navel.gr>
|
|
2
|
+
# (c) 2004-2005 Navel, all rights reserved.
|
|
5
3
|
# $Id: render.rb 200 2004-12-27 11:24:41Z gmosx $
|
|
6
4
|
|
|
7
5
|
require 'cgi'
|
|
@@ -11,19 +9,19 @@ module N
|
|
|
11
9
|
# = RenderUtils
|
|
12
10
|
#
|
|
13
11
|
# Various render related utilities.
|
|
14
|
-
|
|
12
|
+
|
|
15
13
|
module RenderUtils
|
|
16
14
|
|
|
17
15
|
# Split the path to base, render_class and method.
|
|
18
16
|
#
|
|
19
|
-
# Examples
|
|
17
|
+
# == Examples
|
|
20
18
|
#
|
|
21
19
|
# / -> nil, index, nil
|
|
22
20
|
# /add_user -> nil, add_user, nil
|
|
23
21
|
# /add_user?user=gmosx -> nil, add_user, user=gmosx
|
|
24
22
|
# /blog/new_entry -> blog, new_entry
|
|
25
23
|
# /blog -> blog, index, nil
|
|
26
|
-
|
|
24
|
+
|
|
27
25
|
def self.split_path(path)
|
|
28
26
|
# paths that start with rest/xxx are REST requests.
|
|
29
27
|
# FIXME: better chack here!
|
|
@@ -86,7 +84,7 @@ module RenderUtils
|
|
|
86
84
|
# Transform a template to ruby rendering code.
|
|
87
85
|
#
|
|
88
86
|
def self.transform_template(path)
|
|
89
|
-
|
|
87
|
+
Logger.debug "Transforming '#{path}'" if $DBG
|
|
90
88
|
|
|
91
89
|
text = File.read(path)
|
|
92
90
|
hash, text = $shader.process(path, text)
|
|
@@ -98,7 +96,7 @@ module RenderUtils
|
|
|
98
96
|
# Compile a HTTP method.
|
|
99
97
|
#
|
|
100
98
|
def self.compile_http_method(klass, base, meth)
|
|
101
|
-
|
|
99
|
+
Logger.debug "Compiling HTTP method '#{klass}:#{meth}'" if $DBG
|
|
102
100
|
|
|
103
101
|
valid = false
|
|
104
102
|
|
|
@@ -173,7 +171,7 @@ module RenderUtils
|
|
|
173
171
|
# Compile a REST method.
|
|
174
172
|
#
|
|
175
173
|
def self.compile_rest_method(klass, base, meth)
|
|
176
|
-
|
|
174
|
+
Logger.debug "Compiling REST method '#{klass}:#{meth}'" if $DBG
|
|
177
175
|
|
|
178
176
|
valid = false
|
|
179
177
|
|
|
@@ -250,12 +248,12 @@ end
|
|
|
250
248
|
# = RenderExit
|
|
251
249
|
#
|
|
252
250
|
# Raise this exception to stop rendering.
|
|
253
|
-
|
|
251
|
+
|
|
254
252
|
class RenderExit < Exception
|
|
255
253
|
end
|
|
256
254
|
|
|
257
255
|
# = Render
|
|
258
|
-
|
|
256
|
+
|
|
259
257
|
module Render
|
|
260
258
|
# The outbut buffer. The output of a script/action is accumulated
|
|
261
259
|
# in this buffer.
|
|
@@ -321,9 +319,12 @@ module Render
|
|
|
321
319
|
if self.class == render_class
|
|
322
320
|
self.send(meth)
|
|
323
321
|
else
|
|
322
|
+
=begin
|
|
323
|
+
gmosx: reolading fucks up validation and meta data propagation.
|
|
324
324
|
if $reload_scripts and defined?(render_class::SOURCE_FILE)
|
|
325
325
|
load(render_class::SOURCE_FILE)
|
|
326
326
|
end
|
|
327
|
+
=end
|
|
327
328
|
r = render_class.new(base, @request, @response, @session)
|
|
328
329
|
r.send(meth)
|
|
329
330
|
@out = r.out
|
|
@@ -362,8 +363,8 @@ module Render
|
|
|
362
363
|
|
|
363
364
|
# Redirect to the referer of this method.
|
|
364
365
|
#
|
|
365
|
-
def redirect_referer(status = 303)
|
|
366
|
-
redirect(@request.referer, status)
|
|
366
|
+
def redirect_referer(postfix = nil, status = 303)
|
|
367
|
+
redirect("#{@request.referer}#{postfix}", status)
|
|
367
368
|
end
|
|
368
369
|
|
|
369
370
|
# Log a rendering error.
|
|
@@ -373,7 +374,7 @@ module Render
|
|
|
373
374
|
def log_error(str)
|
|
374
375
|
@rendering_errors ||= []
|
|
375
376
|
@rendering_errors << str
|
|
376
|
-
|
|
377
|
+
Logger.error str
|
|
377
378
|
end
|
|
378
379
|
|
|
379
380
|
# --------------------------------------------------------------------
|
|
@@ -400,6 +401,7 @@ module Render
|
|
|
400
401
|
@out = @out_buffers.pop
|
|
401
402
|
@out << nested_buffer
|
|
402
403
|
end
|
|
404
|
+
|
|
403
405
|
# --------------------------------------------------------------------
|
|
404
406
|
# Caching methods.
|
|
405
407
|
|
data/lib/nitro/server/request.rb
CHANGED
|
@@ -68,7 +68,7 @@ module RequestUtils
|
|
|
68
68
|
return obj
|
|
69
69
|
end
|
|
70
70
|
else
|
|
71
|
-
#
|
|
71
|
+
# Logger.error "request.get_object('#{oid_param}') failed!"
|
|
72
72
|
return nil
|
|
73
73
|
end
|
|
74
74
|
end
|
|
@@ -89,7 +89,7 @@ module RequestUtils
|
|
|
89
89
|
return nil
|
|
90
90
|
end
|
|
91
91
|
else
|
|
92
|
-
#
|
|
92
|
+
# Logger.error "request.get_object_by_name('#{name_param}') failed!"
|
|
93
93
|
return obj
|
|
94
94
|
end
|
|
95
95
|
else
|
|
@@ -352,7 +352,7 @@ class Request
|
|
|
352
352
|
def get(key, default=nil)
|
|
353
353
|
val = @parameters[key]
|
|
354
354
|
|
|
355
|
-
if !val or (val.is_a?(String) and (not
|
|
355
|
+
if !val or (val.is_a?(String) and (not N::StringUtils.valid?(val)))
|
|
356
356
|
@parameters[key] = default
|
|
357
357
|
return default
|
|
358
358
|
elsif default.is_a?(Integer)
|
|
@@ -429,7 +429,7 @@ class Request
|
|
|
429
429
|
# Check if a parameter is valid
|
|
430
430
|
#
|
|
431
431
|
def param?(param)
|
|
432
|
-
return
|
|
432
|
+
return N::StringUtils.valid?(self[param])
|
|
433
433
|
end
|
|
434
434
|
alias_method :action?, :param?
|
|
435
435
|
|
|
@@ -465,7 +465,7 @@ class Request
|
|
|
465
465
|
end
|
|
466
466
|
|
|
467
467
|
# gmosx: to avoid using param?
|
|
468
|
-
if param.is_a?(String) and (not
|
|
468
|
+
if param.is_a?(String) and (not N::StringUtils.valid?(param))
|
|
469
469
|
return nil
|
|
470
470
|
else
|
|
471
471
|
return param
|
|
@@ -547,7 +547,7 @@ class Request
|
|
|
547
547
|
def log_error(str)
|
|
548
548
|
@error_log = [] unless @error_log
|
|
549
549
|
@error_log << str if @error_log.size < 200 # gmosx: dod attack!
|
|
550
|
-
|
|
550
|
+
Logger.error str
|
|
551
551
|
end
|
|
552
552
|
|
|
553
553
|
# ====================================================================
|
data/lib/nitro/server/script.rb
CHANGED
|
@@ -63,7 +63,7 @@ class Script
|
|
|
63
63
|
|
|
64
64
|
# sub-scripts set: a set of files this script depends on.
|
|
65
65
|
# We use a hash to implement a set.
|
|
66
|
-
@sub_scripts =
|
|
66
|
+
@sub_scripts = N::SafeArray.new
|
|
67
67
|
|
|
68
68
|
# a cache for the script outputs (fragments). Keeps multiple revisions
|
|
69
69
|
# of the script output according to user, access rights etc.
|
|
@@ -74,7 +74,7 @@ class Script
|
|
|
74
74
|
#
|
|
75
75
|
# DISK CACHING IS SLOW!
|
|
76
76
|
#
|
|
77
|
-
@fragment_cache =
|
|
77
|
+
@fragment_cache = N::LRUCache.new(1000)
|
|
78
78
|
|
|
79
79
|
__init()
|
|
80
80
|
end
|
data/lib/nitro/server/server.rb
CHANGED
|
@@ -25,7 +25,7 @@ module ServerMixin
|
|
|
25
25
|
$sessions = DRbObject.new(nil, $drb_sessions_cluster)
|
|
26
26
|
else
|
|
27
27
|
# NoCluster mode: use standard Ruby onjects.
|
|
28
|
-
$lm =
|
|
28
|
+
$lm = N::SafeHash.new
|
|
29
29
|
$sessions = N::App::SessionManager.new
|
|
30
30
|
end
|
|
31
31
|
|
|
@@ -50,7 +50,7 @@ class Server < N::Server
|
|
|
50
50
|
super
|
|
51
51
|
initialize_app()
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
Logger.info "Server listening at #$srv_url"
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
|
data/lib/nitro/server/session.rb
CHANGED
|
@@ -23,13 +23,13 @@ module N
|
|
|
23
23
|
#
|
|
24
24
|
# SOS: This object lives in the Cluster!
|
|
25
25
|
#
|
|
26
|
-
class SessionManager <
|
|
26
|
+
class SessionManager < N::SafeHash
|
|
27
27
|
# the collection of online users.
|
|
28
28
|
attr_reader :online
|
|
29
29
|
|
|
30
30
|
def initialize
|
|
31
31
|
super
|
|
32
|
-
@online =
|
|
32
|
+
@online = N::SafeHash.new
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
# Return the number of anonymous sessions.
|
|
@@ -80,12 +80,12 @@ class SessionManager < G::SafeHash
|
|
|
80
80
|
begin
|
|
81
81
|
session = $sessions[key]
|
|
82
82
|
if session.stale?
|
|
83
|
-
|
|
83
|
+
Logger.debug "Session finalized: logging out idle user '#{session.user}'" if $DBG
|
|
84
84
|
session.logout()
|
|
85
85
|
$sessions.delete(key)
|
|
86
86
|
end
|
|
87
87
|
rescue Exception, StandardError => e
|
|
88
|
-
|
|
88
|
+
Logger.error "Session gc errror #$!"
|
|
89
89
|
end
|
|
90
90
|
end
|
|
91
91
|
end
|
|
@@ -138,7 +138,7 @@ class Session < Hash
|
|
|
138
138
|
@user = user
|
|
139
139
|
@user.login(request)
|
|
140
140
|
$sessions.login(@user.oid, @user.name)
|
|
141
|
-
|
|
141
|
+
Logger.info "User '#{user}' logged in!"
|
|
142
142
|
return true
|
|
143
143
|
end
|
|
144
144
|
|
|
@@ -148,7 +148,7 @@ class Session < Hash
|
|
|
148
148
|
self.clear()
|
|
149
149
|
@user.logout()
|
|
150
150
|
$sessions.logout(@user.oid)
|
|
151
|
-
|
|
151
|
+
Logger.info "User '#{user}' logged out!"
|
|
152
152
|
@user = N::AnonymousUser.instance
|
|
153
153
|
end
|
|
154
154
|
|
data/lib/nitro/server/shaders.rb
CHANGED
|
@@ -122,7 +122,7 @@ class RubyShader < N::Shader
|
|
|
122
122
|
# Loads and statically includes a file.
|
|
123
123
|
#
|
|
124
124
|
def load_statically_included(filename)
|
|
125
|
-
|
|
125
|
+
Logger.debug "Statically including '#{filename}'" if $DBG
|
|
126
126
|
|
|
127
127
|
text = File.read(filename)
|
|
128
128
|
text.gsub!(/<\?xml.*\?>/, '')
|
|
@@ -176,7 +176,7 @@ class XSLTShader < N::Shader
|
|
|
176
176
|
# Parse the xsl.
|
|
177
177
|
#
|
|
178
178
|
def parse_xsl
|
|
179
|
-
|
|
179
|
+
Logger.debug "Parsing xsl '#{@xsl_filename}'" if $DBG
|
|
180
180
|
@mtime = File.mtime(@xsl_filename)
|
|
181
181
|
@xslt.xsl = File.read(@xsl_filename)
|
|
182
182
|
end
|
data/lib/nitro/server/webrick.rb
CHANGED
|
@@ -164,7 +164,7 @@ class WebrickDispatcher < WEBrick::HTTPServlet::AbstractServlet
|
|
|
164
164
|
end
|
|
165
165
|
|
|
166
166
|
unless session
|
|
167
|
-
|
|
167
|
+
Logger.debug 'Creating new session.' if $DBG
|
|
168
168
|
# no session cookie or stale session (garbage collected).
|
|
169
169
|
session_id = N::Session.calculate_id()
|
|
170
170
|
cookie = WEBrick::Cookie.new(N::Session::COOKIE_NAME, session_id)
|
data/lib/nitro/sitemap.rb
CHANGED
|
@@ -85,7 +85,7 @@ end
|
|
|
85
85
|
# - Use a second class in the UI namespace for rendering
|
|
86
86
|
# related stuff?
|
|
87
87
|
#
|
|
88
|
-
class SiteMap <
|
|
88
|
+
class SiteMap < N::SafeHash
|
|
89
89
|
|
|
90
90
|
# The root page for this sitemap
|
|
91
91
|
attr_accessor :root
|
|
@@ -121,7 +121,7 @@ class SiteMap < G::SafeHash
|
|
|
121
121
|
|
|
122
122
|
return res
|
|
123
123
|
else
|
|
124
|
-
|
|
124
|
+
Logger.warn "The uri #{uri} is not registered in the SiteMap!"
|
|
125
125
|
end
|
|
126
126
|
|
|
127
127
|
return nil
|
data/lib/nitro/uri.rb
CHANGED
data/lib/nitro/version.rb
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
# (c) 2004 Navel, all rights reserved.
|
|
1
|
+
#--
|
|
2
|
+
# George Moschovitis <gm@navel.gr>
|
|
3
|
+
# (c) 2004-2005 Navel, all rights reserved.
|
|
5
4
|
# $Id: version.rb 194 2004-12-20 20:23:57Z gmosx $
|
|
5
|
+
#++
|
|
6
6
|
|
|
7
7
|
# The name of the server.
|
|
8
|
+
|
|
8
9
|
$srv_name = 'Nitro'
|
|
9
10
|
|
|
10
11
|
# The version of the server.
|
|
11
|
-
|
|
12
|
+
|
|
13
|
+
$srv_version = '0.8.0'
|
data/lib/og.rb
CHANGED
|
@@ -4,36 +4,12 @@
|
|
|
4
4
|
# (c) 2004 Navel, all rights reserved.
|
|
5
5
|
# $Id: og.rb 197 2004-12-21 13:50:17Z gmosx $
|
|
6
6
|
|
|
7
|
-
require
|
|
8
|
-
require
|
|
9
|
-
require
|
|
10
|
-
require
|
|
11
|
-
require
|
|
12
|
-
|
|
13
|
-
# If true, only allow reading from the database. Usefull
|
|
14
|
-
# for maintainance.
|
|
15
|
-
#
|
|
16
|
-
$og_read_only_mode = false
|
|
17
|
-
|
|
18
|
-
# If true, the library automatically 'enchants' managed classes.
|
|
19
|
-
# In enchant mode, special db aware methods are added to
|
|
20
|
-
# managed classes and instances.
|
|
21
|
-
#
|
|
22
|
-
$og_enchant_managed_classes = true
|
|
23
|
-
|
|
24
|
-
# If true, use Ruby's advanced introspection capabilities to
|
|
25
|
-
# automatically manage classes tha define properties.
|
|
26
|
-
$og_auto_manage_classes = true
|
|
27
|
-
|
|
28
|
-
# If true, automatically include the Og meta-language into Module.
|
|
29
|
-
$og_include_meta_language = true
|
|
30
|
-
|
|
31
|
-
# Attach the following prefix to all generated SQL table names.
|
|
32
|
-
# Usefull on hosting scenarios where you have to run multiple
|
|
33
|
-
# web applications/sites on a single database.
|
|
34
|
-
$og_table_prefix = nil
|
|
35
|
-
|
|
36
|
-
require "og/meta"
|
|
7
|
+
require 'glue/logger'
|
|
8
|
+
require 'glue/property'
|
|
9
|
+
require 'glue/array'
|
|
10
|
+
require 'glue/hash'
|
|
11
|
+
require 'glue/time'
|
|
12
|
+
require 'glue/pool'
|
|
37
13
|
|
|
38
14
|
# = Og
|
|
39
15
|
#
|
|
@@ -58,11 +34,12 @@ require "og/meta"
|
|
|
58
34
|
# + Transparent support for cascading deletes for all backends.
|
|
59
35
|
# + Hierarchical structures (preorder traversal, materialized paths)
|
|
60
36
|
# + Works safely as part of distributed application.
|
|
61
|
-
# + Simple implementation
|
|
37
|
+
# + Simple implementation.
|
|
62
38
|
#
|
|
63
39
|
# === Meta language
|
|
64
40
|
#
|
|
65
|
-
# primary_key :pid
|
|
41
|
+
# primary_key :pid (NOT IMPLEMENTED)
|
|
42
|
+
# name_key :name (NOT IMPLEMENTED)
|
|
66
43
|
# prop_accessor Fixnum, :pid, :sql => "smallint DEFAULT 1"
|
|
67
44
|
# has_many Child, :children
|
|
68
45
|
# many_to_many Role, :roles
|
|
@@ -71,10 +48,10 @@ require "og/meta"
|
|
|
71
48
|
# === Design
|
|
72
49
|
#
|
|
73
50
|
# Keep the main classes backend agnostic.
|
|
74
|
-
|
|
51
|
+
#--
|
|
75
52
|
# Try to make the methods work with oids. Do NOT implement descendants
|
|
76
53
|
# use a root id (rid).
|
|
77
|
-
|
|
54
|
+
#++
|
|
78
55
|
# For class ids we use the name instead of a hash. Class ids are
|
|
79
56
|
# typically not used in querys, they are stored for completeness.
|
|
80
57
|
# If we store a hash we cannot reclaim the class thus invalidating
|
|
@@ -89,7 +66,7 @@ require "og/meta"
|
|
|
89
66
|
# This is NOT a singleton, an application may access multiple
|
|
90
67
|
# databases.
|
|
91
68
|
#
|
|
92
|
-
# The
|
|
69
|
+
# The og.xxx methods are more flexible and allow you to use
|
|
93
70
|
# multiple databases for example.
|
|
94
71
|
#
|
|
95
72
|
# === Managed Objects Lifecycle Callbacks
|
|
@@ -101,7 +78,6 @@ require "og/meta"
|
|
|
101
78
|
# * og_pre_insert_update
|
|
102
79
|
# * og_post_insert_update
|
|
103
80
|
# * self.og_pre_delete
|
|
104
|
-
# * validate
|
|
105
81
|
#
|
|
106
82
|
# A class level callback is used for delete because typically you call
|
|
107
83
|
# delete with an oid and not an object to avoid a deserialization.
|
|
@@ -114,8 +90,53 @@ require "og/meta"
|
|
|
114
90
|
# * Deserialize to OpenStruct.
|
|
115
91
|
# * Better documentation.
|
|
116
92
|
#
|
|
117
|
-
|
|
93
|
+
class Og
|
|
94
|
+
class << self
|
|
95
|
+
# If true, only allow reading from the database. Usefull
|
|
96
|
+
# for maintainance.
|
|
97
|
+
attr_accessor :read_only_mode
|
|
98
|
+
|
|
99
|
+
# If true, the library automatically 'enchants' managed classes.
|
|
100
|
+
# In enchant mode, special db aware methods are added to
|
|
101
|
+
# managed classes and instances.
|
|
102
|
+
attr_accessor :enchant_managed_classes
|
|
103
|
+
|
|
104
|
+
# If true, use Ruby's advanced introspection capabilities to
|
|
105
|
+
# automatically manage classes tha define properties.
|
|
106
|
+
attr_accessor :auto_manage_classes
|
|
118
107
|
|
|
108
|
+
# If true, automatically include the Og meta-language into Module.
|
|
109
|
+
attr_accessor :include_meta_language
|
|
110
|
+
|
|
111
|
+
# Attach the following prefix to all generated SQL table names.
|
|
112
|
+
# Usefull on hosting scenarios where you have to run multiple
|
|
113
|
+
# web applications/sites on a single database.
|
|
114
|
+
attr_accessor :table_prefix
|
|
115
|
+
|
|
116
|
+
# The active database. Og allows you to access multiple
|
|
117
|
+
# databases from a single application.
|
|
118
|
+
attr_accessor :db
|
|
119
|
+
|
|
120
|
+
def use(db)
|
|
121
|
+
@db = db
|
|
122
|
+
@db.get_connection
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# set default options:
|
|
127
|
+
self.read_only_mode = false
|
|
128
|
+
self.enchant_managed_classes = true
|
|
129
|
+
self.auto_manage_classes = true
|
|
130
|
+
self.include_meta_language = true
|
|
131
|
+
self.table_prefix = nil
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# gmosx: leave this here.
|
|
135
|
+
require 'og/enchant'
|
|
136
|
+
require 'og/meta'
|
|
137
|
+
|
|
138
|
+
class Og
|
|
139
|
+
|
|
119
140
|
# = Unmanageable
|
|
120
141
|
#
|
|
121
142
|
# Marker module. If included this in a class, the Og automanager
|
|
@@ -128,6 +149,7 @@ module Unmanageable; end
|
|
|
128
149
|
# Encapsulates an Og Database.
|
|
129
150
|
#
|
|
130
151
|
class Database
|
|
152
|
+
include Og::Enchant
|
|
131
153
|
|
|
132
154
|
# Managed class metadata
|
|
133
155
|
#
|
|
@@ -166,10 +188,10 @@ class Database
|
|
|
166
188
|
require "og/backends/#{backend}"
|
|
167
189
|
eval %{ @config[:backend] = #{backend.capitalize}Backend }
|
|
168
190
|
|
|
169
|
-
@connection_pool =
|
|
170
|
-
@managed_classes =
|
|
191
|
+
@connection_pool = N::Pool.new
|
|
192
|
+
@managed_classes = N::SafeHash.new
|
|
171
193
|
|
|
172
|
-
|
|
194
|
+
Logger.info "Connecting to database '#{@config[:database]}' using backend '#{backend}'."
|
|
173
195
|
|
|
174
196
|
@config[:connection_count].times do
|
|
175
197
|
@connection_pool << Og::Connection.new(self)
|
|
@@ -178,7 +200,7 @@ class Database
|
|
|
178
200
|
# gmosx, FIXME: this automanage code is not elegant and slow
|
|
179
201
|
# should probably recode this, along with glue/property.rb
|
|
180
202
|
#
|
|
181
|
-
if
|
|
203
|
+
if Og.auto_manage_classes
|
|
182
204
|
# automatically manage classes with properties and metadata.
|
|
183
205
|
# gmosx: Any idea how to optimize this?
|
|
184
206
|
classes_to_manage = []
|
|
@@ -187,10 +209,13 @@ class Database
|
|
|
187
209
|
classes_to_manage << c
|
|
188
210
|
end
|
|
189
211
|
end
|
|
190
|
-
|
|
191
|
-
|
|
212
|
+
Logger.info "Og auto manages the following classes:"
|
|
213
|
+
Logger.info "#{classes_to_manage.inspect}"
|
|
192
214
|
manage_classes(*classes_to_manage)
|
|
193
215
|
end
|
|
216
|
+
|
|
217
|
+
# use the newly created database.
|
|
218
|
+
Og.use(self)
|
|
194
219
|
end
|
|
195
220
|
|
|
196
221
|
# Shutdown the database interface.
|
|
@@ -206,8 +231,6 @@ class Database
|
|
|
206
231
|
# Stores the connection in a thread-local variable.
|
|
207
232
|
#
|
|
208
233
|
def get_connection
|
|
209
|
-
$log.debug "Get Og connection" if $DBG
|
|
210
|
-
|
|
211
234
|
thread = Thread.current
|
|
212
235
|
|
|
213
236
|
unless conn = thread[:og_conn]
|
|
@@ -217,12 +240,11 @@ class Database
|
|
|
217
240
|
|
|
218
241
|
return conn
|
|
219
242
|
end
|
|
243
|
+
alias_method :connection, :get_connection
|
|
220
244
|
|
|
221
245
|
# Restore an unused connection to the pool.
|
|
222
246
|
#
|
|
223
247
|
def put_connection
|
|
224
|
-
$log.debug "Put Og connection" if $DBG
|
|
225
|
-
|
|
226
248
|
thread = Thread.current
|
|
227
249
|
|
|
228
250
|
if conn = thread[:og_conn]
|
|
@@ -263,7 +285,7 @@ class Database
|
|
|
263
285
|
convert(klass)
|
|
264
286
|
|
|
265
287
|
# Add helper methods to the class.
|
|
266
|
-
enchant(klass) if
|
|
288
|
+
enchant(klass) if Og.enchant_managed_classes
|
|
267
289
|
end
|
|
268
290
|
|
|
269
291
|
# Helper method to set multiple managed classes.
|
|
@@ -289,13 +311,16 @@ class Database
|
|
|
289
311
|
# Add standard og functionality to the class
|
|
290
312
|
#
|
|
291
313
|
def convert(klass)
|
|
314
|
+
# Grab backend class
|
|
315
|
+
backend = @config[:backend]
|
|
316
|
+
|
|
292
317
|
# gmosx: this check is needed to allow the developer to customize
|
|
293
318
|
# the sql generated for oid
|
|
294
|
-
|
|
319
|
+
backend.eval_og_oid(klass) unless klass.instance_methods.include?(:oid)
|
|
295
320
|
|
|
296
321
|
klass.class_eval %{
|
|
297
|
-
DBTABLE = "#{
|
|
298
|
-
DBSEQ = "#{
|
|
322
|
+
DBTABLE = "#{backend.table(klass)}"
|
|
323
|
+
DBSEQ = "#{backend.table(klass)}_oids_seq"
|
|
299
324
|
|
|
300
325
|
def to_i()
|
|
301
326
|
@oid
|
|
@@ -308,72 +333,9 @@ class Database
|
|
|
308
333
|
# Precompile some code that gets executed all the time.
|
|
309
334
|
# Deletion code is not precompiled, because it is not used
|
|
310
335
|
# as frequently.
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
end
|
|
315
|
-
|
|
316
|
-
# Enchant a managed class. Add useful DB related methods to the
|
|
317
|
-
# class and its instances.
|
|
318
|
-
#
|
|
319
|
-
def enchant(klass)
|
|
320
|
-
klass.module_eval <<-"end_eval", __FILE__, __LINE__
|
|
321
|
-
def self.create(*params)
|
|
322
|
-
obj = #{klass}.new(*params)
|
|
323
|
-
obj.save!
|
|
324
|
-
end
|
|
325
|
-
|
|
326
|
-
def self.save(obj)
|
|
327
|
-
$og << obj
|
|
328
|
-
end
|
|
329
|
-
|
|
330
|
-
def self.load(oid_or_name)
|
|
331
|
-
$og.load(oid_or_name, #{klass})
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
def self.[](oid_or_name)
|
|
335
|
-
$og.load(oid_or_name, #{klass})
|
|
336
|
-
end
|
|
337
|
-
|
|
338
|
-
def self.load_all(extra_sql = nil)
|
|
339
|
-
$og.load_all(#{klass}, extra_sql)
|
|
340
|
-
end
|
|
341
|
-
|
|
342
|
-
def self.all(extra_sql = nil)
|
|
343
|
-
$og.load_all(#{klass}, extra_sql)
|
|
344
|
-
end
|
|
345
|
-
|
|
346
|
-
def self.count(sql = "SELECT COUNT(*) FROM #{klass::DBTABLE}")
|
|
347
|
-
$og.count(sql, #{klass})
|
|
348
|
-
end
|
|
349
|
-
|
|
350
|
-
def self.select(sql)
|
|
351
|
-
$og.select(sql, #{klass})
|
|
352
|
-
end
|
|
353
|
-
|
|
354
|
-
def self.select_one(sql)
|
|
355
|
-
$og.select_one(sql, #{klass})
|
|
356
|
-
end
|
|
357
|
-
|
|
358
|
-
def self.delete(obj_or_oid)
|
|
359
|
-
$og.delete(obj_or_oid, #{klass})
|
|
360
|
-
end
|
|
361
|
-
|
|
362
|
-
def save
|
|
363
|
-
$og << self
|
|
364
|
-
return self
|
|
365
|
-
end
|
|
366
|
-
alias_method :save!, :save
|
|
367
|
-
|
|
368
|
-
def update_properties(updatesql)
|
|
369
|
-
$og.pupdate(updatesql, self.oid, #{klass})
|
|
370
|
-
end
|
|
371
|
-
alias_method :pupdate!, :update_properties
|
|
372
|
-
|
|
373
|
-
def delete!
|
|
374
|
-
$og.delete(@oid, #{klass})
|
|
375
|
-
end
|
|
376
|
-
end_eval
|
|
336
|
+
backend.eval_og_insert(klass)
|
|
337
|
+
backend.eval_og_update(klass)
|
|
338
|
+
backend.eval_og_deserialize(klass, self)
|
|
377
339
|
end
|
|
378
340
|
|
|
379
341
|
# Automatically wrap connection methods.
|
|
@@ -412,19 +374,23 @@ class Database
|
|
|
412
374
|
wrap_method :query, "sql"
|
|
413
375
|
wrap_method :exec, "sql"
|
|
414
376
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
end
|
|
419
|
-
|
|
420
|
-
def self.drop_db!(config)
|
|
421
|
-
backend = config[:backend] || "psql"
|
|
422
|
-
require "og/backends/#{backend}"
|
|
423
|
-
eval %{
|
|
424
|
-
#{backend.capitalize}Backend.drop_db(config[:database], config[:user],
|
|
377
|
+
class << self
|
|
378
|
+
def create_db!(config)
|
|
379
|
+
get_connection().db.create_db(config[:database], config[:user],
|
|
425
380
|
config[:password])
|
|
426
|
-
|
|
381
|
+
end
|
|
382
|
+
alias_method :create!, :create_db!
|
|
383
|
+
|
|
384
|
+
def drop_db!(config)
|
|
385
|
+
backend = config[:backend] || "psql"
|
|
386
|
+
require "og/backends/#{backend}"
|
|
387
|
+
eval %{
|
|
388
|
+
#{backend.capitalize}Backend.drop_db(config[:database], config[:user],
|
|
389
|
+
config[:password])
|
|
390
|
+
}
|
|
391
|
+
end
|
|
392
|
+
alias_method :drop!, :drop_db!
|
|
427
393
|
end
|
|
428
394
|
end
|
|
429
395
|
|
|
430
|
-
end #
|
|
396
|
+
end # namespace
|