nxt_registry 0.1.4 → 0.3.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 +4 -4
- data/.circleci/config.yml +56 -0
- data/.editorconfig +15 -0
- data/.rakeTasks +1 -1
- data/CHANGELOG.md +37 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +25 -22
- data/README.md +127 -55
- data/lib/nxt_registry.rb +34 -9
- data/lib/nxt_registry/recursive_registry.rb +1 -1
- data/lib/nxt_registry/registry.rb +97 -44
- data/lib/nxt_registry/{nested_registry_builder.rb → registry_builder.rb} +1 -1
- data/lib/nxt_registry/version.rb +1 -1
- data/nxt_registry.gemspec +2 -2
- metadata +11 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 121af631fa49f89d2b47599adcf3122401409299f65d755f7ba3cb418734cdf4
|
4
|
+
data.tar.gz: e6d94a93edf4bb250186242e5892f0dcda7df9c71c23be5a4b8ddca5420eed0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b0601a25a8325fe3fb21f2cfdf25e8710c3b219c135999fea2bc0bc325713bf3f20f321f4aadbdffcc50f4d03557c0fc4ba1008d52efe69e3f38400e4dfdf0b9
|
7
|
+
data.tar.gz: 770c75ffca22aa1c7de4af1de955abf2044d9dca121b566e277f5d0fd637e41bc58231ae1edfd38a11af69279c05928f001e98561edae77edd060499bcf9bdf4
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# Ruby CircleCI 2.0 configuration file
|
2
|
+
#
|
3
|
+
# Check https://circleci.com/docs/2.0/language-ruby/ for more details
|
4
|
+
#
|
5
|
+
version: 2
|
6
|
+
jobs:
|
7
|
+
build:
|
8
|
+
docker:
|
9
|
+
# specify the version you desire here
|
10
|
+
- image: circleci/ruby:2.6.5-node
|
11
|
+
environment:
|
12
|
+
BUNDLER_VERSION: 2.1.4
|
13
|
+
|
14
|
+
working_directory: ~/repo
|
15
|
+
|
16
|
+
steps:
|
17
|
+
- checkout
|
18
|
+
|
19
|
+
# Download and cache dependencies
|
20
|
+
- restore_cache:
|
21
|
+
keys:
|
22
|
+
- v1-dependencies-{{ checksum "Gemfile.lock" }}
|
23
|
+
|
24
|
+
- run: gem install bundler --version $BUNDLER_VERSION
|
25
|
+
|
26
|
+
- run:
|
27
|
+
name: install dependencies
|
28
|
+
command: |
|
29
|
+
bundle install --jobs=4 --retry=3 --path vendor/bundle
|
30
|
+
|
31
|
+
- save_cache:
|
32
|
+
paths:
|
33
|
+
- ./vendor/bundle
|
34
|
+
key: v1-dependencies-{{ checksum "Gemfile.lock" }}
|
35
|
+
|
36
|
+
# run tests!
|
37
|
+
- run:
|
38
|
+
name: run tests
|
39
|
+
command: |
|
40
|
+
mkdir /tmp/test-results
|
41
|
+
TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | \
|
42
|
+
circleci tests split --split-by=timings)"
|
43
|
+
|
44
|
+
bundle exec rspec \
|
45
|
+
--format progress \
|
46
|
+
--format RspecJunitFormatter \
|
47
|
+
--out /tmp/test-results/rspec.xml \
|
48
|
+
--format progress \
|
49
|
+
$TEST_FILES
|
50
|
+
|
51
|
+
# collect reports
|
52
|
+
- store_test_results:
|
53
|
+
path: /tmp/test-results
|
54
|
+
- store_artifacts:
|
55
|
+
path: /tmp/test-results
|
56
|
+
destination: test-results
|
data/.editorconfig
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# EditorConfig is awesome: http://EditorConfig.org
|
2
|
+
|
3
|
+
# top-most EditorConfig file
|
4
|
+
root = true
|
5
|
+
|
6
|
+
# Unix-style newlines with a newline ending every file
|
7
|
+
[*]
|
8
|
+
end_of_line = lf
|
9
|
+
insert_final_newline = true
|
10
|
+
charset = utf-8
|
11
|
+
|
12
|
+
[*.{rb,yml,json,rake}]
|
13
|
+
indent_style = space
|
14
|
+
indent_size = 2
|
15
|
+
trim_trailing_whitespace = true
|
data/.rakeTasks
CHANGED
@@ -4,4 +4,4 @@ You are allowed to:
|
|
4
4
|
1. Remove rake task
|
5
5
|
2. Add existing rake tasks
|
6
6
|
To add existing rake tasks automatically delete this file and reload the project.
|
7
|
-
--><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Build nxt_registry-0.1.
|
7
|
+
--><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Build nxt_registry-0.1.4.gem into the pkg directory" fullCmd="build" taksId="build" /><RakeTask description="Remove any temporary products" fullCmd="clean" taksId="clean" /><RakeTask description="Remove any generated files" fullCmd="clobber" taksId="clobber" /><RakeTask description="Build and install nxt_registry-0.1.4.gem into system gems" fullCmd="install" taksId="install" /><RakeGroup description="" fullCmd="" taksId="install"><RakeTask description="Build and install nxt_registry-0.1.4.gem into system gems without network access" fullCmd="install:local" taksId="local" /></RakeGroup><RakeTask description="Create tag v0.1.4 and build and push nxt_registry-0.1.4.gem to https://rubygems.org" fullCmd="release[remote]" taksId="release[remote]" /><RakeTask description="Run RSpec code examples" fullCmd="spec" taksId="spec" /><RakeTask description="" fullCmd="default" taksId="default" /><RakeTask description="" fullCmd="release" taksId="release" /><RakeGroup description="" fullCmd="" taksId="release"><RakeTask description="" fullCmd="release:guard_clean" taksId="guard_clean" /><RakeTask description="" fullCmd="release:rubygem_push" taksId="rubygem_push" /><RakeTask description="" fullCmd="release:source_control_push" taksId="source_control_push" /></RakeGroup></RakeGroup></Settings>
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# v0.3.1 2020-09-23
|
2
|
+
|
3
|
+
- Allow to define custom accessors for registries
|
4
|
+
|
5
|
+
# v0.3.0 2020-09-10
|
6
|
+
|
7
|
+
### Breaking Changes
|
8
|
+
|
9
|
+
- Toggled interface for resolve(!) and register(!)
|
10
|
+
- Allow to register values in nested registries
|
11
|
+
- Rename nested method into level
|
12
|
+
- Provide registry readers
|
13
|
+
- Remove Singleton extension
|
14
|
+
- Allow to resolve paths
|
15
|
+
- Pass key to default block when it takes an argument
|
16
|
+
|
17
|
+
[Compare v0.2.1...v0.3.0](https://github.com/nxt-insurance/nxt_registry/compare/v0.2.1...v0.3.0)
|
18
|
+
|
19
|
+
# v0.2.1 2020-08-14
|
20
|
+
|
21
|
+
### Fixed
|
22
|
+
|
23
|
+
- Fixed Registry#fetch to raise key error in case of missing key
|
24
|
+
|
25
|
+
[Compare v0.2.0...v0.2.1](https://github.com/nxt-insurance/nxt_registry/compare/v0.2.0...v0.2.1)
|
26
|
+
|
27
|
+
|
28
|
+
# v0.2.0 2020-07-24
|
29
|
+
|
30
|
+
### Added
|
31
|
+
|
32
|
+
- [internal] Added NxtRegistry::Singleton
|
33
|
+
- Added NxtRegistry::Singleton interface
|
34
|
+
- Make name optional and have object_id.to_s as default name
|
35
|
+
- Fix readme
|
36
|
+
|
37
|
+
[Compare v0.1.5...v0.2.0](https://github.com/nxt-insurance/nxt_registry/compare/v0.1.5...v0.2.0)
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,46 +1,48 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
nxt_registry (0.1
|
4
|
+
nxt_registry (0.3.1)
|
5
5
|
activesupport
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
activesupport (6.0.
|
10
|
+
activesupport (6.0.3.3)
|
11
11
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
12
12
|
i18n (>= 0.7, < 2)
|
13
13
|
minitest (~> 5.1)
|
14
14
|
tzinfo (~> 1.1)
|
15
|
-
zeitwerk (~> 2.2)
|
16
|
-
coderay (1.1.
|
17
|
-
concurrent-ruby (1.1.
|
18
|
-
diff-lcs (1.
|
19
|
-
i18n (1.8.
|
15
|
+
zeitwerk (~> 2.2, >= 2.2.2)
|
16
|
+
coderay (1.1.3)
|
17
|
+
concurrent-ruby (1.1.7)
|
18
|
+
diff-lcs (1.4.4)
|
19
|
+
i18n (1.8.5)
|
20
20
|
concurrent-ruby (~> 1.0)
|
21
|
-
method_source (0.
|
22
|
-
minitest (5.14.
|
23
|
-
pry (0.
|
24
|
-
coderay (~> 1.1
|
25
|
-
method_source (~>
|
26
|
-
rake (
|
21
|
+
method_source (1.0.0)
|
22
|
+
minitest (5.14.2)
|
23
|
+
pry (0.13.1)
|
24
|
+
coderay (~> 1.1)
|
25
|
+
method_source (~> 1.0)
|
26
|
+
rake (12.3.3)
|
27
27
|
rspec (3.9.0)
|
28
28
|
rspec-core (~> 3.9.0)
|
29
29
|
rspec-expectations (~> 3.9.0)
|
30
30
|
rspec-mocks (~> 3.9.0)
|
31
|
-
rspec-core (3.9.
|
32
|
-
rspec-support (~> 3.9.
|
33
|
-
rspec-expectations (3.9.
|
31
|
+
rspec-core (3.9.2)
|
32
|
+
rspec-support (~> 3.9.3)
|
33
|
+
rspec-expectations (3.9.2)
|
34
34
|
diff-lcs (>= 1.2.0, < 2.0)
|
35
35
|
rspec-support (~> 3.9.0)
|
36
|
-
rspec-mocks (3.9.
|
36
|
+
rspec-mocks (3.9.1)
|
37
37
|
diff-lcs (>= 1.2.0, < 2.0)
|
38
38
|
rspec-support (~> 3.9.0)
|
39
|
-
rspec-support (3.9.
|
39
|
+
rspec-support (3.9.3)
|
40
|
+
rspec_junit_formatter (0.4.1)
|
41
|
+
rspec-core (>= 2, < 4, != 2.12.0)
|
40
42
|
thread_safe (0.3.6)
|
41
|
-
tzinfo (1.2.
|
43
|
+
tzinfo (1.2.7)
|
42
44
|
thread_safe (~> 0.1)
|
43
|
-
zeitwerk (2.
|
45
|
+
zeitwerk (2.4.0)
|
44
46
|
|
45
47
|
PLATFORMS
|
46
48
|
ruby
|
@@ -49,8 +51,9 @@ DEPENDENCIES
|
|
49
51
|
bundler (~> 2.0)
|
50
52
|
nxt_registry!
|
51
53
|
pry
|
52
|
-
rake (~>
|
54
|
+
rake (~> 12)
|
53
55
|
rspec (~> 3.0)
|
56
|
+
rspec_junit_formatter
|
54
57
|
|
55
58
|
BUNDLED WITH
|
56
|
-
2.
|
59
|
+
2.1.4
|
data/README.md
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
[](https://circleci.com/gh/nxt-insurance/nxt_registry)
|
2
|
+
|
1
3
|
# NxtRegistry
|
2
4
|
|
3
|
-
NxtRegistry is a simple implementation of the container pattern. It allows you to register and resolve values in nested
|
4
|
-
structures
|
5
|
+
`NxtRegistry` is a simple implementation of the container pattern. It allows you to register and resolve values in nested
|
6
|
+
structures.
|
5
7
|
|
6
8
|
## Installation
|
7
9
|
|
@@ -21,80 +23,148 @@ Or install it yourself as:
|
|
21
23
|
|
22
24
|
## Usage
|
23
25
|
|
26
|
+
### Simple use case
|
27
|
+
|
28
|
+
## Instance Level
|
29
|
+
|
30
|
+
To use `NxtRegistry` on an instance level simply include it and build registries like so:
|
31
|
+
|
24
32
|
```ruby
|
25
33
|
class Example
|
26
34
|
include NxtRegistry
|
27
35
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
nested :via, memoize: true, call: true, default: -> { [] } do
|
33
|
-
attrs %i[train car plane horse] # restrict the attributes that can be registered
|
34
|
-
resolver ->(value) { value } # do something with your registered value here
|
35
|
-
transform_keys ->(key) { key.upcase } # transform keys
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
36
|
+
registry :languages do
|
37
|
+
register(:ruby, 'Stone')
|
38
|
+
register(:python, 'Snake')
|
39
|
+
register(:javascript, 'undefined')
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
43
|
example = Example.new
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
# Register an array with a value by calling the accessor with a key, value pair
|
48
|
-
example.passengers.from(:a).to(:b).via(:train, ['Andy']) # => ['Andy']
|
49
|
-
|
50
|
-
# In case you try to register the same key again you will get an error
|
51
|
-
example.passengers.from(:a).to(:b).via(:train, ['Andy'])
|
52
|
-
# => NxtRegistry::Errors::KeyAlreadyRegisteredError
|
53
|
-
# (Key 'train' already registered in registry 'from.to.via')
|
54
|
-
# NxtRegistry::Errors::KeyAlreadyRegisteredError inherits from KeyError
|
55
|
-
|
56
|
-
# You can force values on the registry by using the bang method
|
57
|
-
example.passengers.from(:a).to(:b).via!(:train, ['Andreas'])
|
44
|
+
example.registry(:languages).resolve(:ruby) # => 'Stone'
|
45
|
+
```
|
58
46
|
|
59
|
-
|
60
|
-
# (meaning no KeyNotRegisteredError will be raised when nothing was registered)
|
61
|
-
example.passengers.from(:a).to(:b).via!(:train)
|
62
|
-
# Since there is a default defined for this registry, it does not make any sense
|
63
|
-
# since there is always a value. But you get the point...
|
47
|
+
Alternatively you can also create instances of `NxtRegistry::Registry`
|
64
48
|
|
65
|
-
|
66
|
-
|
67
|
-
|
49
|
+
```ruby
|
50
|
+
registry = NxtRegistry::Registry.new do
|
51
|
+
register(:andy, 'Andy')
|
52
|
+
register(:anthony, 'Anthony')
|
53
|
+
register(:aki, 'Aki')
|
54
|
+
end
|
68
55
|
|
69
|
-
#
|
70
|
-
example.passengers.from(:a).to(:b).via(:car) << 'Lütfi' # => ['Lütif']
|
71
|
-
example.passengers.from(:a).to(:b).via(:plane) += %w[Nils Rapha]
|
72
|
-
example.passengers.from(:a).to(:b).via(:plane) # => ['Nils', 'Rapha']
|
56
|
+
registry.resolve(:aki) # => 'Aki'
|
73
57
|
|
74
58
|
```
|
75
59
|
|
60
|
+
## Class Level
|
61
|
+
|
62
|
+
You can add registries on the class level simply by extending your class with `NxtRegistry`
|
76
63
|
|
77
64
|
```ruby
|
78
65
|
class OtherExample
|
79
66
|
extend NxtRegistry
|
80
|
-
|
81
|
-
|
82
|
-
REGISTRY = registry(:errors) do
|
83
|
-
# procs are called directly if not defined otherwise
|
67
|
+
|
68
|
+
registry(:errors) do
|
84
69
|
register(KeyError, ->(error) { puts 'KeyError handler' } )
|
85
70
|
register(ArgumentError, ->(error) { puts 'ArgumentError handler' } )
|
86
71
|
end
|
72
|
+
|
73
|
+
registry(:country_codes) do
|
74
|
+
register(:germany, :de)
|
75
|
+
register(:england, :uk)
|
76
|
+
register(:france, :fr)
|
77
|
+
end
|
87
78
|
end
|
88
79
|
|
89
|
-
|
90
|
-
# level where you want to register or resolve values. Equivalently to the named interface you can
|
91
|
-
# use register! and resolve! to softly resolve or forcfully register values.
|
92
|
-
OtherExample::REGISTRY.resolve(KeyError)
|
80
|
+
OtherExample.registry(:errors).resolve(KeyError)
|
93
81
|
# KeyError handler
|
94
82
|
# => nil
|
83
|
+
OtherExample.registry(:country_codes).resolve(:germany)
|
84
|
+
# => :de
|
85
|
+
```
|
86
|
+
### Readers
|
87
|
+
|
88
|
+
Access your defined registries with the `registry(:country_code)` method.
|
89
|
+
|
90
|
+
### Nesting registries
|
91
|
+
|
92
|
+
You can also simply nest registries like so:
|
93
|
+
|
94
|
+
```ruby
|
95
|
+
class Nested
|
96
|
+
extend NxtRegistry
|
97
|
+
|
98
|
+
registry :developers do
|
99
|
+
register(:frontend) do
|
100
|
+
register(:igor, 'Igor')
|
101
|
+
register(:ben, 'Ben')
|
102
|
+
end
|
103
|
+
|
104
|
+
register(:backend) do
|
105
|
+
register(:rapha, 'Rapha')
|
106
|
+
register(:aki, 'Aki')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
Nested.registry(:developers).resolve(:frontend, :igor)
|
112
|
+
# => 'Igor'
|
113
|
+
```
|
114
|
+
|
115
|
+
|
116
|
+
### Defining specific nesting levels of a registry
|
117
|
+
|
118
|
+
Another feature of `NxtRegistry` is that you can define the nesting levels for a registry. Levels allow you to dynamically
|
119
|
+
register values within the defined levels. This means that on any level the registry will resolve to another registry and
|
120
|
+
you can register values into a deeply nested structure.
|
121
|
+
|
122
|
+
```ruby
|
123
|
+
class Layer
|
124
|
+
extend NxtRegistry
|
125
|
+
|
126
|
+
registry :from do
|
127
|
+
level :to do
|
128
|
+
level :via
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
# On every upper level every resolve returns a registry
|
134
|
+
Layer.registry(:from) # => Registry[from]
|
135
|
+
Layer.registry(:from).resolve(:munich) # => Registry[to] -> {}
|
136
|
+
Layer.registry(:from).resolve(:amsterdam) # => Registry[to] -> {}
|
137
|
+
Layer.registry(:from).resolve(:any_key) # => Registry[to] -> {}
|
138
|
+
Layer.registry(:from).resolve(:munich, :amsterdam) # => Registry[via] -> {}
|
139
|
+
|
140
|
+
# Register a value on the bottom level
|
141
|
+
Layer.registry(:from).resolve(:munich, :amsterdam).register(:train, -> { 'train' })
|
142
|
+
# Resolve the complete path
|
143
|
+
Layer.registry(:from).resolve(:munich, :amsterdam, :train) # => 'train'
|
144
|
+
```
|
145
|
+
|
146
|
+
For registries with multiple levels the normal syntax for registering and resolving becomes quite weird and unreadable. This is why
|
147
|
+
every registry can be accessed through it's name or a custom accessor. The above example then can be simplified as follows.
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
class Layer
|
151
|
+
extend NxtRegistry
|
152
|
+
|
153
|
+
registry :path, accessor: :from do # registry named path, can be accessed with .from(...)
|
154
|
+
level :to do
|
155
|
+
level :via
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
95
159
|
|
160
|
+
# Register a value
|
161
|
+
Layer.registry(:path).from(:munich).to(:amsterdam).via(:train, -> { 'train' })
|
162
|
+
# Resolve the complete path
|
163
|
+
Layer.registry(:path).from(:munich).to(:amsterdam).via(:train) # => 'train'
|
96
164
|
```
|
97
165
|
|
166
|
+
*Note that this feature is also available for registries with a single level only.*
|
167
|
+
|
98
168
|
### Restrict attributes to a certain set
|
99
169
|
|
100
170
|
Use `attrs` to restrict which attributes can be registered on a specific level.
|
@@ -113,7 +183,7 @@ registry :example, default: ->(value) { 'default' }
|
|
113
183
|
|
114
184
|
### Blocks
|
115
185
|
|
116
|
-
When you register a block value that can be called,
|
186
|
+
When you register a block value that can be called, it will automatically be called when you resolve the value.
|
117
187
|
If that's not what you want, you can configure your registry (on each level) not to call blocks directly by defining `call false`
|
118
188
|
|
119
189
|
```ruby
|
@@ -124,7 +194,7 @@ end
|
|
124
194
|
|
125
195
|
### Memoize
|
126
196
|
|
127
|
-
Values are memoized per default. Switch it off with `
|
197
|
+
Values are memoized per default. Switch it off with `memoize: false`
|
128
198
|
|
129
199
|
```ruby
|
130
200
|
registry :example, memoize: false do
|
@@ -141,7 +211,8 @@ registry.resolve(:one)
|
|
141
211
|
|
142
212
|
### Resolver
|
143
213
|
|
144
|
-
You can register a resolver block if you want to lay hands on your values after they have been resolved.
|
214
|
+
You can register a resolver block if you want to lay hands on your values after they have been resolved.
|
215
|
+
A resolver can be anything that implements `:call` to which the value is passed.
|
145
216
|
|
146
217
|
```ruby
|
147
218
|
registry :example do
|
@@ -155,9 +226,10 @@ registry.resolve(:one)
|
|
155
226
|
|
156
227
|
### Transform keys
|
157
228
|
|
158
|
-
NxtRegistry uses a plain ruby hash to store values internally. Per default all keys used are transformed with `&:to_s`.
|
159
|
-
Thus you can use symbols or strings to register and resolve values. If it's not what you want, switch it off with
|
160
|
-
or define your own key transformer by assigning a block to transform_keys:
|
229
|
+
`NxtRegistry` uses a plain ruby hash to store values internally. Per default all keys used are transformed with `&:to_s`.
|
230
|
+
Thus you can use symbols or strings to register and resolve values. If it's not what you want, switch it off with
|
231
|
+
`transform_keys false` or define your own key transformer by assigning a block to transform_keys:
|
232
|
+
`transform_keys ->(key) { key.upcase }`
|
161
233
|
|
162
234
|
```ruby
|
163
235
|
registry :example do
|
@@ -172,7 +244,7 @@ registry.resolve('BOMBSHELL')
|
|
172
244
|
### Customize registry errors
|
173
245
|
|
174
246
|
You can also customize what kind of errors are being raised in case a of a key was not registered or was already registered.
|
175
|
-
by providing
|
247
|
+
by providing blocks or a handler responding to :call for `on_key_already_registered` and `on_key_already_registered`
|
176
248
|
|
177
249
|
## Development
|
178
250
|
|
data/lib/nxt_registry.rb
CHANGED
@@ -1,18 +1,43 @@
|
|
1
1
|
require 'active_support/core_ext'
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
2
|
+
require 'nxt_registry/version'
|
3
|
+
require 'nxt_registry/blank'
|
4
|
+
require 'nxt_registry/attribute'
|
5
|
+
require 'nxt_registry/errors'
|
6
|
+
require 'nxt_registry/registry_builder'
|
7
|
+
require 'nxt_registry/registry'
|
8
|
+
require 'nxt_registry/recursive_registry'
|
9
9
|
|
10
10
|
module NxtRegistry
|
11
11
|
def registry(name, **options, &config)
|
12
|
-
Registry
|
12
|
+
build_registry(Registry, name, **options, &config)
|
13
13
|
end
|
14
14
|
|
15
15
|
def recursive_registry(name, **options, &config)
|
16
|
-
RecursiveRegistry
|
16
|
+
build_registry(RecursiveRegistry, name, **options, &config)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def build_registry(registry_class, name, **options, &config)
|
22
|
+
if registries.key?(name)
|
23
|
+
registry = registries.fetch(name)
|
24
|
+
if registry.configured
|
25
|
+
registry
|
26
|
+
else
|
27
|
+
raise_unconfigured_registry_accessed(name)
|
28
|
+
end
|
29
|
+
else
|
30
|
+
registry = registry_class.new(name, **options, &config)
|
31
|
+
registries[name] ||= registry
|
32
|
+
registry
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def raise_unconfigured_registry_accessed(name)
|
37
|
+
raise ArgumentError, "The registry #{name} must be configured before accessed!"
|
38
|
+
end
|
39
|
+
|
40
|
+
def registries
|
41
|
+
@registries ||= {}
|
17
42
|
end
|
18
43
|
end
|
@@ -18,7 +18,7 @@ module NxtRegistry
|
|
18
18
|
attr_reader :options, :config, :level
|
19
19
|
|
20
20
|
def set_nested_builder_as_default
|
21
|
-
self.default =
|
21
|
+
self.default = RegistryBuilder.new do
|
22
22
|
RecursiveRegistry.new("level_#{(level + 1)}", **options.merge(level: (level + 1)), &config)
|
23
23
|
end
|
24
24
|
end
|
@@ -1,40 +1,52 @@
|
|
1
1
|
module NxtRegistry
|
2
2
|
class Registry
|
3
|
-
def initialize(name, **options, &config)
|
3
|
+
def initialize(name = object_id.to_s, **options, &config)
|
4
|
+
@options = options
|
4
5
|
@name = name
|
5
6
|
@parent = options[:parent]
|
6
7
|
@is_leaf = true
|
7
|
-
@namespace =
|
8
|
+
@namespace = build_namespace
|
8
9
|
@config = config
|
9
|
-
@options = options
|
10
10
|
@store = {}
|
11
11
|
@attrs = nil
|
12
|
+
@configured = false
|
12
13
|
|
13
14
|
setup_defaults(options)
|
14
|
-
configure(&config)
|
15
|
+
configure(&config) if block_given? || parent
|
15
16
|
end
|
16
17
|
|
17
18
|
attr_reader :name
|
19
|
+
attr_accessor :configured
|
18
20
|
|
19
|
-
def
|
20
|
-
# TODO: Ensure that nesting is included in defined attrs
|
21
|
+
def level(name, **options, &config)
|
21
22
|
options = options.merge(parent: self)
|
22
23
|
|
23
|
-
if
|
24
|
+
if is_a_blank?(default)
|
24
25
|
self.is_leaf = false
|
25
26
|
|
26
|
-
self.default =
|
27
|
+
self.default = RegistryBuilder.new do
|
27
28
|
Registry.new(name, **options, &config)
|
28
29
|
end
|
29
30
|
|
31
|
+
# Call the builder once to guarantee we do not create a registry with a broken setup
|
30
32
|
default.call
|
31
|
-
elsif default.is_a?(
|
32
|
-
raise ArgumentError,
|
33
|
+
elsif default.is_a?(RegistryBuilder)
|
34
|
+
raise ArgumentError, 'Multiple nestings on the same level'
|
33
35
|
else
|
34
|
-
raise ArgumentError,
|
36
|
+
raise ArgumentError, 'Default values cannot be defined on registries that nest others'
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
40
|
+
def registry(name, **options, &config)
|
41
|
+
opts = options.merge(parent: self)
|
42
|
+
register(name, Registry.new(name, **opts, &config))
|
43
|
+
end
|
44
|
+
|
45
|
+
def registry!(name, **options, &config)
|
46
|
+
opts = options.merge(parent: self)
|
47
|
+
register!(name, Registry.new(name, **opts, &config))
|
48
|
+
end
|
49
|
+
|
38
50
|
def attr(name)
|
39
51
|
key = transformed_key(name)
|
40
52
|
raise KeyError, "Attribute #{key} already registered in #{namespace}" if attrs[key]
|
@@ -49,20 +61,40 @@ module NxtRegistry
|
|
49
61
|
args.each { |name| attr(name) }
|
50
62
|
end
|
51
63
|
|
52
|
-
def register(key, value)
|
53
|
-
|
64
|
+
def register(key = Blank.new, value = Blank.new, **options, &block)
|
65
|
+
if block_given?
|
66
|
+
if is_a_blank?(value)
|
67
|
+
registry(key, **options, &block)
|
68
|
+
else
|
69
|
+
raise_register_argument_error
|
70
|
+
end
|
71
|
+
else
|
72
|
+
__register(key, value, raise_on_key_already_registered: true)
|
73
|
+
end
|
54
74
|
end
|
55
75
|
|
56
|
-
def register!(key, value)
|
57
|
-
|
76
|
+
def register!(key = Blank.new, value = Blank.new, **options, &block)
|
77
|
+
if block_given?
|
78
|
+
if is_a_blank?(value)
|
79
|
+
registry!(key, **options, &block)
|
80
|
+
else
|
81
|
+
raise_register_argument_error
|
82
|
+
end
|
83
|
+
else
|
84
|
+
__register(key, value, raise_on_key_already_registered: false)
|
85
|
+
end
|
58
86
|
end
|
59
87
|
|
60
|
-
def resolve(
|
61
|
-
|
88
|
+
def resolve!(*keys)
|
89
|
+
keys.inject(self) do |current_registry, key|
|
90
|
+
current_registry.send(:__resolve, key, raise_on_key_not_registered: true)
|
91
|
+
end
|
62
92
|
end
|
63
93
|
|
64
|
-
def resolve
|
65
|
-
|
94
|
+
def resolve(*keys)
|
95
|
+
keys.inject(self) do |current_registry, key|
|
96
|
+
current_registry.send(:__resolve, key, raise_on_key_not_registered: false) || break
|
97
|
+
end
|
66
98
|
end
|
67
99
|
|
68
100
|
def to_h
|
@@ -70,11 +102,11 @@ module NxtRegistry
|
|
70
102
|
end
|
71
103
|
|
72
104
|
def [](key)
|
73
|
-
|
105
|
+
resolve!(key)
|
74
106
|
end
|
75
107
|
|
76
108
|
def []=(key, value)
|
77
|
-
|
109
|
+
register(key, value)
|
78
110
|
end
|
79
111
|
|
80
112
|
def keys
|
@@ -93,11 +125,11 @@ module NxtRegistry
|
|
93
125
|
store.exclude?(transformed_key(key))
|
94
126
|
end
|
95
127
|
|
96
|
-
def fetch(key,
|
97
|
-
store.fetch(transformed_key(key),
|
128
|
+
def fetch(key, *args, &block)
|
129
|
+
store.fetch(transformed_key(key), *args, &block)
|
98
130
|
end
|
99
131
|
|
100
|
-
delegate :size, :values, :each, to: :store
|
132
|
+
delegate :size, :values, :each, :freeze, to: :store
|
101
133
|
|
102
134
|
def configure(&block)
|
103
135
|
define_accessors
|
@@ -111,6 +143,8 @@ module NxtRegistry
|
|
111
143
|
instance_exec(&block)
|
112
144
|
end
|
113
145
|
end
|
146
|
+
|
147
|
+
self.configured = true
|
114
148
|
end
|
115
149
|
|
116
150
|
def to_s
|
@@ -121,44 +155,43 @@ module NxtRegistry
|
|
121
155
|
|
122
156
|
private
|
123
157
|
|
124
|
-
attr_reader :namespace, :parent, :config, :store, :options
|
158
|
+
attr_reader :namespace, :parent, :config, :store, :options, :accessor
|
125
159
|
attr_accessor :is_leaf
|
126
160
|
|
127
161
|
def is_leaf?
|
128
162
|
@is_leaf
|
129
163
|
end
|
130
164
|
|
131
|
-
def __register(key, value,
|
165
|
+
def __register(key, value, raise_on_key_already_registered: true)
|
132
166
|
key = transformed_key(key)
|
133
167
|
|
134
168
|
raise ArgumentError, "Not allowed to register values in a registry that contains nested registries" unless is_leaf
|
135
169
|
raise KeyError, "Keys are restricted to #{attrs.keys}" if attribute_not_allowed?(key)
|
136
170
|
|
137
|
-
on_key_already_registered && on_key_already_registered.call(key) if store[key] &&
|
171
|
+
on_key_already_registered && on_key_already_registered.call(key) if store[key] && raise_on_key_already_registered
|
138
172
|
|
139
173
|
store[key] = value
|
140
174
|
end
|
141
175
|
|
142
|
-
def __resolve(key,
|
176
|
+
def __resolve(key, raise_on_key_not_registered: true)
|
143
177
|
key = transformed_key(key)
|
144
178
|
|
145
179
|
value = if is_leaf?
|
146
|
-
if store
|
180
|
+
if store.key?(key)
|
147
181
|
store.fetch(key)
|
148
182
|
else
|
149
|
-
if
|
150
|
-
return unless
|
183
|
+
if is_a_blank?(default)
|
184
|
+
return unless raise_on_key_not_registered
|
151
185
|
|
152
186
|
on_key_not_registered && on_key_not_registered.call(key)
|
153
187
|
else
|
154
|
-
value = resolve_default
|
188
|
+
value = resolve_default(key)
|
155
189
|
return value unless memoize
|
156
190
|
|
157
191
|
store[key] ||= value
|
158
192
|
end
|
159
193
|
end
|
160
194
|
else
|
161
|
-
# Call nested registry builder when we are not a leaf
|
162
195
|
store[key] ||= default.call
|
163
196
|
end
|
164
197
|
|
@@ -176,24 +209,28 @@ module NxtRegistry
|
|
176
209
|
end
|
177
210
|
|
178
211
|
def define_interface
|
179
|
-
|
180
|
-
|
212
|
+
raise_invalid_accessor_name(accessor) if respond_to?(accessor)
|
213
|
+
accessor_with_bang = "#{accessor}!"
|
214
|
+
raise_invalid_accessor_name(accessor_with_bang) if respond_to?(accessor_with_bang)
|
215
|
+
|
216
|
+
define_singleton_method accessor do |key = Blank.new, value = Blank.new|
|
217
|
+
return self if is_a_blank?(key)
|
181
218
|
|
182
219
|
key = transformed_key(key)
|
183
220
|
|
184
|
-
if
|
221
|
+
if is_a_blank?(value)
|
185
222
|
resolve(key)
|
186
223
|
else
|
187
224
|
register(key, value)
|
188
225
|
end
|
189
226
|
end
|
190
227
|
|
191
|
-
define_singleton_method
|
192
|
-
return self if
|
228
|
+
define_singleton_method accessor_with_bang do |key = Blank.new, value = Blank.new|
|
229
|
+
return self if is_a_blank?(key)
|
193
230
|
|
194
231
|
key = transformed_key(key)
|
195
232
|
|
196
|
-
if
|
233
|
+
if is_a_blank?(value)
|
197
234
|
resolve!(key)
|
198
235
|
else
|
199
236
|
register!(key, value)
|
@@ -207,6 +244,7 @@ module NxtRegistry
|
|
207
244
|
@call = options.fetch(:call) { true }
|
208
245
|
@resolver = options.fetch(:resolver, false)
|
209
246
|
@transform_keys = options.fetch(:transform_keys) { ->(key) { key.to_s } }
|
247
|
+
@accessor = options.fetch(:accessor) { name }
|
210
248
|
|
211
249
|
@on_key_already_registered = options.fetch(:on_key_already_registered) { ->(key) { raise_key_already_registered_error(key) } }
|
212
250
|
@on_key_not_registered = options.fetch(:on_key_not_registered) { ->(key) { raise_key_not_registered_error(key) } }
|
@@ -215,10 +253,9 @@ module NxtRegistry
|
|
215
253
|
def define_accessors
|
216
254
|
%w[default memoize call resolver transform_keys on_key_already_registered on_key_not_registered].each do |attribute|
|
217
255
|
define_singleton_method attribute do |value = Blank.new, &block|
|
218
|
-
# TODO: Allowing a block does not make sense for memoize and call?!
|
219
256
|
value = block if block
|
220
257
|
|
221
|
-
if
|
258
|
+
if is_a_blank?(value)
|
222
259
|
instance_variable_get("@#{attribute}")
|
223
260
|
else
|
224
261
|
instance_variable_set("@#{attribute}", value)
|
@@ -237,9 +274,9 @@ module NxtRegistry
|
|
237
274
|
attrs.keys.exclude?(transformed_key(key))
|
238
275
|
end
|
239
276
|
|
240
|
-
def resolve_default
|
277
|
+
def resolve_default(key)
|
241
278
|
if call && default.respond_to?(:call)
|
242
|
-
default.call
|
279
|
+
default.arity > 0 ? default.call(key) : default.call
|
243
280
|
else
|
244
281
|
default
|
245
282
|
end
|
@@ -256,7 +293,7 @@ module NxtRegistry
|
|
256
293
|
def transformed_key(key)
|
257
294
|
@transformed_key ||= {}
|
258
295
|
@transformed_key[key] ||= begin
|
259
|
-
if transform_keys && !
|
296
|
+
if transform_keys && !is_a_blank?(key)
|
260
297
|
transform_keys.call(key)
|
261
298
|
else
|
262
299
|
key
|
@@ -269,5 +306,21 @@ module NxtRegistry
|
|
269
306
|
@store = original.send(:store).deep_dup
|
270
307
|
@options = original.send(:options).deep_dup
|
271
308
|
end
|
309
|
+
|
310
|
+
def build_namespace
|
311
|
+
parent ? name.to_s.prepend("#{parent.send(:namespace)}.") : name.to_s
|
312
|
+
end
|
313
|
+
|
314
|
+
def raise_register_argument_error
|
315
|
+
raise ArgumentError, 'Either provide a key value pair or a block to register'
|
316
|
+
end
|
317
|
+
|
318
|
+
def is_a_blank?(value)
|
319
|
+
value.is_a?(Blank)
|
320
|
+
end
|
321
|
+
|
322
|
+
def raise_invalid_accessor_name(name)
|
323
|
+
raise ArgumentError, "#{self} already implements a method named: #{name}. Please choose a different accessor name"
|
324
|
+
end
|
272
325
|
end
|
273
326
|
end
|
data/lib/nxt_registry/version.rb
CHANGED
data/nxt_registry.gemspec
CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = "nxt_registry"
|
7
7
|
spec.version = NxtRegistry::VERSION
|
8
8
|
spec.authors = ["Andreas Robecke", "Nils Sommer", "Raphael Kallensee", "Lütfi Demirci"]
|
9
|
-
spec.email = [
|
9
|
+
spec.email = ['a.robecke@hellogetsafe.com', 'andreas@robecke.de']
|
10
10
|
|
11
11
|
spec.summary = %q{nxt_registry is a simple implementation of the container pattern}
|
12
12
|
spec.homepage = "https://github.com/nxt-insurance"
|
@@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.add_dependency "activesupport"
|
36
36
|
|
37
37
|
spec.add_development_dependency "bundler", "~> 2.0"
|
38
|
-
spec.add_development_dependency "rake", "~>
|
38
|
+
spec.add_development_dependency "rake", "~> 12"
|
39
39
|
spec.add_development_dependency "rspec", "~> 3.0"
|
40
40
|
spec.add_development_dependency "pry"
|
41
41
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nxt_registry
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andreas Robecke
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: exe
|
13
13
|
cert_chain: []
|
14
|
-
date: 2020-
|
14
|
+
date: 2020-09-25 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: activesupport
|
@@ -47,14 +47,14 @@ dependencies:
|
|
47
47
|
requirements:
|
48
48
|
- - "~>"
|
49
49
|
- !ruby/object:Gem::Version
|
50
|
-
version: '
|
50
|
+
version: '12'
|
51
51
|
type: :development
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
54
54
|
requirements:
|
55
55
|
- - "~>"
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version: '
|
57
|
+
version: '12'
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: rspec
|
60
60
|
requirement: !ruby/object:Gem::Requirement
|
@@ -85,15 +85,19 @@ dependencies:
|
|
85
85
|
version: '0'
|
86
86
|
description:
|
87
87
|
email:
|
88
|
-
- a.robecke@
|
88
|
+
- a.robecke@hellogetsafe.com
|
89
|
+
- andreas@robecke.de
|
89
90
|
executables: []
|
90
91
|
extensions: []
|
91
92
|
extra_rdoc_files: []
|
92
93
|
files:
|
94
|
+
- ".circleci/config.yml"
|
95
|
+
- ".editorconfig"
|
93
96
|
- ".gitignore"
|
94
97
|
- ".rakeTasks"
|
95
98
|
- ".rspec"
|
96
99
|
- ".travis.yml"
|
100
|
+
- CHANGELOG.md
|
97
101
|
- Gemfile
|
98
102
|
- Gemfile.lock
|
99
103
|
- LICENSE.txt
|
@@ -105,9 +109,9 @@ files:
|
|
105
109
|
- lib/nxt_registry/attribute.rb
|
106
110
|
- lib/nxt_registry/blank.rb
|
107
111
|
- lib/nxt_registry/errors.rb
|
108
|
-
- lib/nxt_registry/nested_registry_builder.rb
|
109
112
|
- lib/nxt_registry/recursive_registry.rb
|
110
113
|
- lib/nxt_registry/registry.rb
|
114
|
+
- lib/nxt_registry/registry_builder.rb
|
111
115
|
- lib/nxt_registry/version.rb
|
112
116
|
- nxt_registry.gemspec
|
113
117
|
homepage: https://github.com/nxt-insurance
|
@@ -132,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
132
136
|
- !ruby/object:Gem::Version
|
133
137
|
version: '0'
|
134
138
|
requirements: []
|
135
|
-
rubygems_version: 3.0.
|
139
|
+
rubygems_version: 3.0.3
|
136
140
|
signing_key:
|
137
141
|
specification_version: 4
|
138
142
|
summary: nxt_registry is a simple implementation of the container pattern
|