Class: Money::Allocator
- Inherits:
-
SimpleDelegator
- Object
- SimpleDelegator
- Money::Allocator
- Defined in:
- lib/money/allocator.rb
Constant Summary collapse
- ONE =
BigDecimal("1")
Instance Method Summary collapse
- #allocate(splits, strategy = :roundrobin) ⇒ Object
-
#allocate_max_amounts(maximums) ⇒ Object
Allocates money between different parties up to the maximum amounts specified.
-
#initialize(money) ⇒ Allocator
constructor
A new instance of Allocator.
Constructor Details
#initialize(money) ⇒ Allocator
Returns a new instance of Allocator.
6 7 8 |
# File 'lib/money/allocator.rb', line 6 def initialize(money) super end |
Instance Method Details
#allocate(splits, strategy = :roundrobin) ⇒ Object
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/money/allocator.rb', line 58 def allocate(splits, strategy = :roundrobin) if splits.empty? raise ArgumentError, 'at least one split must be provided' end splits.map!(&:to_r) allocations = splits.inject(0, :+) if (allocations - ONE) > Float::EPSILON raise ArgumentError, "allocations add to more than 100%" end amounts, left_over = amounts_from_splits(allocations, splits) order = case strategy when :roundrobin (0...left_over).to_a when :roundrobin_reverse (0...amounts.length).to_a.reverse when :nearest rank_by_nearest(amounts) else raise ArgumentError, "Invalid strategy. Valid options: :roundrobin, :roundrobin_reverse, :nearest" end left_over.to_i.times do |i| amounts[order[i]][:whole_subunits] += 1 end amounts.map { |amount| Money.from_subunits(amount[:whole_subunits], currency) } end |
#allocate_max_amounts(maximums) ⇒ Object
Allocates money between different parties up to the maximum amounts specified. Left over subunits will be assigned round-robin up to the maximum specified. Subunits are dropped when the maximums are attained.
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/money/allocator.rb', line 109 def allocate_max_amounts(maximums) allocation_currency = extract_currency(maximums + [self.__getobj__]) maximums = maximums.map { |max| max.to_money(allocation_currency) } maximums_total = maximums.reduce(Money.new(0, allocation_currency), :+) splits = maximums.map do |max_amount| next(Rational(0)) if maximums_total.zero? Money.rational(max_amount, maximums_total) end total_allocatable = [maximums_total.subunits, self.subunits].min subunits_amounts, left_over = amounts_from_splits(1, splits, total_allocatable) subunits_amounts.map! { |amount| amount[:whole_subunits] } subunits_amounts.each_with_index do |amount, index| break unless left_over > 0 max_amount = maximums[index].value * allocation_currency.subunit_to_unit next unless amount < max_amount left_over -= 1 subunits_amounts[index] += 1 end subunits_amounts.map { |cents| Money.from_subunits(cents, allocation_currency) } end |