У меня есть хэш. Один из этих ключей - daily_budget
. После некоторого процесса daily_budget
был изменен, а значения всех остальных ключей - нет. Либо значение хэша для этого ключа изменилось, либо я клонирую хеш и устанавливаю это значение в клонированном хэше.
Я хочу шпионить за методом Hash#[]=
, чтобы выяснить, где это происходит. Я бы обезьяна исправил его, следил за ключом с именем daily_budget
и сбрасывал трассировку стека всякий раз, когда он установлен.
Я пытался использовать такой код:
module HashPatches
def []=(key, value)
puts ">>>> hey! I got here!"
super(key, value)
end
end
Hash.send(:include, HashPatches)
Похоже, это изменение игнорируется, в то время как другие исправления на Hash
работают. Я сделал что-то не так?
Я также пробовал использовать set_trace_func
для отслеживания вызовов хеша с помощью этого кода,
set_trace_func proc { |event, file, line, id, binding, classname|
if file =~ //my_project_name//
puts ">>>> #{id}"
puts ">>>> #{classname}"
puts ">>>> #{event}"
puts ">>>> #{file}"
puts ">>>> #{line}"
end
}
но :[]=
не отслеживается. Я удалил пластырь обезьяны. Я не смог заставить использовать :[]=
, чтобы появиться в этом выводе.
Есть ли способ отслеживать изменения хэшей, чтобы я мог отследить, где изменяется значение этого ключа?
Я согласен с вами, но я не уверен, есть ли другой экземпляр хэша, созданный dup
с этим хешем или нет. Это всего лишь один способ увидеть, что происходит.
Если вы оберните его в прокси-объект, вы можете отслеживать все сделанные вызовы, включая дублирование, и переносить дублирование в другой прокси-объект, поэтому я предложил это
Вы можете как обезьяна пропатчить сам класс Hash
. Поместите это в определение модуля / класса,
class Hash
def []=(arg)
# do your magic here with a debugger or pry
end
end
Обновлено: этот способ устарел, но оставлен для справки.
Действительно, это был старый способ. Он устарел уже 5 лет. Современный способ - это Module#prepend
Hash.send(:include, HashPatches)
заставляет ваш HashPatches#[]=
вызываться только тогда, когда (оригинальный) Hash#[]=
недоступен, что не так. Кроме того, super
в вашем определении HashPatches#[]=
не будет работать, поскольку суперкласс Object
вашего HashPatches
не имеет []=
.
Чтобы дать вашему HashPatches#[]=
приоритет над оригинальным Hash#[]=
, вам необходимо сделать:
Hash.prepend(HashPatches)
Вероятно, было бы лучше обернуть оскорбительный Hash в прокси-класс и отслеживать все вызовы, чем было бы обезьяны исправлять класс Hash. Также помните, что переназначение ключа не требуется для изменения значения, например.
h = {n: "hello"}; h[:n].concat(" world"); h[:n] #=> "hello world"
илиh = {n: 12}; h[:n] += 12; h[:n] #=> 24
и, более того,Hash#[]=
- не единственный метод, который изменяет назначения ключей => значений, которые могут сделать другие методы, такие какstore
,transform_values
,update
,merge
и т. д.