lib/twitter_cldr/utils/file_system_trie.rb
# encoding: UTF-8
# Copyright 2012 Twitter, Inc
# http://www.apache.org/licenses/LICENSE-2.0
require 'yaml'
require 'fileutils'
module TwitterCldr
module Utils
class FileSystemTrie
VALUE_FILE = 'value.dump'
attr_reader :path_root
def initialize(path_root, root = Node.new)
@path_root = path_root
@root = root
end
def empty?
!@root.has_children?
end
def add(key, value)
store(key, value, false)
end
def set(key, value)
store(key, value)
end
def get(key)
node = get_node(key)
node && node.value
end
def get_node(key)
traverse(key) do |node, key_element|
return unless node
node.child(key_element)
end
end
# to prevent printing of a possibly huge children list in the IRB
alias_method :inspect, :to_s
private
def store(key, value, override = true)
final = store_p(key)
if final.value.nil? || override
final.value = value
path = File.join(path_root, *key, VALUE_FILE)
File.write(path, Marshal.dump(value))
end
end
def store_p(key)
current_path = path_root
traverse(key) do |node, key_element|
current_path = File.join(current_path, key_element)
mkdir(current_path)
node.child(key_element) || node.set_child(key_element, Node.new)
end
end
def traverse(key)
current_path = path_root
key.inject(@root) do |node, key_element|
next unless node
next unless key_element
current_path = File.join(current_path, key_element)
fill_in_path(current_path, key_element, node)
fill_in_value(current_path, key_element, node)
yield node, key_element if block_given?
end
end
def fill_in_path(current_path, key_element, parent)
if File.exist?(current_path)
unless parent.child(key_element)
parent.set_child(key_element, Node.new)
end
end
end
def fill_in_value(current_path, key_element, parent)
value_file = File.join(current_path, VALUE_FILE)
child = parent.child(key_element)
if File.exist?(value_file) && child && !child.value
parent.child(key_element).value = ::Marshal.load(
File.read(value_file)
)
end
end
def mkdir(path)
FileUtils.mkdir_p(path) unless File.exist?(path)
end
class Node
attr_accessor :value, :children
def initialize(value = nil, children = {})
@value = value
@children = children
end
def child(key)
@children[key]
end
def set_child(key, child)
@children[key] = child
end
def has_children?
!@children.empty?
end
def each_key_and_child(&block)
@children.each(&block)
end
def keys
@children.keys
end
def to_trie
Trie.new(self.class.new(nil, @children)).lock
end
end
end
end
end