Class: Lich::Common::SetupFiles

Inherits:
Object
  • Object
show all
Includes:
MonitorMixin
Defined in:
documented/common/setup_files.rb

Overview

Loads, caches, and merges YAML configuration files for Lich scripts.

SetupFiles manages a cascading merge of base, character-specific, and included configuration files. It handles recursive include resolution with circular dependency protection, automatic caching with modification-time checking, and deep-clone protection to prevent in-memory mutations from affecting cached data.

Files are merged in this order: base.yaml, base-empty.yaml, resolved includes, then character-specific profiles. Keys listed in a file's union_keys property are merged as array unions instead of overwrites, allowing multiple files to contribute to shared lists.

Examples:

Load character settings with a custom profile suffix

setup = SetupFiles.new
settings = setup.get_settings(['custom_suffix'])
puts settings.some_key

Load game data

setup = SetupFiles.new
spells = setup.get_data('spells')

See Also:

Defined Under Namespace

Classes: FileInfo

Instance Method Summary collapse

Constructor Details

#initialize(debug = false) ⇒ SetupFiles

Initializes a SetupFiles instance.

Parameters:

  • debug (Boolean) (defaults to: false)

    if true, logs detailed cache operations to the debug stream; defaults to false



103
104
105
106
107
# File 'documented/common/setup_files.rb', line 103

def initialize(debug = false)
  super()
  @files_cache = {}
  @debug = debug
end

Instance Method Details

#get_data(type) ⇒ OpenStruct

Returns the config in a 'scripts/data/base-type.yaml' file.

Parameters:

  • type (String)

    the data file type (e.g. 'spells', 'town')

Returns:

  • (OpenStruct)

    data from base-type.yaml



171
172
173
174
175
# File 'documented/common/setup_files.rb', line 171

def get_data(type)
  filename = to_base_filename(type)
  reload_data([filename])
  transform_data(cache_get_by_filename(filename)&.data)
end

#get_settings(character_suffixes = []) ⇒ OpenStruct

Returns your character's settings.

Parameters:

  • character_suffixes (Array<String>) (defaults to: [])

    additional profile suffixes to load

Returns:

  • (OpenStruct)

    merged and transformed settings



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'documented/common/setup_files.rb', line 130

def get_settings(character_suffixes = [])
  character_suffixes = ['setup', character_suffixes].flatten.compact.uniq
  character_filenames = character_suffixes_to_filenames(character_suffixes)
  reload_profiles(character_filenames)

  initial_include_suffixes = character_filenames.reduce([]) do |result, filename|
    result + (cache_get_by_filename(filename)&.peek('include') || [])
  end
  initial_include_filenames = initial_include_suffixes.map { |suffix| to_include_filename(suffix) }
  include_filenames = resolve_includes_recursively(initial_include_filenames)
  safe_log "#{self.class}::#{__callee__} resolved include_filenames=#{include_filenames}" if @debug

  all_files = ['base.yaml', 'base-empty.yaml', include_filenames, character_filenames].flatten

  # Peek pass: collect union_keys from all files (always unioned across files).
  # Keys listed in union_keys get array union instead of overwrite during merge,
  # allowing includes and character files to contribute to shared lists.
  union_keys = all_files.reduce([]) do |keys, filename|
    file_keys = cache_get_by_filename(filename)&.peek('union_keys') || []
    (keys + file_keys).uniq
  end

  # Merge pass: union specified keys, overwrite everything else
  settings = all_files.reduce({}) do |result, filename|
    file_info = cache_get_by_filename(filename)
    result.merge(file_info ? file_info.data : {}) do |key, old_val, new_val|
      if union_keys.include?(key.to_s) && old_val.is_a?(Array) && new_val.is_a?(Array)
        (old_val + new_val).uniq
      else
        new_val
      end
    end
  end

  transform_settings(settings)
end

#reloadObject

Reloads cached files that have changed on disk.



178
179
180
181
# File 'documented/common/setup_files.rb', line 178

def reload
  reload_profiles(character_suffixes_to_filenames(['setup']))
  reload_data
end

#safe_load_yaml(filepath) ⇒ Hash

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.

Loads a YAML file safely, converting it to a Hash via OpenStruct.

Silently catches and logs parsing errors, returning an empty Hash on failure. This method is tolerant of YAML errors that occur during script initialization, before full error reporting is available.

Parameters:

  • filepath (String)

    path to the YAML file

Returns:

  • (Hash)

    parsed YAML as a Hash, or {} on parse error



118
119
120
121
122
123
124
# File 'documented/common/setup_files.rb', line 118

def safe_load_yaml(filepath)
  OpenStruct.new(YAML.unsafe_load_file(filepath)).to_h
rescue => e
  safe_message("bold", "*** ERROR PARSING YAML FILE ***")
  safe_message("bold", e.message)
  {}
end