Skip to content
This repository has been archived by the owner on Apr 1, 2019. It is now read-only.

Commit

Permalink
Merge branch 'release/v0.4.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Kevin committed Feb 23, 2014
2 parents 381b010 + bc285d8 commit 0d594d9
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 23 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 0.4.0 (2014-02-23)

* Fix an error when a service use another service
* Add ERB support in YAML loader
* Add file_path option

# 0.3.1 (2013-09-17)

* Nothing adding/removed. Just fix the Gemfile.lock
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ And here's some more details about each keyword:

* `calls`: An array containing an array of each instance method and its parameters. Note that you only need to define the methods during your class instantiation.

* `file_path`: A string containing the file path to require to load the class.

* `lazy`: Returns a Proxy Object if true. The _real_ object will only be instantiated at the first method call.

* `alias`: A string containing the target service name.
Expand Down
6 changes: 5 additions & 1 deletion lib/dependency_injection/container.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ def add_parameter(name, value)
@parameters[name] = value
end

def find(name)
@definitions[name]
end

def get(name)
if (definition = @definitions[name])
if (definition = self.find(name))
definition.object
end
end
Expand Down
25 changes: 22 additions & 3 deletions lib/dependency_injection/definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@

module DependencyInjection
class Definition
attr_accessor :arguments, :configurator, :klass_name, :method_calls, :scope
attr_accessor :arguments, :configurator, :file_path, :klass_name, :method_calls, :scope

def initialize(klass_name, container)
@container = container
self.arguments = []
self.file_path = nil
self.klass_name = klass_name
self.method_calls = {}
self.scope = :container
Expand Down Expand Up @@ -50,6 +51,7 @@ def container_scoped_object
end

def initialize_object
require_object
object = self.klass.new(*resolve(self.arguments))
self.method_calls.each { |method_name, arguments| object.send(method_name, *resolve(arguments)) }
if self.configurator
Expand All @@ -61,10 +63,26 @@ def initialize_object
object
end

def object_already_required?
true if Kernel.const_get(self.klass_name)
rescue
false
end

def prototype_scoped_object
initialize_object
end

def require_object
return if object_already_required?

if self.file_path
require self.file_path
else
require self.klass_name.underscore
end
end

def resolve(arguments)
resolve_references(resolve_container_parameters(arguments))
end
Expand All @@ -82,8 +100,9 @@ def resolve_container_parameters(arguments)
def resolve_references(arguments)
arguments.map do |argument|
if /^@(?<reference_name>.*)/ =~ argument
reference = @container.get(reference_name)
raise ScopeWideningInjectionError if reference.scope == :prototype && scope == :container
reference_definition = @container.find(reference_name)
reference = reference_definition.object
raise ScopeWideningInjectionError if reference_definition.scope == :prototype && scope == :container

reference
else
Expand Down
10 changes: 8 additions & 2 deletions lib/dependency_injection/loaders/yaml.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require 'erb'
require 'yaml'

module DependencyInjection
Expand All @@ -8,7 +9,7 @@ def initialize(container)
end

def load(filename)
file = YAML::load_file(filename)
file = load_file(filename)
add_parameters(file['parameters']) if file['parameters']
add_services(file['services']) if file['services']
end
Expand Down Expand Up @@ -38,7 +39,8 @@ def add_service(name, parameters)
def add_standard_service(name, parameters)
lazy_load = parameters['lazy'] || false
definition = @container.register(name, parameters['class'], lazy_load)
definition.scope = parameters['scope'] if parameters['scope']
definition.scope = parameters['scope'] if parameters['scope']
definition.file_path = parameters['file_path'] if parameters['file_path']
definition.add_arguments(*parameters['arguments']) if parameters['arguments']
if (configurator = parameters['configurator'])
definition.add_configurator(configurator[0], configurator[1])
Expand All @@ -47,6 +49,10 @@ def add_standard_service(name, parameters)
parameters['calls'].each { |method_name, arguments| definition.add_method_call(method_name, *arguments) }
end
end

def load_file(filename)
YAML::load(ERB.new(IO.read(filename)).result)
end
end
end
end
2 changes: 1 addition & 1 deletion lib/dependency_injection/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module DependencyInjection
VERSION = '0.3.1'
VERSION = '0.4.0'
end
16 changes: 12 additions & 4 deletions test/dependency_injection/loaders/test_yaml.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,28 @@ def setup
end

def test_loading_file_without_parameters
YAML.stubs(:load_file).with('services.yml').returns({ 'services' => [] })
@yaml_loader.stubs(:load_file).with('services.yml').returns({ 'services' => [] })
@yaml_loader.expects(:add_parameters).never

@yaml_loader.load('services.yml')
end

def test_loading_file_with_parameters
YAML.stubs(:load_file).with('services.yml').returns({'parameters' => { 'key_1' => 'value_1' }, 'services' => [] })
@yaml_loader.stubs(:load_file).with('services.yml').returns({'parameters' => { 'key_1' => 'value_1' }, 'services' => [] })
@yaml_loader.expects(:add_parameters).with({ 'key_1' => 'value_1' })

@yaml_loader.load('services.yml')
end

def test_loading_file_without_services
YAML.stubs(:load_file).with('services.yml').returns({ 'parameters' => [] })
@yaml_loader.stubs(:load_file).with('services.yml').returns({ 'parameters' => [] })
@yaml_loader.expects(:add_services).never

@yaml_loader.load('services.yml')
end

def test_loading_file_with_services
YAML.stubs(:load_file).with('services.yml').returns({ 'parameters' => {}, 'services' => { 'service_1' => { 'class' => 'MyKlass' }}})
@yaml_loader.stubs(:load_file).with('services.yml').returns({ 'parameters' => {}, 'services' => { 'service_1' => { 'class' => 'MyKlass' }}})
@yaml_loader.expects(:add_services).with({ 'service_1' => { 'class' => 'MyKlass' }})

@yaml_loader.load('services.yml')
Expand Down Expand Up @@ -152,4 +152,12 @@ def test_adding_standard_service_with_configurator

@yaml_loader.send(:add_standard_service, 'key_1', { 'class' => 'MyKlass', 'configurator' => ['ConfiguratorKlass', 'method_name'] })
end

def test_adding_standard_service_with_file_path
definition = mock
@container.stubs(:register).with('key_1', 'MyKlass', false).returns(definition)
definition.expects(:file_path=).with('path/to/file')

@yaml_loader.send(:add_standard_service, 'key_1', { 'class' => 'MyKlass', 'file_path' => 'path/to/file' })
end
end
9 changes: 9 additions & 0 deletions test/dependency_injection/test_container.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ def test_adding_an_already_existing_parameter
assert_equal({ 'my.parameter' => 'other value' }, @container.parameters)
end

def test_find_a_registered_definition_returns_a_definition
@container.register('my_definition', 'MyDefinition')
assert_equal(@definition, @container.find('my_definition'))
end

def test_find_a_not_registered_definition_returns_nil
assert_equal(nil, @container.find('my_definition'))
end

def test_getting_a_registered_definition_returns_an_object
@container.register('my_definition', 'MyDefinition')
assert_equal(@final_object, @container.get('my_definition'))
Expand Down
49 changes: 37 additions & 12 deletions test/dependency_injection/test_definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def test_getting_klass
end

def test_getting_object_with_arguments
@definition.stubs(:require_object).returns(mock)
final_object = mock
final_class = mock
@definition.stubs(:klass).returns(final_class)
Expand All @@ -81,6 +82,7 @@ def test_getting_object_with_arguments
end

def test_getting_object_without_arguments
@definition.stubs(:require_object).returns(mock)
final_object = mock
final_class = mock
@definition.stubs(:klass).returns(final_class)
Expand All @@ -90,6 +92,7 @@ def test_getting_object_without_arguments
end

def test_getting_object_with_method_calls
@definition.stubs(:require_object).returns(mock)
final_object = mock
final_class = mock
@definition.stubs(:klass).returns(final_class)
Expand All @@ -104,6 +107,7 @@ def test_getting_object_with_method_calls
end

def test_getting_object_without_configurator
@definition.stubs(:require_object).returns(mock)
configurator_object = mock
final_object = mock
final_class = mock
Expand All @@ -117,6 +121,7 @@ def test_getting_object_without_configurator
end

def test_getting_object_with_configurator
@definition.stubs(:require_object).returns(mock)
configurator_object = mock
final_object = mock
final_class = mock
Expand Down Expand Up @@ -189,38 +194,58 @@ def test_resolving_references_without_references
end

def test_resolving_references_with_defintion_and_referenced_object_in_container_scope
referenced_object = mock
referenced_object.stubs(:scope).returns(:container)
referenced_definition = mock
referenced_object = mock
referenced_definition.stubs(:object).returns(referenced_object)
referenced_definition.stubs(:scope).returns(:container)
@definition.scope= :container
@container.stubs(:get).with('reference.name').returns(referenced_object)
@container.stubs(:find).with('reference.name').returns(referenced_definition)

assert_equal(['first', referenced_object], @definition.send(:resolve_references, %w(first @reference.name)))
end

def test_resolving_references_with_defintion_and_referenced_object_in_prototype_scope
referenced_object = mock
referenced_object.stubs(:scope).returns(:prototype)
referenced_definition = mock
referenced_object = mock
referenced_definition.stubs(:object).returns(referenced_object)
referenced_definition.stubs(:scope).returns(:prototype)
@definition.scope= :prototype
@container.stubs(:get).with('reference.name').returns(referenced_object)
@container.stubs(:find).with('reference.name').returns(referenced_definition)

assert_equal(['first', referenced_object], @definition.send(:resolve_references, %w(first @reference.name)))
end

def test_resolving_references_with_defintion_in_prototype_scope_and_referenced_object_in_container_scope
referenced_object = mock
referenced_object.stubs(:scope).returns(:container)
referenced_definition = mock
referenced_object = mock
referenced_definition.stubs(:object).returns(referenced_object)
referenced_definition.stubs(:scope).returns(:container)
@definition.scope= :prototype
@container.stubs(:get).with('reference.name').returns(referenced_object)
@container.stubs(:find).with('reference.name').returns(referenced_definition)

assert_equal(['first', referenced_object], @definition.send(:resolve_references, %w(first @reference.name)))
end

def test_resolving_references_with_defintion_in_container_scope_and_referenced_object_in_prototype_scope
referenced_object = mock
referenced_object.stubs(:scope).returns(:prototype)
referenced_definition = mock
referenced_object = mock
referenced_definition.stubs(:object).returns(referenced_object)
referenced_definition.stubs(:scope).returns(:prototype)
@definition.scope= :container
@container.stubs(:get).with('reference.name').returns(referenced_object)
@container.stubs(:find).with('reference.name').returns(referenced_definition)

assert_raises(ScopeWideningInjectionError) { @definition.send(:resolve_references, %w(first @reference.name)) }
end

def test_require_object_with_file_path
@definition.expects(:require).with('/file/to/path').once
@definition.file_path = '/file/to/path'
@definition.send(:require_object)
end

def test_require_object_automatically
@definition.expects(:require).with('my_module/my_class').once
@definition.klass_name = 'MyModule::MyClass'
@definition.send(:require_object)
end
end

0 comments on commit 0d594d9

Please sign in to comment.