active_pubsub_rails 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6bdad702dc5f5c7b7f559897fd91bcbba8172737f0355d3ff4e07d4a864cc7ce
4
+ data.tar.gz: 79a65c0ca27809760e87d981e08d1a37985f21e33e7b4d3846f371e0e304b761
5
+ SHA512:
6
+ metadata.gz: bfc62a703a9c391bcd096fb6fc9cca2accb76ad64354612b233400bf0e96f946c59b12c93c5f91b7a96b1f28119c63421d333ddd2d5f03bb82c4099429cce242
7
+ data.tar.gz: 209419fad924d1e5128319c12c46222e0f7a59cffcc1ff0ada18c83dcbfa8b8c60f35c162d4f55666dce422b8dc754d8f710b1093983cbe6bd2fca381685bee4
@@ -0,0 +1,18 @@
1
+ name: Ruby
2
+
3
+ on: [push,pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v2
10
+ - name: Set up Ruby
11
+ uses: ruby/setup-ruby@v1
12
+ with:
13
+ ruby-version: 3.0.0
14
+ - name: Run the default task
15
+ run: |
16
+ gem install bundler -v 2.2.3
17
+ bundle install
18
+ bundle exec rake
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.rubocop.yml ADDED
@@ -0,0 +1,16 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ TargetRubyVersion: 2.7
4
+ Style/StringLiterals:
5
+ Enabled: true
6
+ EnforcedStyle: double_quotes
7
+
8
+ Style/StringLiteralsInInterpolation:
9
+ Enabled: true
10
+ EnforcedStyle: double_quotes
11
+
12
+ Layout/LineLength:
13
+ Max: 160
14
+
15
+ Style/Documentation:
16
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in active_pubsub_rails.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "minitest", "~> 5.0"
11
+
12
+ gem "rubocop", "~> 0.80"
data/Gemfile.lock ADDED
@@ -0,0 +1,55 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ active_pubsub_rails (0.1.0)
5
+ activesupport (>= 5.2.x)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activesupport (6.1.3.1)
11
+ concurrent-ruby (~> 1.0, >= 1.0.2)
12
+ i18n (>= 1.6, < 2)
13
+ minitest (>= 5.1)
14
+ tzinfo (~> 2.0)
15
+ zeitwerk (~> 2.3)
16
+ ast (2.4.2)
17
+ concurrent-ruby (1.1.8)
18
+ i18n (1.8.10)
19
+ concurrent-ruby (~> 1.0)
20
+ minitest (5.14.4)
21
+ parallel (1.20.1)
22
+ parser (3.0.1.0)
23
+ ast (~> 2.4.1)
24
+ rainbow (3.0.0)
25
+ rake (13.0.3)
26
+ regexp_parser (2.1.1)
27
+ rexml (3.2.5)
28
+ rubocop (0.93.1)
29
+ parallel (~> 1.10)
30
+ parser (>= 2.7.1.5)
31
+ rainbow (>= 2.2.2, < 4.0)
32
+ regexp_parser (>= 1.8)
33
+ rexml
34
+ rubocop-ast (>= 0.6.0)
35
+ ruby-progressbar (~> 1.7)
36
+ unicode-display_width (>= 1.4.0, < 2.0)
37
+ rubocop-ast (1.4.1)
38
+ parser (>= 2.7.1.5)
39
+ ruby-progressbar (1.11.0)
40
+ tzinfo (2.0.4)
41
+ concurrent-ruby (~> 1.0)
42
+ unicode-display_width (1.7.0)
43
+ zeitwerk (2.4.2)
44
+
45
+ PLATFORMS
46
+ x86_64-darwin-19
47
+
48
+ DEPENDENCIES
49
+ active_pubsub_rails!
50
+ minitest (~> 5.0)
51
+ rake (~> 13.0)
52
+ rubocop (~> 0.80)
53
+
54
+ BUNDLED WITH
55
+ 2.2.3
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Gaurav Tiwari
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # ActivePubsub
2
+
3
+ Simple pub-sub message bus for Rails built on top of ActiveSupportNotifications
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'active_pubsub_rails'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install active_pubsub_rails
20
+
21
+ ## Usage
22
+
23
+ Create a subscriber that listens to events:
24
+
25
+ ```rb
26
+ # Create your subscriber under app/subscribers
27
+ # app/subscribers/account_subscriber.rb
28
+
29
+ module AccountSubscriber
30
+ include ActivePubsubRails::Subscriber
31
+
32
+ event_action :account_opened
33
+ event_action :account_verified
34
+ event_action :account_deleted, event_name: :account_removed
35
+
36
+ def account_opened(event)
37
+ # Do something here
38
+ end
39
+
40
+ def account_verified(event)
41
+ # Do something here
42
+ end
43
+
44
+ def account_deleted(event)
45
+ # Do something here
46
+ end
47
+ end
48
+ ```
49
+
50
+ And, publish events like so
51
+
52
+ ```rb
53
+ ActivePubsubRails.fire 'account_opened', account_id: 1
54
+ # => <ActiveSupport::Notifications::Event:0x00007fec80755d90 @name="account_opened", @payload={:account_id=>1}, @time=2021-04-30 13:44:23.997487 +0100, @transaction_id="ff2eeaa4cfa39993eef1", @end=2021-04-30 13:44:23.997494 +0100, @children=[], @cpu_time_start=0, @cpu_time_finish=0, @allocation_count_start=0, @allocation_count_finish=0>
55
+
56
+ ActivePubsubRails.fire 'account_verified', account_id: 1, verfied: true
57
+ ```
58
+
59
+ ## Development
60
+
61
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
62
+
63
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
64
+
65
+ ## Contributing
66
+
67
+ Bug reports and pull requests are welcome on GitHub at https://github.com/gauravtiwari/active_pubsub_rails.
68
+
69
+ ```
70
+
71
+ ```
72
+
73
+ ```
74
+
75
+ ```
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << "test"
8
+ t.libs << "lib"
9
+ t.test_files = FileList["test/**/*_test.rb"]
10
+ end
11
+
12
+ require "rubocop/rake_task"
13
+
14
+ RuboCop::RakeTask.new
15
+
16
+ task default: %i[test rubocop]
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/active_pubsub_rails/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "active_pubsub_rails"
7
+ spec.version = ActivePubsubRails::VERSION
8
+ spec.authors = ["Gaurav Tiwari"]
9
+ spec.email = ["gaurav@gauravtiwari.co.uk"]
10
+
11
+ spec.summary = "Simple pub-sub message bus for Rails built on top of ActiveSupportNotifications"
12
+ spec.description = "Simple pub-sub message bus for Rails built on top of ActiveSupportNotifications"
13
+ spec.homepage = "https://github.com/gauravtiwari/active_pubsub_rails"
14
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.7.1")
15
+ spec.metadata["homepage_uri"] = spec.homepage
16
+ spec.metadata["source_code_uri"] = "https://github.com/gauravtiwari/active_pubsub_rails"
17
+ spec.metadata["changelog_uri"] = "https://github.com/gauravtiwari/active_pubsub_rails"
18
+
19
+ # Specify which files should be added to the gem when it is released.
20
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
23
+ end
24
+ spec.bindir = "exe"
25
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
26
+ spec.require_paths = ["lib"]
27
+
28
+ spec.add_dependency "activesupport", ">= 5.2.x"
29
+ end
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "active_pubsub_rails"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "active_pubsub_rails/version"
4
+ require_relative "active_pubsub_rails/engine"
5
+
6
+ module ActivePubsubRails
7
+ extend self
8
+ delegate :activate_autoloadable_subscribers, :activate_all_subscribers, :deactivate_all_subscribers, to: :subscriber_registry
9
+
10
+ def fire(event_name, opts = {})
11
+ adapter.fire normalize_name(event_name), opts do
12
+ yield opts if block_given?
13
+ end
14
+ end
15
+
16
+ def subscribe(event_name, &block)
17
+ name = normalize_name(event_name)
18
+ listeners_names << name
19
+ adapter.subscribe(name, &block)
20
+ end
21
+
22
+ def unsubscribe(subscriber)
23
+ name_or_subscriber = subscriber.is_a?(String) ? normalize_name(subscriber) : subscriber
24
+ adapter.unsubscribe(name_or_subscriber)
25
+ end
26
+
27
+ def listeners
28
+ adapter.listeners_for(listeners_names)
29
+ end
30
+
31
+ def adapter
32
+ @adapter ||= ActivePubsubRails::Adapters::ActiveSupportNotifications
33
+ end
34
+
35
+ def subscriber_registry
36
+ @subscriber_registry ||= ActivePubsubRails::SubscriberRegistry.new
37
+ end
38
+
39
+ private
40
+
41
+ def normalize_name(name)
42
+ adapter.normalize_name(name)
43
+ end
44
+
45
+ def listeners_names
46
+ @listeners_names ||= Set.new
47
+ end
48
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActivePubsubRails
4
+ module Adapters
5
+ module ActiveSupportNotifications
6
+ class InvalidEventNameType < StandardError; end
7
+
8
+ module_function
9
+
10
+ def fire(event_name, opts)
11
+ ActiveSupport::Notifications.instrument event_name, opts do
12
+ yield opts if block_given?
13
+ end
14
+ end
15
+
16
+ def subscribe(event_name)
17
+ ActiveSupport::Notifications.subscribe event_name do |*args|
18
+ event = ActiveSupport::Notifications::Event.new(*args)
19
+ yield event
20
+ end
21
+ end
22
+
23
+ def unsubscribe(subscriber_or_name)
24
+ ActiveSupport::Notifications.unsubscribe(subscriber_or_name)
25
+ end
26
+
27
+ def listeners_for(names)
28
+ names.each_with_object({}) do |name, memo|
29
+ listeners = ActiveSupport::Notifications.notifier.listeners_for(name)
30
+ memo[name] = listeners if listeners.present?
31
+ end
32
+ end
33
+
34
+ def normalize_name(event_name)
35
+ case event_name
36
+ when Regexp, String, Symbol
37
+ event_name
38
+ else
39
+ raise InvalidEventNameType, "Invalid event name type: #{event_name.class}"
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActivePubsubRails
4
+ class Configuration
5
+ def subscriber_registry
6
+ @subscriber_registry ||= ActivePubsubRails::SubscriberRegistry.new
7
+ end
8
+
9
+ attr_writer :adapter, :autoload_subscribers
10
+
11
+ def autoload_subscribers
12
+ @autoload_subscribers.nil? ? true : !!@autoload_subscribers
13
+ end
14
+
15
+ def adapter
16
+ @adapter ||= ActivePubsubRails::Adapters::ActiveSupportNotifications
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "adapters/active_support_notifications"
4
+ require_relative "subscriber_registry"
5
+ require_relative "configuration"
6
+ require_relative "subscriber"
7
+
8
+ module ActivePubsubRails
9
+ class Engine < ::Rails::Engine
10
+ initializer "spree.core.initialize_subscribers" do |app|
11
+ app.reloader.to_prepare do
12
+ ActivePubsubRails.activate_autoloadable_subscribers
13
+ end
14
+
15
+ app.reloader.before_class_unload do
16
+ ActivePubsubRails.deactivate_all_subscribers
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActivePubsubRails
4
+ module Subscriber
5
+ def self.included(base)
6
+ base.extend base
7
+
8
+ base.mattr_accessor :event_actions
9
+ base.event_actions = {}
10
+
11
+ ActivePubsubRails.subscriber_registry.register(base)
12
+ end
13
+
14
+ def event_action(method_name, event_name: nil)
15
+ event_actions[method_name] = (event_name || method_name).to_s
16
+ end
17
+
18
+ def activate
19
+ ActivePubsubRails.subscriber_registry.activate_subscriber(self)
20
+ end
21
+
22
+ def deactivate(event_action_name = nil)
23
+ ActivePubsubRails.subscriber_registry.deactivate_subscriber(self, event_action_name)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActivePubsubRails
4
+ class SubscriberRegistry
5
+ def initialize
6
+ @registry = {}
7
+ @semaphore = Mutex.new
8
+ end
9
+
10
+ def register(subscriber)
11
+ registry[subscriber.name] ||= {}
12
+ end
13
+
14
+ def activate_autoloadable_subscribers
15
+ require_subscriber_files
16
+ activate_all_subscribers
17
+ end
18
+
19
+ def activate_all_subscribers
20
+ registry.each_key { |subscriber_name| activate_subscriber(subscriber_name.constantize) }
21
+ end
22
+
23
+ def deactivate_all_subscribers
24
+ registry.each_key { |subscriber_name| deactivate_subscriber(subscriber_name.constantize) }
25
+ end
26
+
27
+ def activate_subscriber(subscriber)
28
+ return unless registry[subscriber.name]
29
+
30
+ subscriber.event_actions.each do |event_action, event_name|
31
+ @semaphore.synchronize do
32
+ unsafe_deactivate_subscriber(subscriber, event_action)
33
+ subscription = ActivePubsubRails.subscribe(event_name) { |event| subscriber.send(event_action, event) }
34
+ registry[subscriber.name][event_action] = subscription
35
+ end
36
+ end
37
+ end
38
+
39
+ def deactivate_subscriber(subscriber, event_action_name = nil)
40
+ @semaphore.synchronize do
41
+ unsafe_deactivate_subscriber(subscriber, event_action_name)
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ attr_reader :registry
48
+
49
+ def require_subscriber_files
50
+ pattern = "app/subscribers/**/*_subscriber.rb"
51
+ Rails.root.glob(pattern) { |c| require_dependency(c.to_s) }
52
+ end
53
+
54
+ def unsafe_deactivate_subscriber(subscriber, event_action_name = nil)
55
+ to_unsubscribe = Array.wrap(event_action_name || subscriber.event_actions.keys)
56
+
57
+ to_unsubscribe.each do |event_action|
58
+ next unless (subscription = registry.dig(subscriber.name, event_action))
59
+
60
+ ActivePubsubRails.unsubscribe(subscription)
61
+
62
+ registry[subscriber.name].delete(event_action)
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActivePubsubRails
4
+ VERSION = "0.1.0"
5
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_pubsub_rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Gaurav Tiwari
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-04-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 5.2.x
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 5.2.x
27
+ description: Simple pub-sub message bus for Rails built on top of ActiveSupportNotifications
28
+ email:
29
+ - gaurav@gauravtiwari.co.uk
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".github/workflows/main.yml"
35
+ - ".gitignore"
36
+ - ".rubocop.yml"
37
+ - Gemfile
38
+ - Gemfile.lock
39
+ - LICENSE
40
+ - README.md
41
+ - Rakefile
42
+ - active_pubsub_rails.gemspec
43
+ - bin/console
44
+ - bin/setup
45
+ - lib/active_pubsub_rails.rb
46
+ - lib/active_pubsub_rails/adapters/active_support_notifications.rb
47
+ - lib/active_pubsub_rails/configuration.rb
48
+ - lib/active_pubsub_rails/engine.rb
49
+ - lib/active_pubsub_rails/subscriber.rb
50
+ - lib/active_pubsub_rails/subscriber_registry.rb
51
+ - lib/active_pubsub_rails/version.rb
52
+ homepage: https://github.com/gauravtiwari/active_pubsub_rails
53
+ licenses: []
54
+ metadata:
55
+ homepage_uri: https://github.com/gauravtiwari/active_pubsub_rails
56
+ source_code_uri: https://github.com/gauravtiwari/active_pubsub_rails
57
+ changelog_uri: https://github.com/gauravtiwari/active_pubsub_rails
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: 2.7.1
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubygems_version: 3.2.3
74
+ signing_key:
75
+ specification_version: 4
76
+ summary: Simple pub-sub message bus for Rails built on top of ActiveSupportNotifications
77
+ test_files: []