lib/crepe/config.rb
module Crepe
# A Hash-like object that scopes state changes using an underlying stack.
class Config
# Initializes a {Config} object with a given hash.
#
# @param [Hash] first The basic, "root" hash
def initialize first = {}
@stack = Array.wrap first
end
delegate :pop, :push, :<<, :last,
to: :stack
delegate :[], :[]=, :keys, :update,
to: :last
# Returns a stack of values for the given hash key.
#
# @param [Symbol] key a hash key
# @return [Array] the stack of values for the given key
def all key
stack.select { |l| l.key? key }.map { |l| l[key] }.flatten 1
end
# Pushes a hash onto the stack and pops it after executing a block of code
# when given.
#
# config = Config.new
# # config == {}
# config.scope foo: 'bar' do
# # config == {:foo=>"bar"}
# config.scope bar: 'baz' do
# # config == {:foo=>"bar", :bar=>"baz"}
# config.scope foo: 'fizzbuzz'
# # config == {:foo=>"fizzbuzz", :bar=>"baz"}
# end
# # config == {:foo=>"bar"}
# end
# # config == {}
#
# @param [Hash] scoped a hash to push onto the stack
# @return [void]
def scope **scoped
return update scoped unless block_given?
push Util.deep_merge to_h, scoped
yield
pop
end
# Returns a flattened hash from current stack of hashes.
#
# @return [Hash]
def to_hash
stack.inject { |h, layer| Util.deep_merge h, layer }
end
alias to_h to_hash
# Returns a new {Config} object with a shallowly-duped stack.
#
# @return [Config]
def dup
self.class.new stack.dup
end
# Returns a new {Config} object with a deeply-duped stack.
#
# @return [Config]
# @see Util.deep_collection_dup
def deep_collection_dup
self.class.new Util.deep_collection_dup stack
end
attr_reader :stack
protected :stack
end
end