Ruby — Как объединить хэш в метод

#ruby #ruby-on-rails-3

#ruby #ruby-on-rails-3

Вопрос:

У меня есть такой метод

 def method1
 {
  headers: { 'Content-Type' => 'application/json' }
 }
end
  

и это другой метод для слияния другого ключа и значения в этот хэш method1, поэтому

 def merge_hash
  method1.merge!(body: { params: 123 }
end
  

итак, когда я снова вызываю method1, я ожидаю, что он вернет обведенное тело, и мои вопросы в том, почему этого не происходит или как я могу это сделать?

Комментарии:

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

2. @MatheusLima: По сути, вы хотите иметь метод без параметров, который при каждом вызове возвращает что-то другое, основываясь на том, что с ним происходило раньше. Следовательно, вам нужен метод, который содержит некоторое состояние . Это не запрещено, но я надеюсь, вы знаете, что собираетесь здесь делать. Тривиальное решение для достижения эффекта: поскольку ваш метод находится в некотором классе, вы могли бы использовать переменную экземпляра для записи информации, необходимой для вашей операции.

3. Обратите внимание на это method1.object_id #=> 70130617670800; method1.object_id #=> 70130617701620; method1.object_id #=> 70130621059620 . Вы видите проблему?

Ответ №1:

Каждый раз, когда вы вызываете method1 , он возвращает новый объект:

 > method1.object_id
=> 47220476550040 
> method1.object_id
=> 47220476543700 
  

Чтобы достичь желаемого, вы можете запомнить его после первого вызова:

 def method1
  @method1 ||= {
    headers: { 'Content-Type' => 'application/json' }
  }
end

> method1.object_id
=> 47220477154400 
> method1.object_id
=> 47220477154400 
  

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

Комментарии:

1. Что вы предлагаете делать в этом случае? поскольку мне нужно «объединить» новый ключ и значение с существующим хэшем, когда это необходимо, тело с параметрами в этом случае необязательно

2. Это зависит от вашего приложения. Я бы создал переменную для хранения всех объединенных хэшей, my_hash = method1.merge(body: { params: 123 }) .

3. Как @Tom Lord упомянул в своем комментарии к вопросу. Трудно давать вам советы без контекста.

Ответ №2:

Конечно, method1 возвращаемое значение не меняется, потому что вы не изменили сам метод.

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

 # Define a new method `method1_without_body`
# whose implementation is exactly the same
# as `method1` at this moment.
alias method1_without_body method1

# Define a new method that calls `method1_without_body`.
# Make sure that it does NOT call `method1`,
# or you'll get a stack overflow.
def method1_with_body
  method1_without_body.merge!(body: { params: 123 })
end

# Define a new method `method1`
# whose implementation is exactly the same
# as `method1_with_body`.
# This method shadows the previous implementation of `method1`.
alias method1 method1_with_body
  

или, если вы используете Rails < 5, тогда просто

 def method1_with_body
  method1_without_body.merge!(body: { params: 123 })
end

alias_method_chain :method1, :body
  

затем, когда вы вызываете method1 , он возвращает хэш как с заголовками, так и с телом.

Кстати, этот метод устарел с Rails 5 и был полностью удален позже (я забыл, в какой младшей версии).

Ответ №3:

Возможно, это близко к тому, на что вы смотрите:

 class MyClass

    attr_reader :method1

    def initialize
      @method1 = {  headers: { 'Content-Type' => 'application/json' } }
    end

    def merge_hash
      @method1.merge!(body: { params: 123 }
    end

end
  

Следовательно, если у вас есть

 o = MyClass.new
  

первый o.method1 вернет начальный хэш, но после

 o.merge_hash
  

o.method1 вернет измененный хэш.