Skip to content

Commit

Permalink
Merge pull request #6 from stekker/message-handler-reloading
Browse files Browse the repository at this point in the history
Make `MessageHandler` work with Rails code reloading
  • Loading branch information
bforma authored Sep 17, 2024
2 parents e0651a2 + 1ce5713 commit 9e6950d
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 9 deletions.
22 changes: 15 additions & 7 deletions lib/s2/message_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,30 @@ module MessageHandler
extend ActiveSupport::Concern

included do
class_attribute :handlers, default: {}
class_attribute :message_handlers, instance_writer: false, default: {}
end

class_methods do
def on(message_type, &handler)
if handlers.has_key?(message_type)
raise ArgumentError, "A handler for message class '#{message_type}' already exists"
def on(message_class, &handler)
if find_handler(message_class)
raise ArgumentError, "A handler for message class '#{message_class}' is already defined"
end

handlers[message_type] = handler
self.message_handlers = message_handlers.merge(key(message_class) => handler)
end

def key(message_class)
message_class
end

def find_handler(message_class)
message_handlers[key(message_class)]
end
end

def handle_message(message)
handler = self.class.handlers[message.class]
raise ArgumentError, "No handler found for message class '#{message.class}'" if handler.nil?
handler = self.class.find_handler(message.class)
raise ArgumentError, "No handler defined for message class '#{message.class}'" if handler.nil?

instance_exec(message, &handler)
end
Expand Down
40 changes: 38 additions & 2 deletions spec/lib/s2/message_handler_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,39 @@ def initialize
expect { handler.handle_message(message) }.to change { handler.received_messages }.to([message])
end

it "works with inheritance" do
some_message_class = Class.new
other_message_class = Class.new
base_handler_class = Class.new do
include S2::MessageHandler

attr_reader :received_messages

def initialize
@received_messages = []
end

on some_message_class do |message|
@received_messages << message
end
end

sub_handler_class = Class.new(base_handler_class) do
on other_message_class do |message|
@received_messages << message
end
end

handler = sub_handler_class.new
some_message = some_message_class.new
other_message = other_message_class.new

expect { handler.handle_message(some_message) }
.to change { handler.received_messages }.to([some_message])
expect { handler.handle_message(other_message) }
.to change { handler.received_messages }.to([some_message, other_message])
end

it "raises when a duplicate handler is defined" do
message_class = Class.new
stub_const("TestNamespace::TestMessage", message_class)
Expand All @@ -38,7 +71,10 @@ def initialize
# no-op
end
end
end.to raise_error(ArgumentError, "A handler for message class 'TestNamespace::TestMessage' already exists")
end.to raise_error(
ArgumentError,
"A handler for message class 'TestNamespace::TestMessage' is already defined",
)
end

it "raises when no handler could be found for the given message" do
Expand All @@ -51,7 +87,7 @@ def initialize
message = message_class.new

expect { handler.handle_message(message) }
.to raise_error(ArgumentError, "No handler found for message class '#{message.class}'")
.to raise_error(ArgumentError, "No handler defined for message class '#{message.class}'")
end
end
end

0 comments on commit 9e6950d

Please sign in to comment.