From 3a2bf36359d6d1a076d362e1d9446c5cd99dafba Mon Sep 17 00:00:00 2001 From: Alexander Ljungberg Date: Sat, 4 Aug 2012 13:37:42 +0100 Subject: [PATCH] Very basic `CPNumberFormatter`currency style. --- Foundation/CPNumberFormatter.j | 49 ++++++++++++++++++++++-- Tests/Foundation/CPDecimalNumberTest.j | 9 ++++- Tests/Foundation/CPNumberFormatterTest.j | 33 +++++++++++++++- 3 files changed, 83 insertions(+), 8 deletions(-) diff --git a/Foundation/CPNumberFormatter.j b/Foundation/CPNumberFormatter.j index 361e81a5e..8e8de427c 100644 --- a/Foundation/CPNumberFormatter.j +++ b/Foundation/CPNumberFormatter.j @@ -61,6 +61,8 @@ CPNumberFormatterRoundHalfUp = CPRoundPlain; CPNumberFormatterRoundingMode _roundingMode @accessors(property=roundingMode); CPUInteger _minimumFractionDigits @accessors(property=minimumFractionDigits); CPUInteger _maximumFractionDigits @accessors(property=maximumFractionDigits); + CPString _currencyCode @accessors(property=currencyCode); + CPString _currencySymbol @accessors(property=currencySymbol); // Note that we do not implement the 10.0 style number formatter, but the 10.4+ formatter. Therefore // we don't expose this through a `roundingBehavior` property. @@ -75,6 +77,10 @@ CPNumberFormatterRoundHalfUp = CPRoundPlain; _minimumFractionDigits = 0; _maximumFractionDigits = 0; _groupingSeparator = @","; + + // FIXME Add locale support. + _currencyCode = @"USD"; + _currencySymbol = @"$"; } return self; @@ -87,6 +93,7 @@ CPNumberFormatterRoundHalfUp = CPRoundPlain; // TODO Add locale support. switch (_numberStyle) { + case CPNumberFormatterCurrencyStyle: case CPNumberFormatterDecimalStyle: UPDATE_NUMBER_HANDLER_IF_NECESSARY(); @@ -113,10 +120,19 @@ CPNumberFormatterRoundHalfUp = CPRoundPlain; } } + var string = preFraction; if (fraction) - return preFraction + "." + fraction; - else - return preFraction; + string += "." + fraction; + + if (_numberStyle === CPNumberFormatterCurrencyStyle) + { + if (_currencySymbol) + string = _currencySymbol + string; + else + string = _currencyCode + string; + } + + return string; default: return [number description]; } @@ -150,6 +166,25 @@ CPNumberFormatterRoundHalfUp = CPRoundPlain; return YES; } +- (void)setNumberStyle:(CPNumberFormatterStyle)aStyle +{ + _numberStyle = aStyle; + + switch (aStyle) + { + case CPNumberFormatterDecimalStyle: + _minimumFractionDigits = 0; + _maximumFractionDigits = 3; + SET_NEEDS_NUMBER_HANDLER_UPDATE(); + break; + case CPNumberFormatterCurrencyStyle: + _minimumFractionDigits = 2; + _maximumFractionDigits = 2; + SET_NEEDS_NUMBER_HANDLER_UPDATE(); + break; + } +} + - (void)setRoundingMode:(CPNumberFormatterRoundingMode)aRoundingMode { _roundingMode = aRoundingMode; @@ -174,7 +209,9 @@ var CPNumberFormatterStyleKey = "CPNumberFormatterStyleKey", CPNumberFormatterMinimumFractionDigitsKey = @"CPNumberFormatterMinimumFractionDigitsKey", CPNumberFormatterMaximumFractionDigitsKey = @"CPNumberFormatterMaximumFractionDigitsKey", CPNumberFormatterRoundingModeKey = @"CPNumberFormatterRoundingModeKey", - CPNumberFormatterGroupingSeparatorKey = @"CPNumberFormatterGroupingSeparatorKey"; + CPNumberFormatterGroupingSeparatorKey = @"CPNumberFormatterGroupingSeparatorKey", + CPNumberFormatterCurrencyCodeKey = @"CPNumberFormatterCurrencyCodeKey", + CPNumberFormatterCurrencySymbolKey = @"CPNumberFormatterCurrencySymbolKey"; @implementation CPNumberFormatter (CPCoding) @@ -189,6 +226,8 @@ var CPNumberFormatterStyleKey = "CPNumberFormatterStyleKey", _maximumFractionDigits = [aCoder decodeIntForKey:CPNumberFormatterMaximumFractionDigitsKey]; _roundingMode = [aCoder decodeIntForKey:CPNumberFormatterRoundingModeKey]; _groupingSeparator = [aCoder decodeObjectForKey:CPNumberFormatterGroupingSeparatorKey]; + _currencyCode = [aCoder decodeObjectForKey:CPNumberFormatterCurrencyCodeKey]; + _currencySymbol = [aCoder decodeObjectForKey:CPNumberFormatterCurrencySymbolKey]; } return self; @@ -203,6 +242,8 @@ var CPNumberFormatterStyleKey = "CPNumberFormatterStyleKey", [aCoder encodeInt:_maximumFractionDigits forKey:CPNumberFormatterMaximumFractionDigitsKey]; [aCoder encodeInt:_roundingMode forKey:CPNumberFormatterRoundingModeKey]; [aCoder encodeObject:_groupingSeparator forKey:CPNumberFormatterGroupingSeparatorKey]; + [aCoder encodeObject:_currencyCode forKey:CPNumberFormatterCurrencyCodeKey]; + [aCoder encodeObject:_currencySymbol forKey:CPNumberFormatterCurrencySymbolKey]; } @end diff --git a/Tests/Foundation/CPDecimalNumberTest.j b/Tests/Foundation/CPDecimalNumberTest.j index 4fa59c474..e74788065 100644 --- a/Tests/Foundation/CPDecimalNumberTest.j +++ b/Tests/Foundation/CPDecimalNumberTest.j @@ -130,7 +130,7 @@ // misc - // decimalValue <- if it hasnt been working so far, your would know. + // decimalValue <- if it hasnt been working so far, you would know. dcmn = [CPDecimalNumber zero]; dcm = [dcmn boolValue]; @@ -326,7 +326,7 @@ [self assert:1000 equals:[res doubleValue] message:"220000/220 == 1000"]; } -- (void)testMutliply +- (void)testMultiply { var dcmn1 = [CPDecimalNumber decimalNumberWithString:@"17"], @@ -487,6 +487,11 @@ [self assert:[1] equals:d1._mantissa message:"decimalNumberByRoundingAccordingToBehavior: - mantissa"]; [self assert:NO equals:d1._isNegative message:"decimalNumberByRoundingAccordingToBehavior: - sign"]; [self assert:NO equals:d1._isNaN message:"decimalNumberByRoundingAccordingToBehavior: - NaN is incorrectly set"]; + + h = [CPDecimalNumberHandler decimalNumberHandlerWithRoundingMode:CPRoundBankers scale:2 raiseOnExactness:NO raiseOnOverflow:YES raiseOnUnderflow:YES raiseOnDivideByZero:YES], + + [self assert:@"0.02" equals:[[[CPDecimalNumber decimalNumberWithString:@"0.015"] decimalNumberByRoundingAccordingToBehavior:h] description]]; + [self assert:@"0" equals:[[[CPDecimalNumber decimalNumberWithString:@"0.005"] decimalNumberByRoundingAccordingToBehavior:h] description]]; } - (void)testCompare diff --git a/Tests/Foundation/CPNumberFormatterTest.j b/Tests/Foundation/CPNumberFormatterTest.j index df08fbb66..b45e4c7da 100644 --- a/Tests/Foundation/CPNumberFormatterTest.j +++ b/Tests/Foundation/CPNumberFormatterTest.j @@ -101,7 +101,7 @@ [numberFormatter setNumberStyle:CPNumberFormatterDecimalStyle]; [numberFormatter setMinimumFractionDigits:2]; [numberFormatter setMaximumFractionDigits:3]; - [numberFormatter setRoundingMode:CPNumberFormatterRoundHalfUp]; + [numberFormatter setRoundingMode:CPNumberFormatterRoundHalfDown]; [numberFormatter setGroupingSeparator:@" "]; archived = [CPKeyedArchiver archivedDataWithRootObject:numberFormatter], @@ -110,8 +110,37 @@ [self assert:CPNumberFormatterDecimalStyle equals:[unarchived numberStyle] message:@"numberStyle"]; [self assert:2 equals:[unarchived minimumFractionDigits] message:@"minimumFractionDigits"]; [self assert:3 equals:[unarchived maximumFractionDigits] message:@"maximumFractionDigits"]; - [self assert:CPNumberFormatterRoundHalfUp equals:[unarchived roundingMode] message:@"roundingMode"]; + [self assert:CPNumberFormatterRoundHalfDown equals:[unarchived roundingMode] message:@"roundingMode"]; [self assert:@" " equals:[unarchived groupingSeparator] message:@"groupingSeparator"]; } +- (void)testCurrencyStyle +{ + var numberFormatter = [CPNumberFormatter new]; + [numberFormatter setNumberStyle:CPNumberFormatterCurrencyStyle]; + [numberFormatter setCurrencyCode:@"USD"]; + + [self assert:@"$1.00" equals:[numberFormatter stringFromNumber:[CPDecimalNumber decimalNumberWithString:@"1"]]]; + [self assert:@"$12.00" equals:[numberFormatter stringFromNumber:[CPDecimalNumber decimalNumberWithString:@"12"]]]; + [self assert:@"$12.10" equals:[numberFormatter stringFromNumber:[CPDecimalNumber decimalNumberWithString:@"12.1"]]]; + [self assert:@"$12.10" equals:[numberFormatter stringFromNumber:[CPDecimalNumber decimalNumberWithString:@"12.10"]]]; + [self assert:@"$0.10" equals:[numberFormatter stringFromNumber:[CPDecimalNumber decimalNumberWithString:@"0.1"]]]; + [self assert:@"$0.10" equals:[numberFormatter stringFromNumber:[CPDecimalNumber decimalNumberWithString:@"0.10"]]]; + [self assert:@"$0.00" equals:[numberFormatter stringFromNumber:[CPDecimalNumber decimalNumberWithString:@"0.005"]]]; + [self assert:@"$0.02" equals:[numberFormatter stringFromNumber:[CPDecimalNumber decimalNumberWithString:@"0.015"]]]; + + + [numberFormatter setCurrencyCode:@"SEK"]; + [numberFormatter setCurrencySymbol:@""]; + + [self assert:@"SEK1.00" equals:[numberFormatter stringFromNumber:[CPDecimalNumber decimalNumberWithString:@"1"]]]; + [self assert:@"SEK12.00" equals:[numberFormatter stringFromNumber:[CPDecimalNumber decimalNumberWithString:@"12"]]]; + [self assert:@"SEK12.10" equals:[numberFormatter stringFromNumber:[CPDecimalNumber decimalNumberWithString:@"12.1"]]]; + [self assert:@"SEK12.10" equals:[numberFormatter stringFromNumber:[CPDecimalNumber decimalNumberWithString:@"12.10"]]]; + [self assert:@"SEK0.10" equals:[numberFormatter stringFromNumber:[CPDecimalNumber decimalNumberWithString:@"0.1"]]]; + [self assert:@"SEK0.10" equals:[numberFormatter stringFromNumber:[CPDecimalNumber decimalNumberWithString:@"0.10"]]]; + [self assert:@"SEK0.00" equals:[numberFormatter stringFromNumber:[CPDecimalNumber decimalNumberWithString:@"0.005"]]]; + [self assert:@"SEK0.02" equals:[numberFormatter stringFromNumber:[CPDecimalNumber decimalNumberWithString:@"0.015"]]]; +} + @end