require 'dotenv' # Hot Live Constants module HotConstants HOTENV = {} # rubocop:disable Style/MutableConstant LISTENERS = {} # rubocop:disable Style/MutableConstant LOGGER = SemanticLogger[to_s] class << self def initialize env_sample = Dotenv.parse('.env.sample') # TODO: able to detect add/remove, then either call define_method or undef_method! env_sample.each do |key, value| dkey = key.downcase method = method_from_value(value) singleton_class.define_method(dkey) { method.call(key, value) } LOGGER.info("create method <#{dkey}> performing <#{method.name}> with default value <#{value}> ") end reload! end def reload! HOTENV.replace Dotenv.parse # TODO: detect true changes before processing block below (or yield) LISTENERS.each_pair do |key, block| old_value = nil # TODO: remember last previous value new_value = method(key).call block.call(new_value, old_value) end end def on_change(key, &block) LISTENERS[key.downcase.to_sym] = block end private 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 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 end