lib/configatron/root_store.rb
require 'singleton'
require 'forwardable'
# This is the root configatron object, and contains methods which
# operate on the entire configatron hierarchy.
class Configatron::RootStore < BasicObject
include ::Singleton
extend ::Forwardable
attr_reader :store
# Have one global RootStore instance, but allow people to create
# their own parallel ones if they desire.
class << self
public :new
end
@@cow = 0
def initialize
@locked = false
@cow = nil
@temporary_locks = []
@temporary_states = []
reset!
end
def __cow
@cow
end
def __cow_path(path)
start = @store.__cow_clone
node = start
branch = path.map do |key|
node = node[key]
node.__cow_clone
end
nodes = [start] + branch
# [node1, node2, node3] with
# [node2, node3, node4] and
# ['key1', 'key2, 'key3']
nodes[0...-1].zip(nodes[1..-1], path) do |parent, child, key|
# These are all cow_clones, so won't trigger a further cow
# modification.
parent[key] = child
end
@store = nodes.first
nodes.last
end
def method_missing(name, *args, &block)
store.__send__(name, *args, &block)
end
def reset!
@store = ::Configatron::Store.new(self)
end
def temp(&block)
temp_start
begin
yield
ensure
temp_end
end
end
def temp_start
@temp_cow = @cow
# Just need to have a unique Copy-on-Write generation ID
@cow = @@cow += 1
@temporary_locks.push(@locked)
@temporary_states.push(@store)
end
def temp_end
@cow = @temp_cow
@locked = @temporary_locks.pop
@store = @temporary_states.pop
end
def locked?
@locked
end
def lock!(&blk)
if blk
orig = @locked
begin
@locked = true
blk.call
ensure
@locked = orig
end
else
@locked = true
end
end
def unlock!(&blk)
if blk
orig = @locked
begin
@locked = false
blk.call
ensure
@locked = orig
end
else
@locked = false
end
end
def_delegator :@store, :to_s
def_delegator :@store, :inspect
end