Skip to content

Commit f5d9c02

Browse files
Use HashWithIndifferentAccess for event payloads, tags, and context
1 parent 749934b commit f5d9c02

File tree

3 files changed

+45
-25
lines changed

3 files changed

+45
-25
lines changed

activesupport/lib/active_support/event_reporter.rb

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
# typed: true
22
# frozen_string_literal: true
33

4+
require "active_support/core_ext/hash/indifferent_access"
45
require_relative "event_reporter/encoders"
56

67
module ActiveSupport
78
class TagStack # :nodoc:
8-
EMPTY_TAGS = {}.freeze
9+
EMPTY_TAGS = {}.with_indifferent_access.freeze
910
FIBER_KEY = :event_reporter_tags
1011

1112
class << self
@@ -29,24 +30,27 @@ def with_tags(*args, **kwargs)
2930

3031
private
3132
def resolve_tags(args, kwargs)
32-
tags = args.each_with_object({}) do |arg, tags|
33+
tags = {}.with_indifferent_access
34+
35+
args.each do |arg|
3336
case arg
3437
when String, Symbol
35-
tags[arg.to_sym] = true
38+
tags[arg] = true
3639
when Hash
37-
arg.each { |key, value| tags[key.to_sym] = value }
40+
arg.each { |key, value| tags[key] = value }
3841
else
39-
tags[arg.class.name.to_sym] = arg
42+
tags[arg.class.name] = arg
4043
end
4144
end
42-
kwargs.each { |key, value| tags[key.to_sym] = value }
45+
46+
kwargs.each { |key, value| tags[key] = value }
4347
tags
4448
end
4549
end
4650
end
4751

4852
class EventContext # :nodoc:
49-
EMPTY_CONTEXT = {}.freeze
53+
EMPTY_CONTEXT = {}.with_indifferent_access.freeze
5054
FIBER_KEY = :event_reporter_context
5155

5256
class << self
@@ -56,7 +60,7 @@ def context
5660

5761
def set_context(context_hash)
5862
new_context = self.context.dup
59-
context_hash.each { |key, value| new_context[key.to_sym] = value }
63+
context_hash.each { |key, value| new_context[key] = value }
6064

6165
Fiber[FIBER_KEY] = new_context.freeze
6266
end
@@ -265,6 +269,8 @@ def subscribe(subscriber)
265269
# # source_location: { filepath: "path/to/file.rb", lineno: 123, label: "UserService#create" }
266270
# # }
267271
#
272+
# Note that the payload is converted to a HashWithIndifferentAccess, so keys can be accessed as strings or symbols.
273+
#
268274
# Alternatively, an event object can be provided:
269275
#
270276
# Rails.event.notify(UserCreatedEvent.new(id: 123))
@@ -395,6 +401,8 @@ def debug(name_or_object, payload = nil, caller_depth: 1, **kwargs)
395401
# # source_location: { filepath: "path/to/file.rb", lineno: 123, label: "UserService#create" }
396402
# # }
397403
#
404+
# Note that tags are converted to a HashWithIndifferentAccess, so keys can be accessed as strings or symbols.
405+
#
398406
# The +tagged+ API can also receive a tag object:
399407
#
400408
# graphql_tag = GraphqlTag.new(operation_name: "user_created", operation_type: "mutation")
@@ -465,9 +473,9 @@ def resolve_payload(name_or_object, payload, **kwargs)
465473
when String, Symbol
466474
handle_unexpected_args(name_or_object, payload, kwargs) if payload && kwargs.any?
467475
if kwargs.any?
468-
kwargs
476+
kwargs.with_indifferent_access
469477
elsif payload
470-
payload
478+
payload.with_indifferent_access
471479
end
472480
else
473481
handle_unexpected_args(name_or_object, payload, kwargs) if payload || kwargs.any?

activesupport/lib/active_support/event_reporter/test_helper.rb

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,33 @@ def emit(event)
1616
def event_matcher(name:, payload: nil, tags: {}, context: {}, source_location: nil)
1717
->(event) {
1818
return false unless event[:name] == name
19-
return false unless event[:payload] == payload
20-
return false unless event[:tags] == tags
21-
return false unless event[:context] == context
19+
return false unless hash_matches?(event[:payload], payload)
20+
return false unless hash_matches?(event[:tags], tags)
21+
return false unless hash_matches?(event[:context], context)
2222

2323
if source_location
24-
return false unless event[:source_location][:filepath] == source_location[:filepath] if source_location[:filepath]
25-
return false unless event[:source_location][:lineno] == source_location[:lineno] if source_location[:lineno]
26-
return false unless event[:source_location][:label] == source_location[:label] if source_location[:label]
24+
[:filepath, :lineno, :label].each do |key|
25+
return false unless event[:source_location][key] == source_location[key] if source_location[key]
26+
end
2727
end
2828

2929
true
3030
}
3131
end
32+
33+
private
34+
def hash_matches?(actual, expected)
35+
return true if actual.nil? && expected.nil?
36+
return false if actual.nil? || expected.nil?
37+
38+
return actual == expected unless actual.is_a?(Hash) && expected.is_a?(Hash)
39+
40+
return false unless actual.size == expected.size
41+
42+
expected.each do |key, value|
43+
return false unless actual[key] == value
44+
end
45+
46+
true
47+
end
3248
end

activesupport/test/event_reporter_test.rb

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -447,24 +447,20 @@ class ContextStoreTest < ActiveSupport::TestCase
447447

448448
test "#set_context sets context data" do
449449
@reporter.set_context(shop_id: 123)
450-
assert_equal({ shop_id: 123 }, @reporter.context)
450+
assert_equal(123, @reporter.context[:shop_id])
451451
end
452452

453453
test "#set_context merges with existing context" do
454454
@reporter.set_context(shop_id: 123)
455455
@reporter.set_context(user_id: 456)
456-
assert_equal({ shop_id: 123, user_id: 456 }, @reporter.context)
456+
assert_equal(123, @reporter.context[:shop_id])
457+
assert_equal(456, @reporter.context[:user_id])
457458
end
458459

459460
test "#set_context overwrites existing keys" do
460461
@reporter.set_context(shop_id: 123)
461462
@reporter.set_context(shop_id: 456)
462-
assert_equal({ shop_id: 456 }, @reporter.context)
463-
end
464-
465-
test "#set_context with string keys converts them to symbols" do
466-
@reporter.set_context("shop_id" => 123)
467-
assert_equal({ shop_id: 123 }, @reporter.context)
463+
assert_equal(456, @reporter.context[:shop_id])
468464
end
469465

470466
test "#clear_context removes all context data" do
@@ -525,7 +521,7 @@ class ContextStoreTest < ActiveSupport::TestCase
525521
@reporter.set_context(shop_id: 123)
526522

527523
@reporter.tagged(request_id: "abc") do
528-
assert_equal({ shop_id: 123 }, @reporter.context)
524+
assert_equal(123, @reporter.context[:shop_id])
529525

530526
assert_called_with(@subscriber, :emit, [
531527
event_matcher(name: "test_event", payload: { key: "value" }, tags: { request_id: "abc" }, context: { shop_id: 123 })

0 commit comments

Comments
 (0)