Пета задача

  1. Публикували сме и последната за този курс пета задача. Както обикновено, срокът е до идната сряда следобед.

    Задачата е ретроспективна и ви дава възможност да затвърдите и усъвършенствате знанията си до момента, както и да попълните евентуални пропуски. Това е може би една от най-важните и полезни задачи в курса. Не я пропускайте.

    В тази тема може да задавате въпросите си, или да обсъждате неща по задачата.

  2. Искам да ви дам за пример процеса на работа на Мария Терзиева по пета задача, който намирам за правилния подход в случая. Вижте commit историята ѝ в GitHub.

    Малки, атомарни и подробни commit-и, описващи всяка стъпка от рефакторинга ѝ. Това не само, че много добре документира процеса на подобрение, през който е минала, но и ще ѝ е от помощ впоследствие, когато си сглабя и списъка с научените неща.

  3. Имах един въпрос по трета задача за който предложихте да коментираме след края на срока за предаване, но така и беше повдигнат на ново. Проблема ми е че след като Canvas#render_as(renderer), получи аргумент, ще трябва да знае за неговите методи. Вместо Canvas#render_as, които да приема като аргумет обект от тип Renderers, мисля че е по-добре в Renderers да има метод, който да взима като аргумент обект от тип Canvas, за да го рендерира. Така Renderers и ще е плъгин, защото Canvas няма да знае за него. Предполагам, че ако се подава обект от Canvas ще е нужно предварително да се фиксира вътрешната структура на представяне. Но това може да се избегне ако се изиска метод Canvas#export_to_map който да връща някакво представяне, чийто резултат да се използва като аргумет за Renderers.

  4. @Мария:

    Относно първия ти въпрос, може да погледнеш документацията на Hash.new, формата, приемаща блок. Накратко, блокът се вика, когато някой се опита да достъпи несъществуващ ключ в хеша. Мисля, че в документацията е описан добре този случай:

    "If a block is specified, it will be called with the hash object and the key, and should return the default value. It is the block’s responsibility to store the value in the hash if required."

    Относно втория ти въпрос, погледни документацията на Object#tap. В случая, environment е обектът, на който tap е извикан. С други думи, това е инстанцията на класа Asm::Asm, която Asm::Asm.new връща.

  5. @Илиян

    Проблема ми е че след като Canvas#render_as(renderer), получи аргумент, ще трябва да знае за неговите методи.

    Не е нужно да знае особено много, както се вижда от моето решение на този проблем.

    Вместо Canvas#render_as, които да приема като аргумет обект от тип Renderers, мисля че е по-добре в Renderers да има метод, който да взима като аргумент обект от тип Canvas, за да го рендерира. Така Renderers и ще е плъгин, защото Canvas няма да знае за него.

    Принципно, тази идея не е лоша. Въпросът е, че в момента интерфейсът (и условието) на трета задача са фиксирани и са това, което са. Трябва да направим най-доброто решение, на което сме способни, при така дадените ограничения. Нямаме право да променяме интерфейсните спецификации.

    Предполагам, че ако се подава обект от Canvas ще е нужно предварително да се фиксира вътрешната структура на представяне.

    С това не съм съгласен. Рендерерите биха могли да използват спокойно вече дефинирания публичен интерфейс на Canvas, както аз го правя в моето решение. Както се вижда, Ако го нямаше методът Canvas#render_as, моето решение е почти същото като това, което ти си представяш – паното знае много малко, даже почти нищо за рендерерите. Самите рендерери могат да се приемат и като "плъгини", както ти ги наричаш.

  6. @Кристиян, може би вече си се оправил и сам, но при мен следната последователност от команди проработи:

    Това би трябвало да провери дали решенията ти спазват skeptik и дали минават тестовете.

    Ако нямаш инсталиран bundle:

  7. @Кристиян, каквото каза Мария, с две малки уточнения:

    1. Ако нямаш инсталиран bundler (казва ти, че не намира команда bundle), инсталира се с gem install bundler.
    2. Символът "$" в началото на команди е индикатор, че това, което следва, е команда, която трявба да пуснете в терминала/конзолата. Нещо като неформален, но дефакто стандарт. Самият символ "$" не е част от командата и се пропуска.
  8. @Кристиян, според мен причината за тази грешка е aspell. Инсталирал ли си aspell и коя версия на Ruby използваш?

    Ако ползваш Ruby 2.1.0dev, тоест си инсталирал Ruby с RubyInstaller-a от тази тема, ще имаш проблеми с aspell. (погледни тази тема).

    Опитай да инсталираш Ruby 2.0 и да изпълниш отново инструкциите от предния пост. (Можеш да ползваш pik за да превключваш между повече от една версии на Ruby.)

  9. @Давид, аз бих пробвал да преинсталирам gem-а така:

    1. gem uninstall aspell aspell-ffi (или както беше името на gem-овете)
    2. Деинсталираш и след това инсталираш aspell наново, както е описано в темата във форума, копирайки файла в C:\Ruby200\lib, примерно.
    3. Инсталираш си Ruby DevKit за Ruby 2.0, 32-битовата версия, отново от Ruby Installer сайта.
    4. Инсталираш aspell-ffi с gem install aspell-ffi --platform=ruby. Това би трябвало да го компилира от нулата. Инсталирай и gem-а aspell по същия начин.

    Ако тези стъпки не помогнат, просто коментирай тази проверка за английските думи от скептик ограниченията и се опитай да използваш добри имена :)

    Може и да си донесеш машината на лекцията днес или в сряда и ще погледна проблема. Това важи и за други хора, които имат проблем, който не могат да преборят.

  10. Може и някъде да греша, но този код от официалното решение на първа задача:

    def combine_with(other)
      longer, shorter = self.length > other.length ? [self, other] : [other, self]
    
      combined = take(shorter.length).zip(other.take(shorter.length)).flatten
      rest     = longer.drop(shorter.length)
    
      combined + rest
    end
    

    гърми на този тест:

    [[1]].combine_with([1]).should                      eq [[1],1]
    

    Според мен трябва на flatten да се добави (1). Да направя PR в GitHub?

  11. Още нещо по повод добри практики - това добър workflow ли е:

    • git co -b task-1
    • git commit...
    • ...
    • git commit...
    • git co master
    • git merge task-1
    • git tag task1

    Мисълта ми е - искам да има някакъв ясен маркер за това къде свършват commit-ите, свързани с първа задача и къде започват за втора и май трябва да се ползват git tags.

  12. @Сашо, прав си за гърмящия тест. Проблемът е, че версията на решението там е стара. Ето тук е последната. Благодаря за напомнянето, обнових решението и в хранилището с домашните.

    Относно втория ти въпрос, стъпката с merge трябва да я правиш с --no-ff. Ето едно добро обяснение на примерен Git workflow, който ми допада и който често следвам. Близък е до това, което ти описваш.

  13. @Мария, Aspell проблем. Речникът не хваща всичко. Добави го като изключение в english_words_for_names опцията в skeptic.yml. И аз го направих в нашия fork.

    @Венцислав, това са само предупреждения, а не грешки и би трябвало да работи и с тях. Не им обръщай внимание. Ако процесът по проверка работи (приключва), просто го ползвай така. Ако не става, прати ни имейл, за да го видим и да отговорим по-бързо.

Трябва да сте влезли в системата, за да може да отговаряте на теми.