Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions lib/money/money.rb
Original file line number Diff line number Diff line change
Expand Up @@ -987,11 +987,18 @@ def to_money
self
end

# Common inspect function
#
# @return [String]
def inspect
"#<Money cents:#{cents} currency:#{currency}>"
end

# Allocates money between different parties without loosing pennies.
# After the mathmatically split has been performed, left over pennies will
# be distributed round-robin amongst the parties. This means that parties
# listed first will likely recieve more pennies then ones that are listed later
#
#
# @param [0.50, 0.25, 0.25] to give 50% of the cash to party1, 25% ot party2, and 25% to party3.
#
# @return [Array<Money, Money, Money>]
Expand All @@ -1004,7 +1011,7 @@ def allocate(splits)
raise ArgumentError, "splits add to more then 100%" if allocations > 1.0

left_over = cents

amounts = splits.collect do |ratio|
fraction = (cents * ratio / allocations).floor
left_over -= fraction
Expand All @@ -1016,6 +1023,29 @@ def allocate(splits)
return amounts.collect { |cents| Money.new(cents, currency) }
end

# Split money amongst parties evenly without loosing pennies.
#
# @param [2] number of parties.
#
# @return [Array<Money, Money, Money>]
#
# @example
# Money.new(100, "USD").split(3) #=> [Money.new(34), Money.new(33), Money.new(33)]
def split(num)
raise ArgumentError, "need at least one party" if num < 1
low = Money.new(cents / num)
high = Money.new(low.cents + 1)

remainder = cents % num
result = []

num.times do |index|
result[index] = index < remainder ? high : low
end

return result
end

private

# Cleans up formatting rules.
Expand Down
29 changes: 28 additions & 1 deletion spec/money_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1061,7 +1061,34 @@ def to_money
end
end

describe "allocation"do
describe "split" do
specify "#split needs at least one party" do
lambda {Money.us_dollar(1).split(0)}.should raise_error(ArgumentError)
lambda {Money.us_dollar(1).split(-1)}.should raise_error(ArgumentError)
end


specify "#gives 1 cent to both people if we start with 2" do
Money.us_dollar(2).split(2).should == [Money.us_dollar(1), Money.us_dollar(1)]
end

specify "#split may distribute no money to some parties if there isnt enough to go around" do
Money.us_dollar(2).split(3).should == [Money.us_dollar(1), Money.us_dollar(1), Money.us_dollar(0)]
end

specify "#split does not lose pennies" do
Money.us_dollar(5).split(2).should == [Money.us_dollar(3), Money.us_dollar(2)]
end

specify "#split a dollar" do
moneys = Money.us_dollar(100).split(3)
moneys[0].cents.should == 34
moneys[1].cents.should == 33
moneys[2].cents.should == 33
end
end

describe "allocation" do
specify "#allocate takes no action when one gets all" do
Money.us_dollar(005).allocate([1]).should == [Money.us_dollar(5)]
end
Expand Down