Class: PRC::CoreConfig

Inherits:
Object show all
Defined in:
lib/prc_core_config.rb,
lib/prc_core_config.rb,
lib/prc_core_config.rb,
lib/prc_core_config.rb

Overview

This class implement The CoreConfig system of lorj.

  • You can use it directly. See ::new.

  • you can enhance it with class heritage feature. See Class child discussion later in this class documentation.

Public functions implemented:

It implements several layer of CoreConfig object type to provide several source of data in layers priorities. Ex: RunTime => LocalConfig => AppDefault

It implements config features:

  • #[] - To get a value for a key or tree of keys

  • #[]= - To set a Config value in the highest config.

  • #del - To delete key or simply nil the value in highest config.

  • #exist? - To check the existence of a value in config levels.

  • #where? - To get the name of the level where the value was found.

  • #file - To get or set a filename to a config layer.

  • #save - To save one config data level in a yaml file.

  • #load - To load data from a yaml file to a config data layer.

  • #merge - To merge several layers data values. Values must be Hash.

When the instance is initialized, it defines 3 Config layers (BaseConfig).

If you need to define layers differently, consider to create your child class. You will be able to use SectionConfig or even any BaseConfig Child class as well.

For details about a Config layers, See BaseConfig or SectionConfig.

Child Class implementation:

This class can be enhanced with any kind of additional functionality.

You can redefine following functions exist?, [], []=, file, save, load, del, merge.

Each public functions calls pendant function, private, prefixed by _, with default options

public => private

  • #exist? => #p_exist?

  • #[] => #p_get

  • #[]= => #p_set

  • #file => #p_file

  • #save => #p_save

  • #load => #p_load

  • #del => #p_del

  • #merge => #p_get(:merge => true).

Examples:

  • Your child class can limit or re-organize config layers to query. Use :indexes or :names options to select which layer you want to query and call the core function.

    Ex: If you have 4 config levels and want to limit to 2 top ones

    def [](*keys)
      options = { keys: keys}
      options[:indexes] = [0, 1]
      p_get(options)
    end
    

    Ex: If you have 4 config levels and want to limit to 2 names.

     def [](*keys)
       options = { keys: keys}
       options[:names] = ['local', 'default_app']
       p_get(options)
    end
    
  • Your child class can force some levels options or define some extra options.

    Use :data_options to define each of them

    # Ex: If your class has 4 levels. /:name is not updatable for level 1.
    
    def [](*keys)
      options = { keys: keys }
      # The following defines data_readonly for the config level 1
      if keys[0] == :name
         options[:data_options] = [nil, {data_readonly: true}]
      end
      p_get(options)
    end
    
    # Ex: if some layer takes care of option :section, and apply to each
    # layers.
    def [](section, *keys)
      options = { keys: keys, section: section }
      p_get(options)
    end
    
    # Ex: if some layer takes care of option :section, and to apply to some
    # layers, like layer 1 and 2. (Assume with 4 layers.)
    
    def [](section, *keys)
      options = { keys: keys }
      options[:data_options] = [nil, {section: section}, {section: section}]
      p_get(options)
    end
    

Direct Known Subclasses

Lorj::Config, Lorj::MetaAppConfig

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config_layers = nil) ⇒ CoreConfig

initialize CoreConfig

  • Args

    • config_layers : Array config layers configuration. Each layer options have those options:

      • :config : optional. See ‘Defining Config layer instance` for details

      • :name : required. String. Name of the config layer. Warning! unique name on layers is no tested.

      • :set : boolean. True if authorized. Default is True.

      • :load : boolean. True if authorized. Default is False.

      • :save : boolean. True if authorized. Default is False.

      • :file_set : boolean. True if authorized to update a filename. Default is False.

each layers can defines some options for the layer to behave differently CoreConfig call a layer data_options to set some options, before exist?, get or [], set or []=, save and load functions. See BaseConfig::data_options for predefined options.

Core config provides some private additionnal functions for child class functions:

  • #_set_data_options(layers, options) - To set data_options on one or more config layers

  • #p_get(options) - core get function

  • #p_set(options) - core set function

  • #p_save(options) core save function

  • #p_load(options) - core load function

if config_layers is not provided, CoreConfig will instanciate a runtime like system:

config = CoreConfig.New
# is equivalent to :
config_layers = [{name: 'runtime',
                  config: PRC::BaseConfig.new, set: true}]
config = CoreConfig.New(config_layers)

Defining Config layer instance:

:config value requires it to be of type ‘BaseConfig’ By default, it uses ‘:config => PRC::BaseConfig.new` Instead, you can set:

  • directly BaseConfig. ‘:config => PRC::BaseConfig.new`

  • a child based on BaseConfig. ‘:config => MyConfig.new`

  • some predefined enhanced BaseConfig:

    • PRC::SectionConfig. See prc_section_config.rb. ‘:config => PRC::SectionConfig.new`



705
706
707
708
709
710
711
# File 'lib/prc_core_config.rb', line 705

def initialize(config_layers = nil)
  if config_layers.nil?
    config_layers = []
    config_layers << CoreConfig.define_layer
  end
  initialize_layers(config_layers)
end

Class Method Details

.define_layer(options = {}) ⇒ Object

Function to define layer options. By default, :set is true and :config is attached to a new PRC::BaseConfig instance.

Supported options:

  • :config : optional. See ‘Defining Config layer instance` for details

  • :name : required. String. Name of the config layer. Warning! unique name on layers is no tested.

  • :set : boolean. True if authorized. Default is True.

  • :load : boolean. True if authorized. Default is False.

  • :save : boolean. True if authorized. Default is False.

  • :file_set : boolean. True if authorized to update a filename. Default is False.



789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
# File 'lib/prc_core_config.rb', line 789

def self.define_layer(options = {})
  attributes = [:name, :config, :set, :load, :save, :file_set]

  layer = {}

  attributes.each do |attribute|
    if options.key?(attribute)
      layer[attribute] = options[attribute]
    else
      layer[attribute] = case attribute
                         when :name
                           'runtime'
                         when :config
                           PRC::BaseConfig.new
                         when :set
                           true
                         else
                           false
                         end
    end
  end
  layer
end

Instance Method Details

#[](*keys) ⇒ Object

Get function

  • Args

    • keys : Array of key path to found

  • Returns value found or nil.



1048
1049
1050
# File 'lib/prc_core_config.rb', line 1048

def [](*keys)
  p_get(:keys => keys)
end

#[]=(*keys, value) ⇒ Object

Set function

  • Args

    • keys : Array of key path to found

  • Returns

    • The value set or nil

ex: value = CoreConfig.New

value[:level1, :level2] = ‘value’ # => => {:level2 => ‘value’}



1083
1084
1085
# File 'lib/prc_core_config.rb', line 1083

def []=(*keys, value)
  p_set(:keys => keys, :value => value)
end

#del(*keys) ⇒ Object

Del function

  • Args

    • keys : Array of key path to found and delete the last element.

  • Returns

    • The Hash updated.

ex: value = CoreConfig.New

value[:level1, :level2] = ‘value’ # => => {:level2 => ‘value’} => {:level2 => ‘value’}.del(:level1, :level2) # => => {}



1101
1102
1103
# File 'lib/prc_core_config.rb', line 1101

def del(*keys)
  p_del(:keys => keys)
end

#exist?(*keys) ⇒ Boolean

exist?

  • Args

    • keys : Array of key path to found

  • Returns

    • boolean : true if the key path was found

Class child: A class child can redefine this function to increase default features.

Returns:

  • (Boolean)


1024
1025
1026
# File 'lib/prc_core_config.rb', line 1024

def exist?(*keys)
  p_exist?(:keys => keys)
end

#file(filename = nil, options = {}) ⇒ Object

Get/Set the file name.

  • Args

    • :file : file name for the layer identified.

    • options : Supported options for save

      • :index: layer index to get data.

      • :name : layer to get data. If neither :name or :index is set, nil is returned.

  • Returns

    • The file name.



1148
1149
1150
# File 'lib/prc_core_config.rb', line 1148

def file(filename = nil, options = {})
  p_file(filename, options)
end

#layer_add(options) ⇒ Object

This function add a config layer at runtime. The new layer added at runtime, can be removed at runtime with layer_remove The name MUST be different than other existing config layer names

Args

- +options+ : Hash data
  - :name     : Required. Name of the layer to add
  - :index    : Config position to use. 0 is the default. 0 is the first
    Config layer use by get.
  - :config   : A Config instance of class type PRC::BaseConfig
  - :set      : Boolean. True if is authorized to set a variable.
  - :load     : Boolean. True if is authorized to load from a file.
  - :save     : Boolean. True if is authorized to save to a file.
  - :file_set : Boolean. True if is authorized to change the file name.

returns

- true if layer is added.
OR
- nil : if layer name already exist


733
734
735
736
737
738
739
740
741
742
743
744
745
746
# File 'lib/prc_core_config.rb', line 733

def layer_add(options)
  layer = CoreConfig.define_layer(options)

  layer[:init] = false # Runtime layer

  index = 0
  index = options[:index] if options[:index].is_a?(Fixnum)
  names = []
  @config_layers.each { |alayer| names << alayer[:name] }

  return nil if names.include?(layer[:name])
  @config_layers.insert(index, layer)
  true
end

#layer_index(name) ⇒ Object

layer_index function

  • Args

  • :name : layer to identify.

  • Returns first index found or nil.



843
844
845
846
847
848
849
850
851
# File 'lib/prc_core_config.rb', line 843

def layer_index(name)
  return nil unless name.is_a?(String)
  return nil if @config_layers.nil?

  @config_layers.each_index do |index|
    return index if @config_layers[index][:name] == name
  end
  nil
end

#layer_indexes(names) ⇒ Object

layer_indexes function

  • Args

  • :name : layer to identify.

  • Returns first index found or nil.



821
822
823
824
825
826
827
828
829
830
831
832
833
# File 'lib/prc_core_config.rb', line 821

def layer_indexes(names)
  names = [names] if names.is_a?(String)
  return nil unless names.is_a?(Array)

  layers = []

  names.each do |name|
    index = layer_index(name)
    layers << index unless index.nil?
  end
  return layers if layers.length > 0
  nil
end

#layer_remove(options) ⇒ Object

Function to remove a runtime layer. You cannot remove a predefined layer, created during CoreConfig instanciation. Args

- +options+ : Hash data
  - +:name+ : Name of the layer to remove.
  - +:index+: Index of the layer to remove.

At least, :name or :index is required. If both; :name and :index are set, :name is used. return

- true if layer name is removed.
OR
- nil : if not found or invalid.


762
763
764
765
766
767
768
769
770
771
772
773
774
# File 'lib/prc_core_config.rb', line 762

def layer_remove(options)
  index = layer_index(options[:name])
  index = options[:index] if index.nil?

  return nil if index.nil?

  layer = @config_layers[index]

  return nil if layer.nil? || layer[:init]

  @config_layers.delete_at(index)
  true
end

#layersObject

List all config layers defined in this instance.



1190
1191
1192
1193
1194
# File 'lib/prc_core_config.rb', line 1190

def layers
  result = []
  @config_layers.each { |layer| result << layer[:name] }
  result
end

#load(options = {}) ⇒ Object

Load from a file to the highest layer or a specific layer.

  • Args :

    • options : Supported options for load

      • :name : layer to get data.

      • :index: layer index to get data. If neither :name or :index is set, set will use the highest layer

  • Returns : -

  • Raises :

    • ++ ->



1118
1119
1120
# File 'lib/prc_core_config.rb', line 1118

def load(options = {})
  p_load(options)
end

#merge(*keys) ⇒ Object

Merge function Compare to get, merge will extract all values from each layers If those values are found and are type of Hash, merge will merge each layers values from the bottom to the top layer. ie invert of CoreConfig.layers

Note that if a layer contains a data, but not Hash, this layer will be ignored.

  • Args

    • keys : Array of key path to found

  • Returns value found merged or nil.



1067
1068
1069
# File 'lib/prc_core_config.rb', line 1067

def merge(*keys)
  p_get(:keys => keys, :merge => true)
end

#mergeable?(options) ⇒ Boolean

Function to check if merge can be used on a key. merge can return data only if at least one key value accross layers are of type Hash or Array.

  • Args

    • options : Hash of how to get the data

      • :value : Value to set

      • :keys : Array of key path to found

      • :name : layer to get data.

      • :index : layer index to get data. If neither :name or :index is set, set will use the highest layer.

      • :data_opts : Array or Hash. Define data options per layer.

      • :exclusive : true to ensure values found are exclusively Hash or Array

Returns:

  • (Boolean)


1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
# File 'lib/prc_core_config.rb', line 1166

def mergeable?(options)
  parameters = _common_options_get(options, [:keys], [:exclusive])
  return nil if parameters.nil?

  # Required options : parameters[0]
  config_layers, data_opts, keys = parameters[0]
  # Optional options : parameters[1]
  be_exclusive = parameters[1][0]

  # Merge is done in the reverse order. ie from deepest to top.
  config_layers = config_layers.reverse

  return nil if keys.length == 0 || keys[0].nil? || config_layers[0].nil?

  data_options = options.clone
  data_options.delete_if do |key|
    [:keys, :names, :indexes, :name, :index, :merge].include?(key)
  end

  _check_from_layers(keys, config_layers, data_opts, data_options,
                     be_exclusive)
end

#save(options = {}) ⇒ Object

Save to a file

  • Args :

    • options : Supported options for save

      • :name : layer to get data.

      • :index: layer index to get data. If neither :name or :index is set, set will use the highest layer

  • Returns : -



1133
1134
1135
# File 'lib/prc_core_config.rb', line 1133

def save(options = {})
  p_save(options)
end

#to_sObject

Display in human format.



1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
# File 'lib/prc_core_config.rb', line 1197

def to_s
  data = "Configs list ordered:\n"
  @config_layers.each do |layer|
    data += format("---- Config : %s ----\noptions: ", layer[:name])

    data += 'predefined, ' if layer[:init].is_a?(TrueClass)
    if layer[:set]
      data += 'data RW '
    else
      data += 'data RO '
    end
    data += format(", %s\n", to_s_file_opts(layer))

    data += format("%s\n", layer[:config].to_s)
  end
  data
end

#where?(*keys) ⇒ Boolean

where?

  • Args

    • keys : Array of key path to found

  • Returns

    • boolean : true if the key path was found

Returns:

  • (Boolean)


1036
1037
1038
# File 'lib/prc_core_config.rb', line 1036

def where?(*keys)
  p_where?(:keys => keys)
end