carb-container 0.1.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 +7 -0
- data/.gitignore +41 -0
- data/.rspec +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/README.md +152 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/carb-container.gemspec +30 -0
- data/lib/carb-container.rb +1 -0
- data/lib/carb/container.rb +15 -0
- data/lib/carb/container/already_registered_error.rb +14 -0
- data/lib/carb/container/base.rb +14 -0
- data/lib/carb/container/class_name_to_method_name.rb +29 -0
- data/lib/carb/container/container_validator.rb +21 -0
- data/lib/carb/container/delegate_container.rb +75 -0
- data/lib/carb/container/dependency_missing_error.rb +15 -0
- data/lib/carb/container/error_container.rb +26 -0
- data/lib/carb/container/registerer.rb +34 -0
- data/lib/carb/container/registration_glue.rb +36 -0
- data/lib/carb/container/registry_container.rb +98 -0
- data/lib/carb/container/version.rb +5 -0
- metadata +149 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 95c46b2436f16825eb22774536485297b23ad8ba
|
4
|
+
data.tar.gz: 60f675251e578ea250cae6f2f47e16e8194714d0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: aa4c49159f53467cff172a8dd54214c702ebaa4b7987f9d015c611c3483f09dc60775debe3406ce22099b54fb4edcef58d0c86c3ba5ed8d7b3a9224bedeb1418
|
7
|
+
data.tar.gz: c32e3f6ef95c1ca332e58a802aeb67415f1631a31b5800c98f73b922117e94dc8bfa1f6a0f12a917d35672df056e9907c2c67acbe59641bd940d293600b82a46
|
data/.gitignore
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
/.bundle/
|
2
|
+
/.yardoc
|
3
|
+
/Gemfile.lock
|
4
|
+
/_yardoc/
|
5
|
+
/coverage/
|
6
|
+
/doc/
|
7
|
+
/pkg/
|
8
|
+
/spec/reports/
|
9
|
+
/tmp/
|
10
|
+
|
11
|
+
.project
|
12
|
+
.directory
|
13
|
+
*.swp
|
14
|
+
*~
|
15
|
+
.DS_Store
|
16
|
+
.idea
|
17
|
+
.envrc
|
18
|
+
.nvmrc
|
19
|
+
.ruby-gemset
|
20
|
+
.ruby-version
|
21
|
+
.rspec-local
|
22
|
+
public
|
23
|
+
*.backup
|
24
|
+
npm-debug.log
|
25
|
+
.rspec_status
|
26
|
+
|
27
|
+
# Ignore bundler config
|
28
|
+
/.bundle
|
29
|
+
/vendor/bundle
|
30
|
+
|
31
|
+
# Ignore all logfiles and tempfiles.
|
32
|
+
/log/*.log
|
33
|
+
/tmp
|
34
|
+
/binstubs/
|
35
|
+
|
36
|
+
# Ignore user import data
|
37
|
+
/data
|
38
|
+
|
39
|
+
# YARD
|
40
|
+
.yardoc
|
41
|
+
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
# Carb::Container
|
2
|
+
|
3
|
+
A set of simple container objects to store dependencies. Can be used in
|
4
|
+
conjuction with [carb-inject](https://github.com/Carburetor/carb-inject) as
|
5
|
+
an IoC container.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'carb-container'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install carb-container
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
There are 3 containers available, one interface to create custom containers and
|
26
|
+
a utility class that helps you register classes inside the container.
|
27
|
+
|
28
|
+
### Carb::Container::Base
|
29
|
+
|
30
|
+
This is a simple module that is an interface. Has two methods which must both
|
31
|
+
be provided by the developer:
|
32
|
+
|
33
|
+
- `[](name)` which is the method used to get dependencies. If you need to raise
|
34
|
+
an error because dependency is missing, you can use
|
35
|
+
`Carb::Container::DependencyMissingError` which accepts the dependency name
|
36
|
+
in the constructor (to improve the error message)
|
37
|
+
- `has_key?(name)` which is the method used to check if the key exists on a
|
38
|
+
given container
|
39
|
+
|
40
|
+
### Carb::Container::RegistryContainer
|
41
|
+
|
42
|
+
This is the main container and probably the only one you will be using. It
|
43
|
+
respects the `Carb::Container::Base` interface.
|
44
|
+
It stores dependencies (with some utilities) in a hashmap and can be fetched
|
45
|
+
back with `#[]` which raises `Carb::Container::DependencyMissingError` in
|
46
|
+
case no dependency is found. To register a dependency you simply call
|
47
|
+
`#register(name, dependency_enclosed_in_proc)` and it will be stored inside.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
class MyClass
|
51
|
+
def hello
|
52
|
+
puts "hi"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
container = Carb::Container::RegistryContainer.new
|
57
|
+
container.register(:my_class, -> { MyClass })
|
58
|
+
|
59
|
+
container[:my_class].new.hello
|
60
|
+
```
|
61
|
+
|
62
|
+
### Carb::Container::RegistrationGlue
|
63
|
+
|
64
|
+
A utility class that allows you to create a class method inside `Class` so that
|
65
|
+
you can easily register any newly created class. This is entirely optional, for
|
66
|
+
people who don't like monkey patching, can be skipped.
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
MyContainer = Carb::Container::RegistryContainer.new
|
70
|
+
Carb::Container::RegistrationGlue.call(MyContainer)
|
71
|
+
|
72
|
+
module My
|
73
|
+
class Person
|
74
|
+
carb_container
|
75
|
+
|
76
|
+
def greet
|
77
|
+
puts "hi"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class Dog
|
83
|
+
carb_container as: :special_dog
|
84
|
+
|
85
|
+
def bark
|
86
|
+
puts "woff"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
person = MyContainer[:my_person].new
|
91
|
+
dog = MyContainer[:special_dog].new
|
92
|
+
|
93
|
+
person.greet
|
94
|
+
person.bark
|
95
|
+
```
|
96
|
+
|
97
|
+
### Carb::Container::DelegateContainer
|
98
|
+
|
99
|
+
Special container which allows chaining containers together so that a
|
100
|
+
dependency not found in the first one, is searched in the subsequent ones. If
|
101
|
+
no dependency is found, `Carb::Container::DependencyMissingError` is raised.
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
Container1 = Carb::Container::RegistryContainer.new
|
105
|
+
Container2 = Carb::Container::RegistryContainer.new
|
106
|
+
Delegate = Carb::Container::DelegateContainer.new([Container1, Container2])
|
107
|
+
|
108
|
+
class Person
|
109
|
+
def greet
|
110
|
+
puts "hello"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class Dog
|
115
|
+
def bark
|
116
|
+
puts "woff"
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
Container1.register(:person, -> { Person })
|
121
|
+
Container2.register(:dog, -> { Dog })
|
122
|
+
|
123
|
+
Delegate[:dog] == Dog # => true
|
124
|
+
Delegate[:person] == Person # => true
|
125
|
+
|
126
|
+
Delegate[:foo] # raises DependencyMissingError
|
127
|
+
```
|
128
|
+
|
129
|
+
### Carb::Container::ErrorContainer
|
130
|
+
|
131
|
+
Special container which doesn't allow to register any dependency, always
|
132
|
+
raises `Carb::Container::DependencyMissingError` and always returns `false`
|
133
|
+
for `has_key?` method. It's only useful within the DelegateContainer or as a
|
134
|
+
null object (as in null object pattern).
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
container = Carb::Container::ErrorContainer.new
|
138
|
+
|
139
|
+
container[:foo] # raises DependencyMissingError
|
140
|
+
container.has_key?(:bar) # => false
|
141
|
+
```
|
142
|
+
|
143
|
+
## Development
|
144
|
+
|
145
|
+
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.
|
146
|
+
|
147
|
+
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 tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
148
|
+
|
149
|
+
## Contributing
|
150
|
+
|
151
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/Carburetor/carb-container.
|
152
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "carb/container"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "carb/container/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "carb-container"
|
8
|
+
spec.version = Carb::Container::VERSION
|
9
|
+
spec.authors = ["Fire-Dragon-DoL"]
|
10
|
+
spec.email = ["francesco.belladonna@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Set of IoC containers for carb-inject}
|
13
|
+
spec.description = %q{Set of IoC containers for carb-inject}
|
14
|
+
spec.homepage = "https://github.com/Carburetor/carb-container"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_dependency "carb-core", ">= 1.0.0"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
26
|
+
spec.add_development_dependency "rake", "~> 11.0"
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
28
|
+
spec.add_development_dependency "activesupport"
|
29
|
+
spec.add_development_dependency "pry-byebug"
|
30
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require "carb/container"
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "carb/container/version"
|
2
|
+
require "carb/container/base"
|
3
|
+
require "carb/container/already_registered_error"
|
4
|
+
require "carb/container/dependency_missing_error"
|
5
|
+
require "carb/container/container_validator"
|
6
|
+
require "carb/container/registry_container"
|
7
|
+
require "carb/container/error_container"
|
8
|
+
require "carb/container/delegate_container"
|
9
|
+
require "carb/container/registerer"
|
10
|
+
require "carb/container/registration_glue"
|
11
|
+
|
12
|
+
module Carb
|
13
|
+
module Container
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "carb"
|
2
|
+
|
3
|
+
module Carb::Container
|
4
|
+
# Error when a dependency with same name already exists
|
5
|
+
class AlreadyRegisteredError < StandardError
|
6
|
+
MESSAGE = "Dependency %s already exists, registered at:\n%s".freeze
|
7
|
+
|
8
|
+
attr_reader :name
|
9
|
+
|
10
|
+
def initialize(name)
|
11
|
+
@name = name
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require "carb"
|
2
|
+
|
3
|
+
module Carb::Container
|
4
|
+
# Interface for container definition
|
5
|
+
module Base
|
6
|
+
def [](name)
|
7
|
+
raise NotImplementedError, "#[] not implemented"
|
8
|
+
end
|
9
|
+
|
10
|
+
def has_key?(name)
|
11
|
+
raise NotImplementedError, "#has_key? not implemented"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "carb"
|
2
|
+
|
3
|
+
module Carb::Container
|
4
|
+
# Converts a fully qualified class name to a valid method name. Uses
|
5
|
+
# activesupport if available, otherwise just replaces / with _
|
6
|
+
class ClassNameToMethodName
|
7
|
+
def call(text)
|
8
|
+
snaked = maybe_snake_case(text)
|
9
|
+
snaked = snaked.gsub("/", "_")
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def maybe_snake_case(text)
|
15
|
+
return text unless maybe_require_activesupport
|
16
|
+
return text unless defined?(::ActiveSupport)
|
17
|
+
return text.underscore if text.respond_to?(:underscore)
|
18
|
+
|
19
|
+
ActiveSupport::Inflector.underscore(text)
|
20
|
+
end
|
21
|
+
|
22
|
+
def maybe_require_activesupport
|
23
|
+
require "active_support/inflector/methods"
|
24
|
+
true
|
25
|
+
rescue
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "carb"
|
2
|
+
|
3
|
+
module Carb::Container
|
4
|
+
# Checks if object is a valid container
|
5
|
+
class ContainerValidator
|
6
|
+
# @param container [Object]
|
7
|
+
# @return [Boolean] true if object is a container, false otherwise
|
8
|
+
def call(container)
|
9
|
+
is_container = container.respond_to?(:[])
|
10
|
+
is_container &&= container.respond_to?(:has_key?)
|
11
|
+
|
12
|
+
is_container
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param container [Object]
|
16
|
+
# @return [Boolean] true if object is a container, false otherwise
|
17
|
+
def self.call(container)
|
18
|
+
new.call(container)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require "carb"
|
2
|
+
require "carb/container/base"
|
3
|
+
require "carb/container/dependency_missing_error"
|
4
|
+
require "carb/container/container_validator"
|
5
|
+
|
6
|
+
module Carb::Container
|
7
|
+
# Container which requests dependency in sequence to a list of containers
|
8
|
+
# otherwise and if none returns, it raises
|
9
|
+
class DelegateContainer
|
10
|
+
include ::Carb::Container::Base
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
attr_reader :containers
|
15
|
+
attr_reader :dependencies
|
16
|
+
|
17
|
+
public
|
18
|
+
|
19
|
+
# @param containers [Array] an array of container objects. Must have at
|
20
|
+
# least one container
|
21
|
+
# @raise [ArgumentError] unless at least one container is supplied
|
22
|
+
def initialize(containers, **dependencies)
|
23
|
+
@containers = containers
|
24
|
+
@dependencies = dependencies
|
25
|
+
dependencies[:container_validator] ||= ContainerValidator.new
|
26
|
+
|
27
|
+
ensure_at_least_one_container!(containers)
|
28
|
+
ensure_all_are_containers!(containers)
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param name [Object] dependency name
|
32
|
+
# @return [Object] dependency for given name if present in any container
|
33
|
+
# (only the first in sequence is returned), otherwise raises
|
34
|
+
# @raise [DependencyMissingError]
|
35
|
+
def [](name)
|
36
|
+
containers.each do |container|
|
37
|
+
return container[name] if container.has_key?(name)
|
38
|
+
end
|
39
|
+
|
40
|
+
error_class = ::Carb::Container::DependencyMissingError
|
41
|
+
raise error_class.new(name), format(error_class::MESSAGE, name.to_s)
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param name [Object] dependency name
|
45
|
+
# @return [Boolean] true if dependency is present in any container, false
|
46
|
+
# otherwise
|
47
|
+
def has_key?(name)
|
48
|
+
containers.any? { |container| container.has_key?(name) }
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def ensure_at_least_one_container!(containers)
|
54
|
+
return if containers.size > 0
|
55
|
+
|
56
|
+
raise ArgumentError, "At least one container is required"
|
57
|
+
end
|
58
|
+
|
59
|
+
def ensure_object_is_container!(container, index)
|
60
|
+
return if container_validator.(container)
|
61
|
+
|
62
|
+
raise TypeError, "Container at index #{index} is not valid"
|
63
|
+
end
|
64
|
+
|
65
|
+
def ensure_all_are_containers!(containers)
|
66
|
+
containers.each_with_index do |container, index|
|
67
|
+
ensure_object_is_container!(container, index)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def container_validator
|
72
|
+
dependencies[:container_validator]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "carb"
|
2
|
+
|
3
|
+
module Carb::Container
|
4
|
+
# Error when trying to fetch a dependency which doesn't exist
|
5
|
+
class DependencyMissingError < StandardError
|
6
|
+
MESSAGE = "Dependency \"%s\" doesn't exist " \
|
7
|
+
"in this container".freeze
|
8
|
+
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
def initialize(name)
|
12
|
+
@name = name
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require "carb"
|
2
|
+
require "carb/container/base"
|
3
|
+
require "carb/container/dependency_missing_error"
|
4
|
+
|
5
|
+
module Carb::Container
|
6
|
+
# Container which holds no dependency and will raise every time
|
7
|
+
# one is being fetched
|
8
|
+
class ErrorContainer
|
9
|
+
include ::Carb::Container::Base
|
10
|
+
|
11
|
+
# This method will always raise an error
|
12
|
+
# @param name [Object] dependency name
|
13
|
+
# @raise [::Carb::Container::DependencyMissingError] raised
|
14
|
+
# whenever a dependency is being fetched from this container
|
15
|
+
def [](name)
|
16
|
+
error_class = ::Carb::Container::DependencyMissingError
|
17
|
+
raise error_class.new(name), format(error_class::MESSAGE, name.to_s)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param name [Object] dependency name
|
21
|
+
# @return [false]
|
22
|
+
def has_key?(name)
|
23
|
+
false
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "carb"
|
2
|
+
require "carb/container/class_name_to_method_name"
|
3
|
+
|
4
|
+
module Carb::Container
|
5
|
+
# Provides a class method to register classes globally
|
6
|
+
class Registerer < Module
|
7
|
+
private
|
8
|
+
|
9
|
+
attr_reader :container
|
10
|
+
attr_reader :converter
|
11
|
+
|
12
|
+
# @param container [#register] object which will be used to register
|
13
|
+
# dependencies as {::Proc}
|
14
|
+
# @param converter [#call] object which accepts a string and converts it
|
15
|
+
# into a valid method name. It's used to convert class name to a method
|
16
|
+
# name. By default it uses an instance of {ClassNameToMethodName}
|
17
|
+
def initialize(container, converter: ClassNameToMethodName.new)
|
18
|
+
@container = container
|
19
|
+
@converter = converter
|
20
|
+
end
|
21
|
+
|
22
|
+
def included(klass)
|
23
|
+
# Required for scope purposes
|
24
|
+
kontainer = container
|
25
|
+
convert = converter
|
26
|
+
|
27
|
+
klass.define_singleton_method(:carb_container) do |as: nil|
|
28
|
+
as ||= convert.call(self.name.to_s)
|
29
|
+
as = as.to_sym
|
30
|
+
kontainer.register(as, -> { self })
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "carb"
|
2
|
+
require "carb/container/registerer"
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
module Carb::Container
|
6
|
+
# Provides a method hook in all classes to register them as injectable
|
7
|
+
class RegistrationGlue
|
8
|
+
# Creates a new class method {Class#carb_container} which can be used as
|
9
|
+
# a macro to easily register objects into the supplied container
|
10
|
+
# @param container [#register] a generic object, usually a
|
11
|
+
# {RegistryContainer} which responds to `#register(name, dependency)`,
|
12
|
+
# it's the only required argument
|
13
|
+
# @param target [Object] class where you want to add the class method
|
14
|
+
# `carb_container`. Usually it's {::Class} itself
|
15
|
+
# @param registerer [Module] subclass of a module which can be included.
|
16
|
+
# Usually it's {Registerer} which is an internal module used to store
|
17
|
+
# objects inside a container which responds to `#register`
|
18
|
+
# @param converter [#call] object which accepts a string and converts it
|
19
|
+
# into a valid method name. It's used to convert class name to a method
|
20
|
+
# name. By default it uses an instance of {ClassNameToMethodName}
|
21
|
+
def call(
|
22
|
+
container,
|
23
|
+
target: Class,
|
24
|
+
registerer: Registerer,
|
25
|
+
converter: ClassNameToMethodName.new
|
26
|
+
)
|
27
|
+
target.send(:include, registerer.new(container, converter: converter))
|
28
|
+
end
|
29
|
+
|
30
|
+
class << self
|
31
|
+
extend Forwardable
|
32
|
+
|
33
|
+
def_delegators :new, :call
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require "carb"
|
2
|
+
require "carb/container/base"
|
3
|
+
require "carb/container/already_registered_error"
|
4
|
+
require "carb/container/dependency_missing_error"
|
5
|
+
|
6
|
+
module Carb::Container
|
7
|
+
include ::Carb::Container::Base
|
8
|
+
|
9
|
+
# Simple {Hash} based container for dependency resolution based on name, with
|
10
|
+
# further registration capabilities
|
11
|
+
class RegistryContainer
|
12
|
+
include ::Carb::Container::Base
|
13
|
+
|
14
|
+
Record = Struct.new(:dependency, :registerer)
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_reader :dependencies
|
19
|
+
|
20
|
+
public
|
21
|
+
|
22
|
+
# @param dependencies [Hash{Object => Proc}] dependency name with proc
|
23
|
+
# as value, which will be `call`ed to extract the dependency object
|
24
|
+
def initialize(dependencies = {})
|
25
|
+
@dependencies = {}
|
26
|
+
dependencies.each do |name, dep|
|
27
|
+
register_with_caller(name, dep, caller_locations[0])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# @param name [Object] name used to fetch back the dependency
|
32
|
+
# @param dependency [Proc] dependency to be stored, must be wrapped within
|
33
|
+
# a lambda
|
34
|
+
# @raise [TypeError] raised if dependency is not a {Proc}
|
35
|
+
# @raise [AlreadyRegisteredError] raise when a dependency with same name
|
36
|
+
# already exists
|
37
|
+
# @return [RegistryContainer] self (for chaining purposes)
|
38
|
+
def register(name, dependency)
|
39
|
+
register_with_caller(name, dependency, caller_locations[0])
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
# Gets a dependency
|
44
|
+
# @param name [Object] dependency name with which it was registered
|
45
|
+
# @return [nil, Object] nil if dependency is missing, otherwise the
|
46
|
+
# dependency, unwrapped from proc
|
47
|
+
def [](name)
|
48
|
+
ensure_dependency_present!(name)
|
49
|
+
|
50
|
+
dependencies[name].dependency.()
|
51
|
+
end
|
52
|
+
|
53
|
+
# Checks if the dependency exists within the container
|
54
|
+
# @param name [Object] dependency name with which it was registered
|
55
|
+
# @return [Boolean] true if the dependency exists within the container,
|
56
|
+
# false otherwise
|
57
|
+
def has_key?(name)
|
58
|
+
dependencies.has_key?(name)
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def register_with_caller(name, dependency, registerer)
|
64
|
+
ensure_dependency_type!(dependency)
|
65
|
+
ensure_dependency_uniqueness!(name)
|
66
|
+
|
67
|
+
dependencies[name] = Record.new(dependency, registerer)
|
68
|
+
end
|
69
|
+
|
70
|
+
def ensure_dependency_present!(name)
|
71
|
+
return if has_key?(name)
|
72
|
+
|
73
|
+
raise DependencyMissingError.new(name), missing(name)
|
74
|
+
end
|
75
|
+
|
76
|
+
def ensure_dependency_type!(dependency)
|
77
|
+
return if dependency.respond_to?(:call)
|
78
|
+
|
79
|
+
raise TypeError, "dependency must be a Proc"
|
80
|
+
end
|
81
|
+
|
82
|
+
def ensure_dependency_uniqueness!(name)
|
83
|
+
return unless dependencies.has_key?(name)
|
84
|
+
|
85
|
+
record = dependencies.fetch(name)
|
86
|
+
raise AlreadyRegisteredError.new(name), registered(name, record)
|
87
|
+
end
|
88
|
+
|
89
|
+
def registered(name, record)
|
90
|
+
registerer = record.registerer
|
91
|
+
format(AlreadyRegisteredError::MESSAGE, name.to_s, registerer.to_s)
|
92
|
+
end
|
93
|
+
|
94
|
+
def missing(name)
|
95
|
+
format(DependencyMissingError::MESSAGE, name.to_s)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
metadata
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: carb-container
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Fire-Dragon-DoL
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-05-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: carb-core
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.14'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.14'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '11.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '11.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: activesupport
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry-byebug
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: Set of IoC containers for carb-inject
|
98
|
+
email:
|
99
|
+
- francesco.belladonna@gmail.com
|
100
|
+
executables: []
|
101
|
+
extensions: []
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- ".gitignore"
|
105
|
+
- ".rspec"
|
106
|
+
- ".travis.yml"
|
107
|
+
- Gemfile
|
108
|
+
- README.md
|
109
|
+
- Rakefile
|
110
|
+
- bin/console
|
111
|
+
- bin/setup
|
112
|
+
- carb-container.gemspec
|
113
|
+
- lib/carb-container.rb
|
114
|
+
- lib/carb/container.rb
|
115
|
+
- lib/carb/container/already_registered_error.rb
|
116
|
+
- lib/carb/container/base.rb
|
117
|
+
- lib/carb/container/class_name_to_method_name.rb
|
118
|
+
- lib/carb/container/container_validator.rb
|
119
|
+
- lib/carb/container/delegate_container.rb
|
120
|
+
- lib/carb/container/dependency_missing_error.rb
|
121
|
+
- lib/carb/container/error_container.rb
|
122
|
+
- lib/carb/container/registerer.rb
|
123
|
+
- lib/carb/container/registration_glue.rb
|
124
|
+
- lib/carb/container/registry_container.rb
|
125
|
+
- lib/carb/container/version.rb
|
126
|
+
homepage: https://github.com/Carburetor/carb-container
|
127
|
+
licenses: []
|
128
|
+
metadata: {}
|
129
|
+
post_install_message:
|
130
|
+
rdoc_options: []
|
131
|
+
require_paths:
|
132
|
+
- lib
|
133
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
139
|
+
requirements:
|
140
|
+
- - ">="
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
requirements: []
|
144
|
+
rubyforge_project:
|
145
|
+
rubygems_version: 2.6.12
|
146
|
+
signing_key:
|
147
|
+
specification_version: 4
|
148
|
+
summary: Set of IoC containers for carb-inject
|
149
|
+
test_files: []
|