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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/Gemfile.lock +1 -1
- data/README.md +18 -15
- data/lib/callme.rb +15 -0
- data/lib/callme/const_loaders/active_support.rb +1 -0
- data/lib/callme/const_loaders/native.rb +1 -0
- data/lib/callme/container.rb +45 -54
- data/lib/callme/contract_validator.rb +39 -0
- data/lib/callme/dep_factory.rb +119 -0
- data/lib/callme/{bean_metadata.rb → dep_metadata.rb} +18 -13
- data/lib/callme/deps_metadata_storage.rb +32 -0
- data/lib/callme/errors.rb +17 -3
- data/lib/callme/inject.rb +22 -21
- data/lib/callme/scopes/prototype_scope.rb +14 -14
- data/lib/callme/scopes/request_scope.rb +19 -18
- data/lib/callme/scopes/singleton_scope.rb +19 -18
- data/lib/callme/version.rb +1 -1
- data/spec/callme/container_spec.rb +45 -41
- data/spec/callme/contract_spec.rb +72 -0
- data/spec/callme/inject_spec.rb +7 -4
- metadata +9 -5
- data/lib/callme/bean_factory.rb +0 -115
- data/lib/callme/beans_metadata_storage.rb +0 -32
@@ -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
|
data/spec/callme/inject_spec.rb
CHANGED
@@ -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.
|
21
|
-
c.
|
22
|
-
c.
|
23
|
-
c.
|
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.
|
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-
|
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
|
data/lib/callme/bean_factory.rb
DELETED
@@ -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
|