Method: TypeBalancer::Balancer#call

Defined in:
lib/type_balancer/balancer.rb

#call(collection) ⇒ Array

Main entry point for balancing items

Parameters:

  • collection (Array)

    Items to balance

Returns:

  • (Array)

    Balanced items

Raises:



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/type_balancer/balancer.rb', line 27

def call(collection)
  validate_collection!(collection)
  extractor = TypeExtractorRegistry.get(@type_field)

  begin
    items_by_type = extractor.group_by_type(collection)
  rescue TypeBalancer::Error => e
    raise TypeBalancer::Error, "Cannot access type field '#{@type_field}': #{e.message}"
  end

  # Remove nil types and validate
  items_by_type.delete(nil)
  raise TypeBalancer::Error, "Cannot access type field '#{@type_field}'" if items_by_type.empty?

  validate_types_in_collection!(items_by_type)

  target_counts = calculate_target_counts(items_by_type)
  available_positions = (0...collection.size).to_a

  result = Array.new(collection.size)
  sorted_types = sort_types(items_by_type.keys)

  sorted_types.each do |type|
    items = items_by_type[type]
    target_count = target_counts[type]
    ratio = target_count.to_f / collection.size
    positions = PositionCalculator.calculate_positions(
      total_count: collection.size,
      ratio: ratio,
      available_items: available_positions
    )

    positions.each_with_index do |pos, idx|
      result[pos] = items[idx]
    end

    # Remove used positions from available positions
    available_positions -= positions
  end

  result.compact
end