You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
104 lines
3.3 KiB
104 lines
3.3 KiB
require 'dotenv'
|
|
|
|
module Hot
|
|
# Hot Live Constants
|
|
module Constants
|
|
include SemanticLogger::Loggable
|
|
HOTENV = {} # rubocop:disable Style/MutableConstant
|
|
LISTENERS = {} # rubocop:disable Style/MutableConstant
|
|
|
|
class << self
|
|
def initialize
|
|
@old_definitions = {}
|
|
@hot_definitions = {}
|
|
|
|
logger.level = :fatal
|
|
load_definitions
|
|
load_values
|
|
logger.level = :info
|
|
end
|
|
|
|
def load_definitions
|
|
logger.debug('--load_definitions3')
|
|
|
|
new_definitions = Dotenv.parse('.env.sample')
|
|
|
|
definitions_to_actualize = {}
|
|
@old_definitions.merge(new_definitions) do |key, old_value, new_value|
|
|
definitions_to_actualize[key] = new_value if new_value != old_value
|
|
end
|
|
definitions_to_actualize.each { |key, value| define_method(:actualize, key, value) }
|
|
|
|
@old_definitions = new_definitions
|
|
|
|
definitions_to_remove = @hot_definitions.except(*new_definitions.keys)
|
|
definitions_to_remove.each_pair do |key, dkey|
|
|
logger.info("remove method <#{dkey}>")
|
|
singleton_class.undef_method(dkey)
|
|
@hot_definitions.delete(key)
|
|
end
|
|
|
|
definitions_to_add = new_definitions.except(*@hot_definitions.keys)
|
|
definitions_to_add.each { |key, value| define_method(:add, key, value) }
|
|
end
|
|
|
|
def load_values
|
|
logger.debug('--load_values')
|
|
|
|
new_env = Dotenv.parse
|
|
constants_to_delete = HOTENV.except(*new_env.keys)
|
|
constants_to_delete.each do |name, _|
|
|
# FIXME: default should read default and type from @old_definitions
|
|
type, default = @old_definitions[name]
|
|
logger.info("constant <#{name}> reverts to default value <#{default}> of type <#{type}>")
|
|
end
|
|
|
|
constants_to_add = new_env.except(*HOTENV.keys)
|
|
constants_to_add.each do |constant|
|
|
logger.info("constant to add <#{constant}>")
|
|
end
|
|
|
|
HOTENV.replace new_env
|
|
# LISTENERS.each_pair { |k, b| perform_change(k, b) }
|
|
end
|
|
|
|
def on_change(key, &block)
|
|
LISTENERS[key.downcase.to_sym] = block
|
|
perform_change(key, block)
|
|
end
|
|
|
|
private
|
|
|
|
def define_method(mode, key, value)
|
|
dkey = key.downcase
|
|
method = infer_method_from_value(value)
|
|
|
|
inferred_type = method.name.to_s.split('_')[1]
|
|
logger.info("#{mode} method <#{dkey}> of type <#{inferred_type}> with default value <#{value}> ")
|
|
|
|
singleton_class.define_method(dkey) { method.call(key, value) }
|
|
@hot_definitions.store(key, dkey)
|
|
end
|
|
|
|
def perform_change(key, block)
|
|
old_value = nil # TODO: remember last previous value
|
|
new_value = method(key).call
|
|
block.call(new_value, old_value)
|
|
end
|
|
|
|
def load_boolean(key, default) = HOTENV.fetch(key, default).to_s.downcase == 'true'
|
|
def load_integer(key, default) = HOTENV.fetch(key, default).to_i
|
|
def load_string(key, default) = HOTENV.fetch(key, default)
|
|
|
|
def infer_method_from_value(value)
|
|
case value.downcase
|
|
when /^(true|false)$/ then method(:load_boolean)
|
|
when /^\d+$/ then method(:load_integer)
|
|
else method(:load_string)
|
|
end
|
|
end
|
|
end
|
|
|
|
initialize # done once on first require, cause this is just a module (not a class!)
|
|
end
|
|
end
|