Изучите подход Ruby к передаче объектов в методах и присваиваниях.

Вот простой код на Ruby:

def init_options(options)
  options = { widget: true }
end

def add_default_config(options)
  options[:add_on] ||= true
end

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

options = { plugin: true }

add_default_config(options)
puts options # => {:plugin=>true, :add_on=>true}

init_options(options)
puts options # => {:plugin=>true, :add_on=>true}

Обратите внимание, что после выполнения init_options содержимое остается прежним, даже если внутри есть инструкция, которая создаст экземпляр нового хэша.

Или взгляните на следующий код:

options = { widget: true }

options.tap do |opt|
  opt[:widget] = false
end

puts options # => { :widget => false }

new_options = { plugin: true }
new_options.tap do |opt|
  opt = {}
  opt = { plugin: false }
end

puts new_options # => { :plugin => true }

Почему в этом случае new_options не меняется после выполнения тапа?

Чтобы ответить на этот вопрос, мы должны понять, как в Ruby передаются объекты: по значению или по ссылке?

Давайте узнаем, как работает Ruby, когда речь идет о передаче объектов.

Переменная — это ссылка на объект

Чтобы понять это, я выполню ряд операторов и шаг за шагом объясню, как они работают:

options = {}
puts options.object_id # => 60

Это сделает две вещи:

  • Создает новый объект Hash, который в данном конкретном случае на моей машине имеет идентификатор 60

Создайте метку опции и свяжите ее с вновь созданным объектом.

Затем вызов options.object_id вернет целое число, которое однозначно идентифицирует этот объект во время выполнения программы.

Представьте, что Ruby просто создает связь между меткой options) и объектом, связанным с этой меткой.