dependor-1.0.1/0000755000175000017500000000000012351463151012670 5ustar boutilboutildependor-1.0.1/metadata.yml0000644000175000017500000001173312351463151015200 0ustar boutilboutil--- !ruby/object:Gem::Specification name: dependor version: !ruby/object:Gem::Version version: 1.0.1 prerelease: platform: ruby authors: - Adam Pohorecki autorequire: bindir: bin cert_chain: [] date: 2013-08-27 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: rspec requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: guard requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: guard-rspec requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: growl requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: libnotify requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: rake requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' - !ruby/object:Gem::Dependency name: coveralls requirement: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' description: Dependor is not a framework for Dependency Injection, but something thatt reduces duplication a little bit when doing manual dependency injection in settings like Rails apps. email: - adam@pohorecki.pl executables: [] extensions: [] extra_rdoc_files: [] files: - .gitignore - .pelusa.yml - .travis.yml - Gemfile - Gemfile.lock - Guardfile - MIT-LICENSE - README.md - Rakefile - dependor.gemspec - lib/dependor.rb - lib/dependor/auto_inject.rb - lib/dependor/auto_injector.rb - lib/dependor/class_name_resolver.rb - lib/dependor/constructor.rb - lib/dependor/customized_injector.rb - lib/dependor/dependency_names_cache.rb - lib/dependor/evaluating_injector.rb - lib/dependor/exceptions.rb - lib/dependor/injectable.rb - lib/dependor/instantiator.rb - lib/dependor/isolate.rb - lib/dependor/let.rb - lib/dependor/rspec.rb - lib/dependor/sending_injector.rb - lib/dependor/shorty.rb - lib/dependor/version.rb - pelusa.sh - spec/dependor/auto_inject_spec.rb - spec/dependor/class_name_resolver_spec.rb - spec/dependor/constructor_spec.rb - spec/dependor/customized_injector_spec.rb - spec/dependor/evaluating_injector_spec.rb - spec/dependor/injectable_spec.rb - spec/dependor/instantiator_spec.rb - spec/dependor/isolate_spec.rb - spec/dependor/let_spec.rb - spec/dependor/shorty_spec.rb - spec/spec_helper.rb homepage: http://github.com/psyho/dependor licenses: [] post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' segments: - 0 hash: -3867103565292776709 required_rubygems_version: !ruby/object:Gem::Requirement none: false requirements: - - ! '>=' - !ruby/object:Gem::Version version: '0' segments: - 0 hash: -3867103565292776709 requirements: [] rubyforge_project: dependor rubygems_version: 1.8.25 signing_key: specification_version: 3 summary: A couple of classes and modules that simplify dependency injection in Ruby. test_files: [] dependor-1.0.1/spec/0000755000175000017500000000000012351463151013622 5ustar boutilboutildependor-1.0.1/spec/spec_helper.rb0000644000175000017500000000062512351463151016443 0ustar boutilboutilrequire 'simplecov' require 'coveralls' SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[ SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter] SimpleCov.start do add_filter "/spec/" end $:.push File.expand_path("../../lib", __FILE__) require 'rubygems' require 'rspec' require 'dependor' require 'dependor/shorty' RSpec.configure do |c| c.color_enabled = true end dependor-1.0.1/spec/dependor/0000755000175000017500000000000012351463151015422 5ustar boutilboutildependor-1.0.1/spec/dependor/shorty_spec.rb0000644000175000017500000000131512351463151020311 0ustar boutilboutilrequire 'spec_helper' require 'dependor/shorty' describe Dependor::Shorty do class SampleClassThatUsesTakes takes :foo, :bar, :baz def as_instance_variables {foo: @foo, bar: @bar, baz: @baz} end def as_attributes {foo: foo, bar: bar, baz: baz} end end subject{ SampleClassThatUsesTakes.new('foo value', 'bar value', 'baz value') } it 'defines a constructor with given names' do subject.as_instance_variables.should == { foo: 'foo value', bar: 'bar value', baz: 'baz value' } end it 'defines attr_reader for the given names' do subject.as_attributes.should == { foo: 'foo value', bar: 'bar value', baz: 'baz value' } end end dependor-1.0.1/spec/dependor/let_spec.rb0000644000175000017500000000035612351463151017551 0ustar boutilboutilrequire 'spec_helper' describe Dependor::Let do class SampleClassUsingLet extend Dependor::Let let(:foo) { "foo foo" } end it 'shortens method declaration' do SampleClassUsingLet.new.foo.should == "foo foo" end end dependor-1.0.1/spec/dependor/isolate_spec.rb0000644000175000017500000000200212351463151020413 0ustar boutilboutilrequire 'spec_helper' describe Dependor::Isolate do class ExampleSubject takes :foo, :bar end class ExampleContext include Dependor::Isolate def subject isolate{ExampleSubject} end def override bar = "bar was overriden" isolate{ExampleSubject} end def parameters isolate(ExampleSubject, bar: "the parameter") end def foo "the foo stub" end def bar "the bar stub" end end let(:context) { ExampleContext.new } it "injects the subject's dependencies using methods on context" do context.subject.foo.should == "the foo stub" context.subject.bar.should == "the bar stub" end it "allows overriding dependencies with variables" do context.override.bar.should == "bar was overriden" context.override.foo.should == "the foo stub" end it "allows overriding dependencies with parameters" do context.parameters.bar.should == "the parameter" context.parameters.foo.should == "the foo stub" end end dependor-1.0.1/spec/dependor/instantiator_spec.rb0000644000175000017500000000167212351463151021506 0ustar boutilboutilrequire 'spec_helper' describe Dependor::Instantiator do let(:injector) { double(:injector) } let(:dependency_names) { Dependor::DependencyNamesCache.new } let(:instantiator) { Dependor::Instantiator.new(injector, dependency_names) } it "instantiates objects with no-arg constructors" do klass = Class.new do def foo "foo" end end instance = instantiator.instantiate(klass) instance.foo.should == "foo" end it "instantiates objects with constructors" do klass = Class.new do def initialize(foo, bar, baz) @foo = [foo, bar, baz].join('-') end def foo @foo end end injector.should_receive(:get).with(:foo).and_return("foo") injector.should_receive(:get).with(:bar).and_return("bar") injector.should_receive(:get).with(:baz).and_return("baz") instance = instantiator.instantiate(klass) instance.foo.should == 'foo-bar-baz' end end dependor-1.0.1/spec/dependor/injectable_spec.rb0000644000175000017500000000216312351463151021063 0ustar boutilboutilrequire 'spec_helper' describe Dependor::Injectable do class SampleInjector def foo "foo" end end class SampleInjectable extend Dependor::Injectable inject_from(SampleInjector) inject :foo def hello_foo "hello #{foo}" end end class SampleInjectableWithoutAnInjector extend Dependor::Injectable inject :foo def hello_foo "hello #{foo}" end end it "requires the class to provide injector method" do injectable = SampleInjectableWithoutAnInjector.new expect do injectable.hello_foo end.to raise_exception end it "uses the provided injector" do injectable = SampleInjectable.new injectable.hello_foo.should == 'hello foo' end describe "typical Rails usage" do class ApplicationController extend Dependor::Injectable inject_from SampleInjector end class PostsController < ApplicationController inject :foo def get "render #{foo}" end end it "should return foo value in child controller" do PostsController.new.get.should == "render foo" end end end dependor-1.0.1/spec/dependor/evaluating_injector_spec.rb0000644000175000017500000000072112351463151023015 0ustar boutilboutilrequire 'spec_helper' describe Dependor::EvaluatingInjector do it 'evaluates methods in given binding' do def baz "the method baz" end injector = Dependor::EvaluatingInjector.new(binding) injector.get(:baz).should == "the method baz" end it 'evaluates local variables in given binding' do bar = "the local bar" injector = Dependor::EvaluatingInjector.new(binding) injector.get(:bar).should == "the local bar" end end dependor-1.0.1/spec/dependor/customized_injector_spec.rb0000644000175000017500000000127012351463151023044 0ustar boutilboutilrequire 'spec_helper' describe Dependor::CustomizedInjector do let(:other_injector) { double } it "returns the customized dependency if given" do injector = Dependor::CustomizedInjector.new(other_injector, foo: 'hello') injector.get(:foo).should == 'hello' end it "returns the customized dependency even if nil" do injector = Dependor::CustomizedInjector.new(other_injector, foo: nil) injector.get(:foo).should be_nil end it "delegates to the other injector" do other_injector.should_receive(:get).with(:foo).and_return(:the_foo) injector = Dependor::CustomizedInjector.new(other_injector, bar: 'a') injector.get(:foo).should == :the_foo end end dependor-1.0.1/spec/dependor/constructor_spec.rb0000644000175000017500000000067312351463151021354 0ustar boutilboutilrequire 'spec_helper' describe 'Dependor::Constructor' do class SampleClassUsingConstructor include Dependor::Constructor(:foo, :bar, :baz) def as_instance_variables {foo: @foo, bar: @bar, baz: @baz} end end it 'defines a constructor with given parameters' do sample = SampleClassUsingConstructor.new('aaa', 'bbb', 'ccc') sample.as_instance_variables.should == {foo: 'aaa', bar: 'bbb', baz: 'ccc'} end end dependor-1.0.1/spec/dependor/class_name_resolver_spec.rb0000644000175000017500000000214612351463151023012 0ustar boutilboutilrequire 'spec_helper' describe Dependor::ClassNameResolver do class FooBarBaz end class FooBarBaz2 end module Foo class FooBarBaz end end module Bar class FooBarBaz end end it "returns nil when the class could not be found" do resolver = Dependor::ClassNameResolver.new([]) resolver.for_name(:something).should be_nil end it "uses global scope with no search_modules" do resolver = Dependor::ClassNameResolver.new([]) resolver.for_name(:foo_bar_baz).should == FooBarBaz end it "searches modules in order specified" do resolver = Dependor::ClassNameResolver.new([Foo, Bar]) resolver.for_name(:foo_bar_baz).should == Foo::FooBarBaz end it "searches in order specified, with the global scope last" do resolver = Dependor::ClassNameResolver.new([Foo, Bar]) resolver.for_name(:foo_bar_baz_2).should == FooBarBaz2 end it "doesnt have Object in search modules after calling for_name" do resolver = Dependor::ClassNameResolver.new([]) resolver.for_name(:something) resolver.search_modules.should_not include(Object) end end dependor-1.0.1/spec/dependor/auto_inject_spec.rb0000644000175000017500000000556512351463151021300 0ustar boutilboutilrequire 'spec_helper' require 'dependor/shorty' describe Dependor::AutoInject do class SampleClassWithNoDependencies end class SampleClassWithDependency takes :sample_class_with_no_dependencies end class SampleClassWithManualDependency takes :manual_dep end class DependsOnFactoryMethod takes :create_foo end module SomeModule class SampleClassWithinSomeModule end end class SomeFactory attr_reader :foo, :sample_class_with_no_dependencies def initialize(foo, sample_class_with_no_dependencies) @foo = foo @sample_class_with_no_dependencies = sample_class_with_no_dependencies end end class SampleInjector include Dependor::AutoInject look_in_modules SomeModule def manual_dep "manual dep" end def create_foo(foo_name) inject(SomeFactory, foo: foo_name) end end let(:injector) { SampleInjector.new } shared_examples_for 'dependency injector' do it 'responds to the object name' do injector.should respond_to(object_name) end it 'creates the object' do injector.send(object_name).should be_an_instance_of(object_class) end end context 'no dependencies' do let(:object_name) { :sample_class_with_no_dependencies } let(:object_class) { SampleClassWithNoDependencies } it_behaves_like 'dependency injector' end context 'dependencies on other objects' do let(:object_name) { :sample_class_with_dependency } let(:object_class) { SampleClassWithDependency } it_behaves_like 'dependency injector' end context 'dependencies on objects returned by methods on the injector' do let(:object_name) { :sample_class_with_manual_dependency } let(:object_class) { SampleClassWithManualDependency } it_behaves_like 'dependency injector' end context 'dependencies from another module' do let(:object_name) { :sample_class_within_some_module } let(:object_class) { SomeModule::SampleClassWithinSomeModule } it_behaves_like 'dependency injector' end context 'autoinjecting with custom dependencies' do it "injects the dependencies which are not explicitly specified" do injector.create_foo("the foo name").sample_class_with_no_dependencies.should be_an_instance_of(SampleClassWithNoDependencies) end it "passes through the dependencies that were specified" do injector.create_foo("the foo name").foo.should == "the foo name" end end context 'injecting factory methods' do it "injects factory methods as procs" do object = injector.depends_on_factory_method object.create_foo.call("test").foo.should == "test" end end it "raises an error if the object is not found" do proc{ injector.unknown_object }.should raise_exception(Dependor::UnknownObject) end it 'responds to regular methods on injector' do injector.should respond_to(:manual_dep) end end dependor-1.0.1/pelusa.sh0000755000175000017500000000004112351463151014513 0ustar boutilboutil#!/bin/bash rvm rbx exec pelusa dependor-1.0.1/lib/0000755000175000017500000000000012351463151013436 5ustar boutilboutildependor-1.0.1/lib/dependor/0000755000175000017500000000000012351463151015236 5ustar boutilboutildependor-1.0.1/lib/dependor/version.rb0000644000175000017500000000005012351463151017243 0ustar boutilboutilmodule Dependor VERSION = "1.0.1" end dependor-1.0.1/lib/dependor/shorty.rb0000644000175000017500000000032412351463151017112 0ustar boutilboutilmodule Dependor module Shorty def takes(*names) attr_reader *names include Dependor::Constructor(*names) extend Dependor::Let end end end class Object extend Dependor::Shorty end dependor-1.0.1/lib/dependor/sending_injector.rb0000644000175000017500000000021612351463151021106 0ustar boutilboutilclass Dependor::SendingInjector def initialize(context) @context = context end def get(name) @context.__send__(name) end end dependor-1.0.1/lib/dependor/rspec.rb0000644000175000017500000000010312351463151016671 0ustar boutilboutilRSpec.configure do |config| config.include Dependor::Isolate end dependor-1.0.1/lib/dependor/let.rb0000644000175000017500000000015312351463151016346 0ustar boutilboutilmodule Dependor module Let def let(name, &block) define_method(name, &block) end end end dependor-1.0.1/lib/dependor/isolate.rb0000644000175000017500000000104312351463151017221 0ustar boutilboutilmodule Dependor module Isolate def isolate(klass = nil, overrides = {}, &block) if block_given? klass = block.call caller_binding = block.binding injector = EvaluatingInjector.new(caller_binding) else sending_injector = SendingInjector.new(self) injector = CustomizedInjector.new(sending_injector, overrides) end dependecy_names = DependencyNamesCache.new instantiator = Instantiator.new(injector, dependecy_names) instantiator.instantiate(klass) end end end dependor-1.0.1/lib/dependor/instantiator.rb0000644000175000017500000000056012351463151020303 0ustar boutilboutilmodule Dependor class Instantiator attr_reader :dependency_names def initialize(injector, dependency_names) @injector = injector @dependency_names = dependency_names end def instantiate(klass) dependencies = dependency_names.for_class(klass).map{|name| @injector.get(name)} return klass.new(*dependencies) end end end dependor-1.0.1/lib/dependor/injectable.rb0000644000175000017500000000045112351463151017663 0ustar boutilboutilmodule Dependor module Injectable def inject_from(klass) define_method :injector do @injector ||= klass.new end end def inject(*names) names.each do |name| define_method name do injector.send(name) end end end end end dependor-1.0.1/lib/dependor/exceptions.rb0000644000175000017500000000007612351463151017747 0ustar boutilboutilmodule Dependor class UnknownObject < RuntimeError; end end dependor-1.0.1/lib/dependor/evaluating_injector.rb0000644000175000017500000000022212351463151021613 0ustar boutilboutilclass Dependor::EvaluatingInjector def initialize(binding) @binding = binding end def get(name) @binding.eval(name.to_s) end end dependor-1.0.1/lib/dependor/dependency_names_cache.rb0000644000175000017500000000062512351463151022212 0ustar boutilboutilmodule Dependor class DependencyNamesCache def initialize @constructor_params = {} end def for_class(klass) @constructor_params[klass] ||= get_constructor_params(klass) end private def get_constructor_params(klass) params = klass.instance_method(:initialize).parameters params.select{|type, name| type == :req}.map{|type, name| name} end end end dependor-1.0.1/lib/dependor/customized_injector.rb0000644000175000017500000000041312351463151021644 0ustar boutilboutilclass Dependor::CustomizedInjector def initialize(injector, customizations) @injector = injector @customizations = customizations end def get(name) return @customizations[name] if @customizations.key?(name) return @injector.get(name) end end dependor-1.0.1/lib/dependor/constructor.rb0000644000175000017500000000034312351463151020150 0ustar boutilboutilmodule Dependor def self.Constructor(*names) eval <<-RUBY Module.new do def initialize(#{names.join(', ')}) #{names.map{ |name| "@#{name} = #{name}" }.join("\n") } end end RUBY end end dependor-1.0.1/lib/dependor/class_name_resolver.rb0000644000175000017500000000114612351463151021613 0ustar boutilboutilmodule Dependor class ClassNameResolver attr_reader :search_modules def initialize(search_modules) @search_modules = search_modules end def for_name(name) class_name = camelize(name) modules = search_modules + [Object] klass = nil modules.each do |mod| klass = mod.const_get(class_name) rescue nil break if klass end klass end private def camelize(symbol) string = symbol.to_s string = string.gsub(/_\w/) { |match| match[1].upcase } return string.gsub(/^\w/) { |match| match.upcase } end end end dependor-1.0.1/lib/dependor/auto_injector.rb0000644000175000017500000000176312351463151020437 0ustar boutilboutilmodule Dependor class AutoInjector def initialize(injector, dependency_names, search_modules) @injector = injector @instantiator = Instantiator.new(self, dependency_names) @class_name_resolver = ClassNameResolver.new(search_modules) end def get(name) return @injector.send(name) rescue ArgumentError return @injector.method(name).to_proc rescue NameError get_by_class_name(name) end def get_by_class_name(name) ensure_class_exists!(name) klass = @class_name_resolver.for_name(name) instantiator = @instantiator @injector.define_singleton_method(name) do instantiator.instantiate(klass) end @injector.send(name) end def class_exists?(name) !!@class_name_resolver.for_name(name) end private def ensure_class_exists!(name) unless class_exists?(name) raise UnknownObject.new("Injector does not know how to create object: #{name}") end end end end dependor-1.0.1/lib/dependor/auto_inject.rb0000644000175000017500000000173512351463151020075 0ustar boutilboutilmodule Dependor module AutoInject module ClassMethods def look_in_modules(*modules) search_modules.concat(modules) end def search_modules @search_modules ||= [] end end def self.included(klass) klass.extend ClassMethods end def method_missing(name, *args, &block) auto_injector.get_by_class_name(name) end def respond_to_missing?(name, include_private = false) auto_injector.class_exists?(name) end def inject(klass, overrides = {}) injector = Dependor::CustomizedInjector.new(auto_injector, overrides) instantiator = Dependor::Instantiator.new(injector, dependency_names) instantiator.instantiate(klass) end private def auto_injector @auto_injector ||= Dependor::AutoInjector.new(self, dependency_names, self.class.search_modules) end def dependency_names @dependency_names ||= Dependor::DependencyNamesCache.new end end end dependor-1.0.1/lib/dependor.rb0000644000175000017500000000154612351463151015571 0ustar boutilboutilrequire 'dependor/constructor' module Dependor autoload :AutoInject, 'dependor/auto_inject' autoload :AutoInjector, 'dependor/auto_injector' autoload :ClassNameResolver, 'dependor/class_name_resolver' autoload :CustomizedInjector, 'dependor/customized_injector' autoload :DependencyNamesCache, 'dependor/dependency_names_cache' autoload :EvaluatingInjector, 'dependor/evaluating_injector' autoload :Injectable, 'dependor/injectable' autoload :Instantiator, 'dependor/instantiator' autoload :Isolate, 'dependor/isolate' autoload :Let, 'dependor/let' autoload :SendingInjector, 'dependor/sending_injector' autoload :Shorty, 'dependor/shorty' autoload :UnknownObject, 'dependor/exceptions' autoload :VERSION, 'dependor/version' end dependor-1.0.1/dependor.gemspec0000644000175000017500000000230212351463151016032 0ustar boutilboutil# -*- encoding: utf-8 -*- $:.push File.expand_path("../lib", __FILE__) require "dependor/version" Gem::Specification.new do |s| s.name = "dependor" s.version = Dependor::VERSION s.platform = Gem::Platform::RUBY s.authors = ["Adam Pohorecki"] s.email = ["adam@pohorecki.pl"] s.homepage = "http://github.com/psyho/dependor" s.summary = %q{A couple of classes and modules that simplify dependency injection in Ruby.} s.description = %q{Dependor is not a framework for Dependency Injection, but something thatt reduces duplication a little bit when doing manual dependency injection in settings like Rails apps.} s.rubyforge_project = "dependor" s.add_development_dependency 'rspec' s.add_development_dependency 'guard' s.add_development_dependency 'guard-rspec' s.add_development_dependency 'growl' s.add_development_dependency 'libnotify' s.add_development_dependency 'rake' s.add_development_dependency 'coveralls' s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } s.require_paths = ["lib"] end dependor-1.0.1/Rakefile0000644000175000017500000000044412351463151014337 0ustar boutilboutilrequire 'bundler' Bundler::GemHelper.install_tasks require 'rspec/core' require 'rspec/core/rake_task' desc "Run all specs" RSpec::Core::RakeTask.new(:spec) do |t| t.pattern = "./spec/**/*_spec.rb" t.rspec_opts = ["--profile --color --format=documentation"] end task :default => :spec dependor-1.0.1/README.md0000644000175000017500000001420212351463151014146 0ustar boutilboutil# Dependor [![build status](https://secure.travis-ci.org/psyho/dependor.png)](http://travis-ci.org/psyho/dependor) [![Code Climate](https://codeclimate.com/github/psyho/dependor.png)](https://codeclimate.com/github/psyho/dependor) [![Coverage Status](https://coveralls.io/repos/psyho/dependor/badge.png)](https://coveralls.io/r/psyho/dependor) [![Gem Version](https://badge.fury.io/rb/dependor.png)](http://badge.fury.io/rb/dependor) [![Dependency Status](https://gemnasium.com/psyho/dependor.png)](https://gemnasium.com/psyho/dependor) ## 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 ```ruby 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 ```ruby 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. ```ruby 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. ```ruby class Foo takes :foo, :bar, :baz let(:hello) { "world" } end ``` is equivalent to: ```ruby 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. ```ruby class Foo include Dependor::Constructor(:foo, :bar, :baz) end ``` is equivalent to: ```ruby 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. ```ruby class Foo def foo do_something_or_other end end ``` becomes: ```ruby 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. ```ruby 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: ```ruby 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 ``` ## Testing Dependor doesn't add any dependencies to your classes so you can test them any way you like. Following class: ```ruby class PostCreator takes :post_repository def publish(post) post_repository.store(post) end end ``` can be tested: ```ruby let(:post_repository) { stub } let(:creator) { PostCreator.new(post_repository } it "stores posts" do post = Post.new post_repository.expects(:store).with(post) creator.publish(post) end ``` ## Dependor::Isolate Dependor::Isolate provides `isolate` function that creates an instance of given class with dependencies taken from a local context. It can be easily integrated with rspec by requiring 'dependor/rspec'. Previous example can be rewritten as: ```ruby require 'dependor/rspec' let(:post_repository) { stub } let(:creator) { isolate(PostCreator) } it "stores posts" do post = Post.new post_repository.expects(store).with(post) creator.publish(post) end ``` Dependencies are taken from methods available in local context, but they can be specified in paramaters as well: ```ruby post_repository = stub creator = isolate(PostCreator, post_repository: post_repository) ``` Or they can be captured from local variables when syntax with block is used: ```ruby post_repository = stub creator = isolate{PostCreator} ``` ## 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][das] ["Shorter Class Syntax"][shorter-syntax]. [das]: http://www.destroyallsoftware.com [shorter-syntax]: https://www.destroyallsoftware.com/screencasts/catalog/shorter-class-syntax dependor-1.0.1/MIT-LICENSE0000644000175000017500000000204212351463151014322 0ustar boutilboutilCopyright (C) 2012 Adam Pohorecki Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. dependor-1.0.1/Guardfile0000644000175000017500000000031212351463151014511 0ustar boutilboutilguard 'rspec' do watch(%r{^spec/.+_spec\.rb$}) watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" } watch('spec/spec_helper.rb') { "spec" } watch(%r{^spec/support/(.+)\.rb$}) { "spec" } end dependor-1.0.1/Gemfile.lock0000644000175000017500000000277212351463151015122 0ustar boutilboutilPATH remote: . specs: dependor (1.0.1) GEM remote: http://rubygems.org/ specs: coderay (1.0.9) colorize (0.5.8) coveralls (0.6.7) colorize multi_json (~> 1.3) rest-client simplecov (>= 0.7) thor diff-lcs (1.2.4) ffi (1.9.0) formatador (0.2.4) growl (1.0.3) guard (1.8.2) formatador (>= 0.2.4) listen (>= 1.0.0) lumberjack (>= 1.0.2) pry (>= 0.9.10) thor (>= 0.14.6) guard-rspec (3.0.2) guard (>= 1.8) rspec (~> 2.13) libnotify (0.8.1) ffi (>= 1.0.11) listen (1.3.0) rb-fsevent (>= 0.9.3) rb-inotify (>= 0.9) rb-kqueue (>= 0.2) lumberjack (1.0.4) method_source (0.8.2) mime-types (1.24) multi_json (1.7.9) pry (0.9.12.2) coderay (~> 1.0.5) method_source (~> 0.8) slop (~> 3.4) rake (10.1.0) rb-fsevent (0.9.3) rb-inotify (0.9.1) ffi (>= 0.5.0) rb-kqueue (0.2.0) ffi (>= 0.5.0) rest-client (1.6.7) mime-types (>= 1.16) rspec (2.14.1) rspec-core (~> 2.14.0) rspec-expectations (~> 2.14.0) rspec-mocks (~> 2.14.0) rspec-core (2.14.5) rspec-expectations (2.14.2) diff-lcs (>= 1.1.3, < 2.0) rspec-mocks (2.14.3) simplecov (0.7.1) multi_json (~> 1.0) simplecov-html (~> 0.7.1) simplecov-html (0.7.1) slop (3.4.6) thor (0.18.1) PLATFORMS ruby DEPENDENCIES coveralls dependor! growl guard guard-rspec libnotify rake rspec dependor-1.0.1/Gemfile0000644000175000017500000000013412351463151014161 0ustar boutilboutilsource "http://rubygems.org" # Specify your gem's dependencies in dependor.gemspec gemspec dependor-1.0.1/.travis.yml0000644000175000017500000000014712351463151015003 0ustar boutilboutillanguage: ruby rvm: - 1.9.2 - 1.9.3 - jruby-19mode - rbx-19mode script: bundle exec rspec spec dependor-1.0.1/.pelusa.yml0000644000175000017500000000002512351463151014757 0ustar boutilboutilsources: lib/**/*.rb dependor-1.0.1/.gitignore0000644000175000017500000000007412351463151014661 0ustar boutilboutilpkg/* *.gem coverage/ .bundle .rvmrc .ruby-version tags tmp