В Ruby определения методов также являются выражениями (на самом деле в Ruby все является выражением, нет операторов), поэтому они оцениваются как объект.Выражения определения метода оцениваются как Symbol
, обозначающее имя метода, который был определен.
Итак,
def initialize(*) end
#=> :initialize
В вашем коде у вас есть запятая после attr_reader :slots
, котораяозначает, что вы передаете два аргумента attr_reader
, а именно символ :slots
и выражение def initialize(…) … end
.Поскольку Ruby является строгим языком, аргументы attr_reader
будут оцениваться в первую очередь, прежде чем будет выполнен сам attr_reader
.
Итак, сначала произойдет оценка выражения определения метода.Это определяет (приватный) метод с именем initialize
.Он также оценивается как символ :initialize
.
Далее, вычисляется выражение attr_reader :slots, :initialize
, которое определяет два метода с именами slots
и initialize
, перезаписывая метод, который вы только что определили.Обратите внимание, что это напечатает предупреждение:
lot.rb:3: warning: method redefined; discarding old initialize
lot.rb:5: warning: previous definition of initialize was here
Вы должны всегда читать предупреждения, разработчики Ruby не тратят тяжелую работу, вкладывая их просто для удовольствия!
Решение состоит в том, чтобы убрать запятую, указывающую Ruby искать второй аргумент.
В вашем коде есть вторая ошибка, а именно, что вы ошиблись Array
в Lot#initialize
.
ИЕсть несколько стилистических улучшений, которые вы можете сделать:
- Нет необходимости передавать путь и расширение имени файла в
require_relative
.Это должно быть require_relative 'lot'
. - Неинициализированные переменные экземпляра оцениваются в
nil
, поэтому нет необходимости инициализировать @lot
в nil
. $stdin
и $stdout
являются значениями аргументов по умолчанию для параметров ключевых слов stdin:
и stdout:
, поэтому нет необходимости передавать их явно. - Редко необходимо создавать массив определенного размера, так как Rubyмассивы являются динамическими и могут изменить свой размер в любое время.
С учетом всего этого ваш код будет выглядеть примерно так:
# ./lib/parking_lot
require_relative 'lot'
class ParkingLotInterface
def initialize(input: $stdin, output: $stdout)
@input, @output = input, output
end
def prompt_input
@lot = Lot.new(10)
end
end
parking_lot_interface = ParkingLotInterface.new
parking_lot_interface.prompt_input
# ./lib/lot
class Lot
attr_reader :slots
def initialize(size)
@slots = Array.new(size)
# could be @slots = []
# depending on how you use `@slots` later
end
end