class Wireless::Registry

The public API of the dependency provider (AKA service locator). A hash-like object which maps names (symbols) to dependencies (objects) via blocks which either resolve the dependency every time (factory) or once (singleton).

A class can be supplied instead of the block, in which case it is equivalent to a block which calls new on the class, e.g.:

WL = Wireless.new do
  on(:foo, Foo)
end

is equivalent to:

WL = Wireless.new do
  on(:foo) { Foo.new }
end

Constants

DEFAULT_EXPORTS
DEFAULT_VISIBILITY

Public Class Methods

new(default_visibility = DEFAULT_VISIBILITY, &block) click to toggle source
# File lib/wireless/registry.rb, line 29
def initialize(default_visibility = DEFAULT_VISIBILITY, &block)
  @default_visibility = default_visibility
  @module_cache = SynchronizedStore.new(type: :module)
  @registry = SynchronizedStore.new(type: :resolver)
  @seen = Set.new
  instance_eval(&block) if block
end

Public Instance Methods

factory(name, klass = nil, &block) click to toggle source

Registers a dependency which is resolved every time its value is fetched.

# File lib/wireless/registry.rb, line 38
def factory(name, klass = nil, &block)
  @registry[name.to_sym] = Resolver::Factory.new(block || klass)
end
Also aliased as: on
include?(key) click to toggle source

Returns true if a dependency with the specified name has been registered, false otherwise

# File lib/wireless/registry.rb, line 44
def include?(key)
  @registry.include?(key)
end
mixin(args) click to toggle source

Takes an array or hash specifying the dependencies to export, and returns a module which defines getters for those dependencies.

class Test
  # hash (specify visibilities)
  include Services.mixin private: :foo, protected: %i[bar baz], public: :quux

  # or an array of imports using the default visibility (:private by default)
  include Services.mixin %i[foo bar baz quux]

  def test
    foo + bar + baz + quux # access the dependencies
  end
end

The visibility of the generated getters can be controlled by passing a hash with { visibility => imports } pairs, where imports is an array of import specifiers. An import specifier is a symbol (method name == dependency name) or a hash with { dependency_name => method_name } pairs (aliases). If there's only one import specifier, its enclosing array can be omitted, e.g.:

include Services.mixin(private: :foo, protected: { :baz => :quux })

is equivalent to:

include Services.mixin(private: [:foo], protected: [{ :baz => :quux }])
# File lib/wireless/registry.rb, line 81
def mixin(args)
  # normalize the supplied argument (array or hash) into a hash of
  # { visibility => exports } pairs, where `visibility` is a symbol and
  # `exports` is a hash of { dependency_name => method_name } pairs
  if args.is_a?(Array)
    args = { @default_visibility => args }
  elsif !args.is_a?(Hash)
    raise ArgumentError, "invalid mixin argument: expected array or hash, got: #{args.class}"
  end

  # slurp each array of name (symbol) or name => alias (hash) import
  # specifiers into a normalized hash of { dependency_name => method_name }
  # pairs, e.g.:
  #
  # before:
  #
  #   [:foo, { :bar => :baz }, :quux]
  #
  # after:
  #
  #   { :foo => :foo, :bar => :baz, :quux => :quux }

  # XXX transform_values requires ruby >= 2.5
  args = DEFAULT_EXPORTS.merge(args).transform_values do |exports|
    exports = [exports] unless exports.is_a?(Array)
    exports.reduce({}) do |a, b|
      a.merge(b.is_a?(Hash) ? b : { b => b })
    end
  end

  @module_cache.get!(args) { module_for(args) }
end
on(name, klass = nil, &block)
Alias for: factory
once(name, klass = nil, &block)
Alias for: singleton
singleton(name, klass = nil, &block) click to toggle source

Registers a dependency which is only resolved the first time its value is fetched. On subsequent fetches, the cached value is returned.

# File lib/wireless/registry.rb, line 50
def singleton(name, klass = nil, &block)
  @registry[name.to_sym] = Resolver::Singleton.new(block || klass)
end
Also aliased as: once

Private Instance Methods

module_for(args) click to toggle source

Create a module with the specified exports

# File lib/wireless/registry.rb, line 120
def module_for(args)
  registry = self
  mod = Module.new

  args.each do |visibility, exports|
    exports.each do |dependency_name, method_name|
      # equivalent to (e.g.):
      #
      #   def foo
      #     registry.fetch(:foo)
      #   end
      mod.send(:define_method, method_name) do
        registry.fetch(dependency_name)
      end

      # equivalent to (e.g.):
      #
      #   private :foo
      mod.send(visibility, method_name)
    end
  end

  mod
end