8000 Use ad-hoc configuration system by waiting-for-dev · Pull Request #2 · nebulab/omnes · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Use ad-hoc configuration system #2

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

Merged
merged 1 commit into from
Apr 14, 2022
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
< 10000 div data-target="diff-layout.mainContainer" data-view-component="true" class="Layout-main">
6 changes: 0 additions & 6 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ PATH
remote: .
specs:
omnes (0.1.0)
dry-configurable (~> 0.14)

GEM
remote: https://rubygems.org/
Expand All @@ -19,11 +18,6 @@ GEM
concurrent-ruby (1.1.9)
connection_pool (2.2.5)
diff-lcs (1.5.0)
dry-configurable (0.14.0)
concurrent-ruby (~> 1.0)
dry-core (~> 0.6)
dry-core (0.7.1)
concurrent-ruby (~> 1.0)
globalid (1.0.0)
activesupport (>= 5.0)
i18n (1.10.0)
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,23 @@ subscription identifiers.
There's also a specialized `Omnes::Bus#performing_nothing` method that runs no
subscriptions for the duration of the block.

## Configuration

We've seen the relevant configurable settings in the corresponding sections.
You can also access the configuration in the habitual block syntax:

```ruby
Omnes.configure do |config|
config.subscriber.adapter.sidekiq.serializer = :serialized_payload.to_proc
end
```

Finally, nested settings can also be set directly from the affected class. E.g.:

```ruby
Omnes::Subscriber::Adapter::Sidekiq.config.serializer = :serialized_payload.to_proc
```

## Recipes

### Rails
Expand Down
40 changes: 4 additions & 36 deletions lib/omnes.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require "omnes/bus"
require "omnes/configurable"
require "omnes/event"
require "omnes/subscriber"
require "omnes/version"
Expand Down Expand Up @@ -33,43 +34,10 @@
# Refer to {Omnes::Subscriber} for how to provide event handlers through methods
# defined in a class.
module Omnes
# Shortcut to access the configuration for different Omnes components
#
# TODO: Make automation for it
#
# @return [Omnes::Config]
def self.config
Config
end

# Wrapper for the configuration of Omnes components
module Config
# {Omnes::Subscriber} configuration
#
# @return [Dry::Configurable::Config]
def self.subscriber
Omnes::Subscriber.config.tap do |klass|
klass.define_singleton_method(:adapter) do
Module.new do
def self.sidekiq
Omnes::Subscriber::Adapter::Sidekiq.config
end
extend Configurable

def self.active_job
Omnes::Subscriber::Adapter::ActiveJob.config
end
end
end
end
end

# {Omnes::Event} configuration
#
# @return [Dry::Configurable::Config]
def self.event
Omnes::Event.config
end
end
nest_config Subscriber
nest_config Event

# @api private
def self.included(klass)
Expand Down
108 changes: 108 additions & 0 deletions lib/omnes/configurable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# frozen_string_literal: true

module Omnes
# Ad-hoc configurable behavior for Omnes
#
# Example:
#
# ```
# Omnes.configure do |config|
# config.event.name_builder = MY_NAME_BUILDER
# en EDBE d
# ```
#
# or
#
# ```
# Omnes::Event.config.name_builder = MY_NAME_BUILDER
# ```
module Configurable
# Class where readers and writers are defined
class Config
# @api private
attr_reader :settings

# @api private
def initialize
@_mutex = Mutex.new
@settings = {}
end

# @api private
def add_setting(name, default)
@_mutex.synchronize do
@settings[name] = default
define_setting_reader(name)
define_setting_writter(name)
end
end

# @api private
def add_nesting(constant, name = default_nesting_name(constant))
@_mutex.synchronize do
define_nesting_reader(constant, name)
end
end

private

def define_setting_reader(name)
define_singleton_method(name) { @settings[name] }
end

def define_setting_writter(name)
define_singleton_method(:"#{name}=") do |value|
@_mutex.synchronize do
@settings[name] = value
end
end
end

def define_nesting_reader(constant, name)
define_singleton_method(name) { constant.config }
end
end

# @api private
def self.extended(klass)
klass.instance_variable_set(:@config, Config.new)
end

# Returns the configuration class
#
# Use this class to access readers and writers for the defined settings or
# nested configurations
#
# @return [Configurable::Config]
def config
@config
end

# Yields the configuration class
#
# @see #config
def configure
yield @config
end

# @api private
def setting(name, default:)
config.add_setting(name, default)
end

# @api private
def nest_config(constant, name: default_nesting_name(constant))
config.add_nesting(constant, name)
end

private

def default_nesting_name(constant)
constant.name
.split("::")
.last
.gsub(/([[:alpha:]])([[:upper:]])/, '\1_\2')
.downcase
end
end
end
4 changes: 2 additions & 2 deletions lib/omnes/event.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

require "dry/configurable"
require "omnes/configurable"

module Omnes
# Event mixin for custom classes
Expand All @@ -27,7 +27,7 @@ module Omnes
# bus.publish(MyEvent.new(1))
# ```
module Event
extend Dry::Configurable
extend Configurable

# Generates the event name for an event instance
#
Expand Down
5 changes: 2 additions & 3 deletions lib/omnes/subscriber.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# frozen_string_literal: true

require "dry/configurable"
require "omnes/subscriber/adapter"
require "omnes/subscriber/state"
require "omnes/subscription"
Expand Down Expand Up @@ -122,14 +121,14 @@ module Omnes
# bus. However, you can subscribe distinct instances to the same bus or the
# same instance to different buses.
module Subscriber
extend Dry::Configurable
extend Configurable

# @api private
ON_PREFIX_STRATEGY = ->(event_name) { :"on_#{event_name}" }

setting :autodiscover, default: false

setting :autodiscover_strategy, default: ON_PREFIX_STRATEGY
nest_config Adapter

# Includes with options
#
Expand Down
6 changes: 6 additions & 0 deletions lib/omnes/subscriber/adapter.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# frozen_string_literal: true

require "omnes/configurable"
require "omnes/subscriber/adapter/active_job"
require "omnes/subscriber/adapter/method"
require "omnes/subscriber/adapter/sidekiq"
Expand All @@ -14,6 +15,11 @@ module Subscriber
# Alternatively, they can be curried and only take the instance as an
# argument, returning a one-argument callable taking the event.
module Adapter
extend Configurable

nest_config Sidekiq
nest_config ActiveJob

# @api private
# TODO: Simplify when when we can take callables and Proc in a polymorphic
# way: https://bugs.ruby-lang.org/issues/18644
Expand Down
4 changes: 2 additions & 2 deletions lib/omnes/subscriber/adapter/active_job.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

require "dry/configurable"
require "omnes/configurable"

module Omnes
module Subscriber
Expand Down Expand Up @@ -42,7 +42,7 @@ module Adapter
# Omnes.config.subscriber.adapter.active_job.serializer = :serialized_payload.to_proc
# ```
module ActiveJob
extend Dry::Configurable
extend Configurable

setting :serializer, default: :payload.to_proc

Expand Down
4 changes: 2 additions & 2 deletions lib/omnes/subscriber/adapter/sidekiq.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

require "dry/configurable"
require "omnes/configurable"

module Omnes
module Subscriber
Expand Down Expand Up @@ -49,7 +49,7 @@ module Adapter
# @example
# handle :my_event, with: Adapter::Sidekiq.in(60)
module Sidekiq
extend Dry::Configurable
extend Configurable

setting :serializer, default: :payload.to_proc

Expand Down
2 changes: 0 additions & 2 deletions omnes.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ Gem::Specification.new do |spec|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]

spec.add_dependency "dry-configurable", "~> 0.14"

spec.add_development_dependency "activejob", "~> 7.0"
spec.add_development_dependency "redcarpet", "~> 3.5"
spec.add_development_dependency "sidekiq", "~> 6.4"
Expand Down
85 changes: 85 additions & 0 deletions spec/unit/omnes/configurable_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# frozen_string_literal: true

require "omnes/configurable"

RSpec.describe Omnes::Configurable do
subject { Class.new.extend(described_class) }

describe ".config" do
it "returns configuration class" do
expect(subject.config.is_a?(described_class::Config)).to be(true)
end
end

describe ".configure" do
it "yields the configuration instance" do
subject.configure do |config|
expect(config).to be(subject.config)
end
end
end

describe ".setting" do
it "sets default as the setting value" do
subject.setting :foo, default: :bar

expect(subject.config.settings[:foo]).to be(:bar)
end

it "creates a reader for the setting in config" do
subject.setting :foo, default: :bar

expect(subject.config.foo).to be(:bar)
end

it "creates a writter for the setting in config" do
subject.setting :foo, default: :bar

subject.config.foo = :baz

expect(subject.config.foo).to be(:baz)
end
end

describe ".nest_config" do
it "adds a reader in config to access another constant config" do
other = Class.new.extend(described_class)

subject.nest_config other, name: :other

expect(subject.config.other).to be(other.config)
end

it "defaults reader name to the downcased class name" do
Other = Class.new.extend(described_class)

subject.nest_config Other

expect(subject.config.other).to be(Other.config)
ensure
Object.send(:remove_const, :Other)
end

it "adds an underscore before a capitalized character preceded by a lowercase char in the default name" do
OtherClass = Class.new.extend(described_class)

subject.nest_config OtherClass

expect(subject.config.other_class).to be(OtherClass.config)
ensure
Object.send(:remove_const, :OtherClass)
end

it "only takes the last hierarchy level for the default name" do
module Top
Bottom = Class.new.extend(Omnes::Configurable)
end

subject.nest_config Top::Bottom

expect(subject.config.bottom).to be(Top::Bottom.config)
ensure
Object.send(:remove_const, :Top)
end
end
end
Loading
0