Решение на Първа задача от Димитър Узунов

Обратно към всички решения

Към профила на Димитър Узунов

Резултати

  • 6 точки от тестове
  • 0 бонус точки
  • 6 точки общо
  • 8 успешни тест(а)
  • 0 неуспешни тест(а)

Код

EXCHANGE_RATES = {bgn: 1, usd: 1.7408, eur: 1.9557, gbp: 2.6415}
PRECISION = 2
def convert_to_bgn(price, currency)
(price * EXCHANGE_RATES[currency]).round(PRECISION)
end
def compare_prices(first_price, first_currency, second_price, second_currency)
first_price_bgn = convert_to_bgn(first_price, first_currency)
second_price_bgn = convert_to_bgn(second_price, second_currency)
first_price_bgn <=> second_price_bgn
end

Лог от изпълнението

........

Finished in 0.00644 seconds
8 examples, 0 failures

История (4 версии и 9 коментара)

Димитър обнови решението на 09.10.2015 00:15 (преди над 8 години)

+def convert_to_bgn(price, currency)
+ if currency == :bgn
+ price
+ elsif currency == :usd
+ (price * 1.7408).round(2)
+ elsif currency == :eur
+ (price * 1.9557).round(2)
+ elsif currency == :gbp
+ (price * 2.6415).round(2)
+ end
+end
+
+def compare_prices(first_price, first_currency, second_price, second_currency)
+ first_price_bgn = convert_to_bgn(first_price, first_currency)
+ second_price_bgn = convert_to_bgn(second_price, second_currency)
+ first_price_bgn - second_price_bgn
+end

Хоп! Прилично е, но може да се подобри и затова сега ще ти pimp-нем решението!

pimp-my-ride

Но преди това...

Тестове

Надявам се да си си пуснал примерните тестове. Ако не си, пусни ги! Увери се, че те минават успешно. След това, ако искаш, можеш да допишеш и още някой тест. Отваряш sample_spec.rb и вътре ще намериш следното:

describe '#convert_to_bgn' do
  it 'converts usd' do
    expect(convert_to_bgn(1000, :usd)).to eq 1740.8
  end
end

describe '#compare_prices' do
  it 'compares prices of the same currency' do
    expect(compare_prices(10, :usd, 13, :usd)).to be < 0
    expect(compare_prices(10, :eur, 10, :eur)).to eq 0
    expect(compare_prices(10, :gbp, 8, :gbp)).to be > 0
  end
end

И добавяш, например, тест за конвертиране на GBP към BGN. Това става така:

describe '#convert_to_bgn' do
  it 'converts usd' do
    expect(convert_to_bgn(1000, :usd)).to eq 1740.8
  end

  it 'converts gbp' do
    expect(convert_to_bgn(1000, :gbp)).to eq 2641.5
  end
end

describe '#compare_prices' do
  it 'compares prices of the same currency' do
    expect(compare_prices(10, :usd, 13, :usd)).to be < 0
    expect(compare_prices(10, :eur, 10, :eur)).to eq 0
    expect(compare_prices(10, :gbp, 8, :gbp)).to be > 0
  end
end

Доста е вербозно и шаблонно и вярвам, че ще успееш да добавиш тестове. Ако все пак не успяваш, не му мисли. Ще говорим за тестове по-нататък. Но задължително си пусни примерните тестове!

След като си пуснал примерните тестове и знаеш, че са минали успешно, можем да продължим напред.

Pimp-ване (ака рефакториране)

Да се фокусираме върху convert_to_bgn на този етап. Имаш няколко проблема и сега ще решим един от тях.

Използваш if/elsif/else, което е напълно ок. Обаче всичките ти проверки опират до валутата (currency) и има едно постоянно повторение на код от типа currency == <нещо> . За да не се повтаряме (DRY), може да използваме switch (предполагам ти е познато от други езици) по валутата. В Ruby това се нарича case.

Сега си ти

  1. Потърси как се ползва case в Ruby.
  2. Промени кода си така, че да ползваш case.
  3. Пусни си примерните тестове.
  4. Ако минават успешно, качи pimp-натото решение и пиши, че си готов.
  5. Ако не минават успешно, поправи си кода и се върни на точка 3.

To be continued...

Ако си бърз и отзивчив, ще ти pimp-нем решението до понеделник и междувременно ще научиш как това да се случва на малки и инкрементални стъпки. И освен това, след всяка стъпка ще си сигурен, че не си счупил нещо, понеже знаеш, че тестовете ти минават успешно.

Ако имаш въпроси (каквито и да са), пиши смело тук и не се притеснявай!

Хайде, до скоро!

Димитър обнови решението на 09.10.2015 15:23 (преди над 8 години)

def convert_to_bgn(price, currency)
- if currency == :bgn
- price
- elsif currency == :usd
- (price * 1.7408).round(2)
- elsif currency == :eur
- (price * 1.9557).round(2)
- elsif currency == :gbp
- (price * 2.6415).round(2)
+ in_leva = {dollars: 1.7408, euro: 1.9557, pounds: 2.6415}
+
+ case currency
+ when :bgn
+ price.round(2)
+ when :usd
+ (price * in_leva[:dollars]).round(2)
+ when :eur
+ (price * in_leva[:euro]).round(2)
+ when :gbp
+ (price * in_leva[:pounds]).round(2)
end
end
def compare_prices(first_price, first_currency, second_price, second_currency)
first_price_bgn = convert_to_bgn(first_price, first_currency)
second_price_bgn = convert_to_bgn(second_price, second_currency)
first_price_bgn - second_price_bgn
end

Благодаря за бързите и изчерпателни отговори!

Написах още тестове, оправих закръглянето на bgn, вече използвам case и направих hash за числата.

Това са ми тестовете:

describe '#convert_to_bgn' do
  it 'rounds bgn' do
    expect(convert_to_bgn(1000.2652, :bgn)).to eq 1000.27
  end

  it 'converts usd' do
    expect(convert_to_bgn(1000, :usd)).to eq 1740.8
  end

  it 'converts eur' do
    expect(convert_to_bgn(1000, :eur)).to eq 1955.7
  end

  it 'converts gbp' do
    expect(convert_to_bgn(1000, :gbp)).to eq 2641.5
  end
end

describe '#compare_prices' do
  it 'compares prices of the same currency' do
    expect(compare_prices(10, :usd, 13, :usd)).to be < 0
    expect(compare_prices(10, :eur, 10, :eur)).to eq 0
    expect(compare_prices(10, :gbp, 8, :gbp)).to be > 0
  end

  it 'compares prices of different currencies' do
    expect(compare_prices(10, :bgn, 10, :usd)).to be < 0
    expect(compare_prices(1000, :usd, 890.11607097203048, :eur)).to eq 0
    expect(compare_prices(1000, :gbp, 1000, :eur)).to be > 0
  end
end

Един въпрос: ако си дефинирам хеша извън функциите за лоша практика ли се счита? Също си мисля да добавя константа Precision, която да пази числото 2.

palpatine

Good! Good!

Настъпване по пръстите

Със Сашо сме се застъпили от към коментиране и има неочакван hash, но нищо...

Отговори

Ако си дефинирам хеша извън функциите за лоша практика ли се счита?

Зависи от контекста! В случая, да бъде извън функцията е перфектния избор, понеже курсовете са фиксирани => може да ги набутаме константа.

Също си мисля да добавя константа Precision, която да пази числото 2.

:thumbsup:

Тестове

Браво! Справил си се с дописването на още тестове!

И може да звучи досадно вече, но пусни си тестовете и бъди сигурен, че минават! Това го правиш преди да започнеш да променяш каквото и да е, за да бъдеш сигурен, че кодът е работил както очакваш по начало.

Време за pimp-ване

Следващата стъпка в pimp-ването на твоето решение е да разкараме case-a. trololo

Тук идеята беше да вкараме hash-a, но ти вече си го вкарал. Не го използваш особено адектватно, така че има какво да подобрим.

Засега ще ти дам само hint: Можеш да замениш целия case, използвайки hash. Тоест няма да имаш нито if, нито case в тялото на convert_to_bgn и пак ще получаваш същия резултат (и няма да чупиш тестовете).

Малко храна

in_leva не е добро име! Името трябва да описва изчерпателно нещото, което именува и да е близо до домейна (областта) на проблема, който решаваш.

Прочети тук малко мисли относно именуване.

Сега си ти

  1. Изнеси hash-a с обменните курсове в константа. Дай му добро име!
  2. Помисли как, използвайки дефинирана от точка 1. константа, можеш да се отървеш от case.
  3. Пускай тестовете след всяка промяна, за да си уверен, че не си счупил нещо.

See ya

Опитай се да се сетиш сам за врътката с хеша. Ако не стане, питай. Ще наглеждам и ще коментирам при първа възможност, та до понеделник имаме готино решение (:

Димитър обнови решението на 09.10.2015 23:50 (преди над 8 години)

-def convert_to_bgn(price, currency)
- in_leva = {dollars: 1.7408, euro: 1.9557, pounds: 2.6415}
+EXCHANGE_RATES = {bgn: 1, usd: 1.7408, eur: 1.9557, gbp: 2.6415}
+PRECISION = 2
- case currency
- when :bgn
- price.round(2)
- when :usd
- (price * in_leva[:dollars]).round(2)
- when :eur
- (price * in_leva[:euro]).round(2)
- when :gbp
- (price * in_leva[:pounds]).round(2)
- end
+def convert_to_bgn(price, currency)
+ (price * EXCHANGE_RATES[currency]).round(PRECISION)
end
def compare_prices(first_price, first_currency, second_price, second_currency)
first_price_bgn = convert_to_bgn(first_price, first_currency)
second_price_bgn = convert_to_bgn(second_price, second_currency)
first_price_bgn - second_price_bgn
end

good-job

Smooth!

Готови сме! Pimp-нахме ти решението! Пий една бира докато се радваш на кода си!

Извод

Как се подхожда към решаването на проблеми?

  1. Запознаваш се добре с проблема и какво се изисква от теб.
  2. Ако проблемът е твърде голям за една хапка, го разбиваш на по-малки, лесни за храносмилане хапки.
  3. Атакуваш малките проблеми един по един, като при всеки:
    1. Първо правиш само необходимия минимум, за да сработи. Просто да работи.
    2. Пускаш си тестовете.
      • Ако минат => следваща стъпка.
      • Ако не минат, правиш промени докато не минат.
    3. Рефакторираш - променяш решението, така че да стане по-елегантно, да спазва конвенции, да е по-ефективно (ако е нужно) и тн.
      • Но го правиш на отделни, смислени единици. Стъпка по стъпка.
      • След всяка стъпка пускаш тестове.
      • Минаваш на следващата стъпка, единствено когато си приключил с текущата стъпка от рефакторирането и тестовете минават.

Ще говорим детайлно за тези неща по-нататък в курса, тъй че ако нещо не е ясно на този етап, не се притеснявай.

А ако всичко ти е било ясно, извинявай че съм те занимавал :D

Ако имаш нещо да добавиш, пиши смело.

Последната промяна

Има още нещо, което може да се пипне. На лекция споменахме един оператор с интересно име. Ако се сетиш за какво става въпрос, ще можеш да подобриш малко compare_prices.

Ако не се сетиш, няма проблем. Така е супер.

Димитър обнови решението на 10.10.2015 22:21 (преди над 8 години)

EXCHANGE_RATES = {bgn: 1, usd: 1.7408, eur: 1.9557, gbp: 2.6415}
PRECISION = 2
def convert_to_bgn(price, currency)
(price * EXCHANGE_RATES[currency]).round(PRECISION)
end
def compare_prices(first_price, first_currency, second_price, second_currency)
first_price_bgn = convert_to_bgn(first_price, first_currency)
second_price_bgn = convert_to_bgn(second_price, second_currency)
- first_price_bgn - second_price_bgn
+ first_price_bgn <=> second_price_bgn
end