lib/micro/observers/subscribers.rb
# frozen_string_literal: true
module Micro
module Observers
class Subscribers
EqualTo = -> (observer) { -> subscriber { GetObserver[subscriber] == observer } }
GetObserver = -> subscriber { subscriber[0] == :observer ? subscriber[1] : subscriber[2][0] }
MapObserver = -> (observer, options, once) { [:observer, observer, options[:context], once] }
MapObserversToInitialize = -> arg do
Utils::Arrays.flatten_and_compact(arg).map do |observer|
MapObserver[observer, Utils::EMPTY_HASH, false]
end
end
attr_reader :list
def initialize(arg)
@list = arg.is_a?(Array) ? MapObserversToInitialize[arg] : []
end
def to_inspect
none? ? @list : @list.map(&GetObserver)
end
def count
@list.size
end
def none?
@list.empty?
end
def include?(subscriber)
@list.any?(&EqualTo[subscriber])
end
def attach(args)
options = args.last.is_a?(Hash) ? args.pop : Utils::EMPTY_HASH
once = options.frozen? ? false : options.delete(:perform_once)
Utils::Arrays.fetch_from_args(args).each do |observer|
@list << MapObserver[observer, options, once] unless include?(observer)
end
true
end
def detach(args)
Utils::Arrays.fetch_from_args(args).each do |observer|
delete_observer(observer)
end
true
end
def on(options)
on!(options, once: false)
end
def once(options)
on!(options, once: true)
end
EventNameToCall = -> event_name { -> subscriber { subscriber[0] == :callable && subscriber[1] == event_name } }
def off(args)
Utils::Arrays.fetch_from_args(args).each do |value|
if value.is_a?(Symbol)
@list.delete_if(&EventNameToCall[value])
else
delete_observer(value)
end
end
end
private
def delete_observer(observer)
@list.delete_if(&EqualTo[observer])
end
def on!(options, once:)
event, callable, with, context = options[:event], options[:call], options[:with], options[:context]
return true unless event.is_a?(Symbol) && callable.respond_to?(:call)
observer = [callable, with, context]
@list << [:callable, event, observer, once] unless include_callable?(event, observer)
true
end
CallableHaving = -> (event, observer) do
-> subs { subs[0] == :callable && subs[1] == event && subs[2] == observer }
end
def include_callable?(event, observer)
@list.any?(&CallableHaving[event, observer])
end
private_constant :EqualTo, :EventNameToCall, :CallableHaving
private_constant :GetObserver, :MapObserver, :MapObserversToInitialize
end
private_constant :Subscribers
end
end