Class: FeduxOrgStdlib::AppConfig

Inherits:
Object
  • Object
show all
Defined in:
lib/fedux_org_stdlib/app_config.rb,
lib/fedux_org_stdlib/app_config/exceptions.rb

Overview

This class makes a config file available as an object. The config file needs to be ‘YAML` by default. It is read by `Psych` and converted to a hash. If you chose to use a different file format: Each config file needs to translatable to a hash or another data structure which responds to `[]` by the given `config_engine`. If no suitable config file can be found the config uses only the defined defaults within the class.

By default it will look for a suitable config file in the given order:

  1. $HOME/.config/<application_name>/<config_file>.yaml

  2. $HOME/.<application_name>/<config_file>.yaml

  3. $HOME/.<config_file>.yaml

  4. $HOME/.<config_file>rc

  5. /etc/.<application_name>/<config_file>.yaml

Please keep in mind

  • application_name: Module of your class, e.g. “MyApplication” becomes “my_application”

  • config_file: Pluarized name of your class and “Config” strip off, e.g “ClientConfig” becomes “clients.yaml” (mind the pluralized name)

Most conventions defined by me are implemented as separate methods. If one convention is not suitable for your use case, just overwrite the method.

If you prefer to use a different path to the config file or name of the config file one of the following methods needs to be overwritten:

  • config_file

  • config_name

  • application_name

If you want the class to look for your config file at a different place overwrite the following method

  • allowed_config_file_paths

Below you find some examples for the usage of the class:

Examples:

Create config with one writer and reader

module MyApplication
  class ClientConfig < AppConfig
    # 'data1' is the default for option1
    # if you create a file
    option :option1, 'data1'
  end
end

Create config with a reader only

module MyApplication
  class ClientConfig < AppConfig
    # 'data1' is the default for option1
    # if you create a file
    option_reader :option1, 'data1'
  end
end

Config yaml file for the classes above: clients.yaml

---
option1: 'data2'

Defined Under Namespace

Modules: Exceptions

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file: nil, merge_files: false, config_engine: Psych, logger: FeduxOrgStdlib::Logging::Logger.new, check_unknown_options: true, working_directory: Dir.getwd, safe: true) ⇒ AppConfig

Returns a new instance of AppConfig.



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/fedux_org_stdlib/app_config.rb', line 186

def initialize(
  file: nil,
  merge_files: false,
  config_engine: Psych,
  logger: FeduxOrgStdlib::Logging::Logger.new,
  check_unknown_options: true,
  working_directory: Dir.getwd,
  safe: true
)
  @logger                = logger
  @files                 = Array(file)
  @merge_files           = merge_files
  @config_engine         = config_engine
  @check_unknown_options = check_unknown_options
  @working_directory     = working_directory
  @safe                  = safe

  detect_files if @files.blank?
  load_config
end

Instance Attribute Details

#check_unknown_optionsAppConfig (readonly)

Create a new instance of config

It tries to find a suitable configuration file. If it doesn’t find one the config is empty and uses the defaults defined within a config class

Parameters:

  • file (String)

    Path where config file is stored. The file will be read by the ‘config_engine`.

  • config_engine (Object)

    (Psych) The engine to read config file

  • check_unknown_options (true, false)

    Should a warning be put to stdout if there are unknown options in yaml config file

Returns:

  • (AppConfig)

    The config instance. If the resulting data structure created by the config_engine does not respond to ‘:[]` an empty config object will be created.

Raises:



184
185
186
# File 'lib/fedux_org_stdlib/app_config.rb', line 184

def check_unknown_options
  @check_unknown_options
end

#config_engineAppConfig (readonly)

Create a new instance of config

It tries to find a suitable configuration file. If it doesn’t find one the config is empty and uses the defaults defined within a config class

Parameters:

  • file (String)

    Path where config file is stored. The file will be read by the ‘config_engine`.

  • config_engine (Object)

    (Psych) The engine to read config file

  • check_unknown_options (true, false)

    Should a warning be put to stdout if there are unknown options in yaml config file

Returns:

  • (AppConfig)

    The config instance. If the resulting data structure created by the config_engine does not respond to ‘:[]` an empty config object will be created.

Raises:



184
185
186
# File 'lib/fedux_org_stdlib/app_config.rb', line 184

def config_engine
  @config_engine
end

#filesAppConfig (readonly)

Create a new instance of config

It tries to find a suitable configuration file. If it doesn’t find one the config is empty and uses the defaults defined within a config class

Parameters:

  • file (String)

    Path where config file is stored. The file will be read by the ‘config_engine`.

  • config_engine (Object)

    (Psych) The engine to read config file

  • check_unknown_options (true, false)

    Should a warning be put to stdout if there are unknown options in yaml config file

Returns:

  • (AppConfig)

    The config instance. If the resulting data structure created by the config_engine does not respond to ‘:[]` an empty config object will be created.

Raises:



184
185
186
# File 'lib/fedux_org_stdlib/app_config.rb', line 184

def files
  @files
end

#loggerAppConfig (readonly)

Create a new instance of config

It tries to find a suitable configuration file. If it doesn’t find one the config is empty and uses the defaults defined within a config class

Parameters:

  • file (String)

    Path where config file is stored. The file will be read by the ‘config_engine`.

  • config_engine (Object)

    (Psych) The engine to read config file

  • check_unknown_options (true, false)

    Should a warning be put to stdout if there are unknown options in yaml config file

Returns:

  • (AppConfig)

    The config instance. If the resulting data structure created by the config_engine does not respond to ‘:[]` an empty config object will be created.

Raises:



184
185
186
# File 'lib/fedux_org_stdlib/app_config.rb', line 184

def logger
  @logger
end

#merge_filesAppConfig (readonly)

Create a new instance of config

It tries to find a suitable configuration file. If it doesn’t find one the config is empty and uses the defaults defined within a config class

Parameters:

  • file (String)

    Path where config file is stored. The file will be read by the ‘config_engine`.

  • config_engine (Object)

    (Psych) The engine to read config file

  • check_unknown_options (true, false)

    Should a warning be put to stdout if there are unknown options in yaml config file

Returns:

  • (AppConfig)

    The config instance. If the resulting data structure created by the config_engine does not respond to ‘:[]` an empty config object will be created.

Raises:



184
185
186
# File 'lib/fedux_org_stdlib/app_config.rb', line 184

def merge_files
  @merge_files
end

#safeAppConfig (readonly)

Create a new instance of config

It tries to find a suitable configuration file. If it doesn’t find one the config is empty and uses the defaults defined within a config class

Parameters:

  • file (String)

    Path where config file is stored. The file will be read by the ‘config_engine`.

  • config_engine (Object)

    (Psych) The engine to read config file

  • check_unknown_options (true, false)

    Should a warning be put to stdout if there are unknown options in yaml config file

Returns:

  • (AppConfig)

    The config instance. If the resulting data structure created by the config_engine does not respond to ‘:[]` an empty config object will be created.

Raises:



184
185
186
# File 'lib/fedux_org_stdlib/app_config.rb', line 184

def safe
  @safe
end

#working_directoryAppConfig (readonly)

Create a new instance of config

It tries to find a suitable configuration file. If it doesn’t find one the config is empty and uses the defaults defined within a config class

Parameters:

  • file (String)

    Path where config file is stored. The file will be read by the ‘config_engine`.

  • config_engine (Object)

    (Psych) The engine to read config file

  • check_unknown_options (true, false)

    Should a warning be put to stdout if there are unknown options in yaml config file

Returns:

  • (AppConfig)

    The config instance. If the resulting data structure created by the config_engine does not respond to ‘:[]` an empty config object will be created.

Raises:



184
185
186
# File 'lib/fedux_org_stdlib/app_config.rb', line 184

def working_directory
  @working_directory
end

Class Method Details

.known_optionsObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



74
75
76
# File 'lib/fedux_org_stdlib/app_config.rb', line 74

def known_options
  @options ||= Set.new
end

.option(option, default_value) ⇒ Object

Define a writer and a reader for option

Parameters:

  • option (Symbol)

    Name of option

  • default_value (Object)

    Default value of option



143
144
145
146
# File 'lib/fedux_org_stdlib/app_config.rb', line 143

def option(option, default_value)
  option_reader(option, default_value)
  option_writer(option)
end

.option_reader(option, default_value) ⇒ Object

Define a reader for option

Parameters:

  • option (Symbol)

    Name of option

  • default_value (Object)

    The default value of this option



97
98
99
100
101
102
103
104
105
106
107
# File 'lib/fedux_org_stdlib/app_config.rb', line 97

def option_reader(option, default_value)
  option =  option.to_sym

  fail Exceptions::OptionNameForbidden, JSON.dump(option: option) if _reserved_key_words.include? option

  define_method option do
    _config.fetch(option, default_value)
  end

  known_options << option
end

.option_writer(option) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Define a writer for option

Please make sure that you define a reader as well. Otherwise you cannot access the option. Under normal conditions it does not make sense to use this method.

Parameters:

  • option (Symbol)

    Name of option

Raises:



122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/fedux_org_stdlib/app_config.rb', line 122

def option_writer(option)
  fail Exceptions::OptionNameForbidden, JSON.dump(option: option) if _reserved_key_words.include? "#{option}=".to_sym

  define_method "#{option}=".to_sym do |value|
    begin
      _config[option.to_sym] = value
    rescue RuntimeError
      raise Exceptions::ConfigLocked
    end
  end

  known_options << option
end

.process_environmentObject

Get access to process environment

This might be handy to define default options

Examples:

Get variable


process_environment.fetch('HOME')
# => ENV['HOME']


86
87
88
# File 'lib/fedux_org_stdlib/app_config.rb', line 86

def process_environment
  @process_environment ||= ProcessEnvironment.new
end

Instance Method Details

#clearObject

Clear configuration



267
268
269
# File 'lib/fedux_org_stdlib/app_config.rb', line 267

def clear
  @__config = {}
end

#defaultsObject

Return configuration resetted to defaults



272
273
274
275
276
277
# File 'lib/fedux_org_stdlib/app_config.rb', line 272

def defaults
  config = dup
  config.clear

  config
end

#known_optionsObject

Show known options for configuration



219
220
221
# File 'lib/fedux_org_stdlib/app_config.rb', line 219

def known_options
  self.class.known_options
end

#lockObject

Lock the configuration



224
225
226
# File 'lib/fedux_org_stdlib/app_config.rb', line 224

def lock
  _config.freeze
end

#preferred_configuration_fileString

Return the path to the preferred configuration file

Returns:

  • (String)

    The path to the preferred configuration file



262
263
264
# File 'lib/fedux_org_stdlib/app_config.rb', line 262

def preferred_configuration_file
  _allowed_config_file_paths.first
end

#redetectObject

Redected configuration file and reload config afterwards



213
214
215
216
# File 'lib/fedux_org_stdlib/app_config.rb', line 213

def redetect
  detect_files
  load_config
end

#reloadObject

Reload from already found config file



208
209
210
# File 'lib/fedux_org_stdlib/app_config.rb', line 208

def reload
  load_config
end

#to_h(keys: [], remove_blank: false) ⇒ Object



279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/fedux_org_stdlib/app_config.rb', line 279

def to_h(keys: [], remove_blank: false)
  options_to_return = if keys.blank?
                        known_options.to_a
                      else
                        known_options.to_a & keys.map(&:to_sym)
                     end

  options_to_return.sort.each_with_object({}) do |e, a|
    next if remove_blank && public_send(e).blank?
    a[e] = public_send(e)
  end
end

#to_sString

Output a string presentation of the configuration

Returns:

  • (String)

    An formatted version of the configuration



232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/fedux_org_stdlib/app_config.rb', line 232

def to_s
  # header 'length' = 6 letters
  length = self.class.known_options.reduce(6) { |a, e| e.size > a ? e.size : a }

  result = []
  result << format("%#{length}s | %s", 'option', 'value')
  result << format('%s + %s', '-' * length, '-' * 80)

  self.class.known_options.sort.each do |o|
    value = public_send(o)

    value = if value == false
              Array(value)
            elsif value.blank?
              Array('is undefined')
            elsif value.is_a?(Hash) || value.is_a?(Array)
              value
            else
              Array(value)
            end

    result << format("%#{length}s | %s", o, value.to_list)
  end

  result.join("\n")
end

#to_yaml(prepend: nil, **args) ⇒ Object

Convert config to yaml



293
294
295
296
297
298
299
# File 'lib/fedux_org_stdlib/app_config.rb', line 293

def to_yaml(prepend: nil, **args)
  yaml = Psych.dump to_h(**args).deep_stringify_keys

  return yaml.split("\n").map { |l| l.prepend prepend }.join("\n") if prepend

  yaml
end