Class: Factorix::Dependency::List

Inherits:
Object
  • Object
show all
Includes:
Enumerable, Enumerable[Entry]
Defined in:
lib/factorix/dependency/list.rb,
sig/factorix/dependency/list.rbs

Overview

Represents a collection of MOD dependencies

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dependencies = []) ⇒ List

Initialize a List collection

Parameters:

  • dependencies (Array[Entry]) (defaults to: [])


118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/factorix/dependency/list.rb', line 118

def initialize(dependencies=[])
  unless dependencies.is_a?(Array)
    raise ArgumentError, "dependencies must be an Array, got #{dependencies.class}"
  end

  dependencies.each_with_index do |dep, index|
    unless dep.is_a?(Entry)
      raise ArgumentError, "dependencies[#{index}] must be a Dependency::Entry, got #{dep.class}"
    end
  end

  @dependencies = dependencies.freeze
end

Class Method Details

.detect_circular(mod_dependencies_map) ⇒ Array[Array[String]]

Detect circular dependencies in a collection of MOD dependencies

Parameters:

  • mod_dependencies_map (Hash[String, List])

Returns:

  • (Array[Array[String]])


90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/factorix/dependency/list.rb', line 90

def self.detect_circular(mod_dependencies_map)
  graph = DependencyGraph.new(mod_dependencies_map)
  cycles = []

  # Detect self-dependencies (not detected by strongly_connected_components)
  mod_dependencies_map.each do |mod_name, deps|
    if deps.required.any? {|dep| dep.mod.name == mod_name }
      cycles << [mod_name, mod_name]
    end
  end

  # Get strongly connected components (cycles are components with size > 1)
  scc_cycles = graph.strongly_connected_components.filter_map {|component|
    next if component.size <= 1

    # Add first element at the end to make cycle explicit
    component + [component.first]
  }

  cycles + scc_cycles
end

.from_strings(dependency_strings) ⇒ List

Create List from an array of dependency strings

Parameters:

  • dependency_strings (Array[String])

Returns:



69
70
71
72
73
# File 'lib/factorix/dependency/list.rb', line 69

def self.from_strings(dependency_strings)
  parser = Parser.new
  dependencies = dependency_strings.map {|str| parser.parse(str) }
  new(dependencies)
end

Instance Method Details

#conflicts_with?(available_mods) ⇒ Array[String]

Get list of incompatible MODs that are present

Parameters:

Returns:

  • (Array[String])


204
# File 'lib/factorix/dependency/list.rb', line 204

def conflicts_with?(available_mods) = incompatible.filter_map {|dep| dep.mod.name if available_mods.key?(dep.mod.name) }

#depends_on?(mod_name_or_mod) ⇒ Boolean

Check if this collection depends on a specific MOD

Parameters:

  • mod_name_or_mod (String, MOD)

Returns:

  • (Boolean)


168
169
170
171
172
# File 'lib/factorix/dependency/list.rb', line 168

def depends_on?(mod_name_or_mod)
  mod_name = mod_name_or_mod.is_a?(MOD) ? mod_name_or_mod.name : mod_name_or_mod.to_s

  @dependencies.any? {|dep| dep.mod.name == mod_name && !dep.incompatible? }
end

#each ⇒ List #each ⇒ Enumerator[Entry, void]

Iterate through all dependencies

Overloads:

  • #each ⇒ List

    Returns:

  • #each ⇒ Enumerator[Entry, void]

    Returns:

    • (Enumerator[Entry, void])

Yields:

Yield Parameters:

Yield Returns:

  • (void)


137
138
139
140
141
142
# File 'lib/factorix/dependency/list.rb', line 137

def each(&block)
  return @dependencies.to_enum unless block

  @dependencies.each(&block)
  self
end

#empty? ⇒ Boolean

Check if the collection is empty

Returns:

  • (Boolean)


187
# File 'lib/factorix/dependency/list.rb', line 187

def empty? = @dependencies.empty?

#incompatible ⇒ Array[Entry]

Get all incompatible dependencies

Returns:



157
# File 'lib/factorix/dependency/list.rb', line 157

def incompatible = @dependencies.select(&:incompatible?)

#incompatible_with?(mod_name_or_mod) ⇒ Boolean

Check if this collection marks a MOD as incompatible

Parameters:

  • mod_name_or_mod (String, MOD)

Returns:

  • (Boolean)


178
179
180
181
182
# File 'lib/factorix/dependency/list.rb', line 178

def incompatible_with?(mod_name_or_mod)
  mod_name = mod_name_or_mod.is_a?(MOD) ? mod_name_or_mod.name : mod_name_or_mod.to_s

  @dependencies.any? {|dep| dep.mod.name == mod_name && dep.incompatible? }
end

#load_neutral ⇒ Array[Entry]

Get all load-neutral dependencies

Returns:



162
# File 'lib/factorix/dependency/list.rb', line 162

def load_neutral = @dependencies.select(&:load_neutral?)

#missing_required(available_mods) ⇒ Array[String]

Get list of missing required dependencies

Parameters:

Returns:

  • (Array[String])


210
# File 'lib/factorix/dependency/list.rb', line 210

def missing_required(available_mods) = required.filter_map {|dep| dep.mod.name unless available_mods.key?(dep.mod.name) }

#optional ⇒ Array[Entry]

Get all optional dependencies (including hidden optional)

Returns:



152
# File 'lib/factorix/dependency/list.rb', line 152

def optional = @dependencies.select(&:optional?)

#required ⇒ Array[Entry]

Get all required dependencies

Returns:



147
# File 'lib/factorix/dependency/list.rb', line 147

def required = @dependencies.select(&:required?)

#satisfied_by?(available_mods) ⇒ Boolean

Check if all required dependencies are satisfied

Parameters:

Returns:

  • (Boolean)


198
# File 'lib/factorix/dependency/list.rb', line 198

def satisfied_by?(available_mods) = required.all? {|dep| (version = available_mods[dep.mod.name]) && dep.satisfied_by?(version) }

#size ⇒ Integer

Get the total number of dependencies

Returns:

  • (Integer)


192
# File 'lib/factorix/dependency/list.rb', line 192

def size = @dependencies.size

#to_a ⇒ Array[String]

Convert to array of dependency strings

Returns:

  • (Array[String])


236
# File 'lib/factorix/dependency/list.rb', line 236

def to_a = @dependencies.map(&:to_s)

#to_h ⇒ Hash[String, Entry]

Convert to hash keyed by MOD name

Returns:



241
# File 'lib/factorix/dependency/list.rb', line 241

def to_h = @dependencies.to_h {|dep| [dep.mod.name, dep] }

#unsatisfied_versions(available_mods) ⇒ Hash[String, Hash[Symbol, String]]

Get list of dependencies with unsatisfied version requirements

Parameters:

Returns:

  • (Hash[String, Hash[Symbol, String]])


216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/factorix/dependency/list.rb', line 216

def unsatisfied_versions(available_mods)
  result = {}

  required.each do |dep|
    next unless dep.version_requirement # Skip if no version requirement

    version = available_mods[dep.mod.name]
    next unless version # Skip if not available (covered by missing_required)

    next if dep.satisfied_by?(version)

    result[dep.mod.name] = {required: dep.version_requirement.to_s, actual: version.to_s}
  end

  result
end