Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve plugin setup #639

Merged
merged 1 commit into from
Jun 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/rom/components/core.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def adapter
)
end

# @api public
# @api private
def apply_plugins
plugins.each do |plugin|
plugin.apply_to(constant)
Expand Down
66 changes: 49 additions & 17 deletions lib/rom/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,29 +53,20 @@ def initialize(*args, &block)
configure(*args, &block)
end

# @api public
# This is called internally when you pass a block to ROM.container
#
# @api private
def configure(*args)
unless args.empty?
gateways_config = args.first.is_a?(Hash) ? args.first : {default: args}

gateways_config.each do |name, value|
args = Array(value)

adapter, *rest = args

if rest.size > 1 && rest.last.is_a?(Hash)
load_config(config.gateways[name], {adapter: adapter, args: rest[0..-1], **rest.last})
else
options = rest.first.is_a?(Hash) ? rest.first : {args: rest.flatten(1)}
load_config(config.gateways[name], {adapter: adapter, **options})
end
end
end
infer_config(*args) unless args.empty?

# Load adapters explicitly here to ensure their plugins are present already
# while setup loads components and then triggers finalization
setup.load_adapters

# TODO: this is tricky because if you want to tweak the config in the block
# you end up doing `config.config.foo = "bar"` so it would be good
# to yield configuration object + its config or rename this whole class
# because it's a configuration *DSL* that builds up a config object too
yield(self) if block_given?

# No more changes allowed
Expand All @@ -89,10 +80,30 @@ def configure(*args)

# @api private
def finalize
attach_listeners
setup.finalize
self
end

# @api private
def attach_listeners
# Anything can attach globally to certain events, including plugins, so here
# we're making sure that only plugins that are enabled in this configuration
# will be triggered
global_listeners = Notifications.listeners.to_a
.reject { |(src, *)| plugin_registry.mods.include?(src) }.to_h

plugin_listeners = Notifications.listeners.to_a
.select { |(src, *)| plugins.map(&:mod).include?(src) }.to_h

listeners.update(global_listeners).update(plugin_listeners)
end

# @api private
def listeners
notifications.listeners
end

# Apply a plugin to the configuration
#
# @param [Mixed] plugin The plugin identifier, usually a Symbol
Expand Down Expand Up @@ -156,6 +167,27 @@ def respond_to_missing?(name, include_all = false)

private

# This infers config based on arguments passed to either ROM.container
# or Configuration.ne
#
# @api private
def infer_config(*args)
gateways_config = args.first.is_a?(Hash) ? args.first : {default: args}

gateways_config.each do |name, value|
args = Array(value)

adapter, *rest = args

if rest.size > 1 && rest.last.is_a?(Hash)
load_config(config.gateways[name], {adapter: adapter, args: rest[0..-1], **rest.last})
else
options = rest.first.is_a?(Hash) ? rest.first : {args: rest.flatten(1)}
load_config(config.gateways[name], {adapter: adapter, **options})
end
end
end

# @api private
def load_config(config, hash)
hash.each do |key, value|
Expand Down
5 changes: 5 additions & 0 deletions lib/rom/plugin_registry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@ class PluginRegistry
# @api private
attr_reader :types

# @api private
attr_reader :mods

# @api private
def initialize
@types = ::Concurrent::Map.new
@mods = []
end

# Register a plugin for future use
Expand All @@ -27,6 +31,7 @@ def initialize
# @option options [Symbol] :adapter (:default) which adapter this plugin
# applies to. Leave blank for all adapters
def register(name, mod, options = EMPTY_HASH)
mods << mod
type(options.fetch(:type)).register(name, mod, options)
end

Expand Down
16 changes: 10 additions & 6 deletions lib/rom/support/notifications.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ module Publisher
#
# @api public
def subscribe(event_id, query = EMPTY_HASH, &block)
listeners[event_id] << [block, query]
listeners[self] << [event_id, block, query]
self
end

Expand All @@ -67,7 +67,11 @@ def subscribe(event_id, query = EMPTY_HASH, &block)
def trigger(event_id, payload = EMPTY_HASH)
event = events[event_id]

listeners[event.id].each do |(listener, query)|
event_listeners = listeners.values.flatten(1).group_by(&:first)

return unless event_listeners.key?(event_id)

event_listeners[event_id].each do |(_, listener, query)|
event.payload(payload).trigger(listener, query)
end
end
Expand Down Expand Up @@ -178,7 +182,7 @@ def self.listeners
#
# @api public
def self.event_bus(id)
EventBus.new(id, events: events.dup, listeners: listeners.dup)
EventBus.new(id, events: events.dup)
end

# Extension for objects that can listen to events
Expand All @@ -193,7 +197,7 @@ module Listener
#
# @api public
def subscribe(event_id, query = EMPTY_HASH, &block)
Notifications.listeners[event_id] << [block, query]
Notifications.listeners[self] << [event_id, block, query]
end
end

Expand Down Expand Up @@ -224,9 +228,9 @@ class EventBus
# @param [Hash] listeners A hash with listeners
#
# @api public
def initialize(id, events: EMPTY_HASH, listeners: LISTENERS_HASH.dup)
def initialize(id, events: EMPTY_HASH)
@id = id
@listeners = listeners
@listeners = LISTENERS_HASH.dup
@events = events
end
end
Expand Down
6 changes: 5 additions & 1 deletion spec/shared/changeset/database.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
RSpec.shared_context "changeset / database setup" do
include_context "changeset / db_uri"

let(:configuration) { ROM::Configuration.new(:sql, db_uri) }
let(:configuration) do
ROM::Configuration.new(:sql, db_uri) do |config|
config.plugin(:sql, relation: :auto_restrictions)
end
end

let(:conn) { configuration.gateways[:default].connection }

Expand Down
5 changes: 4 additions & 1 deletion spec/shared/repository/database.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# frozen_string_literal: true

require "rom/sql"
RSpec.shared_context "repository / db_uri" do
let(:base_db_uri) do
ENV.fetch("BASE_DB_URI", "postgres@localhost/rom")
Expand All @@ -14,7 +15,9 @@
include_context "repository / db_uri"

let(:configuration) do
ROM::Configuration.new(:sql, db_uri)
ROM::Configuration.new(:sql, db_uri) do |config|
config.plugin(:sql, relation: :auto_restrictions)
end
end

let(:conn) do
Expand Down