Здесь кроется проблема:
discount_amount = 0 if discount_amount.blank?
discount_percentage = 0 if discount_percentage.blank?
Ruby «видит» переменные сверху вниз и слева направо, поэтому в этой строке он сначала видит локальную переменную (discount_amount =
), поэтому он решает, что discount_amount
вещь в discount_mount.blank?
- это та же самая локальная переменная (а не метод экземпляра. Вы думаете, что переменная еще не определена, но Ruby уже заметил ее). Пока не имеет никакого значения, discount_amount
установлено значение по умолчанию nil
, поэтому nil.blank?
успешно выполняется и присваивается discount_percentage = 0
. То же самое для discount_percentage
. Вот демонстрационный фрагмент:
class ExampleClass
def run
x = "it works as expected" if x == "x"
x
end
def run2
if x == "x"
x = "it works as expected"
end
x
end
def run3
xy = "it works as expected" if x == "x"
xy
end
def x; "x"; end
end
p ExampleClass.new.run #=> nil
p ExampleClass.new.run2 #=> "it works as expected"
p ExampleClass.new.run3 #=> "it works as expected"
Шаг 1: не используйте одинаковые имена для локальных переменных и методов экземпляра. В любом случае это обычно плохая идея, потому что вы теряете, какой из них вы используете, но в этом случае это вас действительно укусило.
Шаг 2: Не пишите императивный код, когда выполняете математические вычисления! Действительно, математика (9X% от того, что вы делаете в типичном приложении, (10-X)% - это неизбежные побочные эффекты) хорошо работает с выражениями , а не с утверждениями. Я бы написал:
def total_price
final_discount_amount = discount_amount || 0
final_discount_percentage = discount_percentage || 0
discounted_amount_from_percent = price * (final_discount_percentage.to_f/100)
applicable_discount = [final_discount_amount, discounted_amount_from_percent].max
price - applicable_discount
end