Dependor

build status

What is Dependor

Dependor is a set of helpers that make writing Ruby apps that use the dependency injection pattern easier. It comes as a set of modules, which you can selectively add to your project. It is designed do play nice with Rails and similar frameworks.

Manual Dependency Injection

class Foo
  def do_foo
    "foo"
  end
end

class Bar
  def initialize(foo)
    @foo = foo
  end

  def do_bar
    @foo.do_foo + "bar"
  end
end

class Injector
  def foo
    Foo.new
  end

  def bar
    Bar.new(foo)
  end
end

class EntryPoint
  def inject
    @injector ||= Injector.new
  end

  def bar
    inject.bar
  end

  def run
    bar.do_bar
  end
end

EntryPoint.new.run

The same thing with Dependor

require 'dependor'
require 'dependor/shorty'

class Foo
  def do_foo
    "foo"
  end
end

class Bar
  takes :foo

  def do_bar
    @foo.do_foo + "bar"
  end
end

class Injector
  include Dependor::AutoInject
end

class EntryPoint
  include Dependor::Injectable
  inject_from Injector

  inject :bar

  def run
    bar.do_bar
  end
end

EntryPoint.new.run

Dependor::AutoInject

This is the core part of the library. It looks at the constructor of a class to find out it's dependencies and instantiates it's instances with proper objects injected. It looks up classes by name.

AutoInject can also use the methods declared on injector as injection sources, which is quite useful for things like configuration.

class Injector
  include Dependor::AutoInject

  attr_reader :session

  def initialize(session)
    @session = session
  end

  let(:current_user) { current_user_service.get }
  let(:users_repository) { User }
  let(:comments_repository) { Comment }
end

class CurrentUserService
  takes :session, :users_repository

  def get
    @current_user ||= users_repository.find(session[:current_user_id])
  end
end

class CreatesComments
  takes :current_user, :comments_repository

  def create
    # ...
  end
end

class User < ActiveRecord::Base
end

class Comment < ActiveRecord::Base
end

Dependor::Shorty

This makes the constructor definition less verbose and includes Dependor::Let for shorter method definition syntax.

class Foo
  takes :foo, :bar, :baz
  let(:hello) { "world" }
end

is equivalent to:

class Foo
  attr_reader :foo, :bar, :baz

  def initialize(foo, bar, baz)
    @foo = foo
    @bar = bar
    @baz = baz
  end

  def hello
    "world"
  end
end

Dependor::Constructor

Sometimes you don't want to pollute every class with a takes method. You can then shorten the class declaration with Dependor::Constructor.

class Foo
  include Dependor::Constructor(:foo, :bar, :baz)
end

is equivalent to:

class Foo
  def initialize(foo, bar, baz)
    @foo = foo
    @bar = bar
    @baz = baz
  end
end

Dependor::Let

It allows a simpler syntax to define getter methods.

class Foo
  def foo
    do_something_or_other
  end
end

becomes:

class Foo
  extend Dependor::Let
  let(:foo) { do_something_or_other }
end

Dependor::Injectable

You can include this to make usage of the injector more convenient. This is used in the entry point of your application, typically a Rails controller.

class MyInjector
  def foo
    "foo"
  end
end

class ApplicationController
  extend Dependor::Injectable
  inject_from MyInjector
end

class PostsController < ApplicationController
  inject :foo

  def get
    render text: foo
  end
end

Sometimes you might want to pass request, params or session to your injector. Here is an example, how to do it:

require 'dependor/shorty'

class MyInjector
  include Dependor::AutoInject

  takes :params, :session, :request

  def foo
    session[:foo]
  end
end

class ApplicationController
  extend Dependor::Injectable

  def injector
    @injector ||= MyInjector.new(params, session, request)
  end
end

class PostsController < ApplicationController
  inject :foo

  def get
    render text: foo
  end
end

License

MIT. See the MIT-LICENSE file.

Author

Adam Pohorecki

Acknowledgements

Dependor::Shorty is inspired (or rather blatantly copied) from Gary Bernhardt's Destroy All Software Screencast "Shorter Class Syntax".