nxt_registry 0.3.3 → 0.3.8

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