class Bogo::Config
Constants
- VERSION
Current library version
Attributes
@return [String, Hash]
@return [String] configuration path
Public Class Methods
Create new instance
@param path_or_hash [String, Hash] file/directory path or base Hash @return [self]
# File lib/bogo/config.rb, line 113 def initialize(path_or_hash=nil) super() @initial = path_or_hash @data = Smash.new init! end
Reload any registered ‘Bogo::Config` instances
@return [TrueClass]
# File lib/bogo/config.rb, line 40 def reload! obj_ids = memoize(:bogo_reloadable_configs, :global) objects = Thread.exclusive do ObjectSpace.each_object.find_all do |obj| obj_ids.include?(obj.object_id) end end objects.map(&:init!) memoize(:bogo_reloadable_configs, :global).delete_if do |oid| !obj_ids.include?(oid) end true end
Register config instance to auto reload on HUP
@param config [Bogo::Config] @return [TrueClass]
# File lib/bogo/config.rb, line 58 def reloadable(config) if(config.is_a?(Bogo::Config)) reloader memoize(:bogo_reloadable_configs, :global){ [] }.push(config.object_id).uniq! else raise TypeError.new "Expecting type `Bogo::Config`. Received: `#{config.class}`" end true end
Internal reloader
@return [Thread]
# File lib/bogo/config.rb, line 71 def reloader memoize(:bogo_config_reloader, :global) do Thread.new do begin loop do begin sleep rescue SignalException => e if(e.signm == 'SIGHUP') if(ENV['BOGO_DEBUG']) $stdout.puts 'SIGHUP encountered. Reloading `Bogo::Config` instances.' end Bogo::Config.reload! else raise end end end rescue => e if(ENV['BOGO_DEBUG']) $stderr.puts "#{e.class}: #{e}\n#{e.backtrace.join("\n")}" end retry end end end end
Public Instance Methods
Override to force consistent data access (removes dirty functionality)
@return [Smash]
# File lib/bogo/config.rb, line 162 def dirty data end
@return [TrueClass, FalseClass]
# File lib/bogo/config.rb, line 313 def eval_disabled? !eval_enabled? end
@return [TrueClass, FalseClass]
# File lib/bogo/config.rb, line 308 def eval_enabled? ENV['BOGO_CONFIG_DISABLE_EVAL'].to_s.downcase != 'true' end
Extract appropriate execption based on path
@param path [String] @param errors [Hash] @return [Exception, NilClass]
# File lib/bogo/config.rb, line 322 def extract_error_for(path, errors) content = File.read(path).strip if(content.start_with?('{')) errors[:json_load] elsif(content.start_with?('<')) errors[:xml_load] elsif(content.match(/\.new\s*(do|\{)/)) errors[:struct_load] else errors[:yaml_load] end end
Freeze underlying configuration data
@return [self]
# File lib/bogo/config.rb, line 131 def immutable! @data = data.to_smash(:freeze) end
Intialize the configuration
@return [self]
# File lib/bogo/config.rb, line 138 def init! if(initial.is_a?(String)) @path = initial.dup hash = load! else hash = initial end if(hash) is_immutable = data.frozen? # TODO: synchronize here load_data(hash) @data = hash.to_smash.deep_merge(data.to_smash) @data.to_smash(:freeze) if is_immutable end self end
Read and parse JSON file
@param file_path @return [Smash]
# File lib/bogo/config.rb, line 244 def json_load(file_path) MultiJson.load(File.read(file_path)).to_smash end
Load configuration from file(s)
@return [self]
# File lib/bogo/config.rb, line 174 def load! if(path) if(File.directory?(path)) conf = Dir.glob(File.join(path, '*')).sort.inject(Smash.new) do |memo, file_path| memo.deep_merge(load_file(file_path)) end elsif(File.file?(path)) conf = load_file(path) else raise Errno::ENOENT.new path end conf end end
Load configuration file
@param file_path [String] path to file @return [Smash]
# File lib/bogo/config.rb, line 193 def load_file(file_path) result = nil errors = Smash.new error = nil begin result = case File.extname(file_path) when '.yaml', '.yml' yaml_load(file_path) when '.json' json_load(file_path) when '.xml' xml_load(file_path) when '.rb' struct_load(file_path) else [:struct_load, :json_load, :yaml_load, :xml_load].each do |loader| begin result = send(loader, file_path) break rescue StandardError, ScriptError => e errors[loader] = e if(ENV['BOGO_DEBUG']) $stderr.puts "#{e.class}: #{e}\n#{e.backtrace.join("\n")}" end end end result end rescue => error end unless(result) raise FileLoadError.new( "Failed to load configuration from file (#{file_path})", error || extract_error_for(file_path, errors) ) end result end
Enables automatic reloading on SIGHUP
@return [TrueClass]
# File lib/bogo/config.rb, line 123 def reloadable! Bogo::Config.reloadable(self) true end
Read and parse AttributeStruct file
@param file_path @return [Smash]
# File lib/bogo/config.rb, line 296 def struct_load(file_path) if(eval_disabled?) raise 'Ruby based configuration evaluation is currently disabled!' else result = Module.new.instance_eval( IO.read(file_path), file_path, 1 ) result._dump.to_smash end end
@return [String]
# File lib/bogo/config.rb, line 167 def to_json(*args) MultiJson.dump(data, *args) end
Format XML types
@param result [Smash] @return [Smash]
# File lib/bogo/config.rb, line 262 def xml_format(result) Smash[result.map{|k,v| [k, xml_format_value(v)]}] end
Format XML value types
@param value [Object] @return [Object]
# File lib/bogo/config.rb, line 270 def xml_format_value(value) case value when Hash xml_format(value) when Array value.map{|v| xml_format_value(v)} else value.strip! if(value == 'true') true elsif(value == 'false') false elsif(value.to_i.to_s == value) value.to_i elsif(value.to_f.to_s == value) value.to_f else value end end end
Read and parse XML file
@param file_path @return [Smash] @note supar ENTERPRISE
# File lib/bogo/config.rb, line 253 def xml_load(file_path) result = MultiXml.parse(File.read(file_path)).to_smash[:configuration] xml_format(result) end
Read and parse YAML file
@param file_path @return [Smash]
# File lib/bogo/config.rb, line 236 def yaml_load(file_path) YAML.load(File.read(file_path)).to_smash end