Skip to content

Commit

Permalink
Raise exception when injecting into modules
Browse files Browse the repository at this point in the history
To me it happened that I accidentally injected my dependencies into a
namespace module instead of into a class, like this:

  module Operations
    module Articles
      include Import["repositories.articles"]

      class Create
        # ...
      end
    end
  end

When I did that, I got a NoMethodError for NilClass somewhere down the
line. This led me to believe that I've somehow incorrectly passed
parameters to `Import[]`, and it took me a while to realize what was the
error.

The error occurred because the downstream code assumes the #initialize
method will be defined, which is not the case for modules. To improve
the developer experience, we detect that we're attempting to inject into
a module and raise an explicit exception.
  • Loading branch information
janko committed Oct 1, 2019
1 parent a501057 commit 29229f4
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 3 deletions.
5 changes: 5 additions & 0 deletions lib/dry/auto_inject.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,9 @@ module Dry
def self.AutoInject(container, options = {})
AutoInject::Builder.new(container, options)
end

module AutoInject
class Error < StandardError
end
end
end
5 changes: 2 additions & 3 deletions lib/dry/auto_inject/dependency_map.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
# frozen_string_literal: true

require 'dry/auto_inject/errors'

module Dry
module AutoInject
DuplicateDependencyError = Class.new(StandardError)
DependencyNameInvalid = Class.new(StandardError)

VALID_NAME = /([a-z_][a-zA-Z_0-9]*)$/

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

module Dry
module AutoInject
Error = Class.new(StandardError)
DuplicateDependencyError = Class.new(Error)
DependencyNameInvalid = Class.new(Error)
end
end
3 changes: 3 additions & 0 deletions lib/dry/auto_inject/strategies/constructor.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

require 'dry/auto_inject/dependency_map'
require 'dry/auto_inject/errors'

module Dry
module AutoInject
Expand All @@ -23,6 +24,8 @@ def initialize(container, *dependency_names)

# @api private
def included(klass)
fail Error, "cannot inject dependencies into a module" unless klass.respond_to?(:new)

define_readers

define_new
Expand Down
28 changes: 28 additions & 0 deletions spec/dry/auto_inject_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ def initialize(*args)
Class.new(child_class)
end

let(:mod) do
Module.new
end

context 'with positioned args' do
let(:parent_class) do
Class.new do
Expand Down Expand Up @@ -167,6 +171,14 @@ def initialize(first, *middle, last)
end
end
end

context 'autoinject in a module' do
it 'raises exception' do
expect {
mod.include Test::AutoInject.args[:one, :two]
}.to raise_error(Dry::AutoInject::Error, /cannot inject/)
end
end
end

context 'with hash arg' do
Expand Down Expand Up @@ -312,6 +324,14 @@ def self.included(klass)
end
end
end

context 'autoinject in a module' do
it 'raises exception' do
expect {
mod.include Test::AutoInject.hash[:one, :two]
}.to raise_error(Dry::AutoInject::Error, /cannot inject/)
end
end
end

context 'with keyword args' do
Expand Down Expand Up @@ -558,5 +578,13 @@ def initialize(other)
end
end
end

context 'autoinject in a module' do
it 'raises exception' do
expect {
mod.include Test::AutoInject.kwargs[:one, :two]
}.to raise_error(Dry::AutoInject::Error, /cannot inject/)
end
end
end
end

0 comments on commit 29229f4

Please sign in to comment.