lib/mongoid/giza/configuration.rb
require "erb"
require "ostruct"
require "yaml"
module Mongoid
module Giza
# Holds the configuration of the module
class Configuration < Riddle::Configuration
include Singleton
attr_reader :source, :index, :file
# Creates the configuration instance
def initialize
super
@source = Riddle::Configuration::XMLSource.new(:source, :xmlpipe2)
@index = Riddle::Configuration::Index.new(:index, @source)
@file = OpenStruct.new(output_path: "./sphinx.conf")
@static_indexes = {}
@generated_indexes = {}
end
# Loads a YAML file with settings defined.
# Settings that are not recognized are ignored
#
# @param path [String] path to the YAML file which contains the settings
# defined
# @param env [String] environment whoose settings will be loaded
def load(path, env)
yaml_safe_load(File.open(path).read)[env].each do |section, settings|
section = instance_variable_get("@#{section}")
next unless section
settings.each do |setting, value|
unless section == @index || section == @source
value = interpolate_string(value, nil)
end
setter(section, setting, value)
end
end
end
# Adds an index to the sphinx configuration,
# so this index can be rendered on the configuration file
#
# @param index [Mongoid::Giza::Index] the index that will be added to the
# configuration
# @param generated [TrueClass, FalseClass] determines if this index was
# generated from a {Mongoid::Giza::DynamicIndex}
def add_index(index, generated = false)
riddle_index = create_index(index)
indexes = generated ? @generated_indexes : @static_indexes
position = register_index(riddle_index, indexes)
indices[position] = riddle_index
end
# Creates a new Riddle::Index based on the given {Mongoid::Giza::Index}
#
# @param index [Mongoid::Giza::Index] the index to generate the
# configuration from
#
# @return [Riddle::Configuration::Index] the created riddle index
def create_index(index)
source = Riddle::Configuration::XMLSource.new(index.name, :xmlpipe2)
riddle_index = Riddle::Configuration::Index.new(index.name, source)
apply_default_settings(@index, riddle_index, index)
apply_default_settings(@source, source, index)
apply_user_settings(index, riddle_index)
apply_user_settings(index, source)
riddle_index.path = File.join(riddle_index.path, index.name.to_s)
riddle_index
end
# Adds the riddle index to it's respective collection
#
# @param riddle_index [Riddle::Configuration::Index] the index that will
# be registrated
# @param indexes [Hash] the collection which will hold this index
#
# @return [Integer] the position where this index should be inserted on
# the configuration indices array
def register_index(riddle_index, indexes)
position = indices.index(indexes[riddle_index.name]) || indices.length
indexes[riddle_index.name] = riddle_index
position
end
# Applies the settings defined on an object loaded from the configuration
# to a Riddle::Configuration::Index or Riddle::Configuration::XMLSource
# instance.
# Used internally by {#add_index} so you should never need to call it
# directly
#
# @param default [Riddle::Configuration::Index,
# Riddle::Configuration::XMLSource] the object that holds the global
# settings values
# @param section [Riddle::Configuration::Index,
# Riddle::Configuration::XMLSource] the object that settings are being
# set
def apply_default_settings(default, section, index)
default.class.settings.each do |setting|
value = interpolate_string(default.send(setting.to_s), index)
setter(section, setting, value) unless value.nil?
end
end
# Applies the settings defined on a {Mongoid::Giza::Index} to the
# Riddle::Configuration::Index or Riddle::Configuration::XMLSource.
# Used internally by {#add_index} so you should never need to call it
# directly
#
# @param index [Mongoid::Giza::Index] the index where the settings were
# defined
# @param section [Riddle::Configuration::Index,
# Riddle::Configuration::XMLSource] where the settings will be applied
def apply_user_settings(index, section)
index.settings.each do |setting, value|
value = interpolate_string(value, index)
setter(section, setting, value)
end
end
# Renders the configuration to the output_path
def render
File.open(@file.output_path, "w") { |file| file.write(super) }
end
# Removes all Riddle::Index from the indices Array that were created from
# a generated {Mongoid::Giza::Index}
def clear_generated_indexes
@generated_indexes.each { |_, index| indices.delete(index) }
@generated_indexes = {}
end
# Removes Riddle::Index's specifieds as params
#
# @param names [Array<Symbol>] names of generated indexes that should be
# removed
def remove_generated_indexes(names)
names.each do |name|
indices.delete(@generated_indexes.delete(name))
end
end
# Interpolates a value if it's a String using ERB.
# Useful for defining dynamic settings.
# The ERB template may reference to the current {Mongoid::Giza::Index} and
# it's methods
#
# @param value [String] the ERB template that will be interpolated
# @param index [Mongoid::Giza::Index] the index that will be accessible
# from the template
#
# @return [Object] if value was a String and contains ERB syntax than it
# will beinterpolated and returned.
# Otherwise it will return the original value
def interpolate_string(value, index)
namespace = index.nil? ? Object.new : OpenStruct.new(index: index)
if value.is_a?(String)
return ERB.new(value).result(namespace.instance_eval { binding })
end
value
end
# Helper method to set a value to a setting from a section (i.e. indexer,
# source) if the section has this setting.
# If the setting is not avaiable on the section, nothing is done
#
# @param section [Riddle::Configuration::Section] a configuration section
# to define the setting
# @param setting [Symbol] the setting that will be defined on the section
# @param value [Object] the value of the setting
def setter(section, setting, value)
method = "#{setting}="
section.send(method, value) if section.respond_to?(method)
end
private
def yaml_safe_load(yaml_code)
if YAML.respond_to?(:safe_load)
YAML.safe_load(yaml_code)
else
YAML.load(yaml_code) # rubocop:disable Security/YAMLLoad
end
end
end
end
end