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.
Files changed (99) hide show
  1. data/AUTHORS +4 -1
  2. data/ChangeLog +290 -7
  3. data/README +3 -3
  4. data/RELEASES +94 -0
  5. data/Rakefile +7 -7
  6. data/benchmark/og/bench.rb +11 -10
  7. data/{ChangeLog.1 → doc/ChangeLog.1} +0 -0
  8. data/doc/apache.txt +9 -0
  9. data/doc/architecture.txt +1 -27
  10. data/doc/bugs.txt +11 -4
  11. data/doc/config.txt +22 -0
  12. data/doc/og_config.txt +35 -0
  13. data/doc/og_tutorial.txt +595 -0
  14. data/doc/tutorial.txt +22 -0
  15. data/examples/blog/conf/apache.conf +30 -0
  16. data/examples/blog/conf/lhttpd.conf +2 -2
  17. data/examples/blog/lib/blog/controller.rb +11 -2
  18. data/examples/blog/log/apache.error_log +5528 -0
  19. data/examples/blog/root/fcgi.rb +1 -1
  20. data/examples/blog/run.rb +9 -3
  21. data/examples/flash/run.rb +2 -2
  22. data/examples/no_xsl_blog/conf/apache.conf +30 -0
  23. data/examples/no_xsl_blog/conf/lhttpd.conf +1 -1
  24. data/examples/no_xsl_blog/lib/blog/controller.rb +2 -2
  25. data/examples/no_xsl_blog/log/apache.error_log +68 -0
  26. data/examples/no_xsl_blog/root/fcgi.rb +2 -2
  27. data/examples/no_xsl_blog/run.rb +3 -3
  28. data/examples/og/run.rb +1 -1
  29. data/examples/tiny/conf/apache.conf +29 -4
  30. data/examples/tiny/conf/lhttpd.conf +1 -1
  31. data/examples/tiny/log/apache.error_log +30 -0
  32. data/examples/tiny/root/fcgi.rb +2 -2
  33. data/examples/tiny/root/index.xhtml +1 -1
  34. data/examples/tiny/run.rb +3 -2
  35. data/examples/wee_style/run.rb +7 -9
  36. data/examples/why_wiki/README +5 -0
  37. data/examples/why_wiki/run.rb +57 -0
  38. data/examples/why_wiki/wiki.yml +6 -0
  39. data/examples/wiki.yml +1 -0
  40. data/lib/glue/array.rb +14 -33
  41. data/lib/glue/hash.rb +32 -53
  42. data/lib/glue/pool.rb +9 -12
  43. data/lib/glue/property.rb +31 -9
  44. data/lib/nitro.rb +30 -8
  45. data/lib/nitro/adapters/cgi.rb +23 -3
  46. data/lib/nitro/adapters/webrick.rb +9 -3
  47. data/lib/nitro/builders/form.rb +21 -13
  48. data/lib/nitro/builders/rss.rb +20 -9
  49. data/lib/nitro/builders/table.rb +69 -10
  50. data/lib/nitro/builders/xhtml.rb +13 -4
  51. data/lib/nitro/component.rb +15 -0
  52. data/lib/nitro/conf.rb +4 -3
  53. data/lib/nitro/context.rb +22 -14
  54. data/lib/nitro/controller.rb +63 -5
  55. data/lib/nitro/dispatcher.rb +11 -6
  56. data/lib/nitro/output.rb +28 -0
  57. data/lib/nitro/render.rb +78 -59
  58. data/lib/nitro/request.rb +5 -1
  59. data/lib/nitro/runner.rb +20 -6
  60. data/lib/nitro/session.rb +89 -18
  61. data/lib/nitro/session/drb.rb +31 -0
  62. data/lib/nitro/session/drbserver.rb +71 -0
  63. data/lib/nitro/session/memory.rb +13 -0
  64. data/lib/nitro/simple.rb +7 -0
  65. data/lib/nitro/ui/date-select.rb +2 -5
  66. data/lib/nitro/ui/pager.rb +4 -4
  67. data/lib/nitro/ui/tabs.rb +2 -4
  68. data/lib/nitro/uri.rb +7 -4
  69. data/lib/og.rb +20 -12
  70. data/lib/og/adapter.rb +40 -13
  71. data/lib/og/adapters/filesys.rb +121 -0
  72. data/lib/og/adapters/mysql.rb +10 -5
  73. data/lib/og/adapters/oracle.rb +374 -0
  74. data/lib/og/adapters/psql.rb +10 -23
  75. data/lib/og/adapters/sqlite.rb +3 -3
  76. data/lib/og/backend.rb +2 -2
  77. data/lib/og/connection.rb +6 -6
  78. data/lib/og/database.rb +5 -5
  79. data/lib/og/enchant.rb +6 -2
  80. data/lib/og/meta.rb +56 -26
  81. data/lib/og/mock.rb +1 -1
  82. data/lib/og/typemacros.rb +23 -0
  83. data/lib/parts/content.rb +4 -10
  84. data/test/nitro/adapters/tc_cgi.rb +1 -1
  85. data/test/nitro/builders/tc_rss.rb +1 -1
  86. data/test/nitro/builders/tc_table.rb +30 -0
  87. data/test/nitro/tc_context.rb +4 -0
  88. data/test/nitro/tc_controller.rb +9 -2
  89. data/test/og/tc_filesys.rb +83 -0
  90. data/test/og/tc_meta.rb +55 -0
  91. data/test/tc_og.rb +115 -36
  92. data/vendor/README +11 -5
  93. data/vendor/breakpoint.rb +35 -38
  94. data/vendor/breakpoint_client.rb +119 -80
  95. data/vendor/composite_sexp_processor.rb +43 -0
  96. data/vendor/parse_tree.rb +745 -0
  97. data/vendor/sexp_processor.rb +453 -0
  98. metadata +34 -7
  99. data/examples/no_xsl_blog/conf/app.conf.rb +0 -47
@@ -0,0 +1,31 @@
1
+ # * George Moschovitis <gm@navel.gr>
2
+ # (c) 2004-2005 Navel, all rights reserved.
3
+ # $Id: drb.rb 264 2005-02-23 13:46:55Z gmosx $
4
+
5
+ require 'drb'
6
+
7
+ require 'glue/attribute'
8
+ require 'nitro/session'
9
+
10
+ Logger.debug 'Using Drb sessions.'
11
+
12
+ module N
13
+
14
+ class Session
15
+
16
+ # The address of the Session DRb server.
17
+
18
+ cattr_accessor :drb_address, '127.0.0.1'
19
+
20
+ # The port of the Session DRb server.
21
+
22
+ cattr_accessor :drb_port, 9069
23
+
24
+ end
25
+
26
+ Session.store = DRbObject.new(
27
+ nil,
28
+ "druby://#{Session.drb_address}:#{Session.drb_port}"
29
+ )
30
+
31
+ end
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # * George Moschovitis <gm@navel.gr>
4
+ # (c) 2004-2005 Navel, all rights reserved.
5
+ # $Id: drbserver.rb 264 2005-02-23 13:46:55Z gmosx $
6
+
7
+ require 'drb'
8
+ require 'optparse'
9
+
10
+ require 'glue/hash'
11
+ require 'nitro/session'
12
+
13
+ # A distributes session store implemented as
14
+ # a simple DRb server.
15
+
16
+ address = '127.0.0.1'
17
+ port = 9069
18
+ debug = false
19
+
20
+ parser = OptionParser.new do |opts|
21
+
22
+ opts.banner = 'Usage: drbserver.rb [options]'
23
+ opts.separator ''
24
+ opts.separator 'Specific options:'
25
+
26
+ opts.on('-a A', '--address A', 'Listening address.') do |a|
27
+ address = a
28
+ end
29
+
30
+ opts.on('-p P', '--port P', Integer, 'Listening port.') do |p|
31
+ port = p
32
+ end
33
+
34
+ opts.on('-D', '--debug', 'Run in debug mode.') do |p|
35
+ debug = true
36
+ end
37
+
38
+ opts.on_tail('-h', '--help', 'Show this message.') do
39
+ puts opts
40
+ exit
41
+ end
42
+
43
+ end
44
+
45
+ begin
46
+ parser.parse!(ARGV)
47
+ rescue OptionParser::InvalidOption
48
+ puts 'Invalid option, pass the --help parameter to get help!'
49
+ exit
50
+ end
51
+
52
+ sessions = N::SafeHash.new
53
+
54
+ if debug
55
+
56
+ class << sessions
57
+ def []=(k, v)
58
+ puts "WRITE: #{k} = #{v}"
59
+ super
60
+ end
61
+
62
+ def [](k)
63
+ puts "READ: #{k}"
64
+ super
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+ DRb.start_service("druby://#{address}:#{port}", sessions)
71
+ DRb.thread.join
@@ -0,0 +1,13 @@
1
+ # * George Moschovitis <gm@navel.gr>
2
+ # (c) 2004-2005 Navel, all rights reserved.
3
+ # $Id: memory.rb 264 2005-02-23 13:46:55Z gmosx $
4
+
5
+ require 'glue/hash'
6
+
7
+ Logger.debug 'Using In-Memory sessions.'
8
+
9
+ module N
10
+
11
+ Session.store = SafeHash.new
12
+
13
+ end
@@ -0,0 +1,7 @@
1
+ require 'nitro/controller'
2
+
3
+ # A simple controller, only handles templates.
4
+ # Useful to implement php/asp/jsp style applications.
5
+ # Dispatcher uses this as the default Controller.
6
+
7
+ class SimpleController < N::Controller; end
@@ -1,7 +1,5 @@
1
- # code:
2
1
  # * George Moschovitis <gm@navel.gr>
3
- #
4
- # (c) 2004 Navel, all rights reserved.
2
+ # (c) 2004-2005 Navel, all rights reserved.
5
3
  # $Id: select.rb 39 2004-09-29 12:40:53Z elathan $
6
4
 
7
5
  module N; module UI
@@ -68,5 +66,4 @@ module N; module UI
68
66
  return str
69
67
  end
70
68
 
71
- end; end # module
72
-
69
+ end; end
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: pager.rb 254 2005-02-10 12:44:05Z gmosx $
3
+ # $Id: pager.rb 266 2005-02-28 14:50:48Z gmosx $
4
4
 
5
5
  require 'nitro/uri'
6
6
 
@@ -17,9 +17,9 @@ module N; module UI
17
17
  #
18
18
  # === Example
19
19
  #
20
- # @pager = N::UI::Pager.new('entries', @request, 5)
21
- # @entries = N::BlogEntry.all("ORDER BY oid #{@pager.sql_limit}")
22
- # @pager.set(N::BlogEntry.count)
20
+ # @pager = UI::Pager.new('entries', @request, 5)
21
+ # @entries = BlogEntry.all("ORDER BY oid #{@pager.sql_limit}")
22
+ # @pager.set(BlogEntry.count)
23
23
  #
24
24
  # default navigation (customize with css):
25
25
  # <div class="pager">#{@pager.navigation}</div>
@@ -1,8 +1,6 @@
1
- # code:
2
1
  # * George Moschovitis <gm@navel.gr>
3
- #
4
- # (c) 2004 Navel, all rights reserved.
5
- # $Id: tabs.rb 101 2004-10-22 12:35:39Z gmosx $
2
+ # (c) 2004-2005 Navel, all rights reserved.
3
+ # $Id: tabs.rb 266 2005-02-28 14:50:48Z gmosx $
6
4
 
7
5
  module N; module UI
8
6
 
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: uri.rb 254 2005-02-10 12:44:05Z gmosx $
3
+ # $Id: uri.rb 263 2005-02-23 13:45:08Z gmosx $
4
4
 
5
5
  require "uri"
6
6
  require "cgi"
@@ -9,9 +9,9 @@ require "glue/string"
9
9
 
10
10
  module N
11
11
 
12
- # URI utilities collection
12
+ # URI utilities collection.
13
13
  #
14
- # === Design:
14
+ # === Design
15
15
  #
16
16
  # Implement as a module to avoid class polution. You can still
17
17
  # use Ruby's advanced features to include the module in your
@@ -19,11 +19,14 @@ module N
19
19
  # which isn't possible if you use self.
20
20
  #
21
21
  # The uris passed as parameters are typically strings.
22
+ #--
23
+ # gmosx, TODO: deprecate this.
24
+ #++
22
25
 
23
26
  module UriUtils
24
27
 
25
28
  # Decode the uri components.
26
- #
29
+
27
30
  def self.decode(uri)
28
31
  # gmosx: hmm is this needed?
29
32
  # guard against invalid filenames for example pictures with
data/lib/og.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: og.rb 259 2005-02-15 08:54:54Z gmosx $
3
+ # $Id: og.rb 266 2005-02-28 14:50:48Z gmosx $
4
4
 
5
5
  require 'glue'
6
6
  require 'glue/logger'
@@ -89,7 +89,7 @@ require 'glue/validation'
89
89
  # * Deserialize to OpenStruct.
90
90
  # * Better documentation.
91
91
 
92
- class Og
92
+ module Og
93
93
 
94
94
  # The name.
95
95
 
@@ -97,7 +97,7 @@ class Og
97
97
 
98
98
  # The version.
99
99
 
100
- Version = '0.10.0'
100
+ Version = '0.11.0'
101
101
 
102
102
  # Library path.
103
103
 
@@ -106,37 +106,45 @@ class Og
106
106
  # If true, only allow reading from the database. Usefull
107
107
  # for maintainance.
108
108
 
109
- cattr_accessor :read_only_mode, false
109
+ mattr_accessor :read_only_mode, false
110
110
 
111
111
  # If true, the library automatically 'enchants' managed classes.
112
112
  # In enchant mode, special db aware methods are added to
113
113
  # managed classes and instances.
114
+ # If false, Og enchants only classes that define properties.
114
115
 
115
- cattr_accessor :enchant_managed_classes, true
116
+ mattr_accessor :enchant_managed_classes, true
116
117
 
117
118
  # If true, use Ruby's advanced introspection capabilities to
118
119
  # automatically manage classes tha define properties.
119
120
 
120
- cattr_accessor :auto_manage_classes, true
121
+ mattr_accessor :auto_manage_classes, true
121
122
 
122
123
  # If true, automatically include the Og meta-language into Module.
123
- #
124
- # By default this is FALSE, to avoid polution of the Module object.
125
- # However if you include a prop_accessor or a managed Mixin in your
124
+ # If false, the polution of the Module object is avoided. However
125
+ # if you include a prop_accessor or a managed Mixin in your
126
126
  # object MetaLanguage gets automatically extended in the class.
127
127
 
128
- cattr_accessor :include_meta_language, true
128
+ mattr_accessor :include_meta_language, true
129
129
 
130
130
  # Attach the following prefix to all generated SQL table names.
131
131
  # Usefull on hosting scenarios where you have to run multiple
132
132
  # web applications/sites on a single database.
133
133
 
134
- cattr_accessor :table_prefix, nil
134
+ mattr_accessor :table_prefix, nil
135
135
 
136
+ # If true, Og tries to create/update the schema in the
137
+ # data store. For production/live environments set this to false
138
+ # and only set to true when the object model is upadated.
139
+ # For debug/development environments this should stay true
140
+ # for convienience.
141
+
142
+ mattr_accessor :create_schema, true
143
+
136
144
  # The active database. Og allows you to access multiple
137
145
  # databases from a single application.
138
146
 
139
- cattr_accessor :db
147
+ mattr_accessor :db
140
148
 
141
149
  # Set the active database.
142
150
 
@@ -1,13 +1,13 @@
1
1
  # * George Moschovitis <gm@navel.gr>
2
2
  # (c) 2004-2005 Navel, all rights reserved.
3
- # $Id: adapter.rb 255 2005-02-10 12:45:32Z gmosx $
3
+ # $Id: adapter.rb 266 2005-02-28 14:50:48Z gmosx $
4
4
 
5
5
  require 'yaml'
6
6
  require 'singleton'
7
7
 
8
8
  require 'og/connection'
9
9
 
10
- class Og
10
+ module Og
11
11
 
12
12
  # An adapter communicates with the backend datastore.
13
13
  # The adapters for all supported datastores extend this
@@ -74,6 +74,7 @@ class Adapter
74
74
  # TODO: Optimize this
75
75
 
76
76
  def self.parse_timestamp(str)
77
+ return nil unless str
77
78
  return Time.parse(str)
78
79
  end
79
80
 
@@ -108,7 +109,7 @@ class Adapter
108
109
  end
109
110
 
110
111
  # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
111
- # :section: OR mapping methods and utilities.
112
+ # :section: O->R mapping methods and utilities.
112
113
  # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
113
114
 
114
115
  # Encode the name of the klass as an sql safe string.
@@ -121,24 +122,40 @@ class Adapter
121
122
  end
122
123
 
123
124
  # The name of the SQL table where objects of this class
124
- # are stored.
125
+ # are stored. A prefix is needed to avoid colision with
126
+ # reserved prefices (for example User maps to user which
127
+ # is reserved in postgresql). The prefix should start
128
+ # with an alphanumeric character to be compatible with
129
+ # all RDBMS (most notable Oracle).
130
+ #
131
+ # You may want to override this method to map an existing
132
+ # database schema using Og.
125
133
 
126
134
  def self.table(klass)
127
- "_#{Og.table_prefix}#{encode(klass)}"
135
+ "og_#{Og.table_prefix}#{encode(klass)}"
128
136
  end
129
137
 
130
138
  # The name of the join table for the two given classes.
139
+ # A prefix is needed to avoid colision with reserved
140
+ # prefices (for example User maps to user which
141
+ # is reserved in postgresql). The prefix should start
142
+ # with an alphanumeric character to be compatible with
143
+ # all RDBMS (most notable Oracle).
144
+ #
145
+ # You may want to override this method to map an existing
146
+ # database schema using Og.
131
147
 
132
148
  def self.join_table(klass1, klass2)
133
- "_#{Og.table_prefix}j_#{encode(klass1)}_#{encode(klass2)}"
149
+ "og_#{Og.table_prefix}j_#{encode(klass1)}_#{encode(klass2)}"
134
150
  end
135
-
151
+
136
152
  # Return an sql string evaluator for the property.
137
153
  # No need to optimize this, used only to precalculate code.
138
154
  # YAML is used to store general Ruby objects to be more
139
155
  # portable.
140
- #
156
+ #--
141
157
  # FIXME: add extra handling for float.
158
+ #++
142
159
 
143
160
  def write_prop(p)
144
161
  if p.klass.ancestors.include?(Integer)
@@ -146,7 +163,7 @@ class Adapter
146
163
  elsif p.klass.ancestors.include?(Float)
147
164
  return "#\{@#{p.symbol} || 'NULL'\}"
148
165
  elsif p.klass.ancestors.include?(String)
149
- return "'#\{#{self.class}.escape(@#{p.symbol})\}'"
166
+ return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol})\}'" : 'NULL'\}|
150
167
  elsif p.klass.ancestors.include?(Time)
151
168
  return %|#\{@#{p.symbol} ? "'#\{#{self.class}.timestamp(@#{p.symbol})\}'" : 'NULL'\}|
152
169
  elsif p.klass.ancestors.include?(Date)
@@ -154,6 +171,7 @@ class Adapter
154
171
  elsif p.klass.ancestors.include?(TrueClass)
155
172
  return "#\{@#{p.symbol} ? \"'t'\" : 'NULL' \}"
156
173
  else
174
+ # gmosx: keep the '' for nil symbols.
157
175
  return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}|
158
176
  end
159
177
  end
@@ -197,9 +215,18 @@ class Adapter
197
215
  field << " #{p.meta[:sql]}"
198
216
  else
199
217
  field << " #{@typemap[p.klass]}"
200
- # attach extra sql
201
- if p.meta and extra_sql = p.meta[:extra_sql]
202
- field << " #{extra_sql}"
218
+
219
+ if p.meta
220
+ # set default value (gmosx: not that useful in the
221
+ # current implementation).
222
+ if default = p.meta[:default]
223
+ field << " DEFAULT #{default.inspect} NOT NULL"
224
+ end
225
+
226
+ # attach extra sql
227
+ if extra_sql = p.meta[:extra_sql]
228
+ field << " #{extra_sql}"
229
+ end
203
230
  end
204
231
  end
205
232
 
@@ -235,7 +262,7 @@ class Adapter
235
262
  # object properties.
236
263
 
237
264
  def calc_field_index(klass, og)
238
- raise 'Not implemented!'
265
+ # Implement if needed.
239
266
  end
240
267
 
241
268
  # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -0,0 +1,121 @@
1
+ # * George Moschovitis <gm@navel.gr>
2
+ # (c) 2004-2005 Navel, all rights reserved.
3
+ # $Id: filesys.rb 264 2005-02-23 13:46:55Z gmosx $
4
+
5
+ require 'fileutils'
6
+
7
+ require 'og/adapter'
8
+ require 'og/connection'
9
+ require 'glue/attribute'
10
+
11
+ module Og
12
+
13
+ # The Filesys adapter. This adapter stores Og objectes in
14
+ # the filesystem. This adapter is a proof of concept and
15
+ # at the moment severely limited. For extra documentation
16
+ # see lib/og/adapter.rb
17
+
18
+ class FilesysAdapter < Adapter
19
+
20
+ # Creates the name of the database root dir.
21
+
22
+ def self.dir(database)
23
+ "#{database}_db"
24
+ end
25
+
26
+ def create_db(database, user = nil, password = nil)
27
+ begin
28
+ FileUtils.mkdir_p(self.class.dir(database))
29
+ rescue
30
+ Logger.error "Cannot create '#{database}'!"
31
+ end
32
+ end
33
+
34
+ def drop_db(database, user = nil, password = nil)
35
+ begin
36
+ FileUtils.rmdir(self.class.dir(database))
37
+ super
38
+ rescue
39
+ Logger.error "Cannot drop '#{database}'!"
40
+ end
41
+ end
42
+
43
+ def insert_code(klass, db, pre_cb, post_cb)
44
+ props = props_for_insert(klass)
45
+ values = props.collect { |p| write_prop(p) }.join(',')
46
+
47
+ sql = "INSERT INTO #{klass::DBTABLE} (#{props.collect {|p| p.name}.join(',')}) VALUES (#{values})"
48
+
49
+ %{
50
+ #{pre_cb}
51
+ conn.store.query("#{sql}").close
52
+ @oid = conn.store.last_insert_row_id
53
+ #{post_cb}
54
+ }
55
+ end
56
+
57
+ def new_connection(db)
58
+ return FilesysConnection.new(db)
59
+ end
60
+
61
+ # A 'table' is emulated by using a directory to store
62
+ # one file per table row. Each file contains an object
63
+ # marshaled in YAML format. A special file called
64
+ # '_sequence' stores the sequence for this 'table'.
65
+
66
+ def create_table(klass, db)
67
+ class_dir = File.join(self.class.dir(db.config[:database]), klass::DBTABLE)
68
+ FileUtils.mkdir_p(class_dir)
69
+
70
+ seq_file = File.join(class_dir, 'seq')
71
+ File.open(seq_file, 'w') { |f| f << '1' }
72
+ rescue => ex
73
+ Logger.error "Cannot create directory to store '#{klass}' classes!"
74
+ end
75
+
76
+ end
77
+
78
+ # The Filesys adapter connection.
79
+
80
+ class FilesysConnection < Connection
81
+
82
+ def initialize(db)
83
+ super
84
+ config = db.config
85
+
86
+ begin
87
+ raise unless File.directory?(FilesysAdapter.dir(config[:database]))
88
+ rescue => ex
89
+ if true # ex.to_s =~ /database .* does not exist/i
90
+ Logger.info "Database '#{config[:database]}' not found!"
91
+ @db.adapter.create_db(config[:database], config[:user])
92
+ retry
93
+ end
94
+ raise
95
+ end
96
+ end
97
+
98
+ def save(obj)
99
+ seq = nil
100
+ class_dir = File.join(FilesysAdapter.dir(@db.config[:database]), obj.class::DBTABLE)
101
+ File.open(File.join(class_dir, 'seq'), 'r') { |f| seq = f.read.to_i }
102
+ obj.oid = seq
103
+ File.open(File.join(class_dir, "#{seq}.yml"), 'w') { |f| f << obj.to_yaml }
104
+ seq += 1
105
+ File.open(File.join(class_dir, 'seq'), 'w') { |f| f << seq }
106
+ end
107
+
108
+ def load(oid, klass)
109
+ obj = nil
110
+ class_dir = File.join(FilesysAdapter.dir(@db.config[:database]), klass::DBTABLE)
111
+ File.open(File.join(class_dir, "#{oid}.yml"), 'r') { |f| obj = YAML::load(f.read) }
112
+ return obj
113
+ end
114
+
115
+ def close
116
+ Logger.debug "Closed DB connection." if $DBG
117
+ end
118
+
119
+ end
120
+
121
+ end