nitro 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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