dumpling 0.1.0 → 0.2.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/README.md +101 -3
- data/dumpling.gemspec +2 -1
- data/lib/dumpling.rb +9 -0
- data/lib/dumpling/container.rb +23 -21
- data/lib/dumpling/errors/specification.rb +0 -3
- data/lib/dumpling/registry.rb +25 -0
- data/lib/dumpling/specification.rb +4 -4
- data/lib/dumpling/specification_validator.rb +7 -2
- data/lib/dumpling/version.rb +1 -1
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07ff2f1a56d0fabcfefe29dec5322d7ff2f57eb6
|
4
|
+
data.tar.gz: bead658711229742bb88e919d913af3257a19883
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf8af125eed37639db305a1fe6639cdb0c91fb2402d24826423909b05f3d53d7bc2531442244917a5597b53d0652ea77e3485cf3c5281b8247757be9385c3d82
|
7
|
+
data.tar.gz: 3b2946aeb843ff9f916b25e495a1d577a6ce5cf91a966464f64a630dc28bb9d56a11ac68bcd9d1302068efe11c96c09020dfecc5a28aaf14bf6bcd344df53b7e
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Dumpling
|
2
2
|
|
3
|
-
|
3
|
+
Dumpling provides you an unobtrusive way to manage dependencies.
|
4
|
+
What is unobtrusive? Unobtrusive means that you don't need to include a module or inherit a class anywhere in your project.
|
5
|
+
Dumpling does not tie your hands. All you have to do is just wire up dependencies.
|
4
6
|
|
5
7
|
## Installation
|
6
8
|
|
@@ -18,9 +20,105 @@ Or install it yourself as:
|
|
18
20
|
|
19
21
|
$ gem install dumpling
|
20
22
|
|
21
|
-
##
|
23
|
+
## Getting started
|
22
24
|
|
23
|
-
|
25
|
+
### Basics
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
class UsersRepository
|
29
|
+
attr_writer :logger
|
30
|
+
end
|
31
|
+
|
32
|
+
Dumpling.configure do
|
33
|
+
set :logger do |s|
|
34
|
+
s.instance Logger.new(STDOUT) # => #<Logger:0x00000000e281a0>
|
35
|
+
end
|
36
|
+
|
37
|
+
set :users_repository do |s|
|
38
|
+
s.class UsersRepository
|
39
|
+
s.dependency :logger
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Every time you invoke the #get method you will get a new instance of the #class
|
44
|
+
Dumpling.get(:users_repository) # => #<UsersRepository:0x00000000ebee20>
|
45
|
+
Dumpling.get(:users_repository) # => #<UsersRepository:0x00000000e8a8f0>
|
46
|
+
|
47
|
+
# Every time you invoke the #get method you will get the same predefined #instance
|
48
|
+
Dumpling.get(:logger) # => #<Logger:0x00000000e281a0>
|
49
|
+
Dumpling.get(:logger) # => #<Logger:0x00000000e281a0>
|
50
|
+
```
|
51
|
+
|
52
|
+
### Defining multiple dependencies
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
container = Dumpling::Container.new
|
56
|
+
container.configure do
|
57
|
+
set :logger do |s|
|
58
|
+
s.instance Logger.new(STDOUT) # => #<Logger:0x00000000e281a0>
|
59
|
+
end
|
60
|
+
|
61
|
+
set :adapter do |s|
|
62
|
+
s.instance PostgreSQLAdapter.new
|
63
|
+
s.dependency :logger
|
64
|
+
end
|
65
|
+
|
66
|
+
set :users_repository do |s|
|
67
|
+
s.class UsersRepository
|
68
|
+
s.dependency :logger
|
69
|
+
s.dependency :adapter
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class UsersRepository
|
74
|
+
attr_accessor :logger, :adapter
|
75
|
+
|
76
|
+
# You can mark a setter method as a private if you need
|
77
|
+
private :adapter=, :logger=
|
78
|
+
end
|
79
|
+
|
80
|
+
container.get(:users_repository).logger # => #<Logger:0x00000000e281a0>
|
81
|
+
container[:users_repository].adapter.logger # => #<Logger:0x00000000e281a0>
|
82
|
+
# Logger will be injected every time an adapter is accessed
|
83
|
+
container[:adapter].logger # => #<Logger:0x00000000e281a0>
|
84
|
+
```
|
85
|
+
|
86
|
+
### Using namespaces
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
container = Dumpling::Container.new
|
90
|
+
container.configure do
|
91
|
+
# All that does not match [a-zA-Z0-9_] is a delimiter
|
92
|
+
set :'billing:repositories:users' do |s|
|
93
|
+
...
|
94
|
+
end
|
95
|
+
|
96
|
+
set :'billing repositories users' do |s|
|
97
|
+
...
|
98
|
+
end
|
99
|
+
|
100
|
+
set :'billing.repositories.users' do |s|
|
101
|
+
...
|
102
|
+
end
|
103
|
+
|
104
|
+
# Delimiters can be mixed up
|
105
|
+
set :'billing repositories-users' do |s|
|
106
|
+
...
|
107
|
+
end
|
108
|
+
|
109
|
+
set :'billing.commands.create' do |s|
|
110
|
+
s.class Billing::Commands::Create
|
111
|
+
# Will automatically guess the name of the attr_writer by the last word (attr_writer :users)
|
112
|
+
s.dependency :'billing.repositories.users'
|
113
|
+
end
|
114
|
+
|
115
|
+
set :'billing.commands.open_dispute' do |s|
|
116
|
+
s.class Billing::Commands::OpenDispute
|
117
|
+
# Define the attr_writer explicitly (attr_writer :customers)
|
118
|
+
s.dependency :'billing.repositories.users', attribute: :customers
|
119
|
+
end
|
120
|
+
end
|
121
|
+
```
|
24
122
|
|
25
123
|
## Development
|
26
124
|
|
data/dumpling.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
spec.homepage = 'https://github.com/antonkuzmenko/dumpling'
|
12
12
|
spec.license = 'MIT'
|
13
13
|
|
14
|
-
spec.summary = 'Dumpling is
|
14
|
+
spec.summary = 'Dumpling is an unobtrusive Dependency Injection Container'
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\Aspec/}) }
|
17
17
|
spec.require_paths = ['lib']
|
@@ -22,4 +22,5 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_development_dependency 'rake', '~> 10.0'
|
23
23
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
24
24
|
spec.add_development_dependency 'rubocop', '~> 0.36.0'
|
25
|
+
spec.add_development_dependency 'simplecov', '~> 0.11'
|
25
26
|
end
|
data/lib/dumpling.rb
CHANGED
@@ -7,5 +7,14 @@ module Dumpling
|
|
7
7
|
require 'dumpling/errors/specification'
|
8
8
|
require 'dumpling/specification'
|
9
9
|
require 'dumpling/specification_validator'
|
10
|
+
require 'dumpling/registry'
|
10
11
|
require 'dumpling/container'
|
12
|
+
|
13
|
+
@container = Container.new
|
14
|
+
|
15
|
+
class << self
|
16
|
+
extend Forwardable
|
17
|
+
|
18
|
+
def_delegators :@container, :set, :get, :[], :configure
|
19
|
+
end
|
11
20
|
end
|
data/lib/dumpling/container.rb
CHANGED
@@ -1,14 +1,24 @@
|
|
1
1
|
module Dumpling
|
2
2
|
class Container
|
3
|
+
attr_writer :validator_class
|
4
|
+
|
3
5
|
def initialize
|
4
|
-
@
|
5
|
-
@
|
6
|
+
@registry = Registry.new
|
7
|
+
@validator_class = SpecificationValidator
|
8
|
+
end
|
9
|
+
|
10
|
+
def set(id, &block)
|
11
|
+
fail(Errors::Container::Duplicate, id) if @registry.has?(id)
|
12
|
+
|
13
|
+
specification = create_specification(&block)
|
14
|
+
@registry.set(id, specification)
|
15
|
+
|
16
|
+
id
|
6
17
|
end
|
7
18
|
|
8
19
|
def get(id)
|
9
|
-
id
|
10
|
-
|
11
|
-
specification = @registry[id]
|
20
|
+
fail(Errors::Container::Missing, id) unless @registry.has?(id)
|
21
|
+
specification = @registry.get(id)
|
12
22
|
instance = build_instance(specification)
|
13
23
|
inject_dependencies(instance, specification)
|
14
24
|
instance
|
@@ -16,21 +26,6 @@ module Dumpling
|
|
16
26
|
|
17
27
|
alias :[] get
|
18
28
|
|
19
|
-
def set(id)
|
20
|
-
id = id.to_sym
|
21
|
-
fail(Errors::Container::Duplicate, id) if @id_list.include?(id)
|
22
|
-
|
23
|
-
specification = Specification.new
|
24
|
-
yield specification
|
25
|
-
SpecificationValidator.new(@id_list, specification).validate!
|
26
|
-
@registry[id] = specification
|
27
|
-
@id_list << id
|
28
|
-
|
29
|
-
nil
|
30
|
-
end
|
31
|
-
|
32
|
-
alias :[]= set
|
33
|
-
|
34
29
|
def configure(&block)
|
35
30
|
instance_eval(&block)
|
36
31
|
self
|
@@ -38,13 +33,20 @@ module Dumpling
|
|
38
33
|
|
39
34
|
private
|
40
35
|
|
36
|
+
def create_specification
|
37
|
+
specification = Specification.new
|
38
|
+
yield specification
|
39
|
+
@validator_class.new(@registry.keys, specification).validate!
|
40
|
+
specification
|
41
|
+
end
|
42
|
+
|
41
43
|
def build_instance(specification)
|
42
44
|
specification.class.nil? ? specification.instance : specification.class.new
|
43
45
|
end
|
44
46
|
|
45
47
|
def inject_dependencies(instance, specification)
|
46
48
|
specification.dependencies.each do |dependency|
|
47
|
-
instance.send("#{dependency[:
|
49
|
+
instance.send("#{dependency[:attribute]}=", get(dependency[:id]))
|
48
50
|
end
|
49
51
|
end
|
50
52
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Dumpling
|
2
|
+
class Registry
|
3
|
+
attr_reader :keys
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@data = {}
|
7
|
+
@keys = Set.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def set(id, value)
|
11
|
+
@data[id] = value
|
12
|
+
@keys << id
|
13
|
+
|
14
|
+
value
|
15
|
+
end
|
16
|
+
|
17
|
+
def get(id)
|
18
|
+
@data[id]
|
19
|
+
end
|
20
|
+
|
21
|
+
def has?(id)
|
22
|
+
@keys.include?(id)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -14,15 +14,15 @@ module Dumpling
|
|
14
14
|
instance.nil? ? @instance : (@instance = instance)
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
dependencies << { id: id
|
17
|
+
def dependency(id, attribute: nil)
|
18
|
+
dependencies << { id: id, attribute: (attribute || guess_attribute(id)).to_sym }
|
19
19
|
end
|
20
20
|
|
21
21
|
private
|
22
22
|
|
23
23
|
def guess_attribute(id)
|
24
|
-
/(?<
|
25
|
-
|
24
|
+
/(?<attribute>\w+)\z/i =~ id
|
25
|
+
attribute || id
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
@@ -13,8 +13,13 @@ module Dumpling
|
|
13
13
|
private
|
14
14
|
|
15
15
|
def validate_value
|
16
|
+
unless @specification.class.nil? || @specification.instance.nil?
|
17
|
+
fail Errors::Specification::Invalid,
|
18
|
+
'Do not define both #class and #instance at the same time'
|
19
|
+
end
|
20
|
+
|
16
21
|
if @specification.class.nil? && @specification.instance.nil?
|
17
|
-
fail Errors::Specification::Invalid, '
|
22
|
+
fail Errors::Specification::Invalid, 'Define #class or #instance'
|
18
23
|
end
|
19
24
|
end
|
20
25
|
|
@@ -29,8 +34,8 @@ module Dumpling
|
|
29
34
|
def missing_dependencies
|
30
35
|
@specification
|
31
36
|
.dependencies
|
32
|
-
.reject { |e| @id_list.include?(e[:id]) }
|
33
37
|
.map { |e| e[:id] }
|
38
|
+
.reject { |e| @id_list.include?(e) }
|
34
39
|
end
|
35
40
|
end
|
36
41
|
end
|
data/lib/dumpling/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dumpling
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anton Kuzmenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -66,6 +66,20 @@ dependencies:
|
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 0.36.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.11'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.11'
|
69
83
|
description:
|
70
84
|
email: antonkuzmenko.dev@gmail.com
|
71
85
|
executables: []
|
@@ -89,6 +103,7 @@ files:
|
|
89
103
|
- lib/dumpling/errors/base_error.rb
|
90
104
|
- lib/dumpling/errors/container.rb
|
91
105
|
- lib/dumpling/errors/specification.rb
|
106
|
+
- lib/dumpling/registry.rb
|
92
107
|
- lib/dumpling/specification.rb
|
93
108
|
- lib/dumpling/specification_validator.rb
|
94
109
|
- lib/dumpling/version.rb
|
@@ -115,5 +130,5 @@ rubyforge_project:
|
|
115
130
|
rubygems_version: 2.5.1
|
116
131
|
signing_key:
|
117
132
|
specification_version: 4
|
118
|
-
summary: Dumpling is
|
133
|
+
summary: Dumpling is an unobtrusive Dependency Injection Container
|
119
134
|
test_files: []
|