nxt_registry 0.3.3 → 0.3.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1f83b8d92a02103b69d4746dfb08e396d827992bc1d1ef21d39fd46d117ce2ac
4
- data.tar.gz: ab40f633dbed120132de18dbec3b1707c2cab85114ff5857330add4845db0209
3
+ metadata.gz: 14c7e9fb583ad7e0962ad09933c359dd60d3d13e1dd701cc4d4b971ed408ed08
4
+ data.tar.gz: 879f214a0ce868bcf28fae668d7572ee2c680785749970b74bb2702074a02715
5
5
  SHA512:
6
- metadata.gz: 9f843eec28980bd3ffd49906b0661cdce4a02f4a027cf48845cfff799fcbd58213260790501a104435ec71b7e7261f9ff49239dd1296af1f40dcec383de99a29
7
- data.tar.gz: 71cb8513d2eb829bf930a96e244bc6914dbc9f62a78e5fa7916ffc0710765c6393063b055779d22226d718bc52c52fd106f7a3ed8ad44536768a58f28968fe56
6
+ metadata.gz: ed961d75f5531d6cdf38ce49c72b7d06aaa836b32114b3e5df9508ea4250d099d0e559a78fae9bdd90093d312e00060d0c418994dd8ec2184557743e740ab0f9
7
+ data.tar.gz: 31e1e1ad67e6d59f1f95bd7b31a12f357333ea9542c51eaf5d4ff7bfabcc7542edf2a61033944f89447d13a8f23667a9a38c97cabab18d493c59e619f764353b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ # v0.3.5 2020-12-23
2
+
3
+ - Allow to inherit options in nested registries
4
+
5
+ # v0.3.5 2020-12-04
6
+
7
+ - Allow patterns as keys
8
+
9
+ # v0.3.4 2020-12-04
10
+
11
+ - Bring back Singleton
12
+ - Fix mistakes in readme
13
+
1
14
  # v0.3.3 2020-11-24
2
15
 
3
16
  - Fix: Pass key to resolver instead of value
data/Gemfile.lock CHANGED
@@ -1,25 +1,25 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nxt_registry (0.3.3)
4
+ nxt_registry (0.3.8)
5
5
  activesupport
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activesupport (6.0.3.4)
10
+ activesupport (6.1.1)
11
11
  concurrent-ruby (~> 1.0, >= 1.0.2)
12
- i18n (>= 0.7, < 2)
13
- minitest (~> 5.1)
14
- tzinfo (~> 1.1)
15
- zeitwerk (~> 2.2, >= 2.2.2)
12
+ i18n (>= 1.6, < 2)
13
+ minitest (>= 5.1)
14
+ tzinfo (~> 2.0)
15
+ zeitwerk (~> 2.3)
16
16
  coderay (1.1.3)
17
- concurrent-ruby (1.1.7)
17
+ concurrent-ruby (1.1.8)
18
18
  diff-lcs (1.4.4)
19
- i18n (1.8.5)
19
+ i18n (1.8.8)
20
20
  concurrent-ruby (~> 1.0)
21
21
  method_source (1.0.0)
22
- minitest (5.14.2)
22
+ minitest (5.14.3)
23
23
  pry (0.13.1)
24
24
  coderay (~> 1.1)
25
25
  method_source (~> 1.0)
@@ -28,24 +28,24 @@ GEM
28
28
  rspec-core (~> 3.10.0)
29
29
  rspec-expectations (~> 3.10.0)
30
30
  rspec-mocks (~> 3.10.0)
31
- rspec-core (3.10.0)
31
+ rspec-core (3.10.1)
32
32
  rspec-support (~> 3.10.0)
33
- rspec-expectations (3.10.0)
33
+ rspec-expectations (3.10.1)
34
34
  diff-lcs (>= 1.2.0, < 2.0)
35
35
  rspec-support (~> 3.10.0)
36
- rspec-mocks (3.10.0)
36
+ rspec-mocks (3.10.1)
37
37
  diff-lcs (>= 1.2.0, < 2.0)
38
38
  rspec-support (~> 3.10.0)
39
- rspec-support (3.10.0)
39
+ rspec-support (3.10.1)
40
40
  rspec_junit_formatter (0.4.1)
41
41
  rspec-core (>= 2, < 4, != 2.12.0)
42
- thread_safe (0.3.6)
43
- tzinfo (1.2.8)
44
- thread_safe (~> 0.1)
45
- zeitwerk (2.4.1)
42
+ tzinfo (2.0.4)
43
+ concurrent-ruby (~> 1.0)
44
+ zeitwerk (2.4.2)
46
45
 
47
46
  PLATFORMS
48
47
  ruby
48
+ x86_64-darwin-19
49
49
 
50
50
  DEPENDENCIES
51
51
  bundler (~> 2.0)
@@ -56,4 +56,4 @@ DEPENDENCIES
56
56
  rspec_junit_formatter
57
57
 
58
58
  BUNDLED WITH
59
- 2.1.4
59
+ 2.2.4
data/README.md CHANGED
@@ -27,24 +27,23 @@ Or install it yourself as:
27
27
 
28
28
  ## Instance Level
29
29
 
30
- To use `NxtRegistry` on an instance level simply include it and build registries like so:
30
+ If you simply need a single global instance of a registry include `NxtRegistry::Singleton`:
31
31
 
32
32
  ```ruby
33
33
  class Example
34
- include NxtRegistry
34
+ include NxtRegistry::Singleton
35
35
 
36
- registry :languages do
36
+ registry do
37
37
  register(:ruby, 'Stone')
38
38
  register(:python, 'Snake')
39
39
  register(:javascript, 'undefined')
40
40
  end
41
41
  end
42
42
 
43
- example = Example.new
44
- example.registry(:languages).resolve(:ruby) # => 'Stone'
43
+ Example.resolve(:ruby) # => 'Stone'
45
44
  ```
46
45
 
47
- Alternatively you can also create instances of `NxtRegistry::Registry`
46
+ Alternatively you can simply create instances of `NxtRegistry::Registry`:
48
47
 
49
48
  ```ruby
50
49
  registry = NxtRegistry::Registry.new do
@@ -59,7 +58,7 @@ registry.resolve(:aki) # => 'Aki'
59
58
 
60
59
  ## Class Level
61
60
 
62
- You can add registries on the class level simply by extending your class with `NxtRegistry`
61
+ You can also add registries on the class level simply by extending your class with `NxtRegistry`
63
62
 
64
63
  ```ruby
65
64
  class OtherExample
@@ -83,6 +82,30 @@ OtherExample.registry(:errors).resolve(KeyError)
83
82
  OtherExample.registry(:country_codes).resolve(:germany)
84
83
  # => :de
85
84
  ```
85
+
86
+ ## Register Patterns
87
+
88
+ You can also register values with patterns as keys. Non pattern keys are always evaluated first and then patterns
89
+ will be tried to match by definition sequence.
90
+
91
+ ```ruby
92
+ class Example
93
+ extend NxtRegistry
94
+
95
+ registry :status_codes do
96
+ register(/\A4\d{2}\z/, 'Client errors')
97
+ register(/\A5.*\z/, 'Server errors')
98
+ register('422', 'Unprocessable Entity')
99
+ register(:'503', 'Internal Server Error')
100
+ end
101
+ end
102
+
103
+ Example.registry(:status_codes).resolve('503') # => "Internal Server Error"
104
+ Example.registry(:status_codes).resolve(503) # => "Internal Server Error"
105
+ Example.registry(:status_codes).resolve(422) # => "Unprocessable Entity"
106
+ Example.registry(:status_codes).resolve(404) # => "Client Errors"
107
+ ```
108
+
86
109
  ### Readers
87
110
 
88
111
  Access your defined registries with the `registry(:country_code)` method.
@@ -112,6 +135,23 @@ Nested.registry(:developers).resolve(:frontend, :igor)
112
135
  # => 'Igor'
113
136
  ```
114
137
 
138
+ #### Inherit options in nested registries
139
+
140
+ ```ruby
141
+ class Nested
142
+ extend NxtRegistry
143
+
144
+ registry :developers, default: 'options can be inherited' do
145
+ register(:frontend, inherit_options: true) do
146
+ register(:igor, 'Igor')
147
+ register(:ben, 'Ben')
148
+ end
149
+ end
150
+ end
151
+
152
+ Nested.registry(:developers).resolve(:frontend, :blank)
153
+ # => 'options can be inherited'
154
+ ```
115
155
 
116
156
  ### Defining specific nesting levels of a registry
117
157
 
@@ -165,12 +205,21 @@ Layer.registry(:path).from(:munich).to(:amsterdam).via(:train) # => 'train'
165
205
 
166
206
  *Note that this feature is also available for registries with a single level only.*
167
207
 
168
- ### Restrict attributes to a certain set
208
+ ### Restrict keys to a certain set
209
+
210
+ Use `allowed_keys` to restrict which keys can be registered on a specific level.
211
+
212
+ ```ruby
213
+ registry :example, allowed_keys: %w[one two three]
214
+ ```
215
+
216
+ ### Require a certain set of keys to be registered
169
217
 
170
- Use `attrs` to restrict which attributes can be registered on a specific level.
218
+ Use `required_keys` to enforce a certain set of keys to be registered on a specific level. This is especially helpful
219
+ if you use registries in multiple places and you want to ensure they all register the same set of keys.
171
220
 
172
221
  ```ruby
173
- registry :example, attrs: %w[one two three]
222
+ registry :example, required_keys: %w[one two three]
174
223
  ```
175
224
 
176
225
  ### Default values
data/lib/nxt_registry.rb CHANGED
@@ -1,11 +1,12 @@
1
+ require 'active_support'
1
2
  require 'active_support/core_ext'
2
3
  require 'nxt_registry/version'
3
4
  require 'nxt_registry/blank'
4
- require 'nxt_registry/attribute'
5
5
  require 'nxt_registry/errors'
6
6
  require 'nxt_registry/registry_builder'
7
7
  require 'nxt_registry/registry'
8
8
  require 'nxt_registry/recursive_registry'
9
+ require 'nxt_registry/singleton'
9
10
 
10
11
  module NxtRegistry
11
12
  def registry(name, **options, &config)
@@ -19,17 +20,17 @@ module NxtRegistry
19
20
  private
20
21
 
21
22
  def build_registry(registry_class, name, **options, &config)
22
- if registries.key?(name)
23
- registry = registries.fetch(name)
23
+ registry = registries.resolve(name)
24
+
25
+ if registry.present?
24
26
  if registry.configured
25
- registry
27
+ return registry
26
28
  else
27
29
  raise_unconfigured_registry_accessed(name)
28
30
  end
29
31
  else
30
32
  registry = registry_class.new(name, **options, &config)
31
- registries[name] ||= registry
32
- registry
33
+ registries.register(name, registry)
33
34
  end
34
35
  end
35
36
 
@@ -38,6 +39,6 @@ module NxtRegistry
38
39
  end
39
40
 
40
41
  def registries
41
- @registries ||= {}
42
+ @registries ||= Registry.new(:registries)
42
43
  end
43
44
  end
@@ -2,5 +2,7 @@ module NxtRegistry
2
2
  module Errors
3
3
  KeyAlreadyRegisteredError = Class.new(KeyError)
4
4
  KeyNotRegisteredError = Class.new(KeyError)
5
+ RequiredKeyMissing = Class.new(KeyError)
6
+ KeyNotAllowed = Class.new(KeyError)
5
7
  end
6
8
  end
@@ -8,10 +8,10 @@ module NxtRegistry
8
8
  @namespace = build_namespace
9
9
  @config = config
10
10
  @store = {}
11
- @attrs = nil
12
11
  @configured = false
12
+ @patterns = []
13
+ @config = config
13
14
 
14
- setup_defaults(options)
15
15
  configure(&config)
16
16
  end
17
17
 
@@ -38,27 +38,33 @@ module NxtRegistry
38
38
  end
39
39
 
40
40
  def registry(name, **options, &config)
41
- opts = options.merge(parent: self)
41
+ opts = conditionally_inherit_options(options)
42
42
  register(name, Registry.new(name, **opts, &config))
43
43
  end
44
44
 
45
45
  def registry!(name, **options, &config)
46
- opts = options.merge(parent: self)
46
+ opts = conditionally_inherit_options(options)
47
47
  register!(name, Registry.new(name, **opts, &config))
48
48
  end
49
49
 
50
- def attr(name)
51
- key = transformed_key(name)
52
- raise KeyError, "Attribute #{key} already registered in #{namespace}" if attrs[key]
50
+ def required_keys(*keys)
51
+ @required_keys ||= []
52
+ return @required_keys if keys.empty?
53
+
54
+ @required_keys += keys.map { |key| transformed_key(key) }
55
+ end
56
+
57
+ def allowed_keys(*keys)
58
+ @allowed_keys ||= []
59
+ return @allowed_keys if keys.empty?
53
60
 
54
- attrs[key] = Attribute.new(key, self)
61
+ @allowed_keys += keys.map { |key| transformed_key(key) }
55
62
  end
56
63
 
57
- def attrs(*args)
58
- @attrs ||= {}
59
- return @attrs unless args.any?
64
+ alias attrs allowed_keys # @deprecated
60
65
 
61
- args.each { |name| attr(name) }
66
+ def attr(key)
67
+ allowed_keys(key) # @deprecated
62
68
  end
63
69
 
64
70
  def register(key = Blank.new, value = Blank.new, **options, &block)
@@ -126,15 +132,18 @@ module NxtRegistry
126
132
  end
127
133
 
128
134
  def fetch(key, *args, &block)
129
- store.fetch(transformed_key(key), *args, &block)
135
+ key = matching_key(key)
136
+ store.fetch(key, *args, &block)
130
137
  end
131
138
 
132
139
  delegate :size, :values, :each, :freeze, to: :store
133
140
 
134
141
  def configure(&block)
142
+ setup_defaults(options)
135
143
  define_accessors
136
144
  define_interface
137
- attrs(*Array(options.fetch(:attrs, [])))
145
+ allowed_keys(*Array(options.fetch(:allowed_keys, [])))
146
+ required_keys(*Array(options.fetch(:required_keys, [])))
138
147
 
139
148
  if block.present?
140
149
  if block.arity == 1
@@ -144,6 +153,7 @@ module NxtRegistry
144
153
  end
145
154
  end
146
155
 
156
+ validate_required_keys_given
147
157
  self.configured = true
148
158
  end
149
159
 
@@ -151,22 +161,40 @@ module NxtRegistry
151
161
  "Registry[#{name}] -> #{store.to_s}"
152
162
  end
153
163
 
154
- alias_method :inspect, :to_s
164
+ alias inspect to_s
155
165
 
156
166
  private
157
167
 
158
- attr_reader :namespace, :parent, :config, :store, :options, :accessor
168
+ attr_reader :namespace, :parent, :config, :store, :options, :accessor, :patterns
159
169
  attr_accessor :is_leaf, :interface_defined
160
170
 
171
+ def conditionally_inherit_options(opts)
172
+ base = opts.delete(:inherit_options) ? options : {}
173
+ base.merge(opts).merge(parent: self)
174
+ end
175
+
176
+ def validate_required_keys_given
177
+ required_keys.each do |key|
178
+ next if store.key?(key)
179
+
180
+ raise Errors::RequiredKeyMissing, "Required key '#{key}' missing in #{self}"
181
+ end
182
+ end
183
+
161
184
  def is_leaf?
162
185
  @is_leaf
163
186
  end
164
187
 
165
188
  def __register(key, value, raise_on_key_already_registered: true)
166
- key = transformed_key(key)
189
+ key = if key.is_a?(Regexp)
190
+ patterns << key
191
+ key
192
+ else
193
+ transformed_key(key)
194
+ end
167
195
 
168
196
  raise ArgumentError, "Not allowed to register values in a registry that contains nested registries" unless is_leaf
169
- raise KeyError, "Keys are restricted to #{attrs.keys}" if attribute_not_allowed?(key)
197
+ raise KeyError, "Keys are restricted to #{allowed_keys}" if key_not_allowed?(key)
170
198
 
171
199
  on_key_already_registered && on_key_already_registered.call(key) if store[key] && raise_on_key_already_registered
172
200
 
@@ -179,6 +207,8 @@ module NxtRegistry
179
207
  value = if is_leaf?
180
208
  if store.key?(key)
181
209
  store.fetch(key)
210
+ elsif (pattern = matching_pattern(key))
211
+ store.fetch(pattern)
182
212
  else
183
213
  if is_a_blank?(default)
184
214
  return unless raise_on_key_not_registered
@@ -195,11 +225,7 @@ module NxtRegistry
195
225
  store[key] ||= default.call
196
226
  end
197
227
 
198
- value = if value.respond_to?(:call) && call && !value.is_a?(NxtRegistry::Registry)
199
- value.call(*[key].take(value.arity))
200
- else
201
- value
202
- end
228
+ value = call_or_value(value, key)
203
229
 
204
230
  if resolver
205
231
  resolver.call(value)
@@ -208,14 +234,35 @@ module NxtRegistry
208
234
  end
209
235
  end
210
236
 
237
+ def matching_key(key)
238
+ key = transformed_key(key)
239
+ # if key is present it always wins over patterns
240
+ return key if store.key?(key)
241
+
242
+ matching_pattern(key) || key
243
+ end
244
+
245
+ def call_or_value(value, key)
246
+ return value unless call
247
+ return value if value.is_a?(NxtRegistry::Registry)
248
+ return value unless value.respond_to?(:call)
249
+
250
+ args = [key, value]
251
+ value.call(*args.take(value.arity))
252
+ end
253
+
254
+ def matching_pattern(key)
255
+ patterns.find { |pattern| key.match?(pattern) }
256
+ end
257
+
211
258
  def define_interface
212
259
  return if interface_defined
213
260
 
214
- raise_invalid_accessor_name(accessor) if respond_to?(accessor)
261
+ raise_invalid_accessor_name(accessor) if respond_to?(accessor.to_s)
215
262
  accessor_with_bang = "#{accessor}!"
216
263
  raise_invalid_accessor_name(accessor_with_bang) if respond_to?(accessor_with_bang)
217
264
 
218
- define_singleton_method accessor do |key = Blank.new, value = Blank.new|
265
+ define_singleton_method accessor.to_s do |key = Blank.new, value = Blank.new|
219
266
  return self if is_a_blank?(key)
220
267
 
221
268
  key = transformed_key(key)
@@ -247,7 +294,7 @@ module NxtRegistry
247
294
  @memoize = options.fetch(:memoize) { true }
248
295
  @call = options.fetch(:call) { true }
249
296
  @resolver = options.fetch(:resolver, false)
250
- @transform_keys = options.fetch(:transform_keys) { ->(key) { key.to_s } }
297
+ @transform_keys = options.fetch(:transform_keys) { ->(key) { key.is_a?(Regexp) ? key : key.to_s } }
251
298
  @accessor = options.fetch(:accessor) { name }
252
299
 
253
300
  @on_key_already_registered = options.fetch(:on_key_already_registered) { ->(key) { raise_key_already_registered_error(key) } }
@@ -272,10 +319,10 @@ module NxtRegistry
272
319
  end
273
320
  end
274
321
 
275
- def attribute_not_allowed?(key)
276
- return if attrs.empty?
322
+ def key_not_allowed?(key)
323
+ return if allowed_keys.empty?
277
324
 
278
- attrs.keys.exclude?(transformed_key(key))
325
+ allowed_keys.exclude?(transformed_key(key))
279
326
  end
280
327
 
281
328
  def resolve_default(key)
@@ -305,12 +352,6 @@ module NxtRegistry
305
352
  end
306
353
  end
307
354
 
308
- def initialize_copy(original)
309
- super
310
- @store = original.send(:store).deep_dup
311
- @options = original.send(:options).deep_dup
312
- end
313
-
314
355
  def build_namespace
315
356
  parent ? name.to_s.prepend("#{parent.send(:namespace)}.") : name.to_s
316
357
  end
@@ -326,5 +367,15 @@ module NxtRegistry
326
367
  def raise_invalid_accessor_name(name)
327
368
  raise ArgumentError, "#{self} already implements a method named: #{name}. Please choose a different accessor name"
328
369
  end
370
+
371
+ def initialize_copy(original)
372
+ super
373
+
374
+ containers = %i[store options]
375
+ variables = %i[patterns required_keys allowed_keys namespace on_key_already_registered on_key_not_registered]
376
+
377
+ containers.each { |c| instance_variable_set("@#{c}", original.send(c).deep_dup) }
378
+ variables.each { |v| instance_variable_set("@#{v}", original.send(v).dup) }
379
+ end
329
380
  end
330
381
  end
@@ -0,0 +1,15 @@
1
+ module NxtRegistry
2
+ module Singleton
3
+ include NxtRegistry
4
+
5
+ def self.included(base)
6
+ base.extend(self)
7
+ end
8
+
9
+ def registry(type = Registry, **options, &config)
10
+ @registry ||= build_registry(type, self.class.name, **options, &config)
11
+ end
12
+
13
+ delegate_missing_to :registry
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
1
  module NxtRegistry
2
- VERSION = "0.3.3"
2
+ VERSION = '0.3.8'
3
3
  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.3.3
4
+ version: 0.3.8
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-11-24 00:00:00.000000000 Z
14
+ date: 2021-02-03 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activesupport
@@ -106,12 +106,12 @@ files:
106
106
  - bin/console
107
107
  - bin/setup
108
108
  - lib/nxt_registry.rb
109
- - lib/nxt_registry/attribute.rb
110
109
  - lib/nxt_registry/blank.rb
111
110
  - lib/nxt_registry/errors.rb
112
111
  - lib/nxt_registry/recursive_registry.rb
113
112
  - lib/nxt_registry/registry.rb
114
113
  - lib/nxt_registry/registry_builder.rb
114
+ - lib/nxt_registry/singleton.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
- class Attribute
3
- def initialize(name, registry, **options)
4
- @name = name
5
- @registry = registry
6
- @namespace = [name, registry.send(:namespace)].join('.')
7
- end
8
-
9
- def eql?(other)
10
- { name => registry.object_id } == { other.send(:name) => other.send(:registry).object_id }
11
- end
12
-
13
- private
14
-
15
- attr_reader :name, :registry
16
- end
17
- end