nitro 0.5.0 → 0.6.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 +4 -2201
- data/ChangeLog.1 +2344 -0
- data/README +4 -4
- data/RELEASES +22 -0
- data/bin/new_app.rb +17 -3
- data/bin/proto/README +34 -0
- data/bin/proto/apache.conf +1 -0
- data/bin/proto/app.rb +20 -0
- data/bin/proto/config.rb +77 -0
- data/bin/proto/root/index.xhtml +43 -0
- data/bin/proto/root/style.css +218 -0
- data/bin/proto/root/style.xsl +130 -0
- data/examples/blog/app.rb +1 -2
- data/examples/blog/config.rb +20 -18
- data/examples/blog/env.rb +22 -0
- data/examples/blog/lib/blog.rb +43 -15
- data/examples/blog/root/entry_form.xhtml +1 -1
- data/examples/blog/root/index.xhtml +5 -0
- data/examples/blog/root/login.xhtml +2 -0
- data/examples/blog/root/m/nitro.gif +0 -0
- data/examples/blog/root/style.css +83 -0
- data/examples/blog/root/style.xsl +7 -3
- data/examples/og/run.rb +41 -2
- data/examples/tiny/app.rb +1 -2
- data/examples/tiny/root/index.xhtml +8 -2
- data/examples/tiny/root/nitro-small.png +0 -0
- data/lib/glue.rb +1 -1
- data/lib/glue/property.rb +9 -3
- data/lib/nitro/application.rb +18 -1
- data/lib/nitro/builders/form.rb +84 -0
- data/lib/nitro/builders/rss.rb +4 -5
- data/lib/nitro/builders/table.rb +23 -0
- data/lib/nitro/filters.rb +157 -0
- data/lib/nitro/l10n.rb +11 -3
- data/lib/nitro/scaffold.rb +1 -1
- data/lib/nitro/server/render.rb +101 -4
- data/lib/nitro/server/shaders.rb +17 -5
- data/lib/nitro/service.rb +5 -5
- data/lib/nitro/ui/pager.rb +35 -11
- data/lib/nitro/version.rb +2 -2
- data/lib/og.rb +25 -17
- data/lib/og/backend.rb +15 -3
- data/lib/og/backends/mysql.rb +30 -3
- data/lib/og/backends/psql.rb +44 -3
- data/lib/og/meta.rb +117 -10
- data/lib/og/version.rb +1 -1
- data/lib/xsl/base.xsl +75 -6
- data/lib/xsl/ui.xsl +51 -0
- data/test/nitro/ui/tc_pager.rb +6 -0
- metadata +23 -2
data/lib/nitro/l10n.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
# = L10N, Localization support
|
2
2
|
#
|
3
|
-
# code:
|
3
|
+
# code: gmosx
|
4
4
|
#
|
5
5
|
# (c) 2002-2003 Navel, all rights reserved.
|
6
|
-
# $Id: l10n.rb
|
6
|
+
# $Id: l10n.rb 185 2004-12-10 13:29:09Z gmosx $
|
7
|
+
|
8
|
+
require 'nitro/filters'
|
7
9
|
|
8
10
|
$lc_en = {}
|
9
11
|
$lc_el = {}
|
@@ -12,7 +14,6 @@ $lc_el = {}
|
|
12
14
|
#
|
13
15
|
# Override as needed in your application.
|
14
16
|
#
|
15
|
-
|
16
17
|
$lc_map = {
|
17
18
|
"en" => $lc_en,
|
18
19
|
"el" => $lc_el
|
@@ -20,3 +21,10 @@ $lc_map = {
|
|
20
21
|
|
21
22
|
# The locales to use for this application.
|
22
23
|
$lc_use = %w{lc-en lc-el}
|
24
|
+
|
25
|
+
module LocalizationFilter
|
26
|
+
def localize
|
27
|
+
@lc = @session[:LC] || $lc_en
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
data/lib/nitro/scaffold.rb
CHANGED
data/lib/nitro/server/render.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# * George Moschovitis <gm@navel.gr>
|
3
3
|
#
|
4
4
|
# (c) 2004 Navel, all rights reserved.
|
5
|
-
# $Id: render.rb
|
5
|
+
# $Id: render.rb 185 2004-12-10 13:29:09Z gmosx $
|
6
6
|
|
7
7
|
module N
|
8
8
|
|
@@ -105,7 +105,15 @@ module RenderUtils
|
|
105
105
|
@response.header['Content-Type'] = 'text/html'
|
106
106
|
@out ||= ''
|
107
107
|
}
|
108
|
+
|
109
|
+
# call 'before' filter chain.
|
110
|
+
if klass.respond_to?(:before_filters)
|
111
|
+
code << %{
|
112
|
+
#{klass.gen_filters_call_code(klass.before_filters)}
|
113
|
+
}
|
114
|
+
end
|
108
115
|
|
116
|
+
# call the action
|
109
117
|
if klass.instance_methods.include?(meth)
|
110
118
|
valid = true
|
111
119
|
code << %{
|
@@ -113,6 +121,7 @@ module RenderUtils
|
|
113
121
|
}
|
114
122
|
end
|
115
123
|
|
124
|
+
# call the programmatically generated template if exists.
|
116
125
|
if klass.instance_methods.include?("#{meth}__xhtml")
|
117
126
|
valid = true
|
118
127
|
code << %{
|
@@ -120,6 +129,7 @@ module RenderUtils
|
|
120
129
|
}
|
121
130
|
end
|
122
131
|
|
132
|
+
# call the template
|
123
133
|
if template = template_for_method(base, meth)
|
124
134
|
valid = true
|
125
135
|
code << %{
|
@@ -128,6 +138,13 @@ module RenderUtils
|
|
128
138
|
end
|
129
139
|
|
130
140
|
raise "Invalid method '#{meth}' for service '#{klass}'!" unless valid
|
141
|
+
|
142
|
+
# call 'after' filter chain.
|
143
|
+
if klass.respond_to?(:after_filters)
|
144
|
+
code << %{
|
145
|
+
#{klass.gen_filters_call_code(klass.after_filters)}
|
146
|
+
}
|
147
|
+
end
|
131
148
|
|
132
149
|
code << %{
|
133
150
|
redirect_referer if @out.empty?
|
@@ -142,6 +159,8 @@ module RenderUtils
|
|
142
159
|
}
|
143
160
|
end
|
144
161
|
|
162
|
+
# puts '++', code, '++'
|
163
|
+
|
145
164
|
klass.class_eval(code)
|
146
165
|
|
147
166
|
return "__#{meth}"
|
@@ -160,6 +179,14 @@ module RenderUtils
|
|
160
179
|
@out ||= ''
|
161
180
|
}
|
162
181
|
|
182
|
+
# call 'before' filter chain.
|
183
|
+
if klass.respond_to?(:before_filters)
|
184
|
+
code << %{
|
185
|
+
#{klass.gen_filters_call_code(klass.before_filters)}
|
186
|
+
}
|
187
|
+
end
|
188
|
+
|
189
|
+
# call the action
|
163
190
|
if klass.instance_methods.include?(meth)
|
164
191
|
valid = true
|
165
192
|
code << %{
|
@@ -167,6 +194,7 @@ module RenderUtils
|
|
167
194
|
}
|
168
195
|
end
|
169
196
|
|
197
|
+
# call the programmatically generated template if exists.
|
170
198
|
if klass.instance_methods.include?("#{meth}__xml")
|
171
199
|
valid = true
|
172
200
|
code << %{
|
@@ -174,6 +202,7 @@ module RenderUtils
|
|
174
202
|
}
|
175
203
|
end
|
176
204
|
|
205
|
+
# call the template
|
177
206
|
if template = template_for_method(base, meth, 'xml')
|
178
207
|
valid = true
|
179
208
|
code << %{
|
@@ -182,7 +211,14 @@ module RenderUtils
|
|
182
211
|
end
|
183
212
|
|
184
213
|
raise "Invalid method '#{meth}' for service #{klass}!" unless valid
|
185
|
-
|
214
|
+
|
215
|
+
# call 'after' filter chain.
|
216
|
+
if klass.respond_to?(:after_filters)
|
217
|
+
code << %{
|
218
|
+
#{klass.gen_filters_call_code(klass.after_filters)}
|
219
|
+
}
|
220
|
+
end
|
221
|
+
|
186
222
|
code << %{
|
187
223
|
end
|
188
224
|
}
|
@@ -200,6 +236,17 @@ module RenderUtils
|
|
200
236
|
return "__rest_#{meth}"
|
201
237
|
end
|
202
238
|
|
239
|
+
#
|
240
|
+
#
|
241
|
+
def load_statically_included(filename)
|
242
|
+
$log.debug "Statically including '#{filename}'" if $DBG
|
243
|
+
|
244
|
+
text = File.read(filename)
|
245
|
+
text.gsub!(/<\?xml.*\?>/, '')
|
246
|
+
text.gsub!(/<\/?root(.*?)>/m, ' ');
|
247
|
+
|
248
|
+
return text
|
249
|
+
end
|
203
250
|
|
204
251
|
end
|
205
252
|
|
@@ -234,6 +281,8 @@ module Render
|
|
234
281
|
@response = response
|
235
282
|
@session = session
|
236
283
|
@params = request.query
|
284
|
+
|
285
|
+
@out_buffers = nil
|
237
286
|
end
|
238
287
|
|
239
288
|
# Returns the output of the rendering as string.
|
@@ -268,6 +317,9 @@ module Render
|
|
268
317
|
if self.class == render_class
|
269
318
|
self.send(meth)
|
270
319
|
else
|
320
|
+
if $reload_scripts and defined?(render_class::SOURCE_FILE)
|
321
|
+
load(render_class::SOURCE_FILE)
|
322
|
+
end
|
271
323
|
r = render_class.new(base, @request, @response, @session)
|
272
324
|
r.send(meth)
|
273
325
|
@out = r.out
|
@@ -276,7 +328,7 @@ module Render
|
|
276
328
|
log_error "error while handling '#{path}'."
|
277
329
|
log_error pp_exception(e)
|
278
330
|
# more fault tolerant, only flags the erroneous box with
|
279
|
-
#
|
331
|
+
# error not the full page.
|
280
332
|
@out << '(error)'
|
281
333
|
end
|
282
334
|
|
@@ -311,12 +363,57 @@ module Render
|
|
311
363
|
end
|
312
364
|
|
313
365
|
# Log a rendering error.
|
314
|
-
|
366
|
+
#--
|
367
|
+
# FIXME: find a better name
|
368
|
+
#++
|
315
369
|
def log_error(str)
|
316
370
|
@rendering_errors ||= []
|
317
371
|
@rendering_errors << str
|
318
372
|
$log.error str
|
319
373
|
end
|
374
|
+
|
375
|
+
# --------------------------------------------------------------------
|
376
|
+
# Output buffering methods.
|
377
|
+
|
378
|
+
# Start (push) a new output buffer.
|
379
|
+
#
|
380
|
+
def ob_start
|
381
|
+
@out_buffers = [] unless @out_buffers
|
382
|
+
@out_buffers.push(@out)
|
383
|
+
@out = ''
|
384
|
+
end
|
385
|
+
|
386
|
+
# End (pop) the current output buffer.
|
387
|
+
#
|
388
|
+
def ob_end
|
389
|
+
@out = @out_buffers.pop
|
390
|
+
end
|
391
|
+
|
392
|
+
# End (pop) the current output buffer and write to the parent.
|
393
|
+
#
|
394
|
+
def ob_write_end
|
395
|
+
nested_buffer = @out
|
396
|
+
@out = @out_buffers.pop
|
397
|
+
@out << nested_buffer
|
398
|
+
end
|
399
|
+
# --------------------------------------------------------------------
|
400
|
+
# Caching methods.
|
401
|
+
|
402
|
+
#--
|
403
|
+
# FIXME: pseudocode, not working.
|
404
|
+
#++
|
405
|
+
def cache_start
|
406
|
+
valid?
|
407
|
+
ob_start
|
408
|
+
end
|
409
|
+
|
410
|
+
#--
|
411
|
+
# FIXME: pseudocode, not working.
|
412
|
+
#++
|
413
|
+
def cache_end
|
414
|
+
save_fragment(@out)
|
415
|
+
ob_write_end
|
416
|
+
end
|
320
417
|
end
|
321
418
|
|
322
419
|
end # module
|
data/lib/nitro/server/shaders.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# * George Moschovitis <gm@navel.gr>
|
3
3
|
#
|
4
4
|
# (c) 2004 Navel, all rights reserved.
|
5
|
-
# $Id: shaders.rb
|
5
|
+
# $Id: shaders.rb 188 2004-12-10 14:14:17Z gmosx $
|
6
6
|
|
7
7
|
module N
|
8
8
|
|
@@ -66,6 +66,9 @@ class RubyShader < N::Shader
|
|
66
66
|
# strip the xml header! (interracts with the following gsub!)
|
67
67
|
text.gsub!(/<\?xml.*\?>/, "")
|
68
68
|
|
69
|
+
# statically include files.
|
70
|
+
# TODO: Add here!
|
71
|
+
|
69
72
|
# xform include instructions <include href="xxx" />
|
70
73
|
# must be transformed before the processinc instructions.
|
71
74
|
text.gsub!(/<include href="(.*?)"(.*)(.?)\/>/) { |match|
|
@@ -75,19 +78,28 @@ class RubyShader < N::Shader
|
|
75
78
|
# remove <root> elements. typically removed by xslt but lets
|
76
79
|
# play it safe.
|
77
80
|
text.gsub!(/<(\/)?root>/, '')
|
78
|
-
|
81
|
+
|
82
|
+
# runtime ruby code.
|
83
|
+
|
79
84
|
# xform the processing instructions, use <?r as
|
80
85
|
# a marker.
|
81
86
|
text.gsub!(/\?>/, "\n@out << %^")
|
82
|
-
text.gsub!(/<\?r
|
87
|
+
text.gsub!(/<\?r(\s?)/, "^\n")
|
83
88
|
|
84
|
-
# xform alternative code tags (
|
89
|
+
# xform alternative code tags (very useful in xsl stylesheets)
|
85
90
|
#
|
86
91
|
text.gsub!(/<\/ruby>/, "\n@out << %^")
|
87
92
|
text.gsub!(/<ruby>/, "^\n")
|
88
93
|
|
89
|
-
|
94
|
+
# compile time ruby code.
|
95
|
+
# Usefull for example to prevaluate localization.
|
90
96
|
|
97
|
+
text.gsub!(/\#\[(.*?)\]/) { |match|
|
98
|
+
eval($1)
|
99
|
+
}
|
100
|
+
|
101
|
+
text = "@out << %^" + text + "^"
|
102
|
+
|
91
103
|
process_next(hash, text)
|
92
104
|
end
|
93
105
|
|
data/lib/nitro/service.rb
CHANGED
@@ -2,25 +2,25 @@
|
|
2
2
|
# * George Moschovitis <gm@navel.gr>
|
3
3
|
#
|
4
4
|
# (c) 2004 Navel, all rights reserved.
|
5
|
-
# $Id: service.rb
|
5
|
+
# $Id: service.rb 185 2004-12-10 13:29:09Z gmosx $
|
6
6
|
|
7
7
|
require 'nitro/server/render'
|
8
8
|
require 'nitro/scaffold'
|
9
|
+
require 'nitro/filters'
|
9
10
|
|
10
11
|
module N
|
11
12
|
|
12
13
|
# = Service
|
13
14
|
#
|
14
|
-
#
|
15
|
+
# Defines an application service.
|
15
16
|
#
|
16
17
|
class Service
|
17
18
|
include N::Render
|
19
|
+
include N::Scaffolding
|
20
|
+
include N::Filtering
|
18
21
|
|
19
22
|
# The base path of the service, essentially the mount point.
|
20
23
|
attr :base_path
|
21
24
|
end
|
22
25
|
|
23
|
-
class Methods
|
24
|
-
end
|
25
|
-
|
26
26
|
end # module
|
data/lib/nitro/ui/pager.rb
CHANGED
@@ -2,7 +2,9 @@
|
|
2
2
|
# * George Moschovitis <gm@navel.gr>
|
3
3
|
#
|
4
4
|
# (c) 2004 Navel, all rights reserved.
|
5
|
-
# $Id: pager.rb
|
5
|
+
# $Id: pager.rb 185 2004-12-10 13:29:09Z gmosx $
|
6
|
+
|
7
|
+
require 'nitro/uri'
|
6
8
|
|
7
9
|
module N; module UI
|
8
10
|
|
@@ -20,11 +22,28 @@ module N; module UI
|
|
20
22
|
# The pager does not extend Array (it includes an Array instead) to
|
21
23
|
# avoid a concat() in the initialization step.
|
22
24
|
#
|
23
|
-
# TODO:
|
24
|
-
# - Extend from array? (would be more elegant)
|
25
25
|
#
|
26
26
|
# === Example:
|
27
27
|
#
|
28
|
+
# @pager = N::UI::Pager.new('entries', @request, 5)
|
29
|
+
# @entries = N::BlogEntry.all("ORDER BY oid #{@pager.sql_limit}")
|
30
|
+
# @pager.set(N::BlogEntry.count)
|
31
|
+
#
|
32
|
+
# default navigation (customize with css):
|
33
|
+
# <div class="pager">#{@pager.navigation}</div>
|
34
|
+
#
|
35
|
+
# custom navigation:
|
36
|
+
#
|
37
|
+
# <table cellspacing="0" width="100%" border="1">
|
38
|
+
# <tr>
|
39
|
+
# <td width="64"><x:pager-prev>Previous</x:pager-prev></td>
|
40
|
+
# <td width="100%"></td>
|
41
|
+
# <td width="64"><x:pager-next>Next</x:pager-next></td>
|
42
|
+
# </tr>
|
43
|
+
# </table>
|
44
|
+
#
|
45
|
+
# === Investigate:
|
46
|
+
#
|
28
47
|
# INVESTIGATE:
|
29
48
|
# mysql> SELECT SQL_CALC_FOUND_ROWS * FROM tbl_name
|
30
49
|
# -> WHERE id > 100 LIMIT 10;
|
@@ -39,11 +58,11 @@ class Pager < Array
|
|
39
58
|
# read needed variables from the request.
|
40
59
|
attr_accessor :request
|
41
60
|
|
42
|
-
def initialize(name, request, items_per_page, items = nil)
|
61
|
+
def initialize(name, request, items_per_page = 10, items = nil)
|
43
62
|
raise "items_per_page should be > 0" unless items_per_page > 0
|
44
63
|
|
45
64
|
@request, @name = request, name
|
46
|
-
@page = request.
|
65
|
+
@page = request.query.fetch("__pg#{@name}", 1).to_i
|
47
66
|
@items_per_page = items_per_page
|
48
67
|
@start_idx = (@page - 1) * items_per_page
|
49
68
|
|
@@ -131,15 +150,15 @@ class Pager < Array
|
|
131
150
|
|
132
151
|
unless @page == first_page()
|
133
152
|
nav << %{
|
134
|
-
<div class="first"><a href="#{target_uri(first_page())}"
|
135
|
-
<div class="previous"><a href="#{target_uri(previous_page())}"
|
153
|
+
<div class="first"><a href="#{target_uri(first_page())}">First</a></div>
|
154
|
+
<div class="previous"><a href="#{target_uri(previous_page())}">Previous</a></div>
|
136
155
|
}
|
137
156
|
end
|
138
157
|
|
139
158
|
unless @page == last_page()
|
140
159
|
nav << %{
|
141
|
-
<div class="last"><a href="#{target_uri(last_page())}"
|
142
|
-
<div class="next"><a href="#{target_uri(next_page())}"
|
160
|
+
<div class="last"><a href="#{target_uri(last_page())}">Last</a></div>
|
161
|
+
<div class="next"><a href="#{target_uri(next_page())}">Next</a></div>
|
143
162
|
}
|
144
163
|
end
|
145
164
|
|
@@ -174,15 +193,20 @@ class Pager < Array
|
|
174
193
|
end
|
175
194
|
end
|
176
195
|
|
196
|
+
# Returns the current offset. The offset is zero-based.
|
197
|
+
#
|
198
|
+
def offset
|
199
|
+
(@page-1) * @items_per_page
|
200
|
+
end
|
201
|
+
|
177
202
|
# ------------------------------------------------------------------
|
178
203
|
|
179
204
|
# Generate the target URI.
|
180
205
|
#
|
181
206
|
def target_uri(page)
|
182
207
|
params = {"__pg#{@name}" => page}
|
183
|
-
return N::UriUtils.update_query_string(@request.
|
208
|
+
return N::UriUtils.update_query_string(@request.request_uri.to_s, params)
|
184
209
|
end
|
185
|
-
private :target_uri
|
186
210
|
|
187
211
|
end
|
188
212
|
|
data/lib/nitro/version.rb
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
# * George Moschovitis <gm@navel.gr>
|
3
3
|
#
|
4
4
|
# (c) 2004 Navel, all rights reserved.
|
5
|
-
# $Id: version.rb
|
5
|
+
# $Id: version.rb 185 2004-12-10 13:29:09Z gmosx $
|
6
6
|
|
7
7
|
# The name of the server.
|
8
8
|
$srv_name = 'Nitro'
|
9
9
|
|
10
10
|
# The version of the server.
|
11
|
-
$srv_version = '0.
|
11
|
+
$srv_version = '0.6.0'
|
data/lib/og.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# * George Moschovitis <gm@navel.gr>
|
3
3
|
#
|
4
4
|
# (c) 2004 Navel, all rights reserved.
|
5
|
-
# $Id: og.rb
|
5
|
+
# $Id: og.rb 185 2004-12-10 13:29:09Z gmosx $
|
6
6
|
|
7
7
|
require "glue/property"
|
8
8
|
require "glue/array"
|
@@ -10,6 +10,24 @@ require "glue/hash"
|
|
10
10
|
require "glue/time"
|
11
11
|
require "glue/pool"
|
12
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
|
+
|
13
31
|
require "og/meta"
|
14
32
|
|
15
33
|
# = Og
|
@@ -93,21 +111,6 @@ require "og/meta"
|
|
93
111
|
#
|
94
112
|
module Og
|
95
113
|
|
96
|
-
# If true, only allow reading from the database. Usefull
|
97
|
-
# for maintainance.
|
98
|
-
#
|
99
|
-
$og_read_only_mode = false
|
100
|
-
|
101
|
-
# If true, the library automatically 'enchants' managed classes.
|
102
|
-
# In enchant mode, special db aware methods are added to
|
103
|
-
# managed classes and instances.
|
104
|
-
#
|
105
|
-
$og_enchant_managed_classes = true
|
106
|
-
|
107
|
-
# If true, use Ruby's advanced introspection capabilities to
|
108
|
-
# automatically manage classes tha define properties.
|
109
|
-
$og_auto_manage_classes = true
|
110
|
-
|
111
114
|
# = Unmanageable
|
112
115
|
#
|
113
116
|
# Marker module. If included this in a class, the Og automanager
|
@@ -328,7 +331,11 @@ class Database
|
|
328
331
|
def self.all(extra_sql = nil)
|
329
332
|
$og.load_all(#{klass}, extra_sql)
|
330
333
|
end
|
331
|
-
|
334
|
+
|
335
|
+
def self.count(sql = "SELECT COUNT(*) FROM #{klass::DBTABLE}")
|
336
|
+
$og.count(sql, #{klass})
|
337
|
+
end
|
338
|
+
|
332
339
|
def self.select(sql)
|
333
340
|
$og.select(sql, #{klass})
|
334
341
|
end
|
@@ -343,6 +350,7 @@ class Database
|
|
343
350
|
|
344
351
|
def save
|
345
352
|
$og << self
|
353
|
+
return self
|
346
354
|
end
|
347
355
|
alias_method :save!, :save
|
348
356
|
|