require 'mutant/actor' # A fake actor used from specs module FakeActor class Expectation include Concord::Public.new(:name, :message, :block) include Equalizer.new(:name, :message) def self.new(_name, _message, _block = nil) super end def verify(other) unless eql?(other) fail "Got:\n#{other.inspect}\nExpected:\n#{inspect}" end block.call(other.message) if block end end class MessageSequence include Adamantium::Flat, Concord::Public.new(:messages) def self.new super([]) end def add(name, *message_arguments, &block) messages << Expectation.new(name, Mutant::Actor::Message.new(*message_arguments), block) self end def sending(expectation) fail "Unexpected send: #{expectation.inspect}" if messages.empty? expected = messages.shift expected.verify(expectation) self end def receiving(name) fail "No message to read for #{name.inspect}" if messages.empty? expected = messages.shift fail "Unexpected message #{expected.inspect} for #{name.inspect}" unless expected.name.eql?(name) expected.message end def consumed? messages.empty? end end class Env include Concord.new(:messages, :mailbox_names) def spawn mailbox = mailbox(next_name) yield mailbox if block_given? mailbox.sender end def mailbox(name) Mailbox.new(name, @messages) end def new_mailbox mailbox(:current) end private def next_name @mailbox_names.shift.tap do |name| name or fail 'Tried to spawn actor when no name available' end end end # Env class Mailbox include Concord.new(:name, :messages) def receiver Receiver.new(name, messages) end def sender Sender.new(name, messages) end def bind(sender) Mutant::Actor::Binding.new(self, sender) end end class Sender include Concord.new(:name, :messages) def call(message) messages.sending(Expectation.new(name, message)) end end # Sender class Receiver include Concord::Public.new(:name, :messages) def call messages.receiving(name) end end end