Created
November 25, 2009 23:37
-
-
Save lsegal/243096 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module ODB | |
def self.new(store = nil) | |
Database.new(store || HashStore.new) | |
end | |
class Database | |
attr_accessor :store | |
class << self | |
attr_accessor :current | |
end | |
def initialize(store) | |
self.store = store | |
self.store.db = self | |
self.class.current = self unless self.class.current | |
end | |
def transaction(&block) | |
Transaction.new(self, &block) | |
end | |
end | |
class DataStore | |
attr_reader :name | |
def initialize(name) | |
@name = name | |
end | |
def read(key) | |
raise NotImplementedError | |
end | |
def write(key, value) | |
raise NotImplementedError | |
end | |
def [](key) read(key) end | |
def []=(key, value) write(key, value) end | |
end | |
class Transaction | |
attr_accessor :objects | |
def self.transactions | |
Thread.current['__odb_transactions'] ||= [] | |
end | |
def self.current | |
transactions.last | |
end | |
def initialize(db = ODB.current, &block) | |
@objects = [] | |
@db = db | |
transaction(&block) if block_given? | |
end | |
def transaction(&block) | |
self.class.transactions << self | |
yield | |
commit | |
self.class.transactions.pop | |
end | |
def commit | |
while objects.size > 0 | |
object = objects.pop | |
@db.store[object.object_id] = object | |
end | |
end | |
end | |
class FileStore < DataStore | |
def read(key) | |
Marshal.load(IO.read(resource(key))) | |
end | |
def write(key, value) | |
File.open(resource(key), "wb") do |file| | |
file.write(Marshal.dump(value)) | |
end | |
end | |
protected | |
def resource(key) | |
File.join(@name, key) | |
end | |
end | |
class HashStore < DataStore | |
attr_accessor :db | |
def initialize | |
super(nil) | |
@store = {} | |
end | |
def read(key) | |
@store[key].__deserialize__(db) | |
end | |
def write(key, value) | |
@store[key] = value.__serialize__ | |
end | |
end | |
end | |
class Object | |
def __serialize__ | |
obj = {:class => self.class, :ivars => {}} | |
instance_variables.each do |ivar| | |
subobj = instance_variable_get(ivar) | |
ODB::Transaction.current.objects << subobj unless Fixnum === subobj | |
obj[:ivars][ivar[1..-1]] = Fixnum === subobj ? subobj.__serialize__ : subobj.object_id | |
end | |
obj | |
end | |
end | |
class String | |
def __serialize__ | |
super().update(:value => self) | |
end | |
end | |
class Array | |
def __serialize__ | |
obj = super | |
obj[:items] = [] | |
each do |item| | |
ODB::Transaction.current.objects << item | |
obj[:items].push = item.object_id | |
end | |
obj | |
end | |
end | |
class Fixnum | |
def __serialize__ | |
{:class => Fixnum, :value => self} | |
end | |
end | |
class Float | |
def __serialize__ | |
super().update(:value => self) | |
end | |
end | |
class Hash | |
def __deserialize__(db = ODB::Database.current) | |
object = self[:value] ? self[:value] : self[:class].allocate | |
self[:ivars].each do |ivar, value| | |
object.instance_variable_set("@#{ivar}", Hash === value ? value[:value] : db.store[value]) | |
end | |
if self[:class] == Array | |
self[:list].each do |item| | |
object.push(db.store[item]) | |
end | |
end | |
object | |
end | |
end | |
class NilClass | |
def __deserialize__(db = nil) | |
nil | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'odb' | |
Post = Struct.new(:title, :author, :comment) | |
class Comment | |
def initialize | |
@name = 1 | |
@value = 2.5 | |
end | |
end | |
db = ODB.new | |
db.transaction do | |
post = Post.new.tap {|p| p.title = "x"; p.author = "Joe"; p.comment = Comment.new } | |
db.store[:foo] = post | |
end | |
p db.store[:foo] | |
# #<Post:0x100123170 @comment=#<Comment:0x100123030 @name=1, @value=2.5>, @author="Joe", @title="x"> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment