lib/temple/map.rb
# frozen_string_literal: true
module Temple
# Immutable map class which supports map merging
# @api public
class ImmutableMap
include Enumerable
def initialize(*map)
@map = map.compact
end
def include?(key)
@map.any? {|h| h.include?(key) }
end
def [](key)
@map.each {|h| return h[key] if h.include?(key) }
nil
end
def each
keys.each {|k| yield(k, self[k]) }
end
def keys
@map.inject([]) {|keys, h| keys.concat(h.keys) }.uniq
end
def values
keys.map {|k| self[k] }
end
def to_hash
result = {}
each {|k, v| result[k] = v }
result
end
end
# Mutable map class which supports map merging
# @api public
class MutableMap < ImmutableMap
def initialize(*map)
super({}, *map)
end
def []=(key, value)
@map.first[key] = value
end
def update(map)
@map.first.update(map)
end
end
class OptionMap < MutableMap
def initialize(*map, &block)
super(*map)
@handler = block
@valid = {}
@deprecated = {}
end
def []=(key, value)
validate_key!(key)
super
end
def update(map)
validate_map!(map)
super
end
def valid_keys
(keys + @valid.keys +
@map.map {|h| h.valid_keys if h.respond_to?(:valid_keys) }.compact.flatten).uniq
end
def add_valid_keys(*keys)
keys.flatten.each { |key| @valid[key] = true }
end
def add_deprecated_keys(*keys)
keys.flatten.each { |key| @valid[key] = @deprecated[key] = true }
end
def validate_map!(map)
map.to_hash.keys.each {|key| validate_key!(key) }
end
def validate_key!(key)
@handler.call(self, key, :deprecated) if deprecated_key?(key)
@handler.call(self, key, :invalid) unless valid_key?(key)
end
def deprecated_key?(key)
@deprecated.include?(key) ||
@map.any? {|h| h.deprecated_key?(key) if h.respond_to?(:deprecated_key?) }
end
def valid_key?(key)
include?(key) || @valid.include?(key) ||
@map.any? {|h| h.valid_key?(key) if h.respond_to?(:valid_key?) }
end
end
end