Created
July 1, 2019 16:28
-
-
Save jubishop/10b78b7d6b934ab0daa946ab2ff1c313 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def Dollar(val) | |
Dollar.createRoundedDollar(val.kind_of?(Dollar) ? val.raw : val) | |
end | |
def getDollar | |
input = gets.chomp | |
return nil if (input.empty?) | |
Dollar.createRoundedDollar(input) | |
end | |
class Dollar | |
include Comparable | |
# By default no dollar amount can be instantiated with a rounding error | |
# This lets you enable rounding behaviors | |
DO_NOT_ROUND = 1 | |
ROUND = 2 | |
ROUND_FLOOR = 3 | |
ROUND_CEIL = 4 | |
@@roundingBehavior = DO_NOT_ROUND | |
def self.setRoundingBehavior(behavior) | |
raise 'Rounding behavior must be one of DO_NOT_ROUND, ROUND, ROUND_FLOOR, or ROUND_CEIL' unless | |
[DO_NOT_ROUND, ROUND, ROUND_FLOOR, ROUND_CEIL].include?(behavior) | |
@@roundingBehavior = behavior | |
end | |
def self.createRoundedDollar(init_raw) | |
init_raw = Rational(init_raw) | |
case @@roundingBehavior | |
when DO_NOT_ROUND | |
self.new(init_raw) | |
when ROUND | |
self.newRoundPenny(init_raw) | |
when ROUND_FLOOR | |
self.newFloorPenny(init_raw) | |
when ROUND_CEIL | |
self.newCeilPenny(init_raw) | |
else | |
raise "@@roundingBehavior is #{@@roundingBehavior} ??!" | |
end | |
end | |
# Actual rational value representing dollar amount | |
attr_accessor :raw | |
# Initializers for rounding to the nearest penny | |
def self.newRoundPenny(init_raw) | |
self.new(init_raw.rationalize.round(2)) | |
end | |
def self.newFloorPenny(init_raw) | |
self.new((init_raw * 100).floor.rationalize / 100) | |
end | |
def self.newCeilPenny(init_raw) | |
self.new((init_raw * 100).ceil.rationalize / 100) | |
end | |
# Object Overrides | |
def ===(other) | |
raw === other.rationalize | |
end | |
def ==(other) | |
raw == other.rationalize | |
end | |
def to_s | |
"$#{sprintf('%.2f', raw)}" | |
end | |
def inspect | |
to_s | |
end | |
def rationalize | |
raw | |
end | |
# Numeric Overrides | |
def %(other) | |
self.class.new(raw % other.rationalize) | |
end | |
def +(other) | |
self.class.new(raw + other.rationalize) | |
end | |
def -(other) | |
self.class.new(raw - other.rationalize) | |
end | |
def <=>(other) # Comparable mixin | |
raw <=> other.rationalize | |
end | |
def abs | |
self.class.new(raw.abs) | |
end | |
def abs2 | |
self.class.new(raw.abs2) | |
end | |
def ceil | |
self.class.new(raw.ceil) | |
end | |
def floor | |
self.class.new(raw.floor) | |
end | |
def round | |
self.class.new(raw.round) | |
end | |
def div(other) | |
self.class.new(raw.div(other.rationalize)) | |
end | |
def divmod(other) | |
raw.divmod(other.rationalize) | |
end | |
def remainder(other) | |
raw.remainder(other.rationalize) | |
end | |
def nonzero? | |
raw.nonzero? | |
end | |
def zero? | |
raw.zero? | |
end | |
# Rational Overrides | |
def *(other) | |
self.class.createRoundedDollar(raw * other.rationalize) | |
end | |
def /(other) | |
self.class.createRoundedDollar(raw / other.rationalize) | |
end | |
def **(other) | |
self.class.createRoundedDollar(raw ** other.rationalize) | |
end | |
# Dollar Specific | |
def whole_dollar? | |
raw.round == raw | |
end | |
def has_change? | |
raw.round != raw | |
end | |
private | |
# Demands new value have 2 decimal points for pennies at most | |
def initialize(init_raw) | |
self.raw = Rational(init_raw) | |
raise "#{raw} has more than 2 digits for cents" unless (raw.round(2) == raw) | |
freeze | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment