dry-component 0.0.1
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 +36 -0
- data/.rspec +3 -0
- data/.rubocop.yml +34 -0
- data/.rubocop_todo.yml +26 -0
- data/.travis.yml +26 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +9 -0
- data/LICENSE +20 -0
- data/README.md +218 -0
- data/Rakefile +12 -0
- data/dry-component.gemspec +27 -0
- data/lib/dry-component.rb +1 -0
- data/lib/dry/component.rb +4 -0
- data/lib/dry/component/config.rb +23 -0
- data/lib/dry/component/container.rb +181 -0
- data/lib/dry/component/loader.rb +47 -0
- data/lib/dry/component/version.rb +5 -0
- data/spec/fixtures/other/config/boot/bar.rb +11 -0
- data/spec/fixtures/other/lib/test/dep.rb +4 -0
- data/spec/fixtures/other/lib/test/foo.rb +5 -0
- data/spec/fixtures/other/lib/test/models.rb +4 -0
- data/spec/fixtures/other/lib/test/models/book.rb +6 -0
- data/spec/fixtures/other/lib/test/models/user.rb +6 -0
- data/spec/fixtures/test/config/application.yml +2 -0
- data/spec/fixtures/test/core/boot/bar.rb +11 -0
- data/spec/fixtures/test/lib/test/dep.rb +4 -0
- data/spec/fixtures/test/lib/test/foo.rb +5 -0
- data/spec/fixtures/test/lib/test/models.rb +4 -0
- data/spec/fixtures/test/lib/test/models/book.rb +6 -0
- data/spec/fixtures/test/lib/test/models/user.rb +6 -0
- data/spec/spec_helper.rb +46 -0
- data/spec/unit/config_spec.rb +15 -0
- data/spec/unit/container_spec.rb +102 -0
- data/spec/unit/loader_spec.rb +66 -0
- metadata +213 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: ee78e672954f38457a8469c522b169caff7433ae
|
|
4
|
+
data.tar.gz: 8b649eed1db04abef81ac6d0512f38bbafd26cb3
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: a0bf880fd5c645e2fa85c40061f66a9a8da31be70f0fadff877b15cccede26560215b52895fa9e1a443609f8db9dc587b00c821e1d75d0768675f98d28d978cd
|
|
7
|
+
data.tar.gz: 4ac3f8c0f089975e808736577bfb0e8fc3fcafebfeb6ca8ed440d4a060d9c2ef8eaadfc8801c3609e6991926bbd08fafc8fd4a9ce5aa4a55232f626f33a00843
|
data/.gitignore
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
*.gem
|
|
2
|
+
*.rbc
|
|
3
|
+
/.config
|
|
4
|
+
/coverage/
|
|
5
|
+
/InstalledFiles
|
|
6
|
+
/pkg/
|
|
7
|
+
/spec/reports/
|
|
8
|
+
/test/tmp/
|
|
9
|
+
/test/version_tmp/
|
|
10
|
+
/tmp/
|
|
11
|
+
|
|
12
|
+
## Specific to RubyMotion:
|
|
13
|
+
.dat*
|
|
14
|
+
.repl_history
|
|
15
|
+
build/
|
|
16
|
+
|
|
17
|
+
## Documentation cache and generated files:
|
|
18
|
+
/.yardoc/
|
|
19
|
+
/_yardoc/
|
|
20
|
+
/doc/
|
|
21
|
+
/rdoc/
|
|
22
|
+
|
|
23
|
+
## Environment normalisation:
|
|
24
|
+
/.bundle/
|
|
25
|
+
/vendor/bundle
|
|
26
|
+
/lib/bundler/man/
|
|
27
|
+
|
|
28
|
+
# for a library or gem, you might want to ignore these files since the code is
|
|
29
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
30
|
+
# Gemfile.lock
|
|
31
|
+
# .ruby-version
|
|
32
|
+
# .ruby-gemset
|
|
33
|
+
|
|
34
|
+
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
|
35
|
+
.rvmrc
|
|
36
|
+
Gemfile.lock
|
data/.rspec
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Generated by `rubocop --auto-gen-config`
|
|
2
|
+
inherit_from: .rubocop_todo.yml
|
|
3
|
+
|
|
4
|
+
# No need to handle LoadError in spec helper
|
|
5
|
+
Lint/HandleExceptions:
|
|
6
|
+
Exclude:
|
|
7
|
+
- spec/spec_helper.rb
|
|
8
|
+
|
|
9
|
+
Style/FileName:
|
|
10
|
+
Exclude:
|
|
11
|
+
- 'lib/dry-component.rb'
|
|
12
|
+
|
|
13
|
+
# Documentation checked by Inch CI
|
|
14
|
+
Style/Documentation:
|
|
15
|
+
Enabled: false
|
|
16
|
+
|
|
17
|
+
# Ain't nobody got time for that!
|
|
18
|
+
Style/MethodCallParentheses:
|
|
19
|
+
Enabled: false
|
|
20
|
+
|
|
21
|
+
Style/Lambda:
|
|
22
|
+
Enabled: false
|
|
23
|
+
|
|
24
|
+
Style/BlockDelimiters:
|
|
25
|
+
Enabled: false
|
|
26
|
+
|
|
27
|
+
Style/LambdaCall:
|
|
28
|
+
EnforcedStyle: braces
|
|
29
|
+
|
|
30
|
+
Style/MultilineBlockChain:
|
|
31
|
+
Enabled: false
|
|
32
|
+
|
|
33
|
+
Style/StabbyLambdaParentheses:
|
|
34
|
+
EnforcedStyle: require_no_parentheses
|
data/.rubocop_todo.yml
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# This configuration was generated by
|
|
2
|
+
# `rubocop --auto-gen-config`
|
|
3
|
+
# on 2015-12-23 21:42:26 +0000 using RuboCop version 0.35.1.
|
|
4
|
+
# The point is for the user to remove these configuration records
|
|
5
|
+
# one by one as the offenses are removed from the code base.
|
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
|
8
|
+
|
|
9
|
+
# Offense count: 1
|
|
10
|
+
Metrics/AbcSize:
|
|
11
|
+
Max: 25
|
|
12
|
+
|
|
13
|
+
# Offense count: 1
|
|
14
|
+
# Configuration parameters: CountComments.
|
|
15
|
+
Metrics/ClassLength:
|
|
16
|
+
Max: 130
|
|
17
|
+
|
|
18
|
+
# Offense count: 1
|
|
19
|
+
# Configuration parameters: AllowURI, URISchemes.
|
|
20
|
+
Metrics/LineLength:
|
|
21
|
+
Max: 84
|
|
22
|
+
|
|
23
|
+
# Offense count: 2
|
|
24
|
+
# Configuration parameters: CountComments.
|
|
25
|
+
Metrics/MethodLength:
|
|
26
|
+
Max: 14
|
data/.travis.yml
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
language: ruby
|
|
2
|
+
sudo: false
|
|
3
|
+
cache: bundler
|
|
4
|
+
bundler_args: --without tools
|
|
5
|
+
script:
|
|
6
|
+
- bundle exec rake spec
|
|
7
|
+
rvm:
|
|
8
|
+
- 2.0
|
|
9
|
+
- 2.1
|
|
10
|
+
- 2.2
|
|
11
|
+
- rbx-2
|
|
12
|
+
- jruby-9000
|
|
13
|
+
- ruby-head
|
|
14
|
+
- jruby-head
|
|
15
|
+
matrix:
|
|
16
|
+
allow_failures:
|
|
17
|
+
- rvm: ruby-head
|
|
18
|
+
- rvm: jruby-head
|
|
19
|
+
notifications:
|
|
20
|
+
email: false
|
|
21
|
+
webhooks:
|
|
22
|
+
urls:
|
|
23
|
+
- https://webhooks.gitter.im/e/19098b4253a72c9796db
|
|
24
|
+
on_success: change # options: [always|never|change] default: always
|
|
25
|
+
on_failure: always # options: [always|never|change] default: always
|
|
26
|
+
on_start: false # default: false
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014 Dryrb Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
7
|
+
the Software without restriction, including without limitation the rights to
|
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
10
|
+
subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# dry-component <a href="https://gitter.im/dryrb/chat" target="_blank"></a>
|
|
2
|
+
|
|
3
|
+
<a href="https://rubygems.org/gems/dry-component" target="_blank"></a>
|
|
4
|
+
<a href="https://travis-ci.org/dryrb/dry-component" target="_blank"></a>
|
|
5
|
+
<a href="https://gemnasium.com/dryrb/dry-component" target="_blank"></a>
|
|
6
|
+
<a href="https://codeclimate.com/github/dryrb/dry-component" target="_blank"></a>
|
|
7
|
+
<a href="http://inch-ci.org/github/dryrb/dry-component" target="_blank"></a>
|
|
8
|
+
|
|
9
|
+
Sane dependency management system allowing you to configure reusable components
|
|
10
|
+
in any environment, set up their load-paths, require needed files and instantiate
|
|
11
|
+
objects automatically with the ability to have them injected as dependencies.
|
|
12
|
+
|
|
13
|
+
Originally built for [rodakase](https://github.com/solnic/rodakase) stack, now as
|
|
14
|
+
a standalone, small library.
|
|
15
|
+
|
|
16
|
+
This is a simple system that relies on very basic mechanisms provided by Ruby,
|
|
17
|
+
specifically `require` and managing `$LOAD_PATH`. It does not rely on any magic
|
|
18
|
+
like automatic const resolution, it's pretty much the opposite and forces you to
|
|
19
|
+
be explicit about dependencies in your applications.
|
|
20
|
+
|
|
21
|
+
It does a couple of things for you that are really not something you want to do
|
|
22
|
+
yourself:
|
|
23
|
+
|
|
24
|
+
* Provides an abstract dependency container implementation
|
|
25
|
+
* Handles `$LOAD_PATH` configuration
|
|
26
|
+
* Loads needed files using `require`
|
|
27
|
+
* Resolves dependencies automatically
|
|
28
|
+
* Supports auto-registration of dependencies via file/dir naming conventions
|
|
29
|
+
* Provides support for custom configuration loaded from external sources (ie YAML)
|
|
30
|
+
|
|
31
|
+
To put it all together, this allows you to configure your system in a way where
|
|
32
|
+
you have full control over dependencies and it's very easy to draw the boundaries
|
|
33
|
+
between individual components.
|
|
34
|
+
|
|
35
|
+
This comes with a bunch of nice benefits:
|
|
36
|
+
|
|
37
|
+
* Your system relies on abstractions rather than concrete classes and modules
|
|
38
|
+
* It helps in decoupling your code from 3rd party code
|
|
39
|
+
* It makes it possible to load components in complete isolation. In example you
|
|
40
|
+
can run a single test for a single component and only required files will be
|
|
41
|
+
loaded, or you can run a rake task and it will only load the things it needs.
|
|
42
|
+
* It opens up doors for better instrumentation and debugging tools
|
|
43
|
+
|
|
44
|
+
## Container
|
|
45
|
+
|
|
46
|
+
Main API is the abstract container that you inherit from. It allows you to configure
|
|
47
|
+
basic settings and exposes APIs for requiring files easily.
|
|
48
|
+
|
|
49
|
+
Let's say you want to define an application container that will provide a logger:
|
|
50
|
+
|
|
51
|
+
``` ruby
|
|
52
|
+
require 'dry/component/container'
|
|
53
|
+
|
|
54
|
+
class Application < Dry::Component::Container
|
|
55
|
+
configure do |config|
|
|
56
|
+
config.root = '/my/app'
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# now you can register a logger
|
|
61
|
+
require 'logger'
|
|
62
|
+
Application.register('utils.logger', Logger.new($stdout))
|
|
63
|
+
|
|
64
|
+
# and access it
|
|
65
|
+
Application['utils.logger']
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Auto-Registration
|
|
69
|
+
|
|
70
|
+
By using simple naming conventions we can automatically register objects within
|
|
71
|
+
our container.
|
|
72
|
+
|
|
73
|
+
Let's provide a custom logger object and put it under a custom load-path that we
|
|
74
|
+
will configure:
|
|
75
|
+
|
|
76
|
+
``` ruby
|
|
77
|
+
require 'dry/component/container'
|
|
78
|
+
|
|
79
|
+
class Application < Dry::Component::Container
|
|
80
|
+
configure do |config|
|
|
81
|
+
config.root = '/my/app'
|
|
82
|
+
|
|
83
|
+
# we set 'lib' relative to `root` as a path which contains class definitions
|
|
84
|
+
# that can be auto-registered
|
|
85
|
+
config.auto_register = 'lib'
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# this alters $LOAD_PATH hence the `!`
|
|
89
|
+
load_paths!('lib')
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# under /my/app/lib/logger.rb we put
|
|
93
|
+
class Logger
|
|
94
|
+
# some neat logger implementation
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# we can finalize the container which triggers auto-registration
|
|
98
|
+
Application.finalize!
|
|
99
|
+
|
|
100
|
+
# the logger becomes available
|
|
101
|
+
Application['logger']
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Auto-Import Mechanism
|
|
105
|
+
|
|
106
|
+
After defining a container, we can use its import module that will inject object
|
|
107
|
+
dependencies automatically.
|
|
108
|
+
|
|
109
|
+
Let's say we have an object that will need a logger:
|
|
110
|
+
|
|
111
|
+
``` ruby
|
|
112
|
+
# let's define an import module
|
|
113
|
+
Import = Application.import_module
|
|
114
|
+
|
|
115
|
+
# in a class definition you simply specify what it needs
|
|
116
|
+
class PostPublisher
|
|
117
|
+
include Import['utils.logger']
|
|
118
|
+
|
|
119
|
+
def call(post)
|
|
120
|
+
# some stuff
|
|
121
|
+
logger.debug("post published: #{post}")
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Directory Structure
|
|
127
|
+
|
|
128
|
+
You need to provide a specific directory/file structure but names of directories
|
|
129
|
+
are configurable. The default is as follows:
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
#{root}
|
|
133
|
+
|- core
|
|
134
|
+
|- boot
|
|
135
|
+
# arbitrary files that are automatically loaded on finalization
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Booting a Dependency
|
|
139
|
+
|
|
140
|
+
In some cases a dependency can be huge, so huge it needs to load some additional
|
|
141
|
+
files (often 3rd party code) and it may rely on custom configuration.
|
|
142
|
+
|
|
143
|
+
Because of this reason `dry-component` has the concept of booting a dependency.
|
|
144
|
+
|
|
145
|
+
The convention is pretty simple. You put files under `boot` directory and use
|
|
146
|
+
your container to register dependencies with the ability to postpone finalization.
|
|
147
|
+
This gives us a way to define what's needed but load it and boot it on demand.
|
|
148
|
+
|
|
149
|
+
Here's a simple example:
|
|
150
|
+
|
|
151
|
+
``` ruby
|
|
152
|
+
# under /my/app/boot/heavy_dep.rb
|
|
153
|
+
|
|
154
|
+
Application.finalize(:persistence) do
|
|
155
|
+
# some 3rd-party dependency
|
|
156
|
+
require '3rd-party/database'
|
|
157
|
+
|
|
158
|
+
container.register('database') do
|
|
159
|
+
# some code which initializes this thing
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
After defining the finalization block our container will not call it until its
|
|
165
|
+
own finalization. This means we can require file that defines our container
|
|
166
|
+
and ask it to boot *just that one :persistence dependency*:
|
|
167
|
+
|
|
168
|
+
``` ruby
|
|
169
|
+
# under /my/app/boot/container.rb
|
|
170
|
+
class Application < Dry::Component::Container
|
|
171
|
+
configure do |config|
|
|
172
|
+
config.root = '/my/app'
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
Application.boot!(:persistence)
|
|
177
|
+
|
|
178
|
+
# and now `database` becomes available
|
|
179
|
+
Application['database']
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Environment & Providing Arbitrary Options
|
|
183
|
+
|
|
184
|
+
In most of the systems you need some kind of options for your runtime. Typically
|
|
185
|
+
it's provided via ENV vars or a yaml file in development mode. `dry-component`
|
|
186
|
+
has a built-in support for this.
|
|
187
|
+
|
|
188
|
+
You can simply put a file under `#{root}/config/application.yml` and it will be
|
|
189
|
+
loaded:
|
|
190
|
+
|
|
191
|
+
``` yaml
|
|
192
|
+
# /my/app/config/application.yml
|
|
193
|
+
development:
|
|
194
|
+
foo: 'bar'
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Now let's configure our container for a specific env:
|
|
198
|
+
|
|
199
|
+
``` ruby
|
|
200
|
+
class Application < Dry::Component::Container
|
|
201
|
+
configure('development') do |config|
|
|
202
|
+
config.root = '/my/app'
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
# now our application options are available
|
|
207
|
+
Application.options.foo # => "bar"
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Underlying Tools
|
|
211
|
+
|
|
212
|
+
`dry-component` uses [dry-container](https://github.com/dryrb/dry-container) and
|
|
213
|
+
[dry-auto_inject](https://github.com/dryrb/dry-auto_inject) under the hood. These
|
|
214
|
+
gems are very small and simple with a total 254LOC. Just saying.
|
|
215
|
+
|
|
216
|
+
## LICENSE
|
|
217
|
+
|
|
218
|
+
See `LICENSE` file.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env rake
|
|
2
|
+
require 'bundler/gem_tasks'
|
|
3
|
+
|
|
4
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
|
5
|
+
|
|
6
|
+
require 'rspec/core'
|
|
7
|
+
require 'rspec/core/rake_task'
|
|
8
|
+
|
|
9
|
+
task default: :spec
|
|
10
|
+
|
|
11
|
+
desc 'Run all specs in spec directory'
|
|
12
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
require File.expand_path('../lib/dry/component/version', __FILE__)
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |spec|
|
|
5
|
+
spec.name = 'dry-component'
|
|
6
|
+
spec.version = Dry::Component::VERSION
|
|
7
|
+
spec.authors = ['Piotr Solnica']
|
|
8
|
+
spec.email = ['piotr.solnica@gmail.com']
|
|
9
|
+
spec.summary = 'Organize your code into reusable components'
|
|
10
|
+
spec.homepage = 'https://github.com/dryrb/dry-component'
|
|
11
|
+
spec.license = 'MIT'
|
|
12
|
+
|
|
13
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
14
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
15
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
16
|
+
spec.require_paths = ['lib']
|
|
17
|
+
|
|
18
|
+
spec.add_runtime_dependency 'memoizable', '~> 0.4'
|
|
19
|
+
spec.add_runtime_dependency 'inflecto', '>= 0.0.2'
|
|
20
|
+
spec.add_runtime_dependency 'dry-container', '~> 0.2', '>= 0.2.7'
|
|
21
|
+
spec.add_runtime_dependency 'dry-auto_inject', '~> 0.1'
|
|
22
|
+
spec.add_runtime_dependency 'dry-configurable', '~> 0.1'
|
|
23
|
+
|
|
24
|
+
spec.add_development_dependency 'bundler'
|
|
25
|
+
spec.add_development_dependency 'rake'
|
|
26
|
+
spec.add_development_dependency 'rspec'
|
|
27
|
+
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'dry/component'
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
|
|
3
|
+
module Dry
|
|
4
|
+
module Component
|
|
5
|
+
class Config
|
|
6
|
+
extend Dry::Configurable
|
|
7
|
+
|
|
8
|
+
def self.load(root, env)
|
|
9
|
+
path = root.join('config').join('application.yml')
|
|
10
|
+
|
|
11
|
+
return {} unless File.exist?(path)
|
|
12
|
+
|
|
13
|
+
yaml = YAML.load_file(path)
|
|
14
|
+
|
|
15
|
+
yaml.fetch(env.to_s).each do |key, value|
|
|
16
|
+
setting key.downcase.to_sym, ENV.fetch(key, value)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
config
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
require 'inflecto'
|
|
2
|
+
require 'dry-container'
|
|
3
|
+
require 'dry-auto_inject'
|
|
4
|
+
|
|
5
|
+
require 'dry/component/loader'
|
|
6
|
+
require 'dry/component/config'
|
|
7
|
+
|
|
8
|
+
module Dry
|
|
9
|
+
module Component
|
|
10
|
+
class Container
|
|
11
|
+
extend Dry::Container::Mixin
|
|
12
|
+
|
|
13
|
+
setting :env
|
|
14
|
+
setting :root, Pathname.pwd.freeze
|
|
15
|
+
setting :core_dir, 'core'.freeze
|
|
16
|
+
setting :auto_register
|
|
17
|
+
setting :options
|
|
18
|
+
|
|
19
|
+
def self.configure(env = config.env, &block)
|
|
20
|
+
return self if configured?
|
|
21
|
+
|
|
22
|
+
super() do |config|
|
|
23
|
+
yield(config) if block
|
|
24
|
+
config.options = Config.load(root, env)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
load_paths!(config.core_dir)
|
|
28
|
+
|
|
29
|
+
@configured = true
|
|
30
|
+
|
|
31
|
+
self
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def self.options
|
|
35
|
+
config.options
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def self.finalize(name, &block)
|
|
39
|
+
finalizers[name] = block
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.configured?
|
|
43
|
+
@configured
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def self.finalize!(&_block)
|
|
47
|
+
yield(self) if block_given?
|
|
48
|
+
|
|
49
|
+
Dir[root.join("#{config.core_dir}/boot/**/*.rb")].each do |path|
|
|
50
|
+
boot!(File.basename(path, '.rb').to_sym)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
auto_register.each(&method(:auto_register!)) if auto_register?
|
|
54
|
+
|
|
55
|
+
freeze
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.import_module
|
|
59
|
+
auto_inject = Dry::AutoInject(self)
|
|
60
|
+
|
|
61
|
+
-> *keys {
|
|
62
|
+
keys.each { |key| load_component(key) unless key?(key) }
|
|
63
|
+
auto_inject[*keys]
|
|
64
|
+
}
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def self.auto_register!(dir, &_block)
|
|
68
|
+
dir_root = root.join(dir.to_s.split('/')[0])
|
|
69
|
+
|
|
70
|
+
Dir["#{root}/#{dir}/**/*.rb"].each do |path|
|
|
71
|
+
component_path = path.to_s.gsub("#{dir_root}/", '').gsub('.rb', '')
|
|
72
|
+
Component.Loader(component_path).tap do |component|
|
|
73
|
+
next if key?(component.identifier)
|
|
74
|
+
|
|
75
|
+
Kernel.require component.path
|
|
76
|
+
|
|
77
|
+
if block_given?
|
|
78
|
+
register(component.identifier, yield(component.constant))
|
|
79
|
+
else
|
|
80
|
+
register(component.identifier) { component.instance }
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
self
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def self.boot!(name)
|
|
89
|
+
check_component_identifier!(name)
|
|
90
|
+
return self unless booted?(name)
|
|
91
|
+
boot(name)
|
|
92
|
+
self
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def self.boot(name)
|
|
96
|
+
require "#{config.core_dir}/boot/#{name}.rb"
|
|
97
|
+
|
|
98
|
+
finalizers[name].tap do |finalizer|
|
|
99
|
+
finalizer.() if finalizer
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
booted[name] = true
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def self.booted?(name)
|
|
106
|
+
!booted.key?(name)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def self.require(*paths)
|
|
110
|
+
paths.flat_map { |path|
|
|
111
|
+
path.include?('*') ? Dir[root.join(path)] : root.join(path)
|
|
112
|
+
}.each { |path|
|
|
113
|
+
Kernel.require path.to_s
|
|
114
|
+
}
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def self.load_component(key)
|
|
118
|
+
require_component(key) { |klass| register(key) { klass.new } }
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def self.require_component(key, &block)
|
|
122
|
+
component = Component.Loader(key)
|
|
123
|
+
path = load_paths.detect { |p| p.join(component.file).exist? }
|
|
124
|
+
|
|
125
|
+
if path
|
|
126
|
+
Kernel.require component.path
|
|
127
|
+
yield(component.constant) if block
|
|
128
|
+
else
|
|
129
|
+
fail ArgumentError, "could not resolve require file for #{key}"
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def self.root
|
|
134
|
+
config.root
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def self.load_paths!(*dirs)
|
|
138
|
+
dirs.map(&:to_s).each do |dir|
|
|
139
|
+
path = root.join(dir)
|
|
140
|
+
load_paths << path
|
|
141
|
+
$LOAD_PATH.unshift(path.to_s)
|
|
142
|
+
end
|
|
143
|
+
self
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def self.load_paths
|
|
147
|
+
@load_paths ||= []
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def self.booted
|
|
151
|
+
@booted ||= {}
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def self.finalizers
|
|
155
|
+
@finalizers ||= {}
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
private
|
|
159
|
+
|
|
160
|
+
def self.auto_register
|
|
161
|
+
Array(config.auto_register)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def self.auto_register?
|
|
165
|
+
!auto_register.empty?
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def self.check_component_identifier!(name)
|
|
169
|
+
fail(
|
|
170
|
+
ArgumentError,
|
|
171
|
+
'component identifier must be a symbol'
|
|
172
|
+
) unless name.is_a?(Symbol)
|
|
173
|
+
|
|
174
|
+
fail(
|
|
175
|
+
ArgumentError,
|
|
176
|
+
"component identifier +#{name}+ is invalid or boot file is missing"
|
|
177
|
+
) unless root.join("#{config.core_dir}/boot/#{name}.rb").exist?
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
require 'memoizable'
|
|
2
|
+
require 'inflecto'
|
|
3
|
+
|
|
4
|
+
module Dry
|
|
5
|
+
module Component
|
|
6
|
+
def self.Loader(input)
|
|
7
|
+
Loader.new(Loader.identifier(input), Loader.path(input))
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
class Loader
|
|
11
|
+
include Memoizable
|
|
12
|
+
|
|
13
|
+
IDENTIFIER_SEPARATOR = '.'.freeze
|
|
14
|
+
PATH_SEPARATOR = '/'.freeze
|
|
15
|
+
|
|
16
|
+
attr_reader :identifier, :path, :file
|
|
17
|
+
|
|
18
|
+
def self.identifier(input)
|
|
19
|
+
input.to_s.gsub(PATH_SEPARATOR, IDENTIFIER_SEPARATOR)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def self.path(input)
|
|
23
|
+
input.to_s.gsub(IDENTIFIER_SEPARATOR, PATH_SEPARATOR)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def initialize(identifier, path)
|
|
27
|
+
@identifier = identifier
|
|
28
|
+
@path = path
|
|
29
|
+
@file = "#{path}.rb"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def name
|
|
33
|
+
Inflecto.camelize(path)
|
|
34
|
+
end
|
|
35
|
+
memoize :name
|
|
36
|
+
|
|
37
|
+
def constant
|
|
38
|
+
Inflecto.constantize(name)
|
|
39
|
+
end
|
|
40
|
+
memoize :constant
|
|
41
|
+
|
|
42
|
+
def instance(*args)
|
|
43
|
+
constant.new(*args)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
if RUBY_ENGINE == 'rbx'
|
|
4
|
+
require 'codeclimate-test-reporter'
|
|
5
|
+
CodeClimate::TestReporter.start
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
begin
|
|
9
|
+
require 'byebug'
|
|
10
|
+
rescue LoadError; end
|
|
11
|
+
|
|
12
|
+
SPEC_ROOT = Pathname(__FILE__).dirname
|
|
13
|
+
|
|
14
|
+
Dir[SPEC_ROOT.join('support/*.rb').to_s].each { |f| require f }
|
|
15
|
+
Dir[SPEC_ROOT.join('shared/*.rb').to_s].each { |f| require f }
|
|
16
|
+
|
|
17
|
+
require 'dry/component/container'
|
|
18
|
+
|
|
19
|
+
class Dry::Component::Container
|
|
20
|
+
setting :env, 'test'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
module TestNamespace
|
|
24
|
+
def remove_constants
|
|
25
|
+
constants.each do |name|
|
|
26
|
+
remove_const(name)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
RSpec.configure do |config|
|
|
32
|
+
config.disable_monkey_patching!
|
|
33
|
+
|
|
34
|
+
config.before do
|
|
35
|
+
@load_paths = $LOAD_PATH.dup
|
|
36
|
+
Object.const_set(:Test, Module.new { |m| m.extend(TestNamespace) })
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
config.after do
|
|
40
|
+
($LOAD_PATH - @load_paths).each do |path|
|
|
41
|
+
$LOAD_PATH.delete(path)
|
|
42
|
+
end
|
|
43
|
+
Test.remove_constants
|
|
44
|
+
Object.send(:remove_const, :Test)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'dry/component/container'
|
|
2
|
+
|
|
3
|
+
RSpec.describe Dry::Component::Config do
|
|
4
|
+
before do
|
|
5
|
+
class Test::App < Dry::Component::Container
|
|
6
|
+
configure do |config|
|
|
7
|
+
config.root = SPEC_ROOT.join('fixtures/test').realpath
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'loads config under component name' do
|
|
13
|
+
expect(Test::App.options.foo).to eql('bar')
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
require 'dry/component/container'
|
|
2
|
+
|
|
3
|
+
RSpec.describe Dry::Component::Container do
|
|
4
|
+
subject(:container) { Test::Container }
|
|
5
|
+
|
|
6
|
+
context 'with default core dir' do
|
|
7
|
+
before do
|
|
8
|
+
class Test::Container < Dry::Component::Container
|
|
9
|
+
configure do |config|
|
|
10
|
+
config.root = SPEC_ROOT.join('fixtures/test').realpath
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
load_paths!('lib')
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module Test
|
|
17
|
+
Import = Container.import_module
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
describe '.require' do
|
|
22
|
+
it 'requires a single file' do
|
|
23
|
+
container.require('lib/test/models')
|
|
24
|
+
|
|
25
|
+
expect(Test.const_defined?(:Models)).to be(true)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'requires many files when glob pattern is passed' do
|
|
29
|
+
container.require('lib/test/models/*.rb')
|
|
30
|
+
|
|
31
|
+
expect(Test::Models.const_defined?(:User)).to be(true)
|
|
32
|
+
expect(Test::Models.const_defined?(:Book)).to be(true)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe '.require_component' do
|
|
37
|
+
it 'requires components from configured load paths' do
|
|
38
|
+
container.require_component('test.foo')
|
|
39
|
+
|
|
40
|
+
expect(Test.const_defined?(:Foo)).to be(true)
|
|
41
|
+
expect(Test.const_defined?(:Dep)).to be(true)
|
|
42
|
+
|
|
43
|
+
expect(Test::Foo.new.dep).to be_instance_of(Test::Dep)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe '.boot!' do
|
|
49
|
+
shared_examples_for 'a booted component' do
|
|
50
|
+
it 'boots a given component and finalizes it' do
|
|
51
|
+
container.boot!(:bar)
|
|
52
|
+
|
|
53
|
+
expect(Test.const_defined?(:Bar)).to be(true)
|
|
54
|
+
expect(container['test.bar']).to eql('I was finalized')
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'expects a symbol identifier matching file name' do
|
|
58
|
+
expect {
|
|
59
|
+
container.boot!('bar')
|
|
60
|
+
}.to raise_error(ArgumentError, 'component identifier must be a symbol')
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'expects identifier to point to an existing boot file' do
|
|
64
|
+
expect {
|
|
65
|
+
container.boot!(:foo)
|
|
66
|
+
}.to raise_error(
|
|
67
|
+
ArgumentError,
|
|
68
|
+
'component identifier +foo+ is invalid or boot file is missing'
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
context 'with the default core dir' do
|
|
74
|
+
it_behaves_like 'a booted component' do
|
|
75
|
+
before do
|
|
76
|
+
class Test::Container < Dry::Component::Container
|
|
77
|
+
configure do |config|
|
|
78
|
+
config.root = SPEC_ROOT.join('fixtures/test').realpath
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
load_paths!('lib')
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
context 'with a custom core dir' do
|
|
88
|
+
it_behaves_like 'a booted component' do
|
|
89
|
+
before do
|
|
90
|
+
class Test::Container < Dry::Component::Container
|
|
91
|
+
configure do |config|
|
|
92
|
+
config.root = SPEC_ROOT.join('fixtures/other').realpath
|
|
93
|
+
config.core_dir = 'config'
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
load_paths!('lib')
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require 'dry/component/loader'
|
|
2
|
+
|
|
3
|
+
RSpec.describe Dry::Component::Loader do
|
|
4
|
+
before do
|
|
5
|
+
module Test
|
|
6
|
+
class Bar
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
shared_examples_for 'a valid component' do
|
|
12
|
+
describe '#name' do
|
|
13
|
+
it 'returns name of the constant' do
|
|
14
|
+
expect(component.name).to eql('Test::Bar')
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe '#constant' do
|
|
19
|
+
it 'returns the constant' do
|
|
20
|
+
expect(component.constant).to be(Test::Bar)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe '#identifier' do
|
|
25
|
+
it 'returns container identifier' do
|
|
26
|
+
expect(component.identifier).to eql('test.bar')
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe '#path' do
|
|
31
|
+
it 'returns relative path to file defining the component constant' do
|
|
32
|
+
expect(component.path).to eql('test/bar')
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe '#file' do
|
|
37
|
+
it 'returns relative path to file with ext defining the component constant' do
|
|
38
|
+
expect(component.file).to eql('test/bar.rb')
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe '#instance' do
|
|
43
|
+
it 'builds a component class instance' do
|
|
44
|
+
expect(component.instance).to be_instance_of(Test::Bar)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context 'from identifier as a symbol' do
|
|
50
|
+
subject(:component) { Dry::Component::Loader(:'test.bar') }
|
|
51
|
+
|
|
52
|
+
it_behaves_like 'a valid component'
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
context 'from identifier as a string' do
|
|
56
|
+
subject(:component) { Dry::Component::Loader('test.bar') }
|
|
57
|
+
|
|
58
|
+
it_behaves_like 'a valid component'
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
context 'from path' do
|
|
62
|
+
subject(:component) { Dry::Component::Loader('test/bar') }
|
|
63
|
+
|
|
64
|
+
it_behaves_like 'a valid component'
|
|
65
|
+
end
|
|
66
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: dry-component
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Piotr Solnica
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2015-12-24 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: memoizable
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0.4'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0.4'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: inflecto
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: 0.0.2
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - ">="
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: 0.0.2
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: dry-container
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0.2'
|
|
48
|
+
- - ">="
|
|
49
|
+
- !ruby/object:Gem::Version
|
|
50
|
+
version: 0.2.7
|
|
51
|
+
type: :runtime
|
|
52
|
+
prerelease: false
|
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
54
|
+
requirements:
|
|
55
|
+
- - "~>"
|
|
56
|
+
- !ruby/object:Gem::Version
|
|
57
|
+
version: '0.2'
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: 0.2.7
|
|
61
|
+
- !ruby/object:Gem::Dependency
|
|
62
|
+
name: dry-auto_inject
|
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - "~>"
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0.1'
|
|
68
|
+
type: :runtime
|
|
69
|
+
prerelease: false
|
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - "~>"
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0.1'
|
|
75
|
+
- !ruby/object:Gem::Dependency
|
|
76
|
+
name: dry-configurable
|
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "~>"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0.1'
|
|
82
|
+
type: :runtime
|
|
83
|
+
prerelease: false
|
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - "~>"
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '0.1'
|
|
89
|
+
- !ruby/object:Gem::Dependency
|
|
90
|
+
name: bundler
|
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '0'
|
|
96
|
+
type: :development
|
|
97
|
+
prerelease: false
|
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - ">="
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '0'
|
|
103
|
+
- !ruby/object:Gem::Dependency
|
|
104
|
+
name: rake
|
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - ">="
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0'
|
|
110
|
+
type: :development
|
|
111
|
+
prerelease: false
|
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - ">="
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '0'
|
|
117
|
+
- !ruby/object:Gem::Dependency
|
|
118
|
+
name: rspec
|
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - ">="
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '0'
|
|
124
|
+
type: :development
|
|
125
|
+
prerelease: false
|
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - ">="
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: '0'
|
|
131
|
+
description:
|
|
132
|
+
email:
|
|
133
|
+
- piotr.solnica@gmail.com
|
|
134
|
+
executables: []
|
|
135
|
+
extensions: []
|
|
136
|
+
extra_rdoc_files: []
|
|
137
|
+
files:
|
|
138
|
+
- ".gitignore"
|
|
139
|
+
- ".rspec"
|
|
140
|
+
- ".rubocop.yml"
|
|
141
|
+
- ".rubocop_todo.yml"
|
|
142
|
+
- ".travis.yml"
|
|
143
|
+
- CHANGELOG.md
|
|
144
|
+
- Gemfile
|
|
145
|
+
- LICENSE
|
|
146
|
+
- README.md
|
|
147
|
+
- Rakefile
|
|
148
|
+
- dry-component.gemspec
|
|
149
|
+
- lib/dry-component.rb
|
|
150
|
+
- lib/dry/component.rb
|
|
151
|
+
- lib/dry/component/config.rb
|
|
152
|
+
- lib/dry/component/container.rb
|
|
153
|
+
- lib/dry/component/loader.rb
|
|
154
|
+
- lib/dry/component/version.rb
|
|
155
|
+
- spec/fixtures/other/config/boot/bar.rb
|
|
156
|
+
- spec/fixtures/other/lib/test/dep.rb
|
|
157
|
+
- spec/fixtures/other/lib/test/foo.rb
|
|
158
|
+
- spec/fixtures/other/lib/test/models.rb
|
|
159
|
+
- spec/fixtures/other/lib/test/models/book.rb
|
|
160
|
+
- spec/fixtures/other/lib/test/models/user.rb
|
|
161
|
+
- spec/fixtures/test/config/application.yml
|
|
162
|
+
- spec/fixtures/test/core/boot/bar.rb
|
|
163
|
+
- spec/fixtures/test/lib/test/dep.rb
|
|
164
|
+
- spec/fixtures/test/lib/test/foo.rb
|
|
165
|
+
- spec/fixtures/test/lib/test/models.rb
|
|
166
|
+
- spec/fixtures/test/lib/test/models/book.rb
|
|
167
|
+
- spec/fixtures/test/lib/test/models/user.rb
|
|
168
|
+
- spec/spec_helper.rb
|
|
169
|
+
- spec/unit/config_spec.rb
|
|
170
|
+
- spec/unit/container_spec.rb
|
|
171
|
+
- spec/unit/loader_spec.rb
|
|
172
|
+
homepage: https://github.com/dryrb/dry-component
|
|
173
|
+
licenses:
|
|
174
|
+
- MIT
|
|
175
|
+
metadata: {}
|
|
176
|
+
post_install_message:
|
|
177
|
+
rdoc_options: []
|
|
178
|
+
require_paths:
|
|
179
|
+
- lib
|
|
180
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
181
|
+
requirements:
|
|
182
|
+
- - ">="
|
|
183
|
+
- !ruby/object:Gem::Version
|
|
184
|
+
version: '0'
|
|
185
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
186
|
+
requirements:
|
|
187
|
+
- - ">="
|
|
188
|
+
- !ruby/object:Gem::Version
|
|
189
|
+
version: '0'
|
|
190
|
+
requirements: []
|
|
191
|
+
rubyforge_project:
|
|
192
|
+
rubygems_version: 2.4.5.1
|
|
193
|
+
signing_key:
|
|
194
|
+
specification_version: 4
|
|
195
|
+
summary: Organize your code into reusable components
|
|
196
|
+
test_files:
|
|
197
|
+
- spec/fixtures/other/config/boot/bar.rb
|
|
198
|
+
- spec/fixtures/other/lib/test/dep.rb
|
|
199
|
+
- spec/fixtures/other/lib/test/foo.rb
|
|
200
|
+
- spec/fixtures/other/lib/test/models.rb
|
|
201
|
+
- spec/fixtures/other/lib/test/models/book.rb
|
|
202
|
+
- spec/fixtures/other/lib/test/models/user.rb
|
|
203
|
+
- spec/fixtures/test/config/application.yml
|
|
204
|
+
- spec/fixtures/test/core/boot/bar.rb
|
|
205
|
+
- spec/fixtures/test/lib/test/dep.rb
|
|
206
|
+
- spec/fixtures/test/lib/test/foo.rb
|
|
207
|
+
- spec/fixtures/test/lib/test/models.rb
|
|
208
|
+
- spec/fixtures/test/lib/test/models/book.rb
|
|
209
|
+
- spec/fixtures/test/lib/test/models/user.rb
|
|
210
|
+
- spec/spec_helper.rb
|
|
211
|
+
- spec/unit/config_spec.rb
|
|
212
|
+
- spec/unit/container_spec.rb
|
|
213
|
+
- spec/unit/loader_spec.rb
|