Given that I\'d like to do the following calculation:
total = subtotal - discount
Because discount
might be greater than
Just to clarify more, we need to add classes to be extended in core_ext.rb . file :
1) Create core_ext.rb file under config\initializers folder in your project.
2) Paste below as mentioned by @songyy in his answer:
class Numeric
def non_negative
self > 0 ? self : 0
end
end
Reference:
https://guides.rubyonrails.org/plugins.html#extending-core-classes
Thinking we can extend the Numeric
class?
class Numeric
def non_negative
self > 0 ? self : 0
end
end
class Calculator
def initialize(subtotal: subtotal, discount: discount)
@subtotal = subtotal
@discount = discount
end
def total
(@subtotal - @discount).non_negative
end
end
A plain if
statement might be easier to understand:
def total
if discount > subtotal
0
else
subtotal - discount
end
end
Some performance numbers:
user system total real
[i, 0.0].max 0.806408 0.001779 0.808187 ( 0.810676)
0.0 if i < 0.0 0.643962 0.001077 0.645039 ( 0.646368)
0.0 if i.negative? 0.625610 0.001680 0.627290 ( 0.629439)
Code:
require 'benchmark'
n = 10_000_000
Benchmark.bm do |benchmark|
benchmark.report('[value, 0.0].max'.ljust(18)) do
n.times do |i|
a = [-1*i, 0.0].max
end
end
benchmark.report('0.0 if value < 0.0'.ljust(18)) do
n.times do |i|
a = 0.0 if -1*i < 0.0
end
end
benchmark.report('0.0 if value.negative?'.ljust(18)) do
n.times do |i|
a = 0.0 if (-1*i).negative?
end
end
end
I think your solution is essentially correct, and probably the most readable besides a small refactor. I might change it slightly like so:
def total
final_total = subtotal - discount
[final_total, 0].max
end
The ruby expression [final_total, 0].max
is essentially the traditional solution in mathematics for the same function: max {final_total, 0}
. The difference is just notation and context. Once you see this max expression once or twice you can read it as follows: "final_total, but at least zero".
Perhaps if you use this expression more than once you can add another at_least_zero
method or something like in Shiko's solution.