callme 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,72 @@
1
+ require "spec_helper"
2
+
3
+ describe "contract validation" do
4
+ class ContactBook
5
+ include Callme::Inject
6
+ inject :contacts_repository
7
+ inject :validator, ref: :contact_validator
8
+ end
9
+ class ContactBookService
10
+ include Callme::Inject
11
+ inject :contacts_repository
12
+ inject :validator, ref: :contact_validator
13
+ end
14
+
15
+ class DummyService
16
+ def execute
17
+ put "JUST DO IT!"
18
+ end
19
+ end
20
+ class ContactsRepository
21
+ end
22
+ class ContactValidator
23
+ def validate(item)
24
+ end
25
+ end
26
+
27
+ class ContractRepoContract
28
+ def get(id); end
29
+ end
30
+ class ValidatorContract
31
+ def validate(item, opts); end
32
+ end
33
+
34
+ class ServiceContract
35
+ def execute; end
36
+ end
37
+
38
+ let(:container){
39
+ Callme::Container.new do |c|
40
+ c.dep(:contacts_repository, class: ContactsRepository, contract: ContractRepoContract)
41
+ c.dep(:contact_validator, class: ContactValidator, contract: ValidatorContract)
42
+ c.dep(:contact_book, class: ContactBook)
43
+ c.dep(:contact_book_service, class: "ContactBookService")
44
+ c.dep(:dummy_service, class: "DummyService", contract: ServiceContract)
45
+ c.dep(:dummy_service2, class: "DummyService", contract: "ServiceContract")
46
+ end
47
+ }
48
+
49
+ it "works when contract matches" do
50
+ container[:dummy_service]
51
+ end
52
+
53
+ it "works when contract is declared as string and matches" do
54
+ container[:dummy_service2]
55
+ end
56
+
57
+ it "raises when trying to access a dependency with unfullfilled contract: method not present" do
58
+ error_message = {:dep=>ContactsRepository, :contract=>ContractRepoContract, :missing=>[:get]}.inspect
59
+ error_class = Callme::Errors::DependencyContractMissingMethodsException
60
+ e = expect{
61
+ container[:contacts_repository]
62
+ }.to raise_error(error_class, error_message)
63
+ end
64
+
65
+ it "raises when trying to access a dependency with unfullfilled contract: params wrong not present" do
66
+ error_message = "The method signature of method: 'validate' does not match the contract parameters: 'req, item, req, opts'"
67
+ error_class = Callme::Errors::DependencyContractInvalidParametersException
68
+ e = expect{
69
+ container[:contact_validator]
70
+ }.to raise_error(error_class, error_message)
71
+ end
72
+ end
@@ -3,10 +3,12 @@ require 'spec_helper'
3
3
  # Ensures that :inject keyword works as it should
4
4
  describe "Object.inject" do
5
5
  class ContactBook
6
+ include Callme::Inject
6
7
  inject :contacts_repository
7
8
  inject :validator, ref: :contact_validator
8
9
  end
9
10
  class ContactBookService
11
+ include Callme::Inject
10
12
  inject :contacts_repository
11
13
  inject :validator, ref: :contact_validator
12
14
  end
@@ -17,10 +19,10 @@ describe "Object.inject" do
17
19
 
18
20
  let(:container) do
19
21
  Callme::Container.new do |c|
20
- c.bean(:contacts_repository, class: ContactsRepository)
21
- c.bean(:contact_validator, class: ContactValidator)
22
- c.bean(:contact_book, class: ContactBook)
23
- c.bean(:contact_book_service, class: "ContactBookService")
22
+ c.dep(:contacts_repository, class: ContactsRepository)
23
+ c.dep(:contact_validator, class: ContactValidator)
24
+ c.dep(:contact_book, class: ContactBook)
25
+ c.dep(:contact_book_service, class: "ContactBookService")
24
26
  end
25
27
  end
26
28
 
@@ -37,6 +39,7 @@ describe "Object.inject" do
37
39
  it "should raise ArgumentError if non-symbol passed as dependency name" do
38
40
  expect do
39
41
  class SomeClass
42
+ include Callme::Inject
40
43
  inject 'bar'
41
44
  end
42
45
  end.to raise_error(ArgumentError, "dependency name should be a symbol")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: callme
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Roman Heinrich
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-06-25 00:00:00.000000000 Z
12
+ date: 2017-06-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: request_store
@@ -64,6 +64,7 @@ files:
64
64
  - ".gitignore"
65
65
  - ".travis.yml"
66
66
  - ".yardops"
67
+ - CHANGELOG.md
67
68
  - Gemfile
68
69
  - Gemfile.lock
69
70
  - LICENSE.txt
@@ -73,12 +74,13 @@ files:
73
74
  - callme.gemspec
74
75
  - lib/callme.rb
75
76
  - lib/callme/args_validator.rb
76
- - lib/callme/bean_factory.rb
77
- - lib/callme/bean_metadata.rb
78
- - lib/callme/beans_metadata_storage.rb
79
77
  - lib/callme/const_loaders/active_support.rb
80
78
  - lib/callme/const_loaders/native.rb
81
79
  - lib/callme/container.rb
80
+ - lib/callme/contract_validator.rb
81
+ - lib/callme/dep_factory.rb
82
+ - lib/callme/dep_metadata.rb
83
+ - lib/callme/deps_metadata_storage.rb
82
84
  - lib/callme/errors.rb
83
85
  - lib/callme/inject.rb
84
86
  - lib/callme/scopes.rb
@@ -88,6 +90,7 @@ files:
88
90
  - lib/callme/version.rb
89
91
  - lib/ext/vendored_activesupport.rb
90
92
  - spec/callme/container_spec.rb
93
+ - spec/callme/contract_spec.rb
91
94
  - spec/callme/inject_spec.rb
92
95
  - spec/spec_helper.rb
93
96
  homepage: http://github.com/mindreframer/callme
@@ -116,5 +119,6 @@ specification_version: 4
116
119
  summary: 'Callme: Simple depencency injection lib'
117
120
  test_files:
118
121
  - spec/callme/container_spec.rb
122
+ - spec/callme/contract_spec.rb
119
123
  - spec/callme/inject_spec.rb
120
124
  - spec/spec_helper.rb
@@ -1,115 +0,0 @@
1
- require 'callme/scopes'
2
- require 'callme/scopes/singleton_scope'
3
- require 'callme/scopes/prototype_scope'
4
- require 'callme/scopes/request_scope'
5
-
6
- # Instantiates beans according to their scopes
7
- class Callme::BeanFactory
8
- attr_reader :const_loader
9
-
10
- # Constructor
11
- # @param beans_metadata_storage [BeansMetadataStorage] storage of bean metadatas
12
- def initialize(const_loader, beans_metadata_storage)
13
- @const_loader = const_loader
14
- @beans_metadata_storage = beans_metadata_storage
15
- @singleton_scope = Callme::Scopes::SingletonScope.new(self)
16
- @prototype_scope = Callme::Scopes::PrototypeScope.new(self)
17
- @request_scope = Callme::Scopes::RequestScope.new(self)
18
- end
19
-
20
- # Get bean from the container by it's +name+.
21
- # According to the bean scope it will be newly created or returned already
22
- # instantiated bean
23
- # @param [Symbol] bean name
24
- # @return bean instance
25
- # @raise MissingBeanError if bean with the specified name is not found
26
- def get_bean(name)
27
- bean_metadata = @beans_metadata_storage.by_name(name)
28
- unless bean_metadata
29
- raise Callme::Errors::MissingBeanError, "Bean with name :#{name} is not defined"
30
- end
31
- get_bean_with_metadata(bean_metadata)
32
- end
33
-
34
- # Get bean by the specified +bean metadata+
35
- # @param [BeanMetadata] bean metadata
36
- # @return bean instance
37
- def get_bean_with_metadata(bean_metadata)
38
- get_scope_by_metadata(bean_metadata).get_bean(bean_metadata)
39
- end
40
-
41
- # Create new bean instance according
42
- # to the specified +bean_metadata+
43
- # @param [BeanMetadata] bean metadata
44
- # @return bean instance
45
- # @raise MissingBeanError if some of bean dependencies are not found
46
- def create_bean_and_save(bean_metadata, beans_storage)
47
- if bean_metadata.bean_class.is_a?(Class)
48
- bean_class = bean_metadata.bean_class
49
- else
50
- bean_class = const_loader.load_const(bean_metadata.bean_class)
51
- bean_metadata.fetch_attrs!(bean_class)
52
- end
53
- bean = bean_metadata.instance ? bean_class.new : bean_class
54
- if bean_metadata.has_factory_method?
55
- set_bean_dependencies(bean, bean_metadata)
56
- bean = bean.send(bean_metadata.factory_method)
57
- beans_storage[bean_metadata.name] = bean
58
- else
59
- # put to container first to prevent circular dependencies
60
- beans_storage[bean_metadata.name] = bean
61
- set_bean_dependencies(bean, bean_metadata)
62
- end
63
-
64
- bean
65
- end
66
-
67
- # Delete bean from the container by it's +name+.
68
- # @param [Symbol] bean name
69
- # @raise MissingBeanError if bean with the specified name is not found
70
- def delete_bean(name)
71
- bean_metadata = @beans_metadata_storage.by_name(name)
72
- unless bean_metadata
73
- raise Callme::Errors::MissingBeanError, "Bean with name :#{name} is not defined"
74
- end
75
- get_scope_by_metadata(bean_metadata).delete_bean(bean_metadata)
76
- end
77
-
78
- private
79
-
80
- def set_bean_dependencies(bean, bean_metadata)
81
- bean_metadata.attrs.each do |attr|
82
- bean_metadata = @beans_metadata_storage.by_name(attr.ref)
83
- unless bean_metadata
84
- raise Callme::Errors::MissingBeanError, "Bean with name :#{attr.ref} is not defined, check #{bean.class}"
85
- end
86
- case bean_metadata.scope
87
- when :singleton
88
- bean.send("#{attr.name}=", get_bean(attr.ref))
89
- when :prototype
90
- bean.instance_variable_set(:@_callme_bean_factory, self)
91
- bean.define_singleton_method(attr.name) do
92
- @_callme_bean_factory.get_bean(attr.ref)
93
- end
94
- when :request
95
- bean.instance_variable_set(:@_callme_bean_factory, self)
96
- bean.define_singleton_method(attr.name) do
97
- @_callme_bean_factory.get_bean(attr.ref)
98
- end
99
- end
100
- end
101
- end
102
-
103
- def get_scope_by_metadata(bean_metadata)
104
- case bean_metadata.scope
105
- when :singleton
106
- @singleton_scope
107
- when :prototype
108
- @prototype_scope
109
- when :request
110
- @request_scope
111
- else
112
- raise Callme::Errors::UnsupportedScopeError, "Bean with name :#{bean_metadata.name} has unsupported scope :#{bean_metadata.scope}"
113
- end
114
- end
115
- end
@@ -1,32 +0,0 @@
1
- # Storage of bean metadatas
2
- class Callme::BeansMetadataStorage
3
- def initialize(bean_metadatas = {})
4
- @bean_metadatas = bean_metadatas
5
- end
6
-
7
- # Finds bean metadata in storage by it's name
8
- # @param name [Symbol] bean metadata name
9
- # @return bean metadata
10
- def by_name(name)
11
- @bean_metadatas[name]
12
- end
13
-
14
- # Saves a given +bean_metadata+ to the storage
15
- # @param bean_metadata [BeanMetadata] bean metadata for saving
16
- def put(bean_metadata)
17
- @bean_metadatas[bean_metadata.name] = bean_metadata
18
- end
19
-
20
- def bean_classes
21
- @bean_metadatas.values.map(&:bean_class)
22
- end
23
-
24
- def keys
25
- @bean_metadatas.keys
26
- end
27
-
28
- # Creates an independent copy of this instance
29
- def copy
30
- self.class.new(@bean_metadatas.dup)
31
- end
32
- end