Моя первая попытка неуклюже объяснить концепцию кодирования на Ruby…

Я собираюсь рассказать об одном из «Эврика!» моменты, которые произошли в течение моей первой недели в Makers — это происходит почти ежедневно (я все еще пытаюсь понять, как окружающая среда способствует этому так хорошо… Я дам вам знать, если я добьюсь прогресса в этом), но это было совершенно особенным, и, честно говоря, я чувствовал себя немного гением, когда это произошло.

Как было сказано в предыдущем посте, мы создавали фальшивую систему Boris Bikes, поэтому объекты в нашей программе на этом этапе были просто классом DockingStation и классом Bike. Вот выдержка из нашего класса DockingStation (некоторые элементы скрыты для краткости):

А вот и велосипедный класс:

Таким образом, у DockingStation есть @capacity и массив @bikes, в котором мы можем «хранить» велосипеды, мы можем передать велосипед в качестве аргумента методу #dock, и в конечном итоге он будет извлечен с помощью метода #release_bike. Довольно простые вещи (вау, я уже чувствую себя таким профессионалом!). Давайте сосредоточимся на #release_bike — сначала он выполняет простую часть — выдает ошибку и останавливается, если велосипедов вообще нет. Затем он проверяет список байков и спрашивает каждый из них, «работают ли они», помещая их (точнее, копию каждого) в новый массив, если они рабочие, затем выдает нам рабочий из этого массив, обязательно удалив его из списка хранения.

Мы написали тест, который проверял, что если все велосипеды в док-станции сломаны, он выдаст ошибку и откажется выпускать один, но он был довольно длинным с точки зрения строк, и в этот момент я все еще изо всех сил пытался вернитесь к мантре Codewars: «Чем короче мой код, тем больше он всех впечатлит!»* — вот этот тест:

Итак, мы создаем новый экземпляр Bike, сохраняем его в переменной, вызываем метод #report_broken для этого велосипеда, чтобы изменить его переменную @working на false, закрепляем его на пустой станции, а затем просим освободить велосипед. Поскольку там только один велосипед (и мы только что его сломали), он выдает ошибку, прямо сообщая нам, что доступных рабочих велосипедов нет.

Вот что получилось из моей блестящей идеи объединить несколько методов, чтобы сделать его короче:

Теперь всю настройку делаем в одну строку — вызываем метод #dock, передавая новый байк, который тут же ломаем. Должно работать нормально, верно? Неправильный. Этот новомодный тест напугал наш код, и мы получили следующее сообщение об ошибке:

Так что же пошло не так? Давайте посмотрим на вторую красную строку выше — часть, где все взорвалось, была, когда мы попытались вызвать «неопределенный метод« работает? »для false: Falseclass». Что это обозначает? Если мы вернемся к нашему методу #release_bike, мы увидим, что #working? вызывается для каждого элемента в нашем массиве @bikes, поэтому мы ожидаем, что там будут только велосипеды (ну, экземпляры класса Bike). Однако в этом случае в массиве оказалось простое логическое значение «false».

Это заняло у нас некоторое время, чтобы разобраться (не слишком много времени, но мы, возможно, сделали бы это быстрее, если бы сначала прочитали эту статью). Давайте очень внимательно следим за кодом здесь… мы будем выполнять каждый шаг по одному в командной строке. Помните, что каждый раз, когда вы вызываете метод в Ruby, он имеет возвращаемое значение (даже если возвращать нечего — вы все равно получите нулевой объект), поэтому возиться с irb в командной строке супер полезно:

Почему метод #report_broken возвращает false? Поскольку мы не сказали Ruby, что возвращать из нашего метода (нам все равно, пока он изменяет переменную экземпляра), он возвращает последнее, что было оценено. Слова, которые мы здесь используем, очень важны — не последнее, что он видит (как я слышал от некоторых людей), а последнее, что оценивается. Таким образом, часть «= false» нашего метода #report_broken — это последняя вещь, которая оценивается — мы говорим ей «эй, переменная, теперь ты равна этому». Более простым способом взглянуть на это может быть то, что возвращается последняя вещь справа от знака равенства, но тогда вы должны знать, как организованы методы, уже существующие в Ruby, и где находятся их знаки равенства. Давайте попробуем все это прямо сейчас:

Если это все еще не имеет смысла, это нормально — помните, как я сказал «он возвращает последнюю вещь, которая оценивается»? Это то же самое для любого метода Ruby без явного возвращаемого значения. Добавьте к этому цепочку методов, и все может быстро пойти не так. Если мы вводим «Kye».upcase.reverse.downcase», все в порядке, и мы получаем «eyk», потому что каждый из этих методов возвращает саму строку (ну, ее копию), которая вызывает следующий метод. Но когда мы вызываем эту небольшую цепочку методов Bike, «false» из метода #report_broken становится возвращаемым значением, и этот объект помещается в наш массив @bikes, что впоследствии вызывает проблему. по линии. Вот правильный способ для полноты картины:

На этот раз мы сохраняем наш велосипед в переменной, мы обязательно сломаем его после его создания (иначе «false» будет возвращаемым значением и попадет в переменную), а затем сам велосипед оказывается в док-станции.

Обычно это часть поста, где я даю советы о том, как предотвратить это с вами, но я все еще новичок во всем, что здесь происходит, поэтому, пожалуйста, не принимайте мои слова за истину, но я сказал бы, что всякий раз, когда вы связываете методы вместе (или даже пишете свои собственные методы), всегда думайте о том, каким будет возвращаемое значение и какие объекты будут передаваться. Если что-то не работает, когда вы чувствуете, что это должно быть, посмотрите, можете ли вы начать с разбивки некоторых из ваших более длинных строк, и пусть Ruby просматривает их по одной и смотрит, не было ли это причиной.

Оставайтесь на высоте,
~ Кай

* Это действительно плохая привычка, пожалуйста, постарайтесь не оказаться в таком месте, как я.