Skip to content
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

Strategy to inject dependencies via class- and instance-methods #70

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions lib/dry/auto_inject/strategies.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@ def self.register_default(name, strategy)
require 'dry/auto_inject/strategies/args'
require 'dry/auto_inject/strategies/hash'
require 'dry/auto_inject/strategies/kwargs'
require 'dry/auto_inject/strategies/methods'
33 changes: 33 additions & 0 deletions lib/dry/auto_inject/strategies/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

module Dry
module AutoInject
class Strategies
# @api private
class Base < Module
ClassMethods = Class.new(Module)
InstanceMethods = Class.new(Module)

attr_reader :container
attr_reader :dependency_map
attr_reader :instance_mod
attr_reader :class_mod

def initialize(container, *dependency_names)
@container = container
@dependency_map = DependencyMap.new(*dependency_names)
@instance_mod = InstanceMethods.new
@class_mod = ClassMethods.new
end

# @api private
def included(klass)
klass.send(:include, instance_mod)
klass.extend(class_mod)

super
end
end
end
end
end
21 changes: 2 additions & 19 deletions lib/dry/auto_inject/strategies/constructor.rb
Original file line number Diff line number Diff line change
@@ -1,36 +1,19 @@
# frozen_string_literal: true

require 'dry/auto_inject/strategies/base'
require 'dry/auto_inject/dependency_map'

module Dry
module AutoInject
class Strategies
class Constructor < Module
ClassMethods = Class.new(Module)
InstanceMethods = Class.new(Module)

attr_reader :container
attr_reader :dependency_map
attr_reader :instance_mod
attr_reader :class_mod

def initialize(container, *dependency_names)
@container = container
@dependency_map = DependencyMap.new(*dependency_names)
@instance_mod = InstanceMethods.new
@class_mod = ClassMethods.new
end

class Constructor < Base
# @api private
def included(klass)
define_readers

define_new
define_initialize(klass)

klass.send(:include, instance_mod)
klass.extend(class_mod)

super
end

Expand Down
59 changes: 59 additions & 0 deletions lib/dry/auto_inject/strategies/methods.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# frozen_string_literal: true

require 'dry/auto_inject/strategies/base'
require 'dry/auto_inject/method_parameters'

module Dry
module AutoInject
class Strategies
# @api private
class Methods < Base
# @api private
def included(klass)
define_class_methods
define_instance_methods

super
end

private

def define_class_methods
class_mod.class_exec(container, dependency_map) do |container, dependency_map|
dependency_map.to_h.each do |name, identifier|
define_method name do
container[identifier]
end
end

def with_deps(**deps)
Class.new(self) do |klass|
deps.each do |name, value|
singleton_class.define_method name do
value
end
end
end
end
end

self
end

def define_instance_methods
instance_mod.class_exec(container, dependency_map) do |container, dependency_map|
dependency_map.to_h.each do |name, identifier|
define_method name do
self.class.send(name)
end
end
end

self
end
end

register :methods, Methods
end
end
end
24 changes: 24 additions & 0 deletions spec/integration/methods_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

RSpec.describe 'methods' do
it 'defines methods returning dependencies' do
module Test
AutoInject = Dry::AutoInject(one: 'dep 1', two: 'dep 2').methods
end

obj = Class.new do
include Test::AutoInject[:one, :two]
end

expect(obj.one).to eq 'dep 1'
expect(obj.new.one).to eq 'dep 1'
expect(obj.two).to eq 'dep 2'
expect(obj.new.two).to eq 'dep 2'

other_obj = obj.with_deps(one: 'other dep 1')
expect(other_obj.one).to eq 'other dep 1'
expect(other_obj.new.one).to eq 'other dep 1'
expect(other_obj.two).to eq 'dep 2'
expect(other_obj.new.two).to eq 'dep 2'
end
end