Трета задача

  1. За да не останете случайно без работа, публикувахме трета задача! :) От вас се иска да си напишете проста файлова система.

    Прочетете хубаво условието и ако имате въпроси можете да ги задавате тук. :)

    Срокът за решения, по изключение, е по-дълъг, за да можете да отидете на OpenFest - до 10 ноември, 17:00.

  2. Все отнякъде се почва... {:

    • Никъде не обещавате, че няма да подавате невалидни данни (само на едно място споменавате да не се грижим за определен случай). Ще подавате ли такива и, ако да, как би следвало ние да се погрижим за това?

    • RBFS::File#parse. Когато се подава стринг, репрезентиращ числа с плаваща запетая, трябва ли да очакваме, че запетаята може да бъде не само ., но и ,? Да очакваме ли числа от вида 1 234 (т.е. с разделител space вместо _ (или никакъв))?

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

    За числата - ще тестваме с форматите, които са валидни в езика. 1,2 е [1,2], а не 1.2 (т.е. не е число). 1 234 е SyntaxError. 1_234 е 1234.

  4. @Герасим, initialize е като hook, на който се закачаш, за да свършиш определена работа. Аз не бих го преизползвал. Ако видя някой да вика initialize в Ruby код, ще се изненадам много, след това ще се намръщя :)

    Препоръчвам да си дефинираш метод или методи, които правят неща вътре в initialize и да извикваш тях, ако/когато ти е необходимо.

  5. @Мая, само ще допълня към отговора на @Никола, че за числата се очаква parse да работи само с низ, който метода to_s може да върне за числото. Тоест дори 1_234 няма да ви бъде подавано като част от низа.

    @Герасим Защо би ти се наложило да извикваш initialize директно? new върху класа го извиква, съответно ако имаш метод, който също вика initialize, то тогава ще го извикваш два пъти. Ако може да дадеш пример, но в момента ми звучи като много объркващо поведение. :)

  6. @Герасим - ти каза, че искаш да извикваш initialize от друг метод. Зачудих се защо би ти трябвало нещо такова, защото както спомена @Димитър, може да си направиш друг метод. Казвам, че за да се стигне до там някой от инстанционните ти методи да извика initialize, той вече ще е бил извикан при конструирането на обекта.

  7. @Георги, по-скоро е трябвало да уточня, че искам да извикам initialize и от друг метод - след инициализация.

    Имам въпрос относно организацията на данните във файл. Ще го изложа спрямо примера:

    2:README:19:string:Hello world!spec.rb:20:string:describe RBFS1:rbfs:4:0:0:
    

    В случая (при сериализация на директория), трябва да се изведе и типа на данните - :string. Но тази информация се пази в @data_type променливата на обекта от тип File. Нали не бъркам и данните трябва да са разделени така (:string не се пази „във“ файла), като в случая просто слепвам двете полета?

    „Името и е rbfs, а данните в нея са с дължина 4 символа.“ - т.е. се взима дължината на името на директорията?

  8. @Герасим, не съм 100% сигурен, че разбирам първия ти въпрос. Типът на данните е част от (метаданните за) файла. Иначе не е задължително да е в инстанционна променлива, важното е да има начин да се вземе. Ако питаш за съдържанието на самия файл - то е само Hello World!.

    Типът трябва за парсването, защото само по данните в низа не може да се разбере.

    Дължината 4 е за 0:0:, не за името. То е съвпадение. :)

  9. @Георги, в условието има пояснение: „Поле за четене data_type, връщащо типа на обекта, който се съхранява - eдин от следните символи: “ Т.е. е задължително да е в инстанционната променлива на File. Не беше много ясно (за мен) от условието как трябва да се сдобия с информация за типа данни, но вече разбирам - от data_type. Да обобщя - проблема е тълкуването. :-)

    Пак не ми стана много ясно за дължината - сбор от дължините на всички файлове във всички поддиректории, или нещо друго?

  10. Важното е публичният интерфейс. Дали ще напишеш...

    def data_type
      # figure out data type
    end
    

    или ще го сметнеш в инстанционна променлива и ще направиш attr_reader няма значение. Може би думата „поле” е малко подвеждаща.

    Дължината е просто дължината на низа, който връща serialize за съответната директория (чието име е преди тази дължина). Аналогично на файловете.

  11. Няколко мисли относно предаването. Системата засича индентирането с whitespace като част от реда и така дължината надхвърля исканите 90 символа. Не смятате ли, че условието за 1 ниво на влагане е малко пресилено за случай, в който примерно в тялото на do и end има един проверяващ if,чието тяло не надхвърля един ред. Някак си безмислено ми се струва да пиша 4 отделни функции от по един ред за подобни неща.

  12. @Александър, skeptic ограниченията са направени, за да ви поощрят да търсите по-добър начин да си разделите кода на смислови части, така че да няма "много код на едно място". Не мога да говоря за твоето решение, без да съм го видял, но със сигурност може да се структурира така, без това да става "изкуствено". Ако не виждаш добър начин да промениш решението си, за да се вложиш в това ограничение или, че ще стане по-лошо - може да ни изпратиш един имейл с линк към secret gist в GitHub, за да можем да разгледаме и да ти дадем насока. Все пак, ако сметнем, че е нужно - ще вдигнем лимита.

    Ще добавя, че вече има предадени решения, които не надхвърлят ограничението. :)

    ПП. whitespace символите е нормално да ги броим в дължината на реда, все пак те отместват кода.

  13. @Камен, предполагам, че имаш предвид skeptic ограничението "едно ниво на влагане". Това означава, например, че не може да вложиш два if-а един в друг. Тоест, ето това е недопустимо:

    def foo
      if something
        # we're one level down in nesting depth
        if another_thing
          # we're two levels down, this is not allowed
        end
      end
    end
    

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

  14. Методите parse и в двата класа трябва да са class методи. Как мога да преизползвам инстанционни методи, които съм дефинирал преди това и ползвам за други операции, в метода parse? И мога ли въобще?

  15. Герасим, май класов метод може само друг класов метод да вика.

    Аз пък се чудя как се получават тези размери на директории. Първо мислех, че е име на директория + данни вътре, но сметките не ми излизат.

    0:1:directory1:40:0:1:directory2:22:1:README:9:number:420:

    Та, зад числата 22 и 40 какво стои?

  16. @Герасим, както каза @Любомир нямаш достъп до инстанционните методи от класовите. Това е така, защото реално нямаш инстанция, върху която да ги викаш. Според ситуацията имаш два избора:

    • Правиш си метода initialize така, че да можеш да му подадеш това, което имаш и той да се оправи, като си използва инстанционните методи.
    • Правиш си private класов метод, който върши това, което ти трябва и го преизползваш в инстанционен метод.

    Специално за parse, в конкретната задача, не съм сигурен кое точно би ти трябвало и като инстанционен метод.

    @Любомир, да - правилно се ориентира. На всяко ниво имаш определения формат, който не го интересува какво се съдържа на следващото ниво.

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