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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3643055d95f31f6addec18700fd8d7d9157bc4f97848acef8340c11668cfa3df
4
- data.tar.gz: 25018d4d1f657991137e0c94bf8afacaca70dcd44008ff6cb96783ea82aa064d
3
+ metadata.gz: 1f83b8d92a02103b69d4746dfb08e396d827992bc1d1ef21d39fd46d117ce2ac
4
+ data.tar.gz: ab40f633dbed120132de18dbec3b1707c2cab85114ff5857330add4845db0209
5
5
  SHA512:
6
- metadata.gz: 74aefe510917560c5dbc3686834ce64aeb815e8f67d99718f6abf38dd08d639f9a8bba14f3cd2275f7f790b3b853b0207006888ee9303ed4d4b706e99d6e1d8b
7
- data.tar.gz: 2225edb2af2a5493b90642934d415115a8577043f69fa329bfe99c0676997d4ad68c023c1c79fc1552519a2ed50a5478ebe440ad936ee5832956a27ebad1caec
6
+ metadata.gz: 9f843eec28980bd3ffd49906b0661cdce4a02f4a027cf48845cfff799fcbd58213260790501a104435ec71b7e7261f9ff49239dd1296af1f40dcec383de99a29
7
+ data.tar.gz: 71cb8513d2eb829bf930a96e244bc6914dbc9f62a78e5fa7916ffc0710765c6393063b055779d22226d718bc52c52fd106f7a3ed8ad44536768a58f28968fe56
@@ -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
@@ -1,48 +1,48 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nxt_registry (0.2.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.2)
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.6)
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.1)
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.9.0)
28
- rspec-core (~> 3.9.0)
29
- rspec-expectations (~> 3.9.0)
30
- rspec-mocks (~> 3.9.0)
31
- rspec-core (3.9.2)
32
- rspec-support (~> 3.9.3)
33
- rspec-expectations (3.9.2)
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.9.0)
36
- rspec-mocks (3.9.1)
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.9.0)
39
- rspec-support (3.9.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.7)
43
+ tzinfo (1.2.8)
44
44
  thread_safe (~> 0.1)
45
- zeitwerk (2.4.0)
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 by allowing nesting registries into each other. In theory this can be indefinitely deep.
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
- ### Instance Level
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
- def passengers
33
- @passengers ||= begin
34
- registry :from do
35
- nested :to do
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
- # Based on the naming of the registry and its nesting you are provided with a simple interface
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 an instance of NxtRegistry::Registry.new('name', **options, &config)
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
- ### Class Level
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 SimpleExample
97
- # By extending NxtRegistry::Singleton you get a super simple class level interface to an underlying instance of a :registry
98
- extend NxtRegistry::Singleton
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
- SimpleExample.resolve(KeyError)
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 OtherExample
95
+ class Nested
120
96
  extend NxtRegistry
121
97
 
122
- # By passing a block to :registry you can directly register your values inline
123
- REGISTRY = registry(:errors) do
124
- # procs are called directly if not defined otherwise
125
- register(KeyError, ->(error) { puts 'KeyError handler' } )
126
- register(ArgumentError, ->(error) { puts 'ArgumentError handler' } )
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
- # Instead of using the name of the registry, you can also always call register and resolve on the
131
- # level where you want to register or resolve values. Equivalently to the named interface you can
132
- # use register! and resolve! to softly resolve or forcfully register values.
133
- OtherExample::REGISTRY.resolve(KeyError)
134
- # KeyError handler
135
- # => nil
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 `transform_keys false`
202
- or define your own key transformer by assigning a block to transform_keys: `transform_keys ->(key) { key.upcase }`
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
@@ -1,19 +1,43 @@
1
1
  require 'active_support/core_ext'
2
- require "nxt_registry/version"
3
- require "nxt_registry/blank"
4
- require "nxt_registry/attribute"
5
- require "nxt_registry/errors"
6
- require "nxt_registry/nested_registry_builder"
7
- require "nxt_registry/registry"
8
- require "nxt_registry/recursive_registry"
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.new(name, **options, &config)
12
+ build_registry(Registry, name, **options, &config)
14
13
  end
15
14
 
16
15
  def recursive_registry(name, **options, &config)
17
- RecursiveRegistry.new(name, **options, &config)
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 = NestedRegistryBuilder.new do
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 = parent ? name.to_s.prepend("#{parent.send(:namespace)}.") : name.to_s
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 nested(name, **options, &config)
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 default.is_a?(Blank)
24
+ if is_a_blank?(default)
24
25
  self.is_leaf = false
25
26
 
26
- self.default = NestedRegistryBuilder.new do
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?(NestedRegistryBuilder)
32
- raise ArgumentError, "Multiple nestings on the same level"
33
+ elsif default.is_a?(RegistryBuilder)
34
+ raise ArgumentError, 'Multiple nestings on the same level'
33
35
  else
34
- raise ArgumentError, "Default values cannot be defined on registries that nest others"
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
- __register(key, value, raise: true)
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
- __register(key, value, raise: false)
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(key)
61
- __resolve(key, raise: true)
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!(key)
65
- __resolve(key, raise: false)
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
- store[transformed_key(key)]
105
+ resolve!(key)
74
106
  end
75
107
 
76
108
  def []=(key, value)
77
- store[transformed_key(key)] = value
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, **opts, &block)
97
- store.fetch(transformed_key(key), **opts, &block)
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, raise: true)
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
- on_key_already_registered && on_key_already_registered.call(key) if store[key] && raise
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, raise: true)
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[key]
180
+ if store.key?(key)
146
181
  store.fetch(key)
147
182
  else
148
- if default.is_a?(Blank)
149
- return unless raise
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(*[value].take(value.arity))
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
- define_singleton_method name do |key = Blank.new, value = Blank.new|
179
- return self if key.is_a?(Blank)
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 value.is_a?(Blank)
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 "#{name}!" do |key = Blank.new, value = Blank.new|
191
- return self if key.is_a?(Blank)
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 value.is_a?(Blank)
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 value.is_a?(Blank)
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 && !key.is_a?(Blank)
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
@@ -1,5 +1,5 @@
1
1
  module NxtRegistry
2
- class NestedRegistryBuilder < Proc
2
+ class RegistryBuilder < Proc
3
3
  def initialize(&block)
4
4
  super(&block)
5
5
  end
@@ -1,3 +1,3 @@
1
1
  module NxtRegistry
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.3"
3
3
  end
@@ -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 = ["a.robecke@getsafe.de"]
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.2.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-07-27 00:00:00.000000000 Z
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@getsafe.de
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/singleton.rb
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