diff --git a/core/app/subscribers/spree/mailer_subscriber.rb b/core/app/subscribers/spree/mailer_subscriber.rb new file mode 100644 index 00000000000..d0872da0d6c --- /dev/null +++ b/core/app/subscribers/spree/mailer_subscriber.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Spree + module MailerSubscriber + include Spree::Event::Subscriber + + event_action :order_finalized + event_action :send_reimbursement_email, event_name: :reimbursement_reimbursed + + def order_finalized(event) + order = event.payload[:order] + unless order.confirmation_delivered? + Spree::Config.order_mailer_class.confirm_email(order).deliver_later + order.update_column(:confirmation_delivered, true) + end + end + + def send_reimbursement_email(event) + reimbursement = event.payload[:reimbursement] + Spree::Config.reimbursement_mailer_class.reimbursement_email(reimbursement.id).deliver_later + end + end +end diff --git a/core/lib/spree/core/engine.rb b/core/lib/spree/core/engine.rb index 3bdfc9c0a34..58645267d38 100644 --- a/core/lib/spree/core/engine.rb +++ b/core/lib/spree/core/engine.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require 'spree/config' -require 'spree/event/processors/mailer_processor' module Spree module Core @@ -45,8 +44,15 @@ class Engine < ::Rails::Engine Migrations.new(config, engine_name).check end - initializer 'spree.core.subscribe_event_mailer_processor' do - Spree::Event::Processors::MailerProcessor.subscribe! + # Setup Event Subscribers + initializer 'spree.core.initialize_subscribers' do |app| + app.reloader.to_prepare do + Spree::Event.subscribers.each(&:subscribe!) + end + + app.reloader.before_class_unload do + Spree::Event.subscribers.each(&:unsubscribe!) + end end # Load in mailer previews for apps to use in development. diff --git a/core/lib/spree/event.rb b/core/lib/spree/event.rb index 20cd2f45295..2378462cab1 100644 --- a/core/lib/spree/event.rb +++ b/core/lib/spree/event.rb @@ -21,7 +21,7 @@ module Event # @order.finalize! # end def fire(event_name, opts = {}) - adapter.fire name_with_suffix(event_name), opts do + adapter.fire name_with_suffix(event_name.to_s), opts do yield opts if block_given? end end @@ -98,6 +98,12 @@ def suffix Spree::Config.events.suffix end + # @!attribute [r] subscribers + # @return [Array] A list of subscribers used to support class reloading for Spree::Event::Subscriber instances + def subscribers + Spree::Config.events.subscribers + end + private def name_with_suffix(name) diff --git a/core/lib/spree/event/configuration.rb b/core/lib/spree/event/configuration.rb index 4190c714d50..ef8d80b0c5f 100644 --- a/core/lib/spree/event/configuration.rb +++ b/core/lib/spree/event/configuration.rb @@ -1,8 +1,16 @@ # frozen_string_literal: true +require 'spree/core/class_constantizer' + module Spree module Event class Configuration + def subscribers + @subscribers ||= ::Spree::Core::ClassConstantizer::Set.new.tap do |set| + set << 'Spree::MailerSubscriber' + end + end + attr_writer :adapter, :suffix def adapter diff --git a/core/lib/spree/event/processors/mailer_processor.rb b/core/lib/spree/event/processors/mailer_processor.rb deleted file mode 100644 index c43797753e4..00000000000 --- a/core/lib/spree/event/processors/mailer_processor.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -module Spree - module Event - module Processors - module MailerProcessor - include Spree::Event::Subscriber - - event_action :order_finalized - event_action :send_reimbursement_email, event_name: :reimbursement_reimbursed - - def order_finalized(event) - order = event.payload[:order] - unless order.confirmation_delivered? - Spree::Config.order_mailer_class.confirm_email(order).deliver_later - order.update_column(:confirmation_delivered, true) - end - end - - def send_reimbursement_email(event) - reimbursement = event.payload[:reimbursement] - Spree::Config.reimbursement_mailer_class.reimbursement_email(reimbursement.id).deliver_later - end - end - end - end -end diff --git a/core/spec/lib/spree/event/subscriber_spec.rb b/core/spec/lib/spree/event/subscriber_spec.rb index e846de2c06b..a70af93bfa1 100644 --- a/core/spec/lib/spree/event/subscriber_spec.rb +++ b/core/spec/lib/spree/event/subscriber_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' require 'spree/event' -RSpec.describe Spree::Event do +RSpec.describe Spree::Event::Subscriber do module M include Spree::Event::Subscriber diff --git a/core/spec/lib/spree/event_spec.rb b/core/spec/lib/spree/event_spec.rb index 49a82835561..26cfdd4f472 100644 --- a/core/spec/lib/spree/event_spec.rb +++ b/core/spec/lib/spree/event_spec.rb @@ -14,21 +14,21 @@ expect(subject.adapter).to eql Spree::Event::Adapters::ActiveSupportNotifications end - before do - # ActiveSupport::Notifications does not provide an interface to clean all - # subscribers at once, so some low level brittle code is required - @old_subscribers = notifier.instance_variable_get('@subscribers').dup - @old_listeners = notifier.instance_variable_get('@listeners_for').dup - notifier.instance_variable_get('@subscribers').clear - notifier.instance_variable_get('@listeners_for').clear - end + context 'with the default adapter' do + before do + # ActiveSupport::Notifications does not provide an interface to clean all + # subscribers at once, so some low level brittle code is required + @old_subscribers = notifier.instance_variable_get('@subscribers').dup + @old_listeners = notifier.instance_variable_get('@listeners_for').dup + notifier.instance_variable_get('@subscribers').clear + notifier.instance_variable_get('@listeners_for').clear + end - after do - notifier.instance_variable_set '@subscribers', @old_subscribers - notifier.instance_variable_set '@listeners_for', @old_listeners - end + after do + notifier.instance_variable_set '@subscribers', @old_subscribers + notifier.instance_variable_set '@listeners_for', @old_listeners + end - context 'with the default adapter' do describe '#listeners' do context 'when there is no subscription' do it { expect(subject.listeners).to be_empty } @@ -89,4 +89,30 @@ end end end + + describe '.subscribers' do + let(:subscriber) { instance_double(Module, 'Subscriber') } + let(:subscriber_name) { instance_double(String, 'Subscriber name') } + + before do + described_class.subscribers.clear + allow(subscriber).to receive(:name).and_return(subscriber_name) + allow(subscriber_name).to receive(:constantize).and_return(subscriber) + allow(subscriber_name).to receive(:to_s).and_return(subscriber_name) + end + + it 'accepts the names of constants' do + Spree::Config.events.subscribers << subscriber_name + + expect(described_class.subscribers.to_a).to eq([subscriber]) + end + + it 'discards duplicates' do + described_class.subscribers << subscriber_name + described_class.subscribers << subscriber_name + described_class.subscribers << subscriber_name + + expect(described_class.subscribers.to_a).to eq([subscriber]) + end + end end diff --git a/core/spec/models/spree/order_spec.rb b/core/spec/models/spree/order_spec.rb index a303d3c87a2..c1fabd9dc59 100644 --- a/core/spec/models/spree/order_spec.rb +++ b/core/spec/models/spree/order_spec.rb @@ -29,14 +29,14 @@ end # These specs show how notifications can be removed, one at a time or - # all the ones set by MailerProcessor module + # all the ones set by MailerSubscriber module context 'when removing the default email notification subscription' do before do - Spree::Event.unsubscribe Spree::Event::Processors::MailerProcessor.order_finalized_handler + Spree::Event.unsubscribe Spree::MailerSubscriber.order_finalized_handler end after do - Spree::Event::Processors::MailerProcessor.subscribe! + Spree::MailerSubscriber.subscribe! end it 'does not send the email' do @@ -47,11 +47,11 @@ context 'when removing all the email notification subscriptions' do before do - Spree::Event::Processors::MailerProcessor.unsubscribe! + Spree::MailerSubscriber.unsubscribe! end after do - Spree::Event::Processors::MailerProcessor.subscribe! + Spree::MailerSubscriber.subscribe! end it 'does not send the email' do diff --git a/guides/source/developers/events/overview.html.md b/guides/source/developers/events/overview.html.md index 77ef6bc7acc..90b89a5450f 100644 --- a/guides/source/developers/events/overview.html.md +++ b/guides/source/developers/events/overview.html.md @@ -25,7 +25,7 @@ Spree::Config.events.adapter = "Spree::EventBus.new" ## Subscribing to events -`Spree::Event.subscribe` allows to subscribe to a certain event. The event name is mandatory, the optional block will be executed everytime the event is fired: +`Spree::Event.subscribe` allows to subscribe to a certain event. The event name is mandatory, the optional block will be executed every time the event is fired: ```ruby Spree::Event.subscribe 'order_finalized' do |event|