o_dbm 0.5.2

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 (3) hide show
  1. data/o_dbm.gemspec +29 -0
  2. data/o_dbm.rb +862 -0
  3. metadata +70 -0
@@ -0,0 +1,29 @@
1
+
2
+ require "rubygems"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "o_dbm"
6
+ s.authors = "Keiju.Ishitsuka"
7
+ s.email = "keiju@ishitsuka.com"
8
+ s.platform = Gem::Platform::RUBY
9
+ s.summary = "Object Base dbm"
10
+ s.rubyforge_project = s.name
11
+ s.homepage = "http://github.com/keiju/o_dbm"
12
+ s.version = `git tag`.split.collect{|e| e.scan(/v([0-9]+)\.([0-9]+)(?:\.([0-9]+))?/)}.flatten(1).collect{|v| [v[0].to_i, v[1].to_i, v[2].nil? ? -1 : v[2].to_i]}.sort.last.join(".")
13
+ s.require_path = "."
14
+ # s.test_file = ""
15
+ # s.executable = ""
16
+ s.files = [
17
+ "o_dbm.rb",
18
+ "o_dbm.gemspec",
19
+ *Dir.glob(" doc/*.{rd,html}")]
20
+ s.description = <<EOF
21
+ Object Base dbm.
22
+ EOF
23
+ end
24
+
25
+ # Editor settings
26
+ # - Emacs -
27
+ # local variables:
28
+ # mode: Ruby
29
+ # end:
@@ -0,0 +1,862 @@
1
+ # encoding: UTF-8
2
+ #
3
+ # o_dbm.rb - オブジェクト指向データベース風Object Base DBM
4
+ # Copyright (C) 1997-2010 Keiju ISHITSUKA
5
+ # (Penta Advanced Labrabries, Co.,Ltd)
6
+ #
7
+ # --
8
+ #
9
+ #
10
+ #
11
+
12
+ require "e2mmap"
13
+
14
+ class ObjectDBM
15
+ @RELEASE_VERSION = "0.5.2"
16
+ @LAST_UPDATE_DATE = "2002/07/12"
17
+
18
+ @RCS_ID='-$Id: o_dbm.rb,v 1.9 2002/07/12 04:46:28 keiju Exp keiju $-'
19
+
20
+ extend Exception2MessageMapper
21
+
22
+ # トップトランザクションでしか実行できないオペレーションを実行しよう
23
+ # とした.
24
+ def_exception(:ErrOnlyUsableTopTransaction,
25
+ "The operation (%s) can only be executed in the top level transaction.")
26
+
27
+ # トランザクション内でないと実行できないオペレーションを実行しようと
28
+ # しました.
29
+ def_exception(:ErrOnlyUsableInTransaction,
30
+ "The operation (%s) can only be executed within a transaction.")
31
+
32
+ # 静的トランザクションと動的トランザクションを混在して利用することは
33
+ # できません.
34
+ def_exception(:ErrMixedTransaction,
35
+ "Static transactions and dynamic transactions cannot be mixed together.")
36
+
37
+ def_exception(:ErrAdapterInterfaceNotImplement,
38
+ "Adapter interfase(%s) is not implemented.")
39
+
40
+ include Enumerable
41
+
42
+ ODBM = ObjectDBM
43
+
44
+ STATIC_TRANSACTION_MODE = :ObjectDBM__STATIC_TRANSACTION_MODE
45
+ DYNAMIC_TRANSACTION_MODE = :ObjectDBM__DYNAMIC_TRANSACTION_MODE
46
+
47
+ NO_CACHING = :ObjectDBM__NO_CACHING
48
+ READ_CACHING = :ObjectDBM__READ_CACHING
49
+ UPDATE_CACHING = :ObjectDBM__UPDATE_CACHING
50
+
51
+ CLEAR_READ_CACHE = :ObjectDBM__CLEAR_READ_CACHE
52
+ HOLD_READ_CACHE = :ObjectDBM__HOLD_READ_CACHE
53
+
54
+ SCAN_DB = :ObjectDBM__SCAN_DB
55
+ SCAN_CACHE_ONLY = :ObjectDBM__SCAN_CACHE_ONLY
56
+ SCAN_DB_ONLY = :ObjectDBM__SCAN_DB_ONLY
57
+
58
+ READ = :ObjectDBM__READ
59
+ UPDATE = :ObjectDBM__UPDATE
60
+ ABORT = :ObjectDBM__ABORT
61
+
62
+ NULL = :ODBM__NULL
63
+
64
+ TRANSACTIONAL_OPERATIONS = [
65
+ "[]", "update", "[]=", "delete", "indexes",
66
+ "root_names", "keys", "roots", "values",
67
+ "size",
68
+ "has_root_name?", "root_name?", "include?", "has_root?", "root?",
69
+ "each", "each_pair", "each_root_name", "each_root", "each_value",
70
+ "commit", "abort"
71
+ ]
72
+
73
+ #----------------------------------------------------------------------
74
+ #
75
+ # initialize and terminating -
76
+ # initialize
77
+ #
78
+ #----------------------------------------------------------------------
79
+ def initialize(dbm_name, adapter = DBM_Adapter)
80
+ @db_adapter = adapter
81
+
82
+ @db_name = File.expand_path(dbm_name)
83
+ @db = nil
84
+
85
+ @default_value = nil
86
+
87
+ @transaction_mode = nil
88
+ @default_caching_mode = nil
89
+ @read_cache = nil
90
+ @write_cache = nil
91
+ @delete_cache = nil
92
+
93
+ @current_transaction = nil
94
+
95
+ disable_transactional_methods
96
+ end
97
+
98
+ def disable_transactional_methods
99
+ for op in TRANSACTIONAL_OPERATIONS
100
+ instance_eval %[
101
+ def #{op}(*opts)
102
+ error_not_transaction_start("#{op}")
103
+ end
104
+ ], __FILE__, __LINE__ - 5
105
+ end
106
+ end
107
+ private :disable_transactional_methods
108
+
109
+ def enable_transactional_methods
110
+ for op in TRANSACTIONAL_OPERATIONS
111
+ (class<<self; self; end).instance_eval{remove_method op}
112
+ end
113
+ end
114
+ private :enable_transactional_methods
115
+
116
+ def error_not_transaction_start(op)
117
+ ODBM.Fail ErrOnlyUsableInTransaction, op
118
+ end
119
+ private :error_not_transaction_start
120
+
121
+ #----------------------------------------------------------------------
122
+ #
123
+ # accessing -
124
+ # [](key, mode)
125
+ # update(key, obj)
126
+ # []=(key, obj)
127
+ # delete(key)
128
+ # indexes
129
+ # root_names
130
+ # keys
131
+ # roots
132
+ # values
133
+ # size
134
+ #
135
+ #----------------------------------------------------------------------
136
+ attr_accessor :default_value
137
+ alias default default_value
138
+ alias default= default_value=
139
+
140
+ def [](key, mode = nil)
141
+ mode = @default_caching_mode unless mode
142
+
143
+ return update(key) if mode == UPDATE
144
+ obj = @read_cache[key]
145
+ return obj unless obj == NULL
146
+
147
+ return @default_value unless obj = @db[key]
148
+ @read_cache[key] = obj if mode != NO_CACHING
149
+ obj
150
+ end
151
+
152
+ def update(key, obj = :NO_OPTION)
153
+ return self[key] = obj unless obj == :NO_OPTION
154
+
155
+ return @write_cache[key] = obj unless (obj = @read_cache[key]) == NULL
156
+ return @default_value unless obj = @db[key]
157
+ @write_cache[key] = @read_cache[key] = obj
158
+
159
+ @delete_cache.delete(key)
160
+ obj
161
+ end
162
+
163
+ def []=(key, obj)
164
+ @write_cache[key] = @read_cache[key] = obj
165
+ @delete_cache.delete(key)
166
+ obj
167
+ end
168
+
169
+ def delete(key)
170
+ value = @write_cache.delete(key)
171
+ value ||= @read_cache.delete(key)
172
+ @delete_cache[key] = true
173
+ value
174
+ end
175
+
176
+ def indexes(*keys)
177
+ keys.collect{|key| self[key]}
178
+ end
179
+ alias indeces indexes
180
+
181
+ def root_names
182
+ keys = []
183
+ each_key do
184
+ |key|
185
+ keys.push keys
186
+ end
187
+ keys
188
+ end
189
+ alias keys root_names
190
+
191
+ def size
192
+ no = 0
193
+ each_key do
194
+ |key|
195
+ no += 1
196
+ end
197
+ no
198
+ end
199
+
200
+ def roots(mode = nil)
201
+ values = []
202
+ each_root(mode) do
203
+ |root|
204
+ values.push root
205
+ end
206
+ values
207
+ end
208
+ alias values roots
209
+
210
+ #----------------------------------------------------------------------
211
+ #
212
+ # testing -
213
+ # has_root_name?
214
+ # root_name?
215
+ # include?
216
+ # has_root?
217
+ # root?
218
+ #
219
+ #----------------------------------------------------------------------
220
+ def has_root_name?(root_name, mode = SCAN_DB)
221
+ return true if @read_cache.key?(root_name)
222
+ return false if mode == SCAN_CACHE_ONLY
223
+ @db.has_key?(root_name)
224
+ end
225
+ alias root_name? has_root_name?
226
+ alias include? has_root_name?
227
+ alias key? has_root_name?
228
+
229
+ def has_root?(root, mode = SCAN_DB)
230
+ return has_root(root, mode){|x,y| x.equal?(y)} if iterator?
231
+
232
+ if mode != SCAN_DB_ONLY
233
+ @read_cache.each_value{|r| return true if yield root, r}
234
+ return false if mode == SCAN_CACHE_ONLY
235
+ end
236
+ @db.each_value{|r| return true if yield root, r}
237
+ false
238
+ end
239
+ alias root? has_root?
240
+
241
+ #----------------------------------------------------------------------
242
+ #
243
+ # enumerating -
244
+ # each
245
+ # each_pair
246
+ # each_root_name
247
+ # each_key
248
+ # each_root
249
+ # each_value
250
+ #
251
+ #----------------------------------------------------------------------
252
+ def each(mode = nil)
253
+ mode = @default_caching_mode unless mode
254
+
255
+ if mode != SCAN_DB_ONLY
256
+ for key, value in @read_cache
257
+ @write_cache[key] = value if mode == UPDATE
258
+ yield key, value
259
+ end
260
+ end
261
+
262
+ if mode != SCAN_CACHE_ONLY
263
+ @db.each do |key, obj|
264
+ next unless mode == SCAN_DB_ONLY or @read_cache[key] == NULL
265
+ @read_cache[key] = obj if mode == READ_CACHING
266
+ @write_cache[key] = obj if mode == UPDATE
267
+ yield key, obj
268
+ end
269
+ end
270
+ end
271
+ alias each_pair each
272
+
273
+ def each_root_name(mode = nil)
274
+ mode = @default_caching_mode unless mode
275
+
276
+ if mode != SCAN_DB_ONLY
277
+ @read_cache.each_key do
278
+ |key|
279
+ yield key
280
+ end
281
+ end
282
+
283
+ if mode != SCAN_CACHE_ONLY
284
+ @db.each_key do
285
+ |key|
286
+ yield key if mode == SCAN_DB_ONLY or @read_cache[key] == NULL
287
+ end
288
+ end
289
+ end
290
+ alias each_key each_root_name
291
+
292
+ def each_root(mode = nil)
293
+ mode = @default_caching_mode unless mode
294
+
295
+ each(mode) do
296
+ |key, root|
297
+ yield root
298
+ end
299
+ end
300
+ alias each_value each_root
301
+
302
+ #----------------------------------------------------------------------
303
+ #
304
+ # transaction accessing -
305
+ # transaction
306
+ # current_transaction
307
+ #
308
+ #----------------------------------------------------------------------
309
+ def transaction(mode = READ_CACHING)
310
+ @default_caching_mode = mode
311
+ open(mode)
312
+
313
+ outer = @current_transaction
314
+ if outer
315
+ # freeze old cache
316
+ outer.read_cache = @read_cache.dup
317
+ outer.write_cache = @write_cache.dup
318
+ outer.delete_cache = @delete_cache.dup
319
+ end
320
+
321
+ if iterator?
322
+ if @transaction_mode == DYNAMIC_TRANSACTION_MODE
323
+ ODBM.Fail ErrMixedTransaction
324
+ end
325
+ @transaction_mode = STATIC_TRANSACTION_MODE
326
+ @current_transaction = StaticTransaction.new(self, mode, outer)
327
+ # @current_transaction.transaction do
328
+ # yield @current_transaction
329
+ # end
330
+ @current_transaction.transaction do |txn|
331
+ yield txn
332
+ end
333
+ else
334
+ if @transaction_mode == STATIC_TRANSACTION_MODE
335
+ ODBM.Fail ErrMixedTransaction
336
+ end
337
+
338
+ @transaction_mode = DYNAMIC_TRANSACTION_MODE
339
+
340
+ @current_transaction = DynamicTransaction.new(self, mode, outer)
341
+ @current_transaction.start
342
+ return @current_transaction
343
+ end
344
+
345
+ end
346
+ attr :current_transaction
347
+
348
+ #----------------------------------------------------------------------
349
+ #
350
+ # openning and closing - system fuctions
351
+ #
352
+ #----------------------------------------------------------------------
353
+ def commit(txn)
354
+ @current_transaction = txn.outer
355
+ if @current_transaction
356
+ @mode = @current_transaction.mode
357
+ @current_transaction.read_cache = @read_cache
358
+ @current_transaction.write_cache = @write_cache
359
+ @current_transaction.delete_cache = @delete_cache
360
+ else
361
+ close
362
+ end
363
+ end
364
+
365
+ def flush(txn)
366
+ if txn.outer
367
+ txn.outer.read_cache = txn.read_cache.dup
368
+ txn.outer.write_cache = txn.write_cache.dup
369
+ txn.outer.delete_cache = txn.delete_cache.dup
370
+ else
371
+ # close(HOLD_READ_CACHE)
372
+ # @db = @db_adapter.open(@db_name)
373
+ flush_db
374
+ end
375
+ end
376
+
377
+
378
+ def abort(txn)
379
+ @current_transaction = txn.outer
380
+ if @current_transaction
381
+ @mode = @current_transaction.mode
382
+ @read_cache = @current_transaction.read_cache
383
+ @write_cache = @current_transaction.write_cache
384
+ @delete_cache = @current_transaction.delete_cache
385
+ else
386
+ close_with_no_flush
387
+ end
388
+ end
389
+ public :abort
390
+
391
+ def open(mode = READ_CACHING)
392
+ if !@db
393
+ @db = @db_adapter.open(@db_name)
394
+ enable_transactional_methods
395
+ end
396
+ unless @read_cache
397
+ @read_cache = {}
398
+ @read_cache.default = NULL
399
+ end
400
+ unless @write_cache
401
+ @write_cache = {}
402
+ @write_cache.default = NULL
403
+ end
404
+ unless @delete_cache
405
+ @delete_cache = {}
406
+ @delete_cache.default = NULL
407
+ end
408
+
409
+ self
410
+ end
411
+ private :open
412
+
413
+ def flush_db
414
+ @delete_cache.each_key do
415
+ |key|
416
+ @db.delete(key)
417
+ end
418
+
419
+ for key, value in @write_cache
420
+ @db[key] = value
421
+ end
422
+ @db.flush
423
+ @write_cache.clear
424
+ end
425
+ private :flush_db
426
+
427
+ def close(opt = CLEAR_READ_CACHE)
428
+ @mode = nil
429
+ flush_db
430
+ @read_cache.clear unless opt == HOLD_READ_CACHE
431
+ @db.close
432
+ @db = nil
433
+
434
+ @transaction_mode = nil
435
+ disable_transactional_methods
436
+ end
437
+ private :close
438
+
439
+ def close_with_no_flush
440
+ @mode = nil
441
+ @read_cache = nil
442
+ @write_cache = nil
443
+ @delete_cache = nil
444
+
445
+ @db.close
446
+ @db = nil
447
+
448
+ @transaction_mode = nil
449
+ disable_transactional_methods
450
+ end
451
+ private :close_with_no_flush
452
+
453
+
454
+ #---------------------------------------
455
+ #
456
+ # Transaction -
457
+ #
458
+ #-----------------------------------------------------------
459
+ class Transaction
460
+
461
+ extend Exception2MessageMapper
462
+ def_exception(:ErrNoStartedTransaction,
463
+ "Transaction is not started yet.")
464
+ def_exception(:ErrClosedTransaction,
465
+ "Transaction is closed already.")
466
+
467
+ NO_START = :ObjectDBM__TXN_NO_START
468
+ START = :ObjectDBM__TXN_START
469
+ ABORTING = :ObjectDBM__TXN_ABORTING
470
+ COMMITING = :ObjectDBM__TXN_COMMITING
471
+ COMMITED = :ObjectDBM__TXN_COMMITED
472
+ ABORTED = :ObjectDBM__TXN_ABORTED
473
+
474
+ def initialize(odbm, m, outer = nil)
475
+ @odbm = odbm
476
+ @mode = m
477
+ @outer = outer
478
+
479
+ @status = NO_START
480
+ end
481
+
482
+ attr :mode
483
+ attr :outer, true
484
+ attr :read_cache, true
485
+ attr :write_cache, true
486
+ attr :delete_cache, true
487
+ end
488
+
489
+
490
+ #---------------------------------------
491
+ #
492
+ # StaticTransaction -
493
+ # ObjectDBM#transaction {...} -- トランザクションの開始
494
+ # abort -- アボート
495
+ # checkpoint -- トランザクションを終了せずにコ
496
+ # ミットする
497
+ # トランザクションの動作:
498
+ # commit: ブロックを正常に終了した時(throw/returnを含む)は, その子ト
499
+ # ランザクションを含めてすべてcommitする.
500
+ # fail: failして終了した時は, その子トランザクションを含めてすべて
501
+ # abortする.
502
+ # abort: 明示的にabortした時は, その子トランザクションを含めすべて
503
+ # abortする.
504
+ #
505
+ #-----------------------------------------------------------
506
+ class StaticTransaction < Transaction
507
+ ABORT_LABEL = "ObjectDBM__TXN_ABORT_LABEL"
508
+
509
+ def initialize(odbm, m, outer)
510
+ super
511
+ end
512
+
513
+ def transaction
514
+ @status = START
515
+ begin
516
+ # txn, value = catch(ABORT_LABEL){[nil, yield(@current_transaction)]}
517
+ txn, value = catch(ABORT_LABEL){[nil, yield(self)]}
518
+ if txn
519
+ @status = ABORTING
520
+ unless txn.equal?(self)
521
+ throw ABORT_LABEL, [txn, value]
522
+ end
523
+ end
524
+ value
525
+ rescue
526
+ # 例外が発生した時
527
+ @status = ABORTING
528
+ fail
529
+
530
+ ensure
531
+ case @status
532
+ when NO_START
533
+ Transaction.Fail ErrNoStartedTransaction
534
+
535
+ when START
536
+ @status = COMMITED
537
+ @odbm.commit(self)
538
+
539
+ when ABORTING
540
+ @status = ABORTED
541
+ @odbm.abort(self)
542
+
543
+ when ABORTED, COMMITED
544
+
545
+ Transactoin.Fail ErrClosedTransaction
546
+ end
547
+ end
548
+ end
549
+
550
+ def abort(value = nil)
551
+ throw ABORT_LABEL, [self, value]
552
+ end
553
+ public :abort
554
+
555
+ def checkpoint
556
+ case @status
557
+ when START
558
+ @odbm.flush(self)
559
+ when COMMITED, ABORTED
560
+ Transaction.Fail ErrClosedTransaction
561
+ end
562
+ end
563
+ end
564
+
565
+
566
+ #---------------------------------------
567
+ #
568
+ # DynamicTransaction -
569
+ # ObjectDBM#transaction -- トランザクションの開始
570
+ # abort -- アボート
571
+ # checkpoint -- トランザクションを終了せずにコミッ
572
+ # トする.
573
+ # commit -- トランザクションをコミットして終了
574
+ # する.
575
+ #
576
+ # 入れ子トランザクションの時の動作:
577
+ # commit: 指定のトランザクションの子トランザクションをすべてコミット
578
+ # する.
579
+ # abort: 指定のトランザクションの子トランザクションをすべてアボート
580
+ # トする.
581
+ #
582
+ #-----------------------------------------------------------
583
+ class DynamicTransaction < Transaction
584
+ def start
585
+ @status = START
586
+ end
587
+
588
+ def commit
589
+ case @status
590
+ when START
591
+ txn = @odbm.current_transaction
592
+ while (txn.equal?(self))
593
+ @status = COMMITED
594
+ txn = txn.outer
595
+ end
596
+ @odbm.commit(self)
597
+ when COMMITED, ABORTED
598
+ Transaction.Fail ErrClosedTransaction
599
+ end
600
+ end
601
+
602
+ def checkpoint
603
+ case @status
604
+ when START
605
+ @odbm.flush(self)
606
+ when COMMITED, ABORTED
607
+ Transaction.Fail ErrClosedTransaction
608
+ end
609
+ end
610
+
611
+ def abort
612
+ case @status
613
+ when START
614
+ txn = @odbm.current_transaction
615
+ until(txn.equal?(self))
616
+ txn.status = ABORTED
617
+ txn = txn.outer
618
+ end
619
+ @status = ABORTED
620
+
621
+ @odbm.abort(self)
622
+ when COMMITED, ABORTED
623
+ Transaction.Fail ErrClosedTransaction
624
+ end
625
+ end
626
+ public :abort
627
+ end
628
+
629
+ class DB_Adapter
630
+ # open database named <name>
631
+ def self.open(name)
632
+ new(name)
633
+ end
634
+
635
+ def initialize(name)
636
+ ODBM.Fail ErrAdapterInterfaceNotImplement, "initialize"
637
+ #@db
638
+ end
639
+
640
+ # restore value with <key>
641
+ def [](key)
642
+ ODBM.Fail ErrAdapterInterfaceNotImplement, "[]"
643
+ end
644
+
645
+ # store value with <key>
646
+ def []=(key, value)
647
+ ODBM.Fail ErrAdapterInterfaceNotImplement, "[]="
648
+ end
649
+
650
+ # testing for which the db have a key <key>
651
+ def has_key?(key)
652
+ @db.each_key do
653
+ |k|
654
+ return true if k == key
655
+ end
656
+ end
657
+ alias key? has_key?
658
+ alias include? has_key?
659
+
660
+ # access all assoc in database.
661
+ def each(&block)
662
+ @db.each_key{|key|yield key, @db[key]}
663
+ end
664
+
665
+ # access all keys in database.
666
+ def each_key(&block)
667
+ ODBM.Fail ErrAdapterInterfaceNotImplement, "each_key"
668
+ end
669
+
670
+ # access all values in database.
671
+ def each_value(&block)
672
+ @db.each_key{|key|yield @db[key]}
673
+ end
674
+
675
+ # delete value with <key>
676
+ def delete(key)
677
+ ODBM.Fail ErrAdapterInterfaceNotImplement, "delete"
678
+ end
679
+
680
+ # flush database
681
+ def flush
682
+ ODBM.Fail ErrAdapterInterfaceNotImplement, "flush"
683
+ end
684
+
685
+ # close database
686
+ def close
687
+ ODBM.Fail ErrAdapterInterfaceNotImplement, "close"
688
+ end
689
+ end
690
+
691
+ module HashLikeInterface
692
+
693
+ def db
694
+ ODBM.Fail ErrAdapterInterfaceNotImplement, "db"
695
+ end
696
+
697
+ def [](key)
698
+ materialize_value(db[key])
699
+ end
700
+
701
+ def []=(key, value)
702
+ db[key] = serialize_value(value)
703
+ end
704
+
705
+ def has_key?(key)
706
+ db.key?(key)
707
+ end
708
+
709
+ def each
710
+ db.each{|k, v| yield k, materialize_value(v)}
711
+ end
712
+
713
+ def each_key(&block)
714
+ db.each_key &block
715
+ end
716
+
717
+ def each_value
718
+ db.each_value{|v| yield materialize_value(v)}
719
+ end
720
+
721
+ def delete(key)
722
+ db.delete(key)
723
+ end
724
+
725
+ def serialize_value(v)
726
+ ODBM.Fail ErrAdapterInterfaceNotImplement, "serialize_value(v)"
727
+ end
728
+ def materialize_value(v)
729
+ ODBM.Fail ErrAdapterInterfaceNotImplement, "materialize_value(v)"
730
+ end
731
+ end
732
+
733
+ autoload :DBM, "dbm"
734
+ class DBM_Adapter<DB_Adapter
735
+
736
+ include HashLikeInterface
737
+
738
+ def initialize(name)
739
+ @db = DBM.open(name)
740
+ end
741
+
742
+ def db
743
+ @db
744
+ end
745
+
746
+ def serialize_value(v)
747
+ Marshal.dump(v)
748
+ end
749
+
750
+ def materialize_value(v)
751
+ return v unless v
752
+ Marshal.load(v)
753
+ end
754
+
755
+ def flush
756
+ # noop
757
+ end
758
+
759
+ def close
760
+ flush
761
+ @db.close
762
+ @db = nil
763
+ end
764
+
765
+ end
766
+
767
+ autoload :GDBM, "gdbm"
768
+ class GDBM_Adapter<DBM_Adapter
769
+ def initialize(name)
770
+ @db = GDBM.open(name)
771
+ end
772
+
773
+ def flush
774
+ @db.sync
775
+ end
776
+ end
777
+
778
+ autoload :SDBM, "sdbm"
779
+ class SDBM_Adapter<DBM_Adapter
780
+ def initialize(name)
781
+ @db = SDBM.open(name)
782
+ end
783
+ end
784
+
785
+ class PHash_Adapter<DB_Adapter
786
+ include HashLikeInterface
787
+
788
+ def initialize(name)
789
+ @db_name = name
790
+ if File.exist?(name)
791
+ file = File::open(name, 'r')
792
+ begin
793
+ @hash = Marshal.load(file)
794
+ ensure
795
+ file.close
796
+ end
797
+ else
798
+ @hash = {}
799
+ end
800
+ end
801
+
802
+ def db
803
+ @hash
804
+ end
805
+ def serialize_value(v)
806
+ v
807
+ end
808
+
809
+ def materialize_value(v)
810
+ v
811
+ end
812
+
813
+ # commit database
814
+ def flush
815
+ newfile = @db_name + '.new'
816
+ file = open(newfile, 'w')
817
+ Marshal.dump(@hash, file)
818
+ file.close
819
+ File.rename(newfile, @db_name)
820
+ end
821
+
822
+ # close database
823
+ def close
824
+ flush
825
+ @hash = nil
826
+ end
827
+ end
828
+
829
+ class VDB_Adapter<DB_Adapter
830
+ include HashLikeInterface
831
+
832
+ VDBS = {}
833
+
834
+ def initialize(name)
835
+ @db_name = name
836
+ @hash = VDBS[@db_name]
837
+ @hash = {} unless @hash
838
+ end
839
+
840
+ def db
841
+ @hash
842
+ end
843
+ def serialize_value(v)
844
+ v
845
+ end
846
+
847
+ def materialize_value(v)
848
+ v
849
+ end
850
+
851
+ # commit database
852
+ def flush
853
+ VDBS[@db_name] = @hash
854
+ end
855
+
856
+ # close database
857
+ def close
858
+ flush
859
+ @hash = nil
860
+ end
861
+ end
862
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: o_dbm
3
+ version: !ruby/object:Gem::Version
4
+ hash: 15
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 5
9
+ - 2
10
+ version: 0.5.2
11
+ platform: ruby
12
+ authors:
13
+ - Keiju.Ishitsuka
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-11-11 00:00:00 +09:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: |
23
+ Object Base dbm.
24
+
25
+ email: keiju@ishitsuka.com
26
+ executables: []
27
+
28
+ extensions: []
29
+
30
+ extra_rdoc_files: []
31
+
32
+ files:
33
+ - o_dbm.rb
34
+ - o_dbm.gemspec
35
+ has_rdoc: true
36
+ homepage: http://github.com/keiju/o_dbm
37
+ licenses: []
38
+
39
+ post_install_message:
40
+ rdoc_options: []
41
+
42
+ require_paths:
43
+ - .
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ hash: 3
50
+ segments:
51
+ - 0
52
+ version: "0"
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ requirements: []
63
+
64
+ rubyforge_project: o_dbm
65
+ rubygems_version: 1.3.7
66
+ signing_key:
67
+ specification_version: 3
68
+ summary: Object Base dbm
69
+ test_files: []
70
+