Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

diftw

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

diftw

  • 2.0.0
  • Rubygems
  • Socket score

Version published
Maintainers
1
Created
Source

DiFtw Build Status

Dependency Injection For The Win! A small, yet surprisingly powerful, dependency injection library for Ruby.

Why DI in Ruby?

If your only concern is testing, mocks/stubs and webmock might be all you need. But if you're working on a large project that hooks into all kinds of enterprisey services, and those services aren't always available in dev/testing/staging, a dash of DI might be just the thing.

Features

  • DI container w/dead-simple registration
  • Inject singletons or factories
  • Lazy injection (by default)
  • Inject into each of a class's instances, a single instance, a class itself, or a module
  • Uses parent-child injectors for max flexibility
  • Threadsafe, after registration

Dead-simple registration API

# Create your root injector/container
DI = DiFtw::Injector.new do
  singleton :foo do
    OpenStruct.new(message: "Everyone will get this same object")
  end

  factory :bar do
    OpenStruct.new(message: "Everyone will get a NEW version of this object")
  end

  # inject dependencies into your dependency
  factory :foobar, [:foo, :bar] do
    OpenStruct.new(message: foo.message + bar.message)
  end
end

# Or register things out here
DI.singleton :zorp do
  OpenStruct.new(message: "Bar")
end

Lazy injection (by default)

class Widget
  include DI.inject :foo, :bar
end

widget = Widget.new
# foo isn't actually injected until it's first called
puts widget.foo.message
=> "Foo"

Lazy injection is usually fine. But if it isn't, use inject!:

class Widget
  include DI.inject :foo, :bar
  
  def initialize
    inject!
  end
end

# foo and bar are immediately injected
widget = Widget.new

Inject into all instances, a single instance, a class, or a module

# Inject :baz into all Widget instance objects
class Widget
  include DI.inject :baz
end
puts Widget.new.baz.message
=> 'Baz'

# Inject :baz into one specific instance
x = SomeClass.new
DI.inject_instance x, :baz
puts x.baz.message
=> 'Baz'

# Inject :baz as a class method
class SomeClass
  extend DI.inject :baz
end
puts SomeClass.baz.message
=> 'Baz'

# Inject :baz as a module method 
module SomeModule
  extend DI.inject :baz
end
puts SomeModule.baz.message
=> 'Baz'

Parent-Child injectors

This is maybe the coolest part. Each time you call inject (or inject_instance) you're creating a fresh, empty child DiFtw::Injector. It will recursively look up dependencies through the parent chain until it finds the nearest registration of that dependency.

This means you can re-register a dependency on a child injector, and it will be injected instead of whatever is registered above it in the chain.

# Create your root injector and register :foo
DI = DiFtw::Injector.new
DI.singleton(:foo) { 'Foo' }

class Widget
  include DI.inject :foo
end

class Spline
  include DI.inject :foo
end

# Widget and Spline each get a new injector instance
Widget.injector.object_id != DI.object_id
=> true
Widget.injector.object_id != Spline.injector.object_id
=> true

# Each Widget instance gets a new injector instance. Same for Spline.
w1 = Widget.new
w1.injector.object_id != Widget.injector.object_id
=> true

w2 = Widget.new
w1.injector.object_id != w2.injector.object_id
=> true

# But all those child injectors are empty. They'll all resolve :foo
# to whatever is in DI[:foo]
Widget.new.foo
=> 'Foo'
Spline.new.foo
=> 'Foo'
Widget.new.foo.object_id == Spline.new.foo.object_id
=> true

# But we could re-register/override :foo in Spline.injector, and all new
# Spline instances would resolve :foo differently.
Spline.injector.singleton(:foo) { 'Bar' }
Spline.new.foo
=> 'Bar'
# But DI and Widget.injector would be unchanged
Widget.new.foo
=> 'Foo'

# We can go even further and override :foo in just one specific instance of Spline
# NOTE This only works if you're using lazy injection (the default) AND if you haven't called #foo yet
s = Spline.new
s.injector.singleton(:foo) { 'Baz' }
s.foo
=> 'Baz'
# Other Spline instances will still get their override from Spline.injector
Spline.new.foo
=> 'Bar'
# While Widget instances will all still get the original value from DI
Widget.new.foo
=> 'Foo'

DI in testing/local dev/staging/etc.

To inject different dependencies in these environments, you have several options. You can simply re-register dependencies in your root injector:

DI.singleton(:foo) { OpenStruct.new(message: 'Test Foo') }

And/Or you can use the parent-child injector features described above to great effect:

before :each do
  # Give all MyService instances 'Test foo' as #foo
  MyService.injector.singleton(:foo) {
    'Test foo'
  }
end

after :each do
  # Remove the override & fallback to whatever was registered in the root injector
  MyService.injector.delete :foo
end

FAQs

Package last updated on 28 Sep 2017

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc