listenable 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aa0682e0a477e1a2367d552bab4b480cfdb2d902628cc0f3eff9b566750332b4
4
- data.tar.gz: 81f80897906e86612474240bf7b1dedb2e7e21e4572d4313e61e65208f830d64
3
+ metadata.gz: ebe46a89c412b54c70f0af2f7851f46176dfd08c3dc5a611ef61c35d0bea1717
4
+ data.tar.gz: c19ed7b192adc50833b432058cfcdf652add0401bbbca28e869c282186ef7e88
5
5
  SHA512:
6
- metadata.gz: 781cc4d59e3a98604a8c2e06a5d0d981513ab08814949695b0da3b4ff4d9bb3ce737386e414969ae13e1fca1bee2b67708a12f71d7b46a9f76fe2b19c4c961f3
7
- data.tar.gz: c2ae5d198f292ea9fb2c9792da90cc0bb9a97ec950b48dbf79090a2c0ddbdef832289a807b958d9f83739d8b0999e48a50560e3a21b3be176041923a903a1669
6
+ metadata.gz: 6083b9a19eb74cceaec96942846f3a7b7754bf0ed27f42686f67351e8b6bd7246392c485a7b0ad4e35d909d85eb2b0f4f2cf33ebf0529ff475c9ed11b9857e68
7
+ data.tar.gz: 2b4c5d0b93694b35f3431f9cef48794182a621e8f937fc01bb745b895d3edbff5b38ce27c42a78c69622fecd2d2e5e1d35d5b2e171f5080dd2fd4344619c6ebd
data/README.md CHANGED
@@ -72,6 +72,57 @@ Under the hood:
72
72
  | `on_updated` | `after_update` |
73
73
  | `on_deleted` | `after_destroy` |
74
74
 
75
+ ## Runtime Toggle
76
+ By default, listeners are always active in development and production.
77
+
78
+ You can enable/disable them dynamically at runtime using:
79
+
80
+ ```ruby
81
+ Listenable.enabled = false # disable all listeners
82
+ Listenable.enabled = true # re-enable listeners
83
+ ```
84
+
85
+ This does not require restarting your Rails server or test suite.
86
+
87
+ ## RSpec/Test Integration
88
+ You usually don’t want listeners firing in tests (e.g. sending jobs or emails).
89
+
90
+ Disable them globally in your test suite:
91
+
92
+ ```ruby
93
+ # spec/rails_helper.rb
94
+ RSpec.configure do |config|
95
+ config.before(:suite) do
96
+ Listenable.enabled = false
97
+ end
98
+
99
+ # Enable listeners selectively
100
+ config.around(:each, listenable: true) do |example|
101
+ prev = Listenable.enabled
102
+ Listenable.enabled = true
103
+ example.run
104
+ Listenable.enabled = prev
105
+ end
106
+ end
107
+ ```
108
+
109
+ Now:
110
+
111
+ ```ruby
112
+ RSpec.describe User do
113
+ it 'does not fire listeners by default' do
114
+ expect(UserListener).not_to receive(:on_created)
115
+ User.create!(name: 'Pedro')
116
+ end
117
+
118
+ it 'fires listeners when enabled', listenable: true do
119
+ expect(UserListener).to receive(:on_created)
120
+ User.create!(name: 'Pedro')
121
+ end
122
+ end
123
+ ```
124
+
125
+
75
126
  ## Development
76
127
 
77
128
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -4,13 +4,13 @@ module Listenable
4
4
  class Railtie < Rails::Railtie
5
5
  initializer "listenable.load" do
6
6
  Rails.application.config.to_prepare do
7
- # Load all listeners (supports nested paths)
7
+ # Load all listeners (recursive, supports namespaced)
8
8
  Dir[Rails.root.join("app/listeners/**/*.rb")].each { |f| require_dependency f }
9
9
 
10
- # Wire models + listeners
10
+ # Find all listener classes
11
11
  ObjectSpace.each_object(Class).select { |klass| klass < Listenable }.each do |listener_class|
12
12
  model_class_name = listener_class.name.sub("Listener", "")
13
- model_class = model_class_name.safe_constantize
13
+ model_class = model_class_name.safe_constantize
14
14
  next unless model_class
15
15
 
16
16
  listener_class.pending_hooks.each do |hook|
@@ -19,22 +19,29 @@ module Listenable
19
19
  method = "on_#{action}"
20
20
  event = "#{model_class_name.underscore}.#{action}"
21
21
 
22
- # Avoid duplicate subscriptions on reload
22
+ # Unsubscribe duplicates
23
23
  ActiveSupport::Notifications.notifier.listeners_for(event).each do |subscriber|
24
24
  ActiveSupport::Notifications.unsubscribe(subscriber)
25
25
  end
26
26
 
27
- # Inject ActiveRecord callback
28
- model_class.send(callback) do
29
- ActiveSupport::Notifications.instrument(event, record: self)
27
+ # Inject AR callback once per model/event
28
+ injected_events = model_class.instance_variable_get(:@_listenable_injected_events) || []
29
+ unless injected_events.include?(event)
30
+ model_class.send(callback) do
31
+ next unless Listenable.enabled
32
+ ActiveSupport::Notifications.instrument(event, record: self)
33
+ end
34
+ injected_events << event
35
+ model_class.instance_variable_set(:@_listenable_injected_events, injected_events)
30
36
  end
31
37
 
32
- # Subscribe listener
33
- next unless listener_class.respond_to?(method)
34
-
35
- ActiveSupport::Notifications.subscribe(event) do |*args|
36
- _name, _start, _finish, _id, payload = args
37
- listener_class.public_send(method, payload[:record])
38
+ # Subscribe listener (runtime-guarded)
39
+ if listener_class.respond_to?(method)
40
+ ActiveSupport::Notifications.subscribe(event) do |*args|
41
+ next unless Listenable.enabled
42
+ _name, _start, _finish, _id, payload = args
43
+ listener_class.public_send(method, payload[:record])
44
+ end
38
45
  end
39
46
  end
40
47
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Listenable
4
- VERSION = "0.1.0"
4
+ VERSION = "0.1.1"
5
5
  end
data/lib/listenable.rb CHANGED
@@ -9,6 +9,8 @@ require_relative "listenable/concern"
9
9
  require_relative "listenable/railtie" if defined?(Rails)
10
10
 
11
11
  module Listenable
12
+ mattr_accessor :enabled, default: true
13
+
12
14
  class Error < StandardError; end
13
15
  # Your code goes here...
14
16
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: listenable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Den Meralpis