Class: ComplexConfig::Settings

Inherits:
BasicObject
Extended by:
Tins::ThreadLocal
Includes:
Kernel, Tins::AskAndSend
Defined in:
lib/complex_config/settings.rb

Overview

A settings class that provides structured access to configuration data

The Settings class serves as a container for configuration values, offering nested access through method calls and providing utilities for converting between different representations like hashes, YAML, and JSON. It supports environment-specific lookups and can be deeply frozen to prevent modification after initialization.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(hash = nil) ⇒ Settings

The initialize method sets up a new Settings object with optional hash initialization

This method creates a new instance of the Settings class, initializing it with an optional hash of values. It sets the name_prefix from the class-level attribute and prepares an internal table for storing configuration attributes.

Parameters:

  • hash (Hash, nil) (defaults to: nil)

    An optional hash containing initial configuration values



126
127
128
129
130
131
132
133
134
135
# File 'lib/complex_config/settings.rb', line 126

def initialize(hash = nil)
  self.name_prefix = self.class.name_prefix
  @table = {}
  if hash
    hash.each_pair do |k, v|
      k = k.to_sym
      @table[k] = v
    end
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(id, *a, &b) ⇒ Object (private)

The method_missing method handles dynamic attribute access and assignment

This method intercepts calls to undefined methods on the Settings object, providing support for attribute retrieval, assignment, existence checking, and plugin-based value resolution. It processes method names ending with '?' for existence checks or safe navigation, '=' for assignment, and other names for attribute lookup or plugin execution.

Parameters:

  • id (Object)

    The name of the method being called

  • a (Array)

    Arguments passed to the method

  • b (Proc)

    Block passed to the method

Returns:

  • (Object)

    The result of the dynamic attribute operation



631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
# File 'lib/complex_config/settings.rb', line 631

def method_missing(id, *a, &b)
  case
  when id =~ /\?\z/
    begin
      public_send $`.to_sym, *a, &b
    rescue ::ComplexConfig::AttributeMissing
      nil
    end
  when id =~ /=\z/
    @table[$`.to_sym] = a.first
  when value = ::ComplexConfig::Provider.apply_plugins(self, id)
    value
  else
    if attribute_set?(id)
      @table[id]
    else
      raise ::ComplexConfig::AttributeMissing, "no attribute named #{id.inspect}"
    end
  end
end

Instance Attribute Details

#name_prefixObject

The name_prefix attribute accessor provides read and write access to the name prefix setting

This method allows getting and setting the name_prefix instance variable, which is used to prefix configuration keys and provide context for configuration lookups.



115
116
117
# File 'lib/complex_config/settings.rb', line 115

def name_prefix
  @name_prefix
end

Class Method Details

.[](*a) ⇒ ComplexConfig::Settings, ...

The [] method converts a hash-like object into a Settings object

This method serves as a convenience accessor that delegates to the from_hash class method, enabling quick conversion of hash-like structures into ComplexConfig::Settings objects for structured configuration access.

Parameters:

  • a (Object)

    the object to convert, which may respond to to_hash or to_ary

Returns:

  • (ComplexConfig::Settings, Array, Object)

    a Settings object if the input responds to to_hash, an array of converted elements if it responds to to_ary, or the original object if neither applies

See Also:



36
37
38
# File 'lib/complex_config/settings.rb', line 36

def [](*a)
  from_hash(*a)
end

.build(name, hash) ⇒ ComplexConfig::Settings

The build method constructs a Settings object from a hash with optional name prefixing

This method takes a name and hash, sets the name as the prefix for the Settings object, validates that the hash can be converted to a hash, then converts it using from_hash. It ensures the name_prefix is reset to nil after the operation completes.

Parameters:

  • name (String, nil)

    The name to use as prefix for the Settings object, or nil

  • hash (Object)

    The object to convert to a Settings object, must respond to to_hash

Returns:

Raises:

  • (TypeError)

    if the hash parameter does not respond to to_hash



85
86
87
88
89
90
91
# File 'lib/complex_config/settings.rb', line 85

def build(name, hash)
  name.nil? or self.name_prefix = name.to_sym
  hash.respond_to?(:to_hash) or raise TypeError, 'require hash to build'
  from_hash(hash)
ensure
  self.name_prefix = nil
end

.from_hash(object) ⇒ ComplexConfig::Settings, ...

The from_hash method converts a hash-like object into a Settings object

This method recursively processes hash-like objects and arrays, converting them into Settings objects with appropriate nested structures while preserving non-hash, non-array values as-is

Parameters:

  • object (Object)

    the object to convert, which may respond to to_hash or to_ary

Returns:

  • (ComplexConfig::Settings, Array, Object)

    a Settings object if the input responds to to_hash, an array of converted elements if it responds to to_ary, or the original object if neither applies



52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/complex_config/settings.rb', line 52

def from_hash(object)
  case
  when object.respond_to?(:to_hash)
    result = new
    object.to_hash.each do |key, value|
      result[key] = from_hash(value)
    end
    result
  when object.respond_to?(:to_ary)
    object.to_ary.map { |a| from_hash(a) }
  else
    object
  end
end

.name_prefixString

The thread_local method sets up a thread-local variable for the name_prefix attribute

This method configures a thread-local storage mechanism for the name_prefix attribute, allowing each thread to maintain its own independent value for this attribute while sharing the same class-level configuration.

Returns:

  • (String)

    the name prefix of the setting



104
# File 'lib/complex_config/settings.rb', line 104

thread_local :name_prefix

Instance Method Details

#==(other) ⇒ TrueClass, FalseClass

The == method compares this settings object with another object for equality

This method checks if the given object responds to to_h and then compares the hash representation of this settings object with the hash representation of the other object to determine if they are equal

Parameters:

  • other (Object)

    the object to compare with this settings object

Returns:

  • (TrueClass, FalseClass)

    true if the other object responds to to_h and their hash representations are equal, false otherwise



308
309
310
# File 'lib/complex_config/settings.rb', line 308

def ==(other)
  other.respond_to?(:to_h) && to_h == other.to_h
end

#[]=(name, value) ⇒ Object

The []= method assigns a value to a configuration attribute

This method stores a configuration attribute value in the internal table using the attribute name as a symbol key. It converts the attribute name to a symbol before storing the value.

Parameters:

  • name (Object)

    the name of the attribute to assign

  • value (Object)

    the value to assign to the attribute

Returns:

  • (Object)

    the assigned value



546
547
548
# File 'lib/complex_config/settings.rb', line 546

def []=(name, value)
  @table[name.to_sym] = value
end

#attribute_get(name) ⇒ Object? Also known as: []

The attribute_get method retrieves a configuration attribute value by name

This method attempts to fetch a configuration attribute value first from the internal table, and if the attribute is not set, it applies registered plugins to generate a value. It provides a unified way to access configuration attributes that may be dynamically generated.

Parameters:

  • name (Object)

    the name of the attribute to retrieve

Returns:

  • (Object, nil)

    the value of the attribute if found, or nil if not found



507
508
509
510
511
512
513
514
515
# File 'lib/complex_config/settings.rb', line 507

def attribute_get(name)
  if !attribute_set?(name) and
    value = ::ComplexConfig::Provider.apply_plugins(self, name)
  then
    value
  else
    @table[name.to_sym]
  end
end

#attribute_get!(name) ⇒ Object

The attribute_get! method retrieves a configuration attribute value by name, raising an exception if the attribute is not set

Parameters:

  • name (Object)

    the name of the attribute to retrieve

Returns:

  • (Object)

    the value of the attribute if found

Raises:



529
530
531
532
533
534
535
# File 'lib/complex_config/settings.rb', line 529

def attribute_get!(name)
  if attribute_set?(name)
    attribute_get(name)
  else
    raise ::ComplexConfig::AttributeMissing, "no attribute named #{name.inspect}"
  end
end

#attribute_namesArray<Symbol>

The attribute_names method retrieves all attribute names stored in the configuration

This method provides access to the internal table of attribute names that have been set on the current Settings object. It returns an array containing all the symbolized keys that represent the configured attributes.

Returns:

  • (Array<Symbol>)

    an array of symbolized attribute names that have been set on this Settings object



176
177
178
# File 'lib/complex_config/settings.rb', line 176

def attribute_names
  @table.keys
end

#attribute_set?(name) ⇒ TrueClass, FalseClass

The attribute_set? method checks whether a specific attribute has been set in the configuration

This method verifies if a given attribute name exists in the internal table of configuration settings, returning true if it has been explicitly set and false otherwise. It converts the provided name to a symbol before performing the lookup.

Parameters:

  • name (Object)

    the name of the attribute to check for existence

Returns:

  • (TrueClass, FalseClass)

    true if the attribute is set, false otherwise



162
163
164
# File 'lib/complex_config/settings.rb', line 162

def attribute_set?(name)
  @table.key?(name.to_sym)
end

#attribute_valuesArray<Object>

The attribute_values method retrieves all values stored in the configuration table

This method provides access to the internal table of configuration values, returning an array containing all the values that have been set on the current Settings object. It exposes the underlying data structure for direct inspection or processing.

table

Returns:

  • (Array<Object>)

    an array of all configuration values stored in the



190
191
192
# File 'lib/complex_config/settings.rb', line 190

def attribute_values
  @table.values
end

#attributes_list(pair_sep: ' = ', path_sep: ?.) ⇒ String

The attributes_list method generates a formatted string representation of all configuration attributes

This method creates a human-readable list of all configuration attributes by combining their paths and values into a structured format with customizable separators for paths and key-value pairs

Parameters:

  • pair_sep (String) (defaults to: ' = ')

    the separator to use between attribute paths and their values, defaults to ' = '

  • path_sep (String) (defaults to: ?.)

    the separator to use between path components, defaults to '.'

Returns:

  • (String)

    a formatted string containing all attribute paths and their corresponding values or the class name if no attributes are present



389
390
391
392
393
394
# File 'lib/complex_config/settings.rb', line 389

def attributes_list(pair_sep: ' = ', path_sep: ?.)
  empty? and return self.class.name
  pathes(path_sep: path_sep).inject('') do |result, (path, value)|
    result + "#{path}#{pair_sep}#{value.inspect}\n"
  end
end

#attributes_update(other) ⇒ Object

The attributes_update method merges configuration attributes from another source

This method updates the current object's internal table with attributes from another source, converting it to a Settings object if necessary. It performs a deep merge of the attribute data while preserving the existing structure.

Parameters:

  • other (Object)

    the source containing attributes to merge, which can be any object that responds to to_hash or to_ary



204
205
206
207
208
209
# File 'lib/complex_config/settings.rb', line 204

def attributes_update(other)
  unless other.is_a? self.class
    other = self.class.from_hash(other)
  end
  @table.update(other.table)
end

#attributes_update_if_nil(other) ⇒ Object

Deprecated.

Use #attributes_update_if_undefined instead. This method is kept for backward compatibility but now delegates to #attributes_update_if_undefined to ensure explicit nil overrides are respected.

The attributes_update_if_nil does the same attributes_update_if_undefined does.

Parameters:

  • other (Object)

    the source containing attributes to merge, which can be any object that responds to to_hash or to_ary



241
242
243
244
245
246
# File 'lib/complex_config/settings.rb', line 241

def attributes_update_if_nil(other)
  warn '[DEPRECATION] `%{method}` is deprecated. Please use `%{new_method}` instead.' % {
    method: __method__, new_method: :attributes_update_if_undefined
  }
  attributes_update_if_undefined(other)
end

#attributes_update_if_undefined(other) ⇒ Object

The attributes_update_if_undefined method merges configuration attributes from another source, updating only those that are completely missing (undefined) in this settings object.

This is specifically used for shared settings patterns where environment-specific configurations must be respected. Because it only updates missing keys, any attribute explicitly set—including an explicit nil value intended to disable a feature or clear a default—will be preserved and not overwritten by the provided shared configuration source.

Parameters:

  • other (Object)

    the source containing attributes to merge, which can be any object that responds to to_hash or to_ary



223
224
225
226
227
228
229
230
# File 'lib/complex_config/settings.rb', line 223

def attributes_update_if_undefined(other)
  unless other.is_a? self.class
    other = self.class.from_hash(other)
  end
  @table.update(other.table) do |key, oldval, newval|
    @table.key?(key) ? oldval : newval
  end
end

#deep_freezeself

The deep_freeze method recursively freezes all nested objects within the configuration

This method traverses the internal table of configuration attributes and applies deep freezing to each value, ensuring that all nested settings objects and their contents are immutable It also freezes the internal table itself to prevent modification of the attribute structure

Returns:

  • (self)

    Returns self to allow for method chaining after freezing



490
491
492
493
494
495
# File 'lib/complex_config/settings.rb', line 490

def deep_freeze
  table_enumerator.each do |_, v|
    v.ask_and_send(:deep_freeze) || (v.freeze rescue v)
  end
  freeze
end

#each {|key, value| ... } ⇒ self

The each method iterates over all configuration attributes

This method provides enumeration support for the configuration settings, yielding each key-value pair from the internal table to the provided block. It delegates to the table enumerator to ensure consistent iteration behavior across different contexts.

Yields:

  • (key, value)

    Yields each configuration attribute key and its corresponding value

Yield Parameters:

  • key (Object)

    The configuration attribute key

  • value (Object)

    The configuration attribute value

Returns:

  • (self)

    Returns self to allow for method chaining after enumeration



562
563
564
# File 'lib/complex_config/settings.rb', line 562

def each(&block)
  table_enumerator.each(&block)
end

#empty?TrueClass, FalseClass

The empty? method checks whether the settings object contains no attributes

This method determines if the current Settings object has zero configured attributes by comparing its size to zero. It provides a convenient way to test for emptiness without having to manually check the size or iterate through all attributes.

Returns:

  • (TrueClass, FalseClass)

    true if the settings object has no attributes, false otherwise



369
370
371
# File 'lib/complex_config/settings.rb', line 369

def empty?
  size == 0
end

#freezeself

The freeze method freezes the internal table and calls the superclass freeze method

This method ensures that the configuration data stored in the internal table is frozen, preventing further modifications to the configuration settings. It then delegates to the parent class's freeze method to complete the freezing process.

Returns:

  • (self)

    Returns self to allow for method chaining after freezing



476
477
478
479
# File 'lib/complex_config/settings.rb', line 476

def freeze
  @table.freeze
  super
end

#initialize_copy(orig) ⇒ self

The initialize_copy method creates a duplicate of the current object

This method is called when an object is being duplicated, typically through the dup or clone methods. It performs a deep copy of the internal table structure while preserving the object's state and ensuring that modifications to the copy don't affect the original object.

Parameters:

  • orig (Object)

    The original object being copied

Returns:

  • (self)

    Returns the duplicated object instance for chaining



146
147
148
149
150
# File 'lib/complex_config/settings.rb', line 146

def initialize_copy(orig)
  super
  @table = @table.dup
  self
end

#pathes(hash = table, path_sep: ?., prefix: name_prefix.to_s, result: {}) ⇒ Hash

The pathes method recursively builds a hash of configuration paths and their values

This method traverses a nested hash structure and constructs a flattened hash where keys are dot-separated paths representing the hierarchical structure of the original data, and values are the corresponding leaf values from the original structure

Parameters:

  • hash (Hash) (defaults to: table)

    the hash to process, defaults to the instance's table

  • path_sep (String) (defaults to: ?.)

    the separator to use between path components, defaults to '.'

  • prefix (String) (defaults to: name_prefix.to_s)

    the prefix to prepend to each path, defaults to the name_prefix

  • result (Hash) (defaults to: {})

    the hash to accumulate results in, defaults to an empty hash

Returns:

  • (Hash)

    a flattened hash with paths as keys and values as leaf values



423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
# File 'lib/complex_config/settings.rb', line 423

def pathes(hash = table, path_sep: ?., prefix: name_prefix.to_s, result: {})
  hash.each do |key, value|
    path = prefix.empty? ? key.to_s : "#{prefix}#{path_sep}#{key}"
    case value
    when ::ComplexConfig::Settings
      pathes(
        value,
        path_sep: path_sep,
        prefix:   path,
        result:   result
      )
    when ::Array
      value.each_with_index do |v, i|
        sub_path = path + "[#{i}]"
        if ::ComplexConfig::Settings === v
          pathes(
            v,
            path_sep: path_sep,
            prefix:   sub_path,
            result:   result
          )
        else
          result[sub_path] = v
        end
      end
    else
      result[path] = value
    end
  end
  result
end

#pretty_print(q) ⇒ Object

The pretty_print method formats the object for pretty printing

This method takes a PrettyPrint object and uses it to format the object's string representation for display purposes

Parameters:

  • q (PrettyPrint)

    the pretty printer object to use for formatting



463
464
465
# File 'lib/complex_config/settings.rb', line 463

def pretty_print(q)
  q.text inspect
end

#replace_attributes(hash) ⇒ self

The replace_attributes method replaces all attributes with those from the provided hash

This method updates the current object's internal table by replacing all existing attributes with new ones derived from the given hash. It converts the hash into a Settings object structure and then updates the internal table with the new data.

Parameters:

  • hash (Object)

    the source containing attributes to replace with, which can be any object that responds to to_hash or to_ary

Returns:

  • (self)

    returns self to allow for method chaining



260
261
262
263
# File 'lib/complex_config/settings.rb', line 260

def replace_attributes(hash)
  @table = self.class.from_hash(hash).table
  self
end

#sizeInteger

The size method returns the number of attributes in the settings object

This method counts all configured attributes by enumerating through the internal table and returning the total number of key-value pairs stored in the settings object

Returns:

  • (Integer)

    the count of attributes stored in this settings object



356
357
358
# File 'lib/complex_config/settings.rb', line 356

def size
  each.count
end

#to_hHash

The to_h method converts the settings object into a hash representation

This method recursively transforms the internal table of configuration attributes into a nested hash structure, preserving the hierarchical organization of settings while handling various value types including arrays, nested settings objects, and primitive values.

Returns:

  • (Hash)

    a hash representation of the settings object with all nested structures converted to their hash equivalents



281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
# File 'lib/complex_config/settings.rb', line 281

def to_h
  table_enumerator.each_with_object({}) do |(k, v), h|
    h[k] =
      if v.respond_to?(:to_ary)
        v.to_ary.map { |x| (x.ask_and_send(:to_h) rescue x) || x }
      elsif v.respond_to?(:to_h)
        if v.nil?
          nil
        else
          v.ask_and_send(:to_h) rescue v
        end
      else
        v
      end
  end
end

#to_json(*a) ⇒ String

The to_json method converts the settings object into JSON format

This method transforms the configuration data stored in the settings object into a JSON string representation, making it suitable for serialization and interchange with other systems that consume JSON data.

Parameters:

  • a (Array)

    Additional arguments to pass to the underlying to_json method

Returns:

  • (String)

    a JSON formatted string representation of the settings object



332
333
334
# File 'lib/complex_config/settings.rb', line 332

def to_json(*a)
  to_h.to_json(*a)
end

#to_s(*a) ⇒ String Also known as: inspect

The to_s method provides a string representation of the settings object

This method returns a human-readable string representation of the settings object, either by returning the class name when the object is empty, or by converting the object to a tree structure and then to a string for non-empty objects

Parameters:

  • a (Array)

    Additional arguments passed to the method (not used)

Returns:

  • (String)

    The string representation of the settings object



405
406
407
408
# File 'lib/complex_config/settings.rb', line 405

def to_s(*a)
  empty? and return self.class.name
  to_tree.to_s
end

#to_treeComplexConfig::Tree

The to_tree method converts the settings object into a tree representation

This method transforms the hierarchical configuration data stored in the settings object into a tree structure that can be used for visualization or display purposes. It utilizes the Tree.convert class method to perform the actual conversion process.

Returns:



345
346
347
# File 'lib/complex_config/settings.rb', line 345

def to_tree
  ::ComplexConfig::Tree.convert(name_prefix, self)
end

#to_yamlString

The to_yaml method converts the settings object into YAML format

This method transforms the configuration data stored in the settings object into a YAML string representation, making it suitable for serialization and storage in YAML files.

Returns:

  • (String)

    a YAML formatted string representation of the settings object



319
320
321
# File 'lib/complex_config/settings.rb', line 319

def to_yaml
  to_h.to_yaml
end