-
-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Compatibility layer for the legacy/new event system
Adds a `SolidusSupport::LegacyCompat` module to provide helpers for extensions that need to support both the legacy event system (`Spree::Event`) and the new one (`Spree::Bus`).
- Loading branch information
1 parent
4dd0c05
commit e3a960b
Showing
8 changed files
with
262 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'solidus_support/legacy_event_compat/bus' | ||
require 'solidus_support/legacy_event_compat/subscriber' | ||
|
||
module SolidusSupport | ||
# Compatibility middleman for {Spree::Event} and {Spree::Bus} | ||
# | ||
# Solidus v3.2 changed to use [Omnes](https://github.com/nebulab/omnes) as the | ||
# backbone for event-driven behavior (see {Spree::Bus}) by default. Before | ||
# that, a custom adapter based on {ActiveSupport::Notifications} was used (see | ||
# {Spree::Event}. Both systems are still supported on v3.2. | ||
# | ||
# This module provides compatibility support so that extensions can easily | ||
# target both systems regardless of the underlying circumstances: | ||
# | ||
# - Solidus v3.2 with the new system. | ||
# - Solidus v3.2 with the legacy system. | ||
# - Solidus v2.9 to v3.1, when only {Spree::Event} existed. | ||
# - Possible future versions of Solidus, whether the legacy system is | ||
# eventually removed or not. | ||
module LegacyEventCompat | ||
# Returns whether the application is using the legacy event system | ||
# | ||
# @return [Boolean] | ||
def self.using_legacy? | ||
legacy_present? && | ||
(legacy_alone? || | ||
legacy_chosen?) | ||
end | ||
|
||
def self.legacy_present? | ||
defined?(Spree::Event) | ||
end | ||
private_class_method :legacy_present? | ||
|
||
def self.legacy_alone? | ||
!Spree::Config.respond_to?(:use_legacy_events) | ||
end | ||
private_class_method :legacy_alone? | ||
|
||
def self.legacy_chosen? | ||
Spree::Config.use_legacy_events | ||
end | ||
private_class_method :legacy_chosen? | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# frozen_string_literal: true | ||
|
||
module SolidusSupport | ||
module LegacyEventCompat | ||
# Compatibility for some event-driven operations | ||
module Bus | ||
# Publication of an event | ||
# | ||
# If extensions want to support the legacy sytem, they need to use a | ||
# compatible API. That means it's not possible to publish an instance as | ||
# event, which is something supported by Omnes but not the legacy adapter. | ||
# Instead, a payload can be given. E.g.: | ||
# | ||
# ``` | ||
# SolidusSupport::LegacyEventCompat::Bus.publish(:foo, bar: :baz) | ||
# ``` | ||
# | ||
# Legacy subscribers will receive an | ||
# `ActiveSupport::Notifications::Fanout`, while omnes subscribers will get | ||
# an `Omnes::UnstructuredEvent`. Both instances are compatible as they | ||
# implement a `#payload` method. | ||
# | ||
# @param event_name [Symbol] | ||
# @param payload [Hash<Symbol, Any>] | ||
def self.publish(event_name, **payload) | ||
if SolidusSupport::LegacyEventCompat.using_legacy? | ||
Spree::Event.fire(event_name, payload) | ||
else | ||
Spree::Bus.publish(event_name, **payload, caller_location: caller_locations(1)[0]) | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# frozen_string_literal: true | ||
|
||
begin | ||
require "omnes" | ||
rescue LoadError | ||
end | ||
|
||
module SolidusSupport | ||
module LegacyEventCompat | ||
# Compatibility for subscriber modules | ||
# | ||
# Thanks to this module, extensions can create legacy subscriber modules | ||
# (see {Spree::Event::Subscriber}) and translate them automatically to an | ||
# {Omnes::Subscriber}). E.g.: | ||
# | ||
# ``` | ||
# module MyExtension | ||
# module MySubscriber | ||
# include Spree::Event::Subscriber | ||
# include SolidusSupport::LegacyEventCompat::Subscriber | ||
# | ||
# event_action :order_finalized | ||
# | ||
# def order_finalized(event) | ||
# event.payload[:order].do_something | ||
# end | ||
# end | ||
# end | ||
# | ||
# MyExtension::MySubscriber.omnes_subscriber.subscribe_to(Spree::Bus) | ||
# ``` | ||
# | ||
# The generated omnes subscriptions will call the corresponding legacy | ||
# subscriber method with the omnes event. It'll compatible as long as the | ||
# omnes event responds to the `#payload` method (see | ||
# {Omnes::UnstructuredEvent}). | ||
module Subscriber | ||
# @api private | ||
ADAPTER = lambda do |legacy_subscriber, legacy_subscriber_method, _omnes_subscriber, omnes_event| | ||
legacy_subscriber.send(legacy_subscriber_method, omnes_event) | ||
end | ||
|
||
def self.included(legacy_subscriber) | ||
legacy_subscriber.define_singleton_method(:omnes_subscriber) do | ||
@omnes_subscriber ||= Class.new.include(::Omnes::Subscriber).tap do |subscriber| | ||
legacy_subscriber.event_actions.each do |(legacy_subscriber_method, event_name)| | ||
subscriber.handle(event_name.to_sym, with: ADAPTER.curry[legacy_subscriber, legacy_subscriber_method]) | ||
end | ||
end.new | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe SolidusSupport::LegacyEventCompat::Bus do | ||
describe '#publish' do | ||
if SolidusSupport::LegacyEventCompat.using_legacy? | ||
it 'forwards to Spree::Event' do | ||
box = nil | ||
subscription = Spree::Event.subscribe(:foo) { |event| box = event.payload[:bar] } | ||
|
||
described_class.publish(:foo, bar: :baz) | ||
|
||
expect(box).to be(:baz) | ||
ensure | ||
Spree::Event.unsubscribe(subscription) | ||
end | ||
else | ||
it 'forwards to Spree::Bus' do | ||
box = nil | ||
Spree::Bus.register(:foo) | ||
subscription = Spree::Bus.subscribe(:foo) { |event| box = event.payload[:bar] } | ||
|
||
described_class.publish(:foo, bar: :baz) | ||
|
||
expect(box).to be(:baz) | ||
ensure | ||
Spree::Bus.unsubscribe(subscription) | ||
Spree::Bus.registry.unregister(:foo) | ||
end | ||
end | ||
end | ||
end |
93 changes: 93 additions & 0 deletions
93
spec/solidus_support/legacy_event_compat/legacy_event_compat_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'omnes' | ||
|
||
RSpec.describe SolidusSupport::LegacyEventCompat::Subscriber do | ||
subject { Module.new.include(Spree::Event::Subscriber).include(described_class) } | ||
|
||
describe '#omnes_subscriber' do | ||
it 'returns an Omnes::Subscriber' do | ||
subject.module_eval do | ||
event_action :foo | ||
|
||
def foo(_event); end | ||
end | ||
|
||
expect(subject.omnes_subscriber.is_a?(Omnes::Subscriber)).to be(true) | ||
end | ||
|
||
it 'adds single-event definitions matching legacy event actions' do | ||
subject.module_eval do | ||
event_action :foo | ||
|
||
def foo(_event); end | ||
end | ||
bus = Omnes::Bus.new | ||
bus.register(:foo) | ||
|
||
subscriptions = subject.omnes_subscriber.subscribe_to(bus) | ||
|
||
event = Struct.new(:omnes_event_name).new(:foo) | ||
expect(subscriptions.first.matches?(event)).to be(true) | ||
end | ||
|
||
it 'coerces event names given as Strings' do | ||
subject.module_eval do | ||
event_action 'foo' | ||
|
||
def foo(_event); end | ||
end | ||
bus = Omnes::Bus.new | ||
bus.register(:foo) | ||
|
||
subscriptions = subject.omnes_subscriber.subscribe_to(bus) | ||
|
||
event = Struct.new(:omnes_event_name).new(:foo) | ||
expect(subscriptions.first.matches?(event)).to be(true) | ||
end | ||
|
||
it 'executes legacy event action methods as handlers with the omnes event' do | ||
subject.module_eval do | ||
event_action :foo | ||
|
||
def foo(event) | ||
event[:bar] | ||
end | ||
end | ||
bus = Omnes::Bus.new | ||
bus.register(:foo) | ||
|
||
subscriptions = subject.omnes_subscriber.subscribe_to(bus) | ||
|
||
expect( | ||
bus.publish(:foo, bar: :baz).executions.first.result | ||
).to be(:baz) | ||
end | ||
|
||
it 'distingish when event name is given explicitly' do | ||
subject.module_eval do | ||
event_action :foo, event_name: :bar | ||
|
||
def foo(_event) | ||
:bar | ||
end | ||
end | ||
bus = Omnes::Bus.new | ||
bus.register(:bar) | ||
|
||
subscriptions = subject.omnes_subscriber.subscribe_to(bus) | ||
|
||
expect( | ||
bus.publish(:bar).executions.first.result | ||
).to be(:bar) | ||
end | ||
|
||
it "returns the same omnes subscriber instance if called again" do | ||
expect(subject.omnes_subscriber).to be(subject.omnes_subscriber) | ||
end | ||
|
||
it "doesn't fail when no event action has been defined" do | ||
expect { subject.omnes_subscriber }.not_to raise_error | ||
end | ||
end | ||
end |