Давайте рассмотрим что-то простое и что-то сложное.

Вы хотите сначала простое или сложное? Думаю, у вас фактически нет выбора, attr_reader; Я принимаю решения здесь, так что давайте начнем с простого. (прочитайте следующий абзац своим лучшим голосом ночного телеведущего.)

Вы когда-нибудь пытались добавить символы или буквы ASCII в свой код только для того, чтобы обнаружить, что они НЕ выглядели так же, когда вы запускали свою программу?! Ты, мой друг, Нет. . Только. Один!

Бьюсь об заклад, у вас есть несколько обратных косых черт, и я уверен, что вы делаете простой оператор «помещает» внутри безобидных двойных кавычек. Маленький "". Это никому не вредит. Но я уверен, что он возвращает что-то вроде этого:

УРА.

Причина этого в том, что ваши простые и полезные двойные кавычки поддерживают «экранирующие символы». По сути, одна ваша обратная косая черта просто исчезает внутри строки, заключенной в двойные кавычки, в то время как ваша обратная косая черта со значимыми символами может выполнять полезные функции в вашем коде; и вы никогда не увидите их во время работы вашей программы.Фактически, я использую один из этих escape-символов в методе, который мы рассмотрим далее.

— — — — — — — — — — — — — — — — — — — — — — — — — —

Итак, давайте продолжим и разберем этот метод по частям, чтобы получить возвращаемое значение понимания, а не разочарования.

Мы начнем с простого определения метода. Это очень просто! Остальная часть этого метода будет кусок пирога! (Говорит она, прежде чем бесцельно смотреть на экран компьютера.)

def display_description
end

Красивый. У нас есть некоторый текст в другом методе, давайте продолжим и вызовем его в этом, мы также определим локальную переменную, пока мы в ней, потому что эй — мы все здесь кодеры! Мы умеем кодировать. Это легко.

def display_description
    self.display_description_text
    user_input = gets.chomp
end

О, простите, вы спрашивали о себе? На самом деле нам это не нужно, потому что если бы мы просто вызвали display_description_text, Ruby просто ЗНАЛ бы, что это метод экземпляра. Руби такой. Умная. Но хорошо бы пойти дальше и дать другим людям знать, что это метод экземпляра, когда они просто просматривают наш код, понимаете? И это поможет вам (мне) тоже вспомнить!

— Что это снова? Ах да, это метод экземпляра. Проще говоря, мы не могли вызвать этот метод для самого класса, но мы могли вызвать его для нового ЭКЗЕМПЛЯРА класса. А поскольку #display_description находится внутри тела класса, мы можем просто вызвать этот метод, #self.display_description_text, здесь.

Перейдем к gets.chomp — — — — — — — — — — — — — — — —

Метод gets именно так и звучит: он получает ввод от пользователя, который затем преобразуется для нас в строку.

Но вот в чем дело: gets интерпретирует ввод пользователя как новую строку. Что там с новыми строками?!

Мы не хотим их. Chomp избавляется от новых строк для нас. Опять же, легкий гороховый лимон сложно. Давайте добавим еще кое-что к этому методу!

def display_description
    self.display_description_text
    user_input = gets.chomp
    if user_input.to_i == 0
       book = Book.find_by_name(user_input.split.map(&:capitalize).join(‘ ‘))
end

"Извините меня? Мы обсуждали вещи, которые казались простыми! Это было приятно, это было легко, это имело смысл читать, это было весело. Как мы сюда попали?!»

Проще говоря, мы пришли сюда, потому что я хотел, чтобы пользователь мог ввести порядковый номер ИЛИ название, и я не хотел, чтобы они ДОЛЖНЫ были вводить его точно. Что, если они не хотят вводить заглавные буквы? Я не несимпатичный. Я хотел, чтобы все варианты были доступны. И вот я здесь. Девушка, стоящая перед блоком кода, просит его принять как строки, так и целые числа.

Итак, сначала мы должны сказать программе преобразовать user_input (строку, которую мы получили от gets, помните?) в целое число. К счастью, для этого есть довольно простой способ — .to_i.

Хорошо, но что произойдет, если я наберу строку и вызову для нее .to_i? Например, если мы вставим «Элизабет».to_i? Что это за возвращаемое значение?

0.

Итак, что мы делаем с этим, довольно просто. Мы сообщаем программе, что если пользовательский ввод в виде целого числа равен 0 (для этого и нужны эти двойные знаки равенства), то мы назначим эту локальную переменную «книга» строке, которую он ввел, используя другой метод под названием #find_by_name. Поскольку мы не хотим заставлять пользователя использовать точное форматирование, у нас также происходит какая-то сумасшедшая итерация.

Давайте сделаем это быстро — .split обрезает введенную строку (первая буква каждого слова в названии книги заглавная), .map вносит изменения в каждую пропущенную через него строку и (&:capitalize) — это то, что мы хотим сделать, чтобы эти отдельные строки (не путать с .uppercase, который изменит каждую букву на заглавную), наконец, мы хотим воссоединить эти строки, чтобы сделать «Каждое название книги» одной строкой, вместо того, чтобы искать «Каждая» «Книга» «Название». » внутри массива, где мы сохранили все наши новые экземпляры класса Book.

«Фу. Мы уже закончили? Нет?"

def display_description
    self.display_description_text
    user_input = gets.chomp
    if user_input.to_i == 0
       book = Book.find_by_name(user_input.split.map(&:capitalize).join(‘ ‘))
          if book == nil
              puts “\nPlease type the name exactly, or use the appropriate number.”
                self.display_description
           else
                puts book.description
           end
end

Хорошо хорошо. К счастью для нас, дальше идет большой кусок кода, и говорить о нем довольно быстро. Но это приводит к вложенному оператору if.

"Что?" Поёт хор…

У меня есть операторы if All. Над. этой программе, приказывая ей делать то или иное действие в зависимости от того, что ввел пользователь. Теперь, когда я ТОЛЬКО проверял допустимые строки (до того, как добавил возможность использовать номер индекса для выбора книги), это было довольно просто. Пользователь либо ввел допустимую строку, что привело к выводу описания книги, либо нет, что привело к сообщению об ошибке. Но потом я добавил в .to_i и дал себе головную боль. Видите, потому что теперь у меня есть место, где код говорит:

«Эй, похоже, что пользователь ввел строку, потому что возвращаемое значение этого ввода равно 0! Давай возьмем книгу!»

Затем, если код не может найти книгу, как капризный ребенок, он просто… как бы… закатывает истерику.

Ладно, на самом деле он просто выходит.

Он ломается.

И это вызывает у меня головную боль.

Итак, здесь, где мы получаем эту книгу для пользователя на основе введенного им названия, мы должны поместить еще один оператор if. Мы должны сказать: «Если строка, которую они ввели, равна нулю, тогда используйте свои слова, маленькая программа, и скажите им, чтобы они ввели что-то правильное!». Потому что, если введена строка, которой НЕ существует в нашем сохраненном списке книг, возвращаемое значение будет равно нулю.

Поэтому мы говорим пользователю ввести что-то действительное и перезапустить цикл. Но предположим, что пользователь действительно вводит что-то действительное; затем срабатывает else и выводит описание книги, которую они выбрали.

И смотри, конец близок! Но вы же не думали, что мы закончили, не так ли?

def display_description
     self.display_description_text
     user_input = gets.chomp
       if user_input.to_i == 0
          book = Book.find_by_name(user_input.split.map(&:capitalize).join(‘ ‘))
             if book == nil
                 puts “\nPlease type the name exactly, or use the appropriate number.”
                 self.display_description
             else
                 puts book.description
             end
        elsif (1..Book.all.length).include?(user_input.to_i)
            book = Book.all[user_input.to_i — 1]
            puts book.description
        else
           puts “\nThe option you have chosen does not seem to exist in this universe, please try again.”
           sleep 1
           self.display_description
        end
end

Мы добираемся туда, хотя. Теперь у нас есть элсиф.

«Подожди, а разве мы не разорвали петлю?» снова вступает хор.

Мы завершили этот вложенный оператор if. Разве этот блок кода не Just. Так. Веселье? Это действительно зигзагообразно всякий раз, когда я думал, что это будет зигом.

Мы же к целым числам! Свет в конце тоннеля! Легкость, с которой мы можем просто выбирать на основе индекса! Мы определяем наш индекс, начиная с 1 (где люди обычно начинают индекс) и заканчивая массивами Book.all length. Разве эти встроенные методы не такие простые и забавные? И здесь мы скажем программе: «Если пользователь ввел целое число (user_input.to_i), входящее в этот индекс, то, пожалуйста, присвойте нашу локальную переменную «книга» объекту, расположенному по выбранному им индексу».

Проще говоря, мы просматриваем Book.all (массив) и выбираем объект по определенному индексу с помощью скобок, а затем внутри этих скобок мы помещаем нашу локальную переменную (независимо от того, что ввел пользователь, минус один, потому что индекс массива начинается в 0). И затем, если они ввели целое число, которое было включено в наш индекс, мы выводим соответствующее описание книги.

Если что угодно. Еще. случается в этот момент, тогда это не будет действительным, потому что мы прочесали все варианты, которые являютсядействительными.

Итак, на этом этапе, если пользователь ввел «dhvkjdfbjkae» (я с уверенностью могу сказать, что это НЕ название книги), мы выведем для него сообщение об ошибке Using. Наш. Побег. Характер! (чтобы перейти на новую строку), и мы начинаем весь цикл заново. И мы выходим из цикла только после того, как выбрана допустимая опция или мы контролируем +c, черт возьми.

— — — — — — — — — — — — — — — — — — — — — — — — —

Спасибо тебе, дорогой читатель, за это! Я знаю, что это очень специфично для моей программы, но, надеюсь, некоторые идеи были разбиты достаточно хорошо, чтобы было легко понять, как поступать в подобных ситуациях.