lib/ultra_settings.rb in ultra_settings-0.0.1.rc1 vs lib/ultra_settings.rb in ultra_settings-1.0.0
- old
+ new
@@ -1,25 +1,37 @@
# frozen_string_literal: true
-require "super_settings"
+require "erb"
+require "yaml"
+require "time"
+require "pathname"
+require "singleton"
require_relative "ultra_settings/configuration"
+require_relative "ultra_settings/coerce"
require_relative "ultra_settings/field"
+require_relative "ultra_settings/rack_app"
+require_relative "ultra_settings/web_view"
+require_relative "ultra_settings/yaml_config"
+require_relative "ultra_settings/version"
+if defined?(Rails::Railtie)
+ require_relative "ultra_settings/railtie"
+end
+
# This is the root namespace for UltraSettings. You can add configurations to
# this namespace using the add method.
#
# @example
# UltraSettings.add(:test)
# UltraSettings.test # => TestConfiguration.instance
module UltraSettings
+ VALID_NAME__PATTERN = /\A[a-z_][a-zA-Z0-9_]*\z/
+
@configurations = {}
@mutex = Mutex.new
- class NonStaticValueError < StandardError
- end
-
class << self
# Adds a configuration to the root namespace. The configuration will be
# available as a method on the UltraSettings module with the provide name.
#
# @param name [Symbol, String] The name of the configuration.
@@ -27,120 +39,201 @@
# provided then the class will be inferred from the name by camelizing the
# name and appending "Configuration" to get the class name.
# @return [void]
def add(name, klass = nil)
name = name.to_s
- unless name.match?(/\A[a-z_][a-zA-Z0-9_]*\z/)
+ unless name.match?(VALID_NAME__PATTERN)
raise ArgementError.new("Invalid configuration name: #{name.inspect}")
end
class_name = klass&.to_s
- class_name ||= "#{name.classify}Configuration"
+ class_name ||= "#{classify(name)}Configuration"
@mutex.synchronize do
- @configurations.delete(name)
+ @configurations[name] = class_name
eval <<-RUBY, binding, __FILE__, __LINE__ + 1 # rubocop:disable Security/Eval
def #{name}
__load_config__(#{name.inspect}, #{class_name.inspect})
end
RUBY
end
+ end
- # Control if settings can be loaded from environment variables. By default
- # environment variables are enabled. This can also be disabled on
- # individual Configuration classes.
- #
- # @param value [Boolean] Whether or not to load settings from environment variables.
- # @return [void]
- def environment_variables_disabled=(value)
- Configuration.environment_variables_disabled = !!value
- end
+ # Returns true if the provided class has been added as a configuration.
+ #
+ # @param class_name [Class, String] The name of the configuration class.
+ # @return [Boolean]
+ def include?(class_name)
+ @configurations.values.collect(&:to_s).include?(class_name.to_s)
+ end
- # Control if settings can be loaded from runtime settings. By default
- # runtime settings are enabled. This can also be disabled on individual
- # Configuration classes.
- #
- # @param value [Boolean] Whether or not to load settings from runtime settings.
- # @return [void]
- def runtime_settings_disabled=(value)
- Configuration.runtime_settings_disabled = !!value
- end
+ # Control if settings can be loaded from environment variables. By default
+ # environment variables are enabled. This can also be disabled on
+ # individual Configuration classes.
+ #
+ # @param value [Boolean] Whether or not to load settings from environment variables.
+ # @return [void]
+ def environment_variables_disabled=(value)
+ Configuration.environment_variables_disabled = !!value
+ end
- # Control if settings can be loaded from YAML configuration files. By
- # default YAML configuration is enabled. This can also be disabled on
- # individual Configuration classes.
- #
- # @param value [Boolean] Whether or not to load settings from YAML configuration.
- # @return [void]
- def yaml_config_disabled=(value)
- Configuration.yaml_config_disabled = !!value
- end
+ # Control if settings can be loaded from runtime settings. By default
+ # runtime settings are enabled. This can also be disabled on individual
+ # Configuration classes.
+ #
+ # @param value [Boolean] Whether or not to load settings from runtime settings.
+ # @return [void]
+ def runtime_settings_disabled=(value)
+ Configuration.runtime_settings_disabled = !!value
+ end
- # Set the delimiter to use when determining environment variable names.
- # By default this is an underscore.
- #
- # @param value [String] The delimiter to use.
- # @return [void]
- def env_var_delimiter=(value)
- Configuration.env_var_delimiter = value.to_s
- end
+ # Control if settings can be loaded from YAML configuration files. By
+ # default YAML configuration is enabled. This can also be disabled on
+ # individual Configuration classes.
+ #
+ # @param value [Boolean] Whether or not to load settings from YAML configuration.
+ # @return [void]
+ def yaml_config_disabled=(value)
+ Configuration.yaml_config_disabled = !!value
+ end
- # Set the delimiter to use when determining setting names. By default
- # this is a period.
- #
- # @param value [String] The delimiter to use.
- def setting_delimiter=(value)
- Configuration.setting_delimiter = value.to_s
- end
+ # Set the environment to use when loading YAML configuration files.
+ # In a Rails application this will be the current Rails environment.
+ # Defaults to "development".
+ #
+ # @param value [String] The environment name to use.
+ def yaml_config_env=(value)
+ Configuration.yaml_config_env = value
+ end
- # Control if environment variable names should be upcased. By default
- # this is true.
- #
- # @param value [Boolean] Whether or not to upcase environment variable names.
- # @return [void]
- def env_var_upcase=(value)
- Configuration.env_var_upcase = !!value
- end
+ # Set the delimiter to use when determining environment variable names.
+ # By default this is an underscore.
+ #
+ # @param value [String] The delimiter to use.
+ # @return [void]
+ def env_var_delimiter=(value)
+ Configuration.env_var_delimiter = value.to_s
+ end
- # Control if setting names should be upcased. By default this is false.
- #
- # @param value [Boolean] Whether or not to upcase setting names.
- # @return [void]
- def setting_upcase=(value)
- Configuration.setting_upcase = !!value
+ # Set the delimiter to use when determining setting names. By default
+ # this is a period.
+ #
+ # @param value [String] The delimiter to use.
+ def runtime_setting_delimiter=(value)
+ Configuration.runtime_setting_delimiter = value.to_s
+ end
+
+ # Control if environment variable names should be upcased. By default
+ # this is true.
+ #
+ # @param value [Boolean] Whether or not to upcase environment variable names.
+ # @return [void]
+ def env_var_upcase=(value)
+ Configuration.env_var_upcase = !!value
+ end
+
+ # Control if setting names should be upcased. By default this is false.
+ #
+ # @param value [Boolean] Whether or not to upcase setting names.
+ # @return [void]
+ def runtime_setting_upcase=(value)
+ Configuration.runtime_setting_upcase = !!value
+ end
+
+ # Set the directory to use when loading YAML configuration files.
+ # In a Rails application this will be the config directory.
+ # Otherwise it will be the current working directory.
+ #
+ # @param value [String, Pathname] The directory to use.
+ # @return [void]
+ def yaml_config_path=(value)
+ Configuration.yaml_config_path = value.to_s
+ end
+
+ # Set the object to use for runtime settings. This can be any object that
+ # responds to the [] method. If you are using the `super_settings` gem,
+ # you can set this to `SuperSettings`.
+ attr_writer :runtime_settings
+
+ # Get the object to use for runtime settings.
+ #
+ # @return [Object, nil]
+ # @api private
+ def __runtime_settings__
+ @runtime_settings ||= nil
+ end
+
+ # Explicitly set setting values within a block. This is useful for testing
+ # or other situations where you want hard code a specific set of values.
+ #
+ # @param settings [Hash] The settings to set.
+ # @return [Object] The result of the block.
+ def override!(settings, &block)
+ settings = settings.to_a
+ config_name, values = settings.first
+ config_name = config_name.to_s
+ other_settings = settings[1..-1]
+
+ unless @configurations.include?(config_name)
+ raise ArgumentError.new("Unknown configuration: #{config_name.inspect}")
end
- # Set the directory to use when loading YAML configuration files. By
- # default this is the config directory in the Rails root.
- #
- # @param value [String, Pathname] The directory to use.
- # @return [void]
- def yaml_config_directory=(value)
- Configuration.yaml_config_directory = value.to_s
+ config = send(config_name)
+ config.override!(values) do
+ if other_settings.empty?
+ yield
+ else
+ override!(other_settings, &block)
+ end
end
end
+ # Get the names of all of the configurations that have been added.
+ #
+ # @return [Array<String>] The names of the configurations.
+ # @api private
+ def __configuration_names__
+ @configurations.keys
+ end
+
private
# Load a configuration class.
def __load_config__(name, class_name)
klass = @configurations[name]
- if klass && !Rails.configuration.cache_classes
- klass = nil if klass != class_name.constantize
+ # Hook for Rails development mode to reload the configuration class.
+ if klass && defined?(Rails.configuration.cache_classes) && !Rails.configuration.cache_classes
+ klass = class_name if klass != constantize(class_name)
end
- unless klass
- klass = class_name.constantize
+ if klass.is_a?(String)
+ klass = constantize(class_name)
@mutex.synchronize do
unless klass < Configuration
raise TypeError.new("Configuration class #{class_name} does not inherit from UltraSettings::Configuration")
end
@configurations[name] = klass
end
end
klass.instance
+ end
+
+ def classify(name)
+ # Use the Rails classify method if it is available since it will
+ # handle custom inflections.
+ if name.respond_to?(:classify)
+ name.classify
+ else
+ name.split("_").map(&:capitalize).join.gsub("/", "::")
+ end
+ end
+
+ def constantize(class_name)
+ class_name.split("::").reduce(Object) do |mod, name|
+ mod.const_get(name)
+ end
end
end
end