class Bogo::Config

Constants

VERSION

Current library version

Attributes

initial[R]

@return [String, Hash]

path[R]

@return [String] configuration path

Public Class Methods

new(path_or_hash=nil) click to toggle source

Create new instance

@param path_or_hash [String, Hash] file/directory path or base Hash @return [self]

Calls superclass method
# File lib/bogo/config.rb, line 113
def initialize(path_or_hash=nil)
  super()
  @initial = path_or_hash
  @data = Smash.new
  init!
end
reload!() click to toggle source

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
reloadable(config) click to toggle source

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
reloader() click to toggle source

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

dirty() click to toggle source

Override to force consistent data access (removes dirty functionality)

@return [Smash]

# File lib/bogo/config.rb, line 162
def dirty
  data
end
eval_disabled?() click to toggle source

@return [TrueClass, FalseClass]

# File lib/bogo/config.rb, line 313
def eval_disabled?
  !eval_enabled?
end
eval_enabled?() click to toggle source

@return [TrueClass, FalseClass]

# File lib/bogo/config.rb, line 308
def eval_enabled?
  ENV['BOGO_CONFIG_DISABLE_EVAL'].to_s.downcase != 'true'
end
extract_error_for(path, errors) click to toggle source

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
immutable!() click to toggle source

Freeze underlying configuration data

@return [self]

# File lib/bogo/config.rb, line 131
def immutable!
  @data = data.to_smash(:freeze)
end
init!() click to toggle source

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
json_load(file_path) click to toggle source

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!() click to toggle source

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_file(file_path) click to toggle source

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
reloadable!() click to toggle source

Enables automatic reloading on SIGHUP

@return [TrueClass]

# File lib/bogo/config.rb, line 123
def reloadable!
  Bogo::Config.reloadable(self)
  true
end
struct_load(file_path) click to toggle source

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
to_json(*args) click to toggle source

@return [String]

# File lib/bogo/config.rb, line 167
def to_json(*args)
  MultiJson.dump(data, *args)
end
xml_format(result) click to toggle source

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
xml_format_value(value) click to toggle source

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
xml_load(file_path) click to toggle source

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
yaml_load(file_path) click to toggle source

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