Решение на Пета задача от Георги Шопов

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

Към профила на Георги Шопов

Резултати

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

Код

REPOSITORY = 'https://github.com/gshopov/ruby-retrospective-3'
# 1. На почти всичките ми решения skeptic се оплакваше за думи, които не са
# английски. Това ме накара да си поиграя с именуването и да открия някои
# доста глупави имена, които преди съм счел за удачни.
# 2. При chain-ване на итератори, например each_with_index.each_with_object([]),
# мога да получа стойността на елемента, индекса и списъка като отделни
# променливи в блока. Тоест не трябва да се прави така:
# { |item_index_tuple, list| ... }, продуцирайки глупави имена, а така:
# { |item, index, list| ... }. По този начин избягвам и глупости от рода на
# item_index_tuple[0], item_index_tuple[1].
# 3. Многократно пренаписвах итерации със select, map, reduce и т.н. вместо
# each_with_object. Така кода стана по-сбит и по-експресивен, защото не
# трябва да се проследява кое влиза в съответния обект и кое не.
# 4. Припомних си какво каза веднъж Петко Борджуков: "по идиоматично за ruby е
# използването на upto вместо на range-ове", и го приложих в първа задача.
# 5. Научих за Integer#remainder, Integer#zero?, Integer#nonzero? и ги
# използвах, защото определено подобряват експресивността и четимостта -
# получават се изрази на почти правилен английски.
# 6. Според препоръка на style guide-а е по-добре да приемаме блока като
# експлицитен аргумент, за да предотвратим ситуация, в която блока предава
# аргументите си на друг блок.
# 7. Може да подаваме символи, които представляват име на метод, който да се
# използва като подаден блок. Синтаксис: &<method_name_as_a_symbol>. Това
# което става е, че се извиква to_proc на самия символ, за да получим Proc
# обект, след което с & казваме, че това ще е блокът, с който е извикан
# методът.
# 8. В първото домашно използвах препоръката на Пламен да се отделя с един
# празен ред, спрямо останалия код, това, което връща метода. Бях го
# използвал на някои места, но не беше консистентно.
# 9. Изкорених още едно нещо от C++: string_number.ord - '0'.ord. Сега вече
# използвам String#to_i. :)
# 10. Едно от най-полезните неща, които предлагат hash-овете е стойности по
# подразбиране и дори блок, който да се извика, ако ключът не се намери.
# Основната промяна в тази насока е в първата задача.
# 11. По-идиоматично е използването на drop и take вместо слайсове, когато
# искаме да отрежем в началото или края, особено, когато това е само първият
# или само последният елемент.
# 12. Според ръководството по стил, структурата на един клас трябва да има
# следната подредба: 1) extend и include, 2) константи, 3) attribute макрота,
# 4) други макрота, 5) public class methods, 6) public instance methods,
# 7) накрая protected и private методи.
# Това не беше спазено във второто домашно.
# 13. Не трябва да се дава достъп до вътрешни применливи, които са свързани с
# имплементацията(във втора задача имах accessor за такава променлива).
# Докато се опитвах да реша проблема, разбрах нуждата от protected в ruby,
# защото имах нужда от непубличен getter, който да може да се извиква от
# инстанция на този клас в самия клас.
# 14. Харесах стила на Димитър да подравнява последователни редове около
# assignment оператора и други. Приложих го почти навсякъде и четимостта
# се подобри в пъти.
# 15. Изцяло пренаписах Criteria класа от втора задача, използвайки блокове,
# за да пазя самото условие, което трябва да е изпълнено, а не да строя
# изрази, които впоследствие да оценявам. Определено кода стана по-кратък и
# ясен и се отървах от някои ужасни имена на променливи. :)
# 16. Във втора задача бях направил ненужно разделение на два класа TodoList и
# TaskList, като TodoList служеше единствено за парсване на текст и
# създаване на TaskList инстанция. Първо, имената и на двата класа са много
# близки по значение, аз поне ги тълкувам по един и същи начин. Второ, няма
# логика да не върна инстанция на TodoList, а на TaskList, защото тогава
# каква всъщност става ролята на TodoList?(не е ясно)
# 17. Многократно е повтаряно и натяквано с домашни и предизвикателства, че
# monkey-patch-ването не е препоръчително и трябва да се избягва, колкото
# се може повече. Въпреки това в две от решенията си бях направил точно
# обратното :). Премахнах monkey-patch-ове на TrueClass, FalseClass и Matrix,
# въпреки че специално матрицата си търсеше боя - нямаше []= метод.
# 18. Във втора задача изцяло откачих парсването на текста от TodoList и
# по-важното от Task. Направих отделен клас, който да се грижи за това.
# Добра практика е да има един отговорник за всяко действие, защото така
# по-лесно се контролира комуникацията между класовете. Така както аз го
# бях направил имах логика за парсване на текст в два отделни класа,
# единият от които дори не трябва да знае, че има нещо наречено "парсване".
# 19. Мега хитринка: ако класът ни имплементира Enumerable(дефинирали сме си
# each), е ясно, че може да използваме всичко дефинирано в Enumerable. Това,
# което е не толкова ясно е, че length метода е скрит под името count.
# Поуката е по-често да се преглежда документацията на стандартната
# библиотека и core, защото ако не друго то в ruby има много синоними и
# в случая нама как, мислейки си за length, да се сетим изведнъж за count.
# 20. Излючително полезно е да се използват вече дефинирани методи. Скъсява се
# кода, избягва се повторение и понякога, както е в моя случай, кода става
# по-ясен и изчистен. В решението ми на втора задача мога да използвам
# вече дефинирания метод tasks_completed и новооткрития count, за да
# изчистя метода completed?.
# 21. Нещо, което бях забравил е, че не е удачно да се използват матрици или
# двумерни масиви за представянето на така наречените sparse matrix -
# матрици, в които повечето елементи са "празни"(дефинира се в контекста на
# проблема). В тези случаи е по-добре да се използват множества и дори
# hash-ове, в които да пазим само "запълнените" елементи. Друга ситуация,
# в която ми се е налагало да използвам множества или hash-ове за
# представяне на такива разредени матрици е при писане на Game of Life,
# където светът е нещо като "Canvas" - в повечето случаи има повече
# "празни" полета.
# 22. Нещо, което наистина трябва да се запомни, защото подвежда хора, писали
# на други езици, е, че "and" и "or" операторите имат равен приоритет, а
# операторът && има по-висок приоритет от ||. Такава грешка, бях допуснал
# в решението на трета задача.
# 23. Научих, че в ruby няма такова нещо като private клас.
# 24. Freeze-нах всички константи, които съм използвал в решенията, защото е
# добра практика - добавя още една защита за невнимаващите. В ruby не може
# да правим така: FOO = 1; FOO = 2;, но можем така: FOO = []; FOO << 1;.
# Freeze ни пази точно от второто.
# 25. "_" се използва за да обозначи параметри, които няма да използваме. Не го
# бях използвал в четвърта задача, въпреки че го знаех. :/

История (2 версии и 1 коментар)

Георги обнови решението на 21.01.2014 22:54 (преди почти 11 години)

+REPOSITORY = 'https://github.com/gshopov/ruby-retrospective-3'
+
+# 1. На почти всичките ми решения skeptic се оплакваше за думи, които не са
+# английски. Това ме накара да си поиграя с именуването и да открия някои
+# доста глупави имена, които преди съм счел за удачни.
+
+# 2. При chain-ване на итератори, например each_with_index.each_with_object([]),
+# мога да получа стойността на елемента, индекса и списъка като отделни
+# променливи в блока. Тоест не трябва да се прави така:
+# { |item_index_tuple, list| ... }, продуцирайки глупави имена, а така
+# { |item, index, list| ... }. По този начин избягвам и глупости от рода на
+# item_index_tuple[0], item_index_tuple[1].
+
+# 3. Многократно пренаписвах итерации със select, map, reduce и т.н. вместо
+# each_with_object. Така кода стана по-сбит и по-експресивен, защото не
+# трябва да се проследява какво точно влиза в съответния обект и кое не.
+
+# 4. Припомних си какво каза веднъж Петко Борджуков: "по идиоматично за ruby е
+# използването на upto вместо на range-ове", и го приложих.
+
+# 5. Научих за Integer#remainder, Integer#zero?, Integer#nonzero? и ги
+# използвах, защото определено подобряват експресивността и четимостта -
+# получават се изрази на почти правилен английски.
+
+# 6. Според препоръка на style guide-а е по-добре да приемаме блока като
+# експлицитен аргумент, за да предотвратим ситуация, в която блока предава
+# аргументите си на друг блок.
+
+# 7. Може да подаваме символи, които представляват име на метод, който да се
+# използва като подаден блок. Синтаксис: &<method_name_as_a_symbol>. Това
+# което става е, че се извиква to_proc на самия символ, за да получим Proc
+# обект, след което с & казваме, че това ще е блокът, с който е извикан
+# number методът.
+
+# 8. В първото домашно използвах препоръката на Пламен да се отделя с един
+# празен ред, спрямо останалия код, това, което връща метода.
+
+# 9. Изкорених още едно нещо от C++: string_number.ord - '0'.ord. Сега вече
+# използвам String#to_i. :)
+
+# 10. Едно от най-полезните неща, които предлагат hash-овете е стойности по
+# подразбиране и дори блок, който да се извика, ако ключът не се намери.
+# Основната промяна в тази насока е в първата задача.
+
+# 11. По-идиоматично и по е използването на drop и take вместо слайсове, когато
+# изкаме да отрежем в началото или края, особоно, когато това е само първия
+# или само последния елемент.
+
+# 12. Според ръководството по стил, структурата на един клас трябва да има
+# следната подредба: 1) extend и include, 2) константи, 3) attribute макрота,
+# 4) други макрота, 5) public class methods, 6) public instance methods,
+# 7) накрая protected и private методи.
+# Това не беше спазено във второто домашно.
+
+# 13. Не трябва да се дава достъп до вътрешни применливи, които са свързани с
+# имплементацията(във втора задача имах accessor за такава променлива).
+# Докато се опитвах да реша проблема, разбрах нуждата от protected в ruby,
+# защото имах нужда от непубличен getter, който да може да се извиква от
+# инстанция на този клас, подадена като аргумент на инстанционен метод.
+
+# 14. Харесах стила на Димитър да подравнява последователни редове около
+# assignment оператора и други. Приложих го почти навсякъде и четимостта
+# се подобри в пъти.
+
+# 15. Изцяло пренаписах Criteria класът от втора задача, използвайки блокове,
+# за да пазя самото условие, което трябва да е изпълнено, а не да строя
+# изрази, които впоследствие да оценявам. Определено кода стана по-кратък и
+# ясен и се отървах от някои ужасни имена на променливи. :)
+
+# 16. Във втора задача бях направил ненужно разделение на два класа TodoList и
+# TaskList, като TodoList служеше единствено за парсване на текст и
+# създаване на TaskList инстанция. Първо, имената и на двата класа са много
+# близки по значение, аз поне ги тълкувам по един и същи начин. Второ, няма
+# логика да не върна инстанция на TodoList, а на TaskList, защото тогава
+# каква всъщност става ролята на TodoList?(не е ясно)
+
+# 17. Многократно е повтаряно и натяквано с домашни и предизвикателства, че
+# monkey-patch-ването не е препоръчително и трябва да се избягва, колкото
+# се може повече. Въпреки това в две от решенията си бях направил точно
+# обратното :). Премахнах monkey-patch-ове на TrueClass, FalseClass и Matrix,
+# въпреки че специално матрицата си търсеше боя - нямаше []= метод.
+
+# 18. Във втора задача изцяло откачих парсването на текста от TodoList и
+# по-важното от Task. Направих отделен клас, който да се грижи за това.
+# Добра практика е да има един отговорник за всяко действие, защото така
+# по-лесно се контролира комуникацията между класовете. Така както аз го
+# бях направил имах логика за парсване на текст в два отделни класа, които
+# дори не трябва да знаят, че има нещо наречено "парсване".
+
+# 19. Мега хитринка: ако класът ни имплементира Enumerable(дефинирали сме си
+# each), е ясно, че може да използваме всичко дефинирано в Enumerable. Това,
+# което е не толкова ясно е, че length метода е скрит под името count.
+# Поуката е по-често да се преглежда документацията на стандартната
+# библиотека и core, защото ако не друго то в ruby има много синоними и
+# в случая нама как, мислейки си за length, да ни дойде изведнъж count.
+
+# 20. Излючително полезно е да се използват вече дефинирани методи. Скъсява се
+# кода, избягва се повторение и понякога, както е в моя случай, кода става
+# по-ясен и изчистен. В решението ми на втора задача мога да използвам
+# вече дефинирания метод tasks_completed и новооткрития count, за да
+# изчистя метода completed?.
+
+# 21. Нещо, което бях забравил е, че не е удачно да се използват матрици или
+# двумерни масиви за представянето на така наречените sparse matrix -
+# матрици, в които повечето елементи са "празни"(дефинира се в контекста на
+# проблема). В тези случаи е по-добре да се използват множества и дори
+# hash-ове, в които да пазим само "запълнените" елементи. Въпреки това, не
+# бих казал, че конкретно 3-та задача е добър пример, защото можеше да са
+# такива примерите и тестовете, че цялото платно да е запълнено. Ситуация,
+# в която наистина ми се е налагало да използвам множества или hash-ове за
+# представяне на такива разредени матрици е при писане на Game of Life.
+
+# 22. Нещо, което наистина трябва да се запомни, защото подвежда хора, писали
+# на други езици, е, че "and" и "or" операторите имат равен приоритет, а
+# операторът && има по-висок приоритет от ||. Такава грешка, бях допуснал
+# в решението на трета задача.
+
+# 23. Научих, че в ruby няма такова нещо като private клас.
+
+# 24. Freeze-нах всички константи, които съм използвал в решенията, защото е
+# добра практика - добавя още една защита за невнимаващите. В ruby не може
+# да правим така: FOO = 1; FOO = 2;, но можем така: FOO = []; FOO << 1;.
+# Freeze ни пази точно от второто.
+
+# 25. "_" се използва за да обозначи параметри, които няма да използваме. Не го
+# бях използвал в четвърта задача, въпреки че го знаех. :/

Георги обнови решението на 22.01.2014 14:51 (преди почти 11 години)

REPOSITORY = 'https://github.com/gshopov/ruby-retrospective-3'
# 1. На почти всичките ми решения skeptic се оплакваше за думи, които не са
# английски. Това ме накара да си поиграя с именуването и да открия някои
# доста глупави имена, които преди съм счел за удачни.
# 2. При chain-ване на итератори, например each_with_index.each_with_object([]),
# мога да получа стойността на елемента, индекса и списъка като отделни
# променливи в блока. Тоест не трябва да се прави така:
-# { |item_index_tuple, list| ... }, продуцирайки глупави имена, а така
+# { |item_index_tuple, list| ... }, продуцирайки глупави имена, а така:
# { |item, index, list| ... }. По този начин избягвам и глупости от рода на
# item_index_tuple[0], item_index_tuple[1].
# 3. Многократно пренаписвах итерации със select, map, reduce и т.н. вместо
# each_with_object. Така кода стана по-сбит и по-експресивен, защото не
-# трябва да се проследява какво точно влиза в съответния обект и кое не.
+# трябва да се проследява кое влиза в съответния обект и кое не.
# 4. Припомних си какво каза веднъж Петко Борджуков: "по идиоматично за ruby е
-# използването на upto вместо на range-ове", и го приложих.
+# използването на upto вместо на range-ове", и го приложих в първа задача.
# 5. Научих за Integer#remainder, Integer#zero?, Integer#nonzero? и ги
# използвах, защото определено подобряват експресивността и четимостта -
# получават се изрази на почти правилен английски.
# 6. Според препоръка на style guide-а е по-добре да приемаме блока като
# експлицитен аргумент, за да предотвратим ситуация, в която блока предава
# аргументите си на друг блок.
# 7. Може да подаваме символи, които представляват име на метод, който да се
# използва като подаден блок. Синтаксис: &<method_name_as_a_symbol>. Това
# което става е, че се извиква to_proc на самия символ, за да получим Proc
# обект, след което с & казваме, че това ще е блокът, с който е извикан
-# number методът.
+# методът.
# 8. В първото домашно използвах препоръката на Пламен да се отделя с един
-# празен ред, спрямо останалия код, това, което връща метода.
+# празен ред, спрямо останалия код, това, което връща метода. Бях го
+# използвал на някои места, но не беше консистентно.
# 9. Изкорених още едно нещо от C++: string_number.ord - '0'.ord. Сега вече
# използвам String#to_i. :)
# 10. Едно от най-полезните неща, които предлагат hash-овете е стойности по
# подразбиране и дори блок, който да се извика, ако ключът не се намери.
# Основната промяна в тази насока е в първата задача.
-# 11. По-идиоматично и по е използването на drop и take вместо слайсове, когато
-# изкаме да отрежем в началото или края, особоно, когато това е само първия
-# или само последния елемент.
+# 11. По-идиоматично е използването на drop и take вместо слайсове, когато
+# искаме да отрежем в началото или края, особено, когато това е само първият
+# или само последният елемент.
# 12. Според ръководството по стил, структурата на един клас трябва да има
# следната подредба: 1) extend и include, 2) константи, 3) attribute макрота,
# 4) други макрота, 5) public class methods, 6) public instance methods,
# 7) накрая protected и private методи.
# Това не беше спазено във второто домашно.
# 13. Не трябва да се дава достъп до вътрешни применливи, които са свързани с
# имплементацията(във втора задача имах accessor за такава променлива).
# Докато се опитвах да реша проблема, разбрах нуждата от protected в ruby,
# защото имах нужда от непубличен getter, който да може да се извиква от
-# инстанция на този клас, подадена като аргумент на инстанционен метод.
+# инстанция на този клас в самия клас.
# 14. Харесах стила на Димитър да подравнява последователни редове около
# assignment оператора и други. Приложих го почти навсякъде и четимостта
# се подобри в пъти.
-# 15. Изцяло пренаписах Criteria класът от втора задача, използвайки блокове,
+# 15. Изцяло пренаписах Criteria класа от втора задача, използвайки блокове,
# за да пазя самото условие, което трябва да е изпълнено, а не да строя
# изрази, които впоследствие да оценявам. Определено кода стана по-кратък и
# ясен и се отървах от някои ужасни имена на променливи. :)
# 16. Във втора задача бях направил ненужно разделение на два класа TodoList и
# TaskList, като TodoList служеше единствено за парсване на текст и
# създаване на TaskList инстанция. Първо, имената и на двата класа са много
# близки по значение, аз поне ги тълкувам по един и същи начин. Второ, няма
# логика да не върна инстанция на TodoList, а на TaskList, защото тогава
# каква всъщност става ролята на TodoList?(не е ясно)
# 17. Многократно е повтаряно и натяквано с домашни и предизвикателства, че
# monkey-patch-ването не е препоръчително и трябва да се избягва, колкото
# се може повече. Въпреки това в две от решенията си бях направил точно
# обратното :). Премахнах monkey-patch-ове на TrueClass, FalseClass и Matrix,
# въпреки че специално матрицата си търсеше боя - нямаше []= метод.
# 18. Във втора задача изцяло откачих парсването на текста от TodoList и
# по-важното от Task. Направих отделен клас, който да се грижи за това.
# Добра практика е да има един отговорник за всяко действие, защото така
# по-лесно се контролира комуникацията между класовете. Така както аз го
-# бях направил имах логика за парсване на текст в два отделни класа, които
-# дори не трябва да знаят, че има нещо наречено "парсване".
+# бях направил имах логика за парсване на текст в два отделни класа,
+# единият от които дори не трябва да знае, че има нещо наречено "парсване".
# 19. Мега хитринка: ако класът ни имплементира Enumerable(дефинирали сме си
# each), е ясно, че може да използваме всичко дефинирано в Enumerable. Това,
# което е не толкова ясно е, че length метода е скрит под името count.
# Поуката е по-често да се преглежда документацията на стандартната
# библиотека и core, защото ако не друго то в ruby има много синоними и
-# в случая нама как, мислейки си за length, да ни дойде изведнъж count.
+# в случая нама как, мислейки си за length, да се сетим изведнъж за count.
# 20. Излючително полезно е да се използват вече дефинирани методи. Скъсява се
# кода, избягва се повторение и понякога, както е в моя случай, кода става
# по-ясен и изчистен. В решението ми на втора задача мога да използвам
# вече дефинирания метод tasks_completed и новооткрития count, за да
# изчистя метода completed?.
# 21. Нещо, което бях забравил е, че не е удачно да се използват матрици или
# двумерни масиви за представянето на така наречените sparse matrix -
# матрици, в които повечето елементи са "празни"(дефинира се в контекста на
# проблема). В тези случаи е по-добре да се използват множества и дори
-# hash-ове, в които да пазим само "запълнените" елементи. Въпреки това, не
-# бих казал, че конкретно 3-та задача е добър пример, защото можеше да са
-# такива примерите и тестовете, че цялото платно да е запълнено. Ситуация,
-# в която наистина ми се е налагало да използвам множества или hash-ове за
-# представяне на такива разредени матрици е при писане на Game of Life.
+# hash-ове, в които да пазим само "запълнените" елементи. Друга ситуация,
+# в която ми се е налагало да използвам множества или hash-ове за
+# представяне на такива разредени матрици е при писане на Game of Life,
+# където светът е нещо като "Canvas" - в повечето случаи има повече
+# "празни" полета.
# 22. Нещо, което наистина трябва да се запомни, защото подвежда хора, писали
# на други езици, е, че "and" и "or" операторите имат равен приоритет, а
# операторът && има по-висок приоритет от ||. Такава грешка, бях допуснал
# в решението на трета задача.
# 23. Научих, че в ruby няма такова нещо като private клас.
# 24. Freeze-нах всички константи, които съм използвал в решенията, защото е
# добра практика - добавя още една защита за невнимаващите. В ruby не може
# да правим така: FOO = 1; FOO = 2;, но можем така: FOO = []; FOO << 1;.
# Freeze ни пази точно от второто.
# 25. "_" се използва за да обозначи параметри, които няма да използваме. Не го
-# бях използвал в четвърта задача, въпреки че го знаех. :/
+# бях използвал в четвърта задача, въпреки че го знаех. :/

Много добре. Доволен съм от решенията ти, от бележките ти тук и от git историята на задачата :) Имам следните коментари:

  • В задача 1, на ред 7 няма никаква нужда от ternary оператора, понеже == си връща true/false
  • Не съм голям фен на renderer частта в трета задача. Дребен пример: по-добре да ползваш join(@line_break).
  • Относно т. 24 -- всъщност можем да предефинираме константи с цената на един warning. За другото си прав.

Сега се усещам, че си стигнал до 25 от 20 нужни неща - което е хубаво. :)