nxt_registry 0.2.0 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|