
Security News
Researcher Exposes Zero-Day Clickjacking Vulnerabilities in Major Password Managers
Hacker Demonstrates How Easy It Is To Steal Data From Popular Password Managers
Install the gem and add to the application's Gemfile by executing:
$ bundle add active_dry_deps
Dependency injection helps to break explicit dependencies between objects making it much easier to maintain a single responsibility and reduce coupling in our class designs. This leads to more testable code and code that is more resilient to change.
For a deeper background on Dependency Injection consider the Wikipedia article on the subject.
Under the hood active_dry_deps
uses a container like dry-container and convert key to underscore for fetch from container.
For auto-registration dependencies use dry-system.
MyApp::Container.register('warehouse.create_departure_service', Class.new { def self.call = 'failure' })
include Deps['Warehouse::CreateDepartureService.call']
Deps['Warehouse::CreateDepartureService.call']
this notation is familiar to Ruby developers, helps to find code in the project, and simplifies the migration from constants in code to defining dependencies.
class CreateOrderService < ServiceObject
include Deps[
'Warehouse::CreateDepartureService.call',
'Warehouse::ReserveJob.perform_later',
'OrderMailer',
'redis',
track: 'StatsApi.message',
]
def call(params)
order = Order.create(params)
ReserveJob(order)
track(order.id, order.created_at)
redis.with do |conn|
conn.incr('order_count')
end
OrderMailer().with(user: user).deliver_later
CreateDepartureService(order.slice(:id, :departure_at))
end
end
describe 'CreateOrderService' do
it 'success create order' do
service = described_class.new(user: create(:user), zip_code: 67_345)
expect(service).to deps(CreateDepartureService: double(success?: true), ReserveJob: spy, track: spy)
expect(service.call.success?).to be true
end
end
You can inject any method from object in your container
MyApp::Container.register(:str, 'str')
MyApp::Container.register(:service, Module.new { def self.success? = true } )
include Deps['str.reverse', 'service.success?']
reverse # => "rts"
success? # => true
By default, when call
or perform_later
methods are imported, the name of the dependency is taken from the name of the constant:
include Deps[
'Warehouse::CreateDepartureService.call', # callable
'Warehouse::ReserveJob.perform_later', # callable
'Warehouse::ReserveJob.perform_now',
'Warehouse::ProductActivateQuery',
]
# use as
CreateDepartureService()
ReserveJob()
perform_now
ProductActivateQuery().run
Recommends using prefixes (Service
, Job
, Query
) in the name of the constant for easy reading of the dependency type.
include Deps[string: 'str.reverse', m: 'module']
string # => "rts"
m # => "success"
gem adds rspec matcher for stub dependency, put require 'active_dry_deps/rspec'
to rspec setup
GpApp::Container.register('order.dependency', Class.new { def self.call = 'failure' })
let(:service_klass) do
Class.new do
include Deps['Order::Dependency.call']
def call = Dependency()
end
end
it 'failure' do
expect(service_klass.new.call).to be 'failure'
end
it 'success' do
service = service_klass.new
expect(service).to deps(Dependency: 'success')
expect(service.call).to be 'success'
end
it 'stub' do
Deps.stub('Order::Dependency', double(call: 'success'))
expect(service_klass.new.call).to be 'success'
Deps.unstub('Order::Dependency') # or simple Deps.unstub for unsub all keys
expect(service_klass.new.call).to be 'failure'
end
gem auto-configuring, but you can override settings
ActiveDryDeps.config.container = 'MyApp::Container'
ActiveDryDeps.config.inflector = ActiveSupport::Inflector
ActiveDryDeps.config.inject_global_constant = 'Deps'
config/initializers/system.rb
require 'dry/system/container'
module GpApp
class ContainerRailtie < Rails::Railtie
LOADER =
Class.new(Dry::System::Loader) do
def self.call(component, *args)
constant = self.constant(component)
if singleton?(constant)
constant.instance(*args)
else
constant # constant.new(*args) - THIS LINE REWRITED from Dry::System::Loader
end
end
end
# https://api.rubyonrails.org/classes/Rails/Railtie.html
# Add a to_prepare block which is executed once in production
# and before each request in development.
config.to_prepare do
ContainerRailtie.finalize
end
def finalize
set_or_reload(:Container, create_container)
Dry::System.register_provider_sources(Pathname(__dir__).join('../system/providers').realpath)
create_container.finalize!(freeze: !(::Rails.env.test? || ::Rails.env.development?))
end
def create_container
Class.new(Dry::System::Container) do
configure do |config|
config.inflector = ActiveSupport::Inflector
config.root = Rails.root.join('app')
%w[domains jobs queries services mailers].each do |dir_name|
config.component_dirs.add dir_name do |dir|
dir.loader = LOADER
dir.memoize = true
end
end
config.component_dirs.add '../lib' do |dir|
dir.loader = LOADER
dir.memoize = true
end
end
end
end
def set_or_reload(const_name, const)
remove_constant(const_name)
GpApp.const_set(const_name, const)
end
def remove_constant(const_name)
if GpApp.const_defined?(const_name, false)
GpApp.__send__(:remove_const, const_name)
end
end
end
end
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and the created tag, and push the .gem
file to rubygems.org.
Bug reports and pull requests are welcome on GitHub at https://github.com/corp-gp/active_dry_deps.
The gem is available as open source under the terms of the MIT License.
FAQs
Unknown package
We found that active_dry_deps demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
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.
Security News
Hacker Demonstrates How Easy It Is To Steal Data From Popular Password Managers
Security News
Oxlint’s new preview brings type-aware linting powered by typescript-go, combining advanced TypeScript rules with native-speed performance.
Security News
A new site reviews software projects to reveal if they’re truly FOSS, making complex licensing and distribution models easy to understand.