nxt_registry 0.2.0 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +35 -0
- data/Gemfile.lock +17 -17
- data/README.md +106 -76
- data/lib/nxt_registry.rb +34 -10
- data/lib/nxt_registry/recursive_registry.rb +1 -1
- data/lib/nxt_registry/registry.rb +102 -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 +1 -1
- metadata +5 -5
- data/lib/nxt_registry/singleton.rb +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f83b8d92a02103b69d4746dfb08e396d827992bc1d1ef21d39fd46d117ce2ac
|
4
|
+
data.tar.gz: ab40f633dbed120132de18dbec3b1707c2cab85114ff5857330add4845db0209
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9f843eec28980bd3ffd49906b0661cdce4a02f4a027cf48845cfff799fcbd58213260790501a104435ec71b7e7261f9ff49239dd1296af1f40dcec383de99a29
|
7
|
+
data.tar.gz: 71cb8513d2eb829bf930a96e244bc6914dbc9f62a78e5fa7916ffc0710765c6393063b055779d22226d718bc52c52fd106f7a3ed8ad44536768a58f28968fe56
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,38 @@
|
|
1
|
+
# v0.3.3 2020-11-24
|
2
|
+
|
3
|
+
- Fix: Pass key to resolver instead of value
|
4
|
+
|
5
|
+
# v0.3.2 2020-09-29
|
6
|
+
|
7
|
+
- Fix interface definition
|
8
|
+
|
9
|
+
# v0.3.1 2020-09-23
|
10
|
+
|
11
|
+
- Allow to define custom accessors for registries
|
12
|
+
|
13
|
+
# v0.3.0 2020-09-10
|
14
|
+
|
15
|
+
### Breaking Changes
|
16
|
+
|
17
|
+
- Toggled interface for resolve(!) and register(!)
|
18
|
+
- Allow to register values in nested registries
|
19
|
+
- Rename nested method into level
|
20
|
+
- Provide registry readers
|
21
|
+
- Remove Singleton extension
|
22
|
+
- Allow to resolve paths
|
23
|
+
- Pass key to default block when it takes an argument
|
24
|
+
|
25
|
+
[Compare v0.2.1...v0.3.0](https://github.com/nxt-insurance/nxt_registry/compare/v0.2.1...v0.3.0)
|
26
|
+
|
27
|
+
# v0.2.1 2020-08-14
|
28
|
+
|
29
|
+
### Fixed
|
30
|
+
|
31
|
+
- Fixed Registry#fetch to raise key error in case of missing key
|
32
|
+
|
33
|
+
[Compare v0.2.0...v0.2.1](https://github.com/nxt-insurance/nxt_registry/compare/v0.2.0...v0.2.1)
|
34
|
+
|
35
|
+
|
1
36
|
# v0.2.0 2020-07-24
|
2
37
|
|
3
38
|
### Added
|
data/Gemfile.lock
CHANGED
@@ -1,48 +1,48 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
nxt_registry (0.
|
4
|
+
nxt_registry (0.3.3)
|
5
5
|
activesupport
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
activesupport (6.0.3.
|
10
|
+
activesupport (6.0.3.4)
|
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
15
|
zeitwerk (~> 2.2, >= 2.2.2)
|
16
16
|
coderay (1.1.3)
|
17
|
-
concurrent-ruby (1.1.
|
17
|
+
concurrent-ruby (1.1.7)
|
18
18
|
diff-lcs (1.4.4)
|
19
19
|
i18n (1.8.5)
|
20
20
|
concurrent-ruby (~> 1.0)
|
21
21
|
method_source (1.0.0)
|
22
|
-
minitest (5.14.
|
22
|
+
minitest (5.14.2)
|
23
23
|
pry (0.13.1)
|
24
24
|
coderay (~> 1.1)
|
25
25
|
method_source (~> 1.0)
|
26
26
|
rake (12.3.3)
|
27
|
-
rspec (3.
|
28
|
-
rspec-core (~> 3.
|
29
|
-
rspec-expectations (~> 3.
|
30
|
-
rspec-mocks (~> 3.
|
31
|
-
rspec-core (3.
|
32
|
-
rspec-support (~> 3.
|
33
|
-
rspec-expectations (3.
|
27
|
+
rspec (3.10.0)
|
28
|
+
rspec-core (~> 3.10.0)
|
29
|
+
rspec-expectations (~> 3.10.0)
|
30
|
+
rspec-mocks (~> 3.10.0)
|
31
|
+
rspec-core (3.10.0)
|
32
|
+
rspec-support (~> 3.10.0)
|
33
|
+
rspec-expectations (3.10.0)
|
34
34
|
diff-lcs (>= 1.2.0, < 2.0)
|
35
|
-
rspec-support (~> 3.
|
36
|
-
rspec-mocks (3.
|
35
|
+
rspec-support (~> 3.10.0)
|
36
|
+
rspec-mocks (3.10.0)
|
37
37
|
diff-lcs (>= 1.2.0, < 2.0)
|
38
|
-
rspec-support (~> 3.
|
39
|
-
rspec-support (3.
|
38
|
+
rspec-support (~> 3.10.0)
|
39
|
+
rspec-support (3.10.0)
|
40
40
|
rspec_junit_formatter (0.4.1)
|
41
41
|
rspec-core (>= 2, < 4, != 2.12.0)
|
42
42
|
thread_safe (0.3.6)
|
43
|
-
tzinfo (1.2.
|
43
|
+
tzinfo (1.2.8)
|
44
44
|
thread_safe (~> 0.1)
|
45
|
-
zeitwerk (2.4.
|
45
|
+
zeitwerk (2.4.1)
|
46
46
|
|
47
47
|
PLATFORMS
|
48
48
|
ruby
|
data/README.md
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
# NxtRegistry
|
4
4
|
|
5
|
-
NxtRegistry is a simple implementation of the container pattern. It allows you to register and resolve values in nested
|
6
|
-
structures
|
5
|
+
`NxtRegistry` is a simple implementation of the container pattern. It allows you to register and resolve values in nested
|
6
|
+
structures.
|
7
7
|
|
8
8
|
## Installation
|
9
9
|
|
@@ -23,61 +23,28 @@ Or install it yourself as:
|
|
23
23
|
|
24
24
|
## Usage
|
25
25
|
|
26
|
-
###
|
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:
|
27
31
|
|
28
32
|
```ruby
|
29
33
|
class Example
|
30
34
|
include NxtRegistry
|
31
35
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
nested :via, memoize: true, call: true, default: -> { [] } do
|
37
|
-
attrs %i[train car plane horse] # restrict the attributes that can be registered
|
38
|
-
resolver ->(value) { value } # do something with your registered value here
|
39
|
-
transform_keys ->(key) { key.upcase } # transform keys
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
36
|
+
registry :languages do
|
37
|
+
register(:ruby, 'Stone')
|
38
|
+
register(:python, 'Snake')
|
39
|
+
register(:javascript, 'undefined')
|
44
40
|
end
|
45
41
|
end
|
46
42
|
|
47
43
|
example = Example.new
|
48
|
-
|
49
|
-
# that allows you to resolve and register values by name
|
50
|
-
|
51
|
-
# Register an array with a value by calling the accessor with a key, value pair
|
52
|
-
example.passengers.from(:a).to(:b).via(:train, ['Andy']) # => ['Andy']
|
53
|
-
|
54
|
-
# In case you try to register the same key again you will get an error
|
55
|
-
example.passengers.from(:a).to(:b).via(:train, ['Andy'])
|
56
|
-
# => NxtRegistry::Errors::KeyAlreadyRegisteredError
|
57
|
-
# (Key 'train' already registered in registry 'from.to.via')
|
58
|
-
# NxtRegistry::Errors::KeyAlreadyRegisteredError inherits from KeyError
|
59
|
-
|
60
|
-
# You can force values on the registry by using the bang method
|
61
|
-
example.passengers.from(:a).to(:b).via!(:train, ['Andreas'])
|
62
|
-
|
63
|
-
# Similarly you can try to resolve values softly
|
64
|
-
# (meaning no KeyNotRegisteredError will be raised when nothing was registered)
|
65
|
-
example.passengers.from(:a).to(:b).via!(:train)
|
66
|
-
# Since there is a default defined for this registry, it does not make any sense
|
67
|
-
# since there is always a value. But you get the point...
|
68
|
-
|
69
|
-
# Resolve values by calling the accessor with the key only
|
70
|
-
# In this case the default is returned because nothing was registered yet
|
71
|
-
example.passengers.from(:a).to(:b).via(:hyperloop) # []
|
72
|
-
|
73
|
-
# Appending values to a default array
|
74
|
-
example.passengers.from(:a).to(:b).via(:car) << 'Lütfi' # => ['Lütif']
|
75
|
-
example.passengers.from(:a).to(:b).via(:plane) += %w[Nils Rapha]
|
76
|
-
example.passengers.from(:a).to(:b).via(:plane) # => ['Nils', 'Rapha']
|
77
|
-
|
44
|
+
example.registry(:languages).resolve(:ruby) # => 'Stone'
|
78
45
|
```
|
79
46
|
|
80
|
-
Alternatively you can create
|
47
|
+
Alternatively you can also create instances of `NxtRegistry::Registry`
|
81
48
|
|
82
49
|
```ruby
|
83
50
|
registry = NxtRegistry::Registry.new do
|
@@ -90,52 +57,114 @@ registry.resolve(:aki) # => 'Aki'
|
|
90
57
|
|
91
58
|
```
|
92
59
|
|
93
|
-
|
60
|
+
## Class Level
|
61
|
+
|
62
|
+
You can add registries on the class level simply by extending your class with `NxtRegistry`
|
94
63
|
|
95
64
|
```ruby
|
96
|
-
class
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
registry do
|
101
|
-
# procs are called directly if not defined otherwise
|
65
|
+
class OtherExample
|
66
|
+
extend NxtRegistry
|
67
|
+
|
68
|
+
registry(:errors) do
|
102
69
|
register(KeyError, ->(error) { puts 'KeyError handler' } )
|
103
70
|
register(ArgumentError, ->(error) { puts 'ArgumentError handler' } )
|
104
|
-
# Custom key error handlers
|
105
|
-
on_key_already_registered ->(key) { raise "Key was already registered dude: #{key}" }
|
106
|
-
on_key_not_registered ->(key) { raise "Key was never registered dude: #{key}" }
|
107
71
|
end
|
72
|
+
|
73
|
+
registry(:country_codes) do
|
74
|
+
register(:germany, :de)
|
75
|
+
register(:england, :uk)
|
76
|
+
register(:france, :fr)
|
77
|
+
end
|
108
78
|
end
|
109
|
-
|
110
|
-
|
111
|
-
# Alternatively: SimpleExample.registry.resolve(KeyError)
|
112
|
-
# Or: SimpleExample.instance.resolve(KeyError)
|
79
|
+
|
80
|
+
OtherExample.registry(:errors).resolve(KeyError)
|
113
81
|
# KeyError handler
|
114
82
|
# => nil
|
115
|
-
|
83
|
+
OtherExample.registry(:country_codes).resolve(:germany)
|
84
|
+
# => :de
|
116
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:
|
117
93
|
|
118
94
|
```ruby
|
119
|
-
class
|
95
|
+
class Nested
|
120
96
|
extend NxtRegistry
|
121
97
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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
|
127
108
|
end
|
128
109
|
end
|
129
110
|
|
130
|
-
|
131
|
-
#
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
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
|
136
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'
|
137
164
|
```
|
138
165
|
|
166
|
+
*Note that this feature is also available for registries with a single level only.*
|
167
|
+
|
139
168
|
### Restrict attributes to a certain set
|
140
169
|
|
141
170
|
Use `attrs` to restrict which attributes can be registered on a specific level.
|
@@ -197,9 +226,10 @@ registry.resolve(:one)
|
|
197
226
|
|
198
227
|
### Transform keys
|
199
228
|
|
200
|
-
NxtRegistry uses a plain ruby hash to store values internally. Per default all keys used are transformed with `&:to_s`.
|
201
|
-
Thus you can use symbols or strings to register and resolve values. If it's not what you want, switch it off with
|
202
|
-
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 }`
|
203
233
|
|
204
234
|
```ruby
|
205
235
|
registry :example do
|
data/lib/nxt_registry.rb
CHANGED
@@ -1,19 +1,43 @@
|
|
1
1
|
require 'active_support/core_ext'
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require "nxt_registry/singleton"
|
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'
|
10
9
|
|
11
10
|
module NxtRegistry
|
12
11
|
def registry(name, **options, &config)
|
13
|
-
Registry
|
12
|
+
build_registry(Registry, name, **options, &config)
|
14
13
|
end
|
15
14
|
|
16
15
|
def recursive_registry(name, **options, &config)
|
17
|
-
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 ||= {}
|
18
42
|
end
|
19
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
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
15
|
configure(&config)
|
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,48 +155,48 @@ module NxtRegistry
|
|
121
155
|
|
122
156
|
private
|
123
157
|
|
124
|
-
attr_reader :namespace, :parent, :config, :store, :options
|
125
|
-
attr_accessor :is_leaf
|
158
|
+
attr_reader :namespace, :parent, :config, :store, :options, :accessor
|
159
|
+
attr_accessor :is_leaf, :interface_defined
|
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
|
+
|
171
|
+
on_key_already_registered && on_key_already_registered.call(key) if store[key] && raise_on_key_already_registered
|
137
172
|
|
138
173
|
store[key] = value
|
139
174
|
end
|
140
175
|
|
141
|
-
def __resolve(key,
|
176
|
+
def __resolve(key, raise_on_key_not_registered: true)
|
142
177
|
key = transformed_key(key)
|
143
178
|
|
144
179
|
value = if is_leaf?
|
145
|
-
if store
|
180
|
+
if store.key?(key)
|
146
181
|
store.fetch(key)
|
147
182
|
else
|
148
|
-
if
|
149
|
-
return unless
|
183
|
+
if is_a_blank?(default)
|
184
|
+
return unless raise_on_key_not_registered
|
150
185
|
|
151
186
|
on_key_not_registered && on_key_not_registered.call(key)
|
152
187
|
else
|
153
|
-
value = resolve_default
|
188
|
+
value = resolve_default(key)
|
154
189
|
return value unless memoize
|
155
190
|
|
156
191
|
store[key] ||= value
|
157
192
|
end
|
158
193
|
end
|
159
194
|
else
|
160
|
-
# Call nested registry builder when we are not a leaf
|
161
195
|
store[key] ||= default.call
|
162
196
|
end
|
163
197
|
|
164
198
|
value = if value.respond_to?(:call) && call && !value.is_a?(NxtRegistry::Registry)
|
165
|
-
value.call(*[
|
199
|
+
value.call(*[key].take(value.arity))
|
166
200
|
else
|
167
201
|
value
|
168
202
|
end
|
@@ -175,29 +209,37 @@ module NxtRegistry
|
|
175
209
|
end
|
176
210
|
|
177
211
|
def define_interface
|
178
|
-
|
179
|
-
|
212
|
+
return if interface_defined
|
213
|
+
|
214
|
+
raise_invalid_accessor_name(accessor) if respond_to?(accessor)
|
215
|
+
accessor_with_bang = "#{accessor}!"
|
216
|
+
raise_invalid_accessor_name(accessor_with_bang) if respond_to?(accessor_with_bang)
|
217
|
+
|
218
|
+
define_singleton_method accessor do |key = Blank.new, value = Blank.new|
|
219
|
+
return self if is_a_blank?(key)
|
180
220
|
|
181
221
|
key = transformed_key(key)
|
182
222
|
|
183
|
-
if
|
223
|
+
if is_a_blank?(value)
|
184
224
|
resolve(key)
|
185
225
|
else
|
186
226
|
register(key, value)
|
187
227
|
end
|
188
228
|
end
|
189
229
|
|
190
|
-
define_singleton_method
|
191
|
-
return self if
|
230
|
+
define_singleton_method accessor_with_bang do |key = Blank.new, value = Blank.new|
|
231
|
+
return self if is_a_blank?(key)
|
192
232
|
|
193
233
|
key = transformed_key(key)
|
194
234
|
|
195
|
-
if
|
235
|
+
if is_a_blank?(value)
|
196
236
|
resolve!(key)
|
197
237
|
else
|
198
238
|
register!(key, value)
|
199
239
|
end
|
200
240
|
end
|
241
|
+
|
242
|
+
self.interface_defined = true
|
201
243
|
end
|
202
244
|
|
203
245
|
def setup_defaults(options)
|
@@ -206,6 +248,7 @@ module NxtRegistry
|
|
206
248
|
@call = options.fetch(:call) { true }
|
207
249
|
@resolver = options.fetch(:resolver, false)
|
208
250
|
@transform_keys = options.fetch(:transform_keys) { ->(key) { key.to_s } }
|
251
|
+
@accessor = options.fetch(:accessor) { name }
|
209
252
|
|
210
253
|
@on_key_already_registered = options.fetch(:on_key_already_registered) { ->(key) { raise_key_already_registered_error(key) } }
|
211
254
|
@on_key_not_registered = options.fetch(:on_key_not_registered) { ->(key) { raise_key_not_registered_error(key) } }
|
@@ -214,10 +257,9 @@ module NxtRegistry
|
|
214
257
|
def define_accessors
|
215
258
|
%w[default memoize call resolver transform_keys on_key_already_registered on_key_not_registered].each do |attribute|
|
216
259
|
define_singleton_method attribute do |value = Blank.new, &block|
|
217
|
-
# TODO: Allowing a block does not make sense for memoize and call?!
|
218
260
|
value = block if block
|
219
261
|
|
220
|
-
if
|
262
|
+
if is_a_blank?(value)
|
221
263
|
instance_variable_get("@#{attribute}")
|
222
264
|
else
|
223
265
|
instance_variable_set("@#{attribute}", value)
|
@@ -236,9 +278,9 @@ module NxtRegistry
|
|
236
278
|
attrs.keys.exclude?(transformed_key(key))
|
237
279
|
end
|
238
280
|
|
239
|
-
def resolve_default
|
281
|
+
def resolve_default(key)
|
240
282
|
if call && default.respond_to?(:call)
|
241
|
-
default.call
|
283
|
+
default.arity > 0 ? default.call(key) : default.call
|
242
284
|
else
|
243
285
|
default
|
244
286
|
end
|
@@ -255,7 +297,7 @@ module NxtRegistry
|
|
255
297
|
def transformed_key(key)
|
256
298
|
@transformed_key ||= {}
|
257
299
|
@transformed_key[key] ||= begin
|
258
|
-
if transform_keys && !
|
300
|
+
if transform_keys && !is_a_blank?(key)
|
259
301
|
transform_keys.call(key)
|
260
302
|
else
|
261
303
|
key
|
@@ -268,5 +310,21 @@ module NxtRegistry
|
|
268
310
|
@store = original.send(:store).deep_dup
|
269
311
|
@options = original.send(:options).deep_dup
|
270
312
|
end
|
313
|
+
|
314
|
+
def build_namespace
|
315
|
+
parent ? name.to_s.prepend("#{parent.send(:namespace)}.") : name.to_s
|
316
|
+
end
|
317
|
+
|
318
|
+
def raise_register_argument_error
|
319
|
+
raise ArgumentError, 'Either provide a key value pair or a block to register'
|
320
|
+
end
|
321
|
+
|
322
|
+
def is_a_blank?(value)
|
323
|
+
value.is_a?(Blank)
|
324
|
+
end
|
325
|
+
|
326
|
+
def raise_invalid_accessor_name(name)
|
327
|
+
raise ArgumentError, "#{self} already implements a method named: #{name}. Please choose a different accessor name"
|
328
|
+
end
|
271
329
|
end
|
272
330
|
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"
|
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.
|
4
|
+
version: 0.3.3
|
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-11-24 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: activesupport
|
@@ -85,7 +85,8 @@ 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: []
|
@@ -108,10 +109,9 @@ files:
|
|
108
109
|
- lib/nxt_registry/attribute.rb
|
109
110
|
- lib/nxt_registry/blank.rb
|
110
111
|
- lib/nxt_registry/errors.rb
|
111
|
-
- lib/nxt_registry/nested_registry_builder.rb
|
112
112
|
- lib/nxt_registry/recursive_registry.rb
|
113
113
|
- lib/nxt_registry/registry.rb
|
114
|
-
- lib/nxt_registry/
|
114
|
+
- lib/nxt_registry/registry_builder.rb
|
115
115
|
- lib/nxt_registry/version.rb
|
116
116
|
- nxt_registry.gemspec
|
117
117
|
homepage: https://github.com/nxt-insurance
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module NxtRegistry
|
2
|
-
module Singleton
|
3
|
-
def self.extended(subclass)
|
4
|
-
subclass.singleton_class.class_eval do
|
5
|
-
default_name = (subclass.name || 'registry')
|
6
|
-
|
7
|
-
define_method :registry do |name = default_name, **options, &block|
|
8
|
-
@registry ||= NxtRegistry::Registry.new(name, **options, &block)
|
9
|
-
end
|
10
|
-
|
11
|
-
delegate_missing_to :registry
|
12
|
-
|
13
|
-
define_method(:instance) { registry }
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|