nxt_registry 0.1.5 → 0.3.2

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: c7580358cb0ea45fffde45350fe3162957158c25a41cabd7a3faeba4e3901515
4
- data.tar.gz: 0dd9ff5a3904ca34ab631d405a29fcd0cf6bed1d62f37fff01f425e6e44b5c45
3
+ metadata.gz: 07e0435f3a696a2f8c653524b7d69e82445645ea852a3747e66079042844f8c7
4
+ data.tar.gz: 3377e35d63ec213f0008987aabdd459171c0e6e2a7dca0b2cd9624fc0d6feac3
5
5
  SHA512:
6
- metadata.gz: a3aa0bec05c05bc39f6db505ef90b29eadd33e750138a00fb21ac21464683de08034ee528343ea3dd775d230d6a7db3b71ea21c21d1e60286aa72c06ac420167
7
- data.tar.gz: fe9f8f96fd76c5810638d33a73b4f0052d1b1e5e533d5bb506120a8abe442c466b16ba766d7788c3d2887f4f6fbe9b34a97cbec27a40b96c1f06bdb6f4c0d5bb
6
+ metadata.gz: 488ac1e21b87244d2ba97d5d767fba560bfa011a74cfebd78601d50509ddad7de9cfdb33d4ea6b1857f0c3ef9a7955d82ec40e9f4e6be64487b596341ed02dcd
7
+ data.tar.gz: 7cad3b456a2075274febf29ff6d25327c713e521a13d541d2640b9acb9344677f3ae89cfd9cdfdf72c3f8c316c4d8f67c4b9718100b74a84dc4c0669e84c1e13
@@ -0,0 +1,56 @@
1
+ # Ruby CircleCI 2.0 configuration file
2
+ #
3
+ # Check https://circleci.com/docs/2.0/language-ruby/ for more details
4
+ #
5
+ version: 2
6
+ jobs:
7
+ build:
8
+ docker:
9
+ # specify the version you desire here
10
+ - image: circleci/ruby:2.6.5-node
11
+ environment:
12
+ BUNDLER_VERSION: 2.1.4
13
+
14
+ working_directory: ~/repo
15
+
16
+ steps:
17
+ - checkout
18
+
19
+ # Download and cache dependencies
20
+ - restore_cache:
21
+ keys:
22
+ - v1-dependencies-{{ checksum "Gemfile.lock" }}
23
+
24
+ - run: gem install bundler --version $BUNDLER_VERSION
25
+
26
+ - run:
27
+ name: install dependencies
28
+ command: |
29
+ bundle install --jobs=4 --retry=3 --path vendor/bundle
30
+
31
+ - save_cache:
32
+ paths:
33
+ - ./vendor/bundle
34
+ key: v1-dependencies-{{ checksum "Gemfile.lock" }}
35
+
36
+ # run tests!
37
+ - run:
38
+ name: run tests
39
+ command: |
40
+ mkdir /tmp/test-results
41
+ TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | \
42
+ circleci tests split --split-by=timings)"
43
+
44
+ bundle exec rspec \
45
+ --format progress \
46
+ --format RspecJunitFormatter \
47
+ --out /tmp/test-results/rspec.xml \
48
+ --format progress \
49
+ $TEST_FILES
50
+
51
+ # collect reports
52
+ - store_test_results:
53
+ path: /tmp/test-results
54
+ - store_artifacts:
55
+ path: /tmp/test-results
56
+ destination: test-results
@@ -0,0 +1,15 @@
1
+ # EditorConfig is awesome: http://EditorConfig.org
2
+
3
+ # top-most EditorConfig file
4
+ root = true
5
+
6
+ # Unix-style newlines with a newline ending every file
7
+ [*]
8
+ end_of_line = lf
9
+ insert_final_newline = true
10
+ charset = utf-8
11
+
12
+ [*.{rb,yml,json,rake}]
13
+ indent_style = space
14
+ indent_size = 2
15
+ trim_trailing_whitespace = true
@@ -0,0 +1,41 @@
1
+ # v0.3.2 2020-09-29
2
+
3
+ - Fix interface definition
4
+
5
+ # v0.3.1 2020-09-23
6
+
7
+ - Allow to define custom accessors for registries
8
+
9
+ # v0.3.0 2020-09-10
10
+
11
+ ### Breaking Changes
12
+
13
+ - Toggled interface for resolve(!) and register(!)
14
+ - Allow to register values in nested registries
15
+ - Rename nested method into level
16
+ - Provide registry readers
17
+ - Remove Singleton extension
18
+ - Allow to resolve paths
19
+ - Pass key to default block when it takes an argument
20
+
21
+ [Compare v0.2.1...v0.3.0](https://github.com/nxt-insurance/nxt_registry/compare/v0.2.1...v0.3.0)
22
+
23
+ # v0.2.1 2020-08-14
24
+
25
+ ### Fixed
26
+
27
+ - Fixed Registry#fetch to raise key error in case of missing key
28
+
29
+ [Compare v0.2.0...v0.2.1](https://github.com/nxt-insurance/nxt_registry/compare/v0.2.0...v0.2.1)
30
+
31
+
32
+ # v0.2.0 2020-07-24
33
+
34
+ ### Added
35
+
36
+ - [internal] Added NxtRegistry::Singleton
37
+ - Added NxtRegistry::Singleton interface
38
+ - Make name optional and have object_id.to_s as default name
39
+ - Fix readme
40
+
41
+ [Compare v0.1.5...v0.2.0](https://github.com/nxt-insurance/nxt_registry/compare/v0.1.5...v0.2.0)
data/Gemfile CHANGED
@@ -2,3 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in nxt_registry.gemspec
4
4
  gemspec
5
+
6
+ group :test do
7
+ gem 'rspec_junit_formatter' # for CircleCI
8
+ end
@@ -1,46 +1,48 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nxt_registry (0.1.5)
4
+ nxt_registry (0.3.2)
5
5
  activesupport
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activesupport (6.0.2.1)
10
+ activesupport (6.0.3.3)
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
- zeitwerk (~> 2.2)
16
- coderay (1.1.2)
17
- concurrent-ruby (1.1.6)
18
- diff-lcs (1.3)
19
- i18n (1.8.2)
15
+ zeitwerk (~> 2.2, >= 2.2.2)
16
+ coderay (1.1.3)
17
+ concurrent-ruby (1.1.7)
18
+ diff-lcs (1.4.4)
19
+ i18n (1.8.5)
20
20
  concurrent-ruby (~> 1.0)
21
- method_source (0.9.2)
22
- minitest (5.14.0)
23
- pry (0.12.2)
24
- coderay (~> 1.1.0)
25
- method_source (~> 0.9.0)
21
+ method_source (1.0.0)
22
+ minitest (5.14.2)
23
+ pry (0.13.1)
24
+ coderay (~> 1.1)
25
+ method_source (~> 1.0)
26
26
  rake (12.3.3)
27
27
  rspec (3.9.0)
28
28
  rspec-core (~> 3.9.0)
29
29
  rspec-expectations (~> 3.9.0)
30
30
  rspec-mocks (~> 3.9.0)
31
- rspec-core (3.9.1)
32
- rspec-support (~> 3.9.1)
33
- rspec-expectations (3.9.0)
31
+ rspec-core (3.9.2)
32
+ rspec-support (~> 3.9.3)
33
+ rspec-expectations (3.9.2)
34
34
  diff-lcs (>= 1.2.0, < 2.0)
35
35
  rspec-support (~> 3.9.0)
36
36
  rspec-mocks (3.9.1)
37
37
  diff-lcs (>= 1.2.0, < 2.0)
38
38
  rspec-support (~> 3.9.0)
39
- rspec-support (3.9.2)
39
+ rspec-support (3.9.3)
40
+ rspec_junit_formatter (0.4.1)
41
+ rspec-core (>= 2, < 4, != 2.12.0)
40
42
  thread_safe (0.3.6)
41
- tzinfo (1.2.6)
43
+ tzinfo (1.2.7)
42
44
  thread_safe (~> 0.1)
43
- zeitwerk (2.2.2)
45
+ zeitwerk (2.4.0)
44
46
 
45
47
  PLATFORMS
46
48
  ruby
@@ -51,6 +53,7 @@ DEPENDENCIES
51
53
  pry
52
54
  rake (~> 12)
53
55
  rspec (~> 3.0)
56
+ rspec_junit_formatter
54
57
 
55
58
  BUNDLED WITH
56
59
  2.1.4
data/README.md CHANGED
@@ -1,7 +1,9 @@
1
+ [![CircleCI](https://circleci.com/gh/nxt-insurance/nxt_registry.svg?style=svg)](https://circleci.com/gh/nxt-insurance/nxt_registry)
2
+
1
3
  # NxtRegistry
2
4
 
3
- NxtRegistry is a simple implementation of the container pattern. It allows you to register and resolve values in nested
4
- 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.
5
7
 
6
8
  ## Installation
7
9
 
@@ -21,80 +23,148 @@ Or install it yourself as:
21
23
 
22
24
  ## Usage
23
25
 
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:
31
+
24
32
  ```ruby
25
33
  class Example
26
34
  include NxtRegistry
27
35
 
28
- def passengers
29
- @passengers ||= begin
30
- registry :from do
31
- nested :to do
32
- nested :via, memoize: true, call: true, default: -> { [] } do
33
- attrs %i[train car plane horse] # restrict the attributes that can be registered
34
- resolver ->(value) { value } # do something with your registered value here
35
- transform_keys ->(key) { key.upcase } # transform keys
36
- end
37
- end
38
- end
39
- end
36
+ registry :languages do
37
+ register(:ruby, 'Stone')
38
+ register(:python, 'Snake')
39
+ register(:javascript, 'undefined')
40
40
  end
41
41
  end
42
42
 
43
43
  example = Example.new
44
- # Based on the naming of the registry and its nesting you are provided with a simple interface
45
- # that allows you to resolve and register values by name
46
-
47
- # Register an array with a value by calling the accessor with a key, value pair
48
- example.passengers.from(:a).to(:b).via(:train, ['Andy']) # => ['Andy']
49
-
50
- # In case you try to register the same key again you will get an error
51
- example.passengers.from(:a).to(:b).via(:train, ['Andy'])
52
- # => NxtRegistry::Errors::KeyAlreadyRegisteredError
53
- # (Key 'train' already registered in registry 'from.to.via')
54
- # NxtRegistry::Errors::KeyAlreadyRegisteredError inherits from KeyError
55
-
56
- # You can force values on the registry by using the bang method
57
- example.passengers.from(:a).to(:b).via!(:train, ['Andreas'])
44
+ example.registry(:languages).resolve(:ruby) # => 'Stone'
45
+ ```
58
46
 
59
- # Similarly you can try to resolve values softly
60
- # (meaning no KeyNotRegisteredError will be raised when nothing was registered)
61
- example.passengers.from(:a).to(:b).via!(:train)
62
- # Since there is a default defined for this registry, it does not make any sense
63
- # since there is always a value. But you get the point...
47
+ Alternatively you can also create instances of `NxtRegistry::Registry`
64
48
 
65
- # Resolve values by calling the accessor with the key only
66
- # In this case the default is returned because nothing was registered yet
67
- example.passengers.from(:a).to(:b).via(:hyperloop) # []
49
+ ```ruby
50
+ registry = NxtRegistry::Registry.new do
51
+ register(:andy, 'Andy')
52
+ register(:anthony, 'Anthony')
53
+ register(:aki, 'Aki')
54
+ end
68
55
 
69
- # Appending values to a default array
70
- example.passengers.from(:a).to(:b).via(:car) << 'Lütfi' # => ['Lütif']
71
- example.passengers.from(:a).to(:b).via(:plane) += %w[Nils Rapha]
72
- example.passengers.from(:a).to(:b).via(:plane) # => ['Nils', 'Rapha']
56
+ registry.resolve(:aki) # => 'Aki'
73
57
 
74
58
  ```
75
59
 
60
+ ## Class Level
61
+
62
+ You can add registries on the class level simply by extending your class with `NxtRegistry`
76
63
 
77
64
  ```ruby
78
65
  class OtherExample
79
66
  extend NxtRegistry
80
-
81
- # By passing a block to :registry you can directly register your values inline
82
- REGISTRY = registry(:errors) do
83
- # procs are called directly if not defined otherwise
67
+
68
+ registry(:errors) do
84
69
  register(KeyError, ->(error) { puts 'KeyError handler' } )
85
70
  register(ArgumentError, ->(error) { puts 'ArgumentError handler' } )
86
71
  end
72
+
73
+ registry(:country_codes) do
74
+ register(:germany, :de)
75
+ register(:england, :uk)
76
+ register(:france, :fr)
77
+ end
87
78
  end
88
79
 
89
- # Instead of using the name of the registry, you can also always call register and resolve on the
90
- # level where you want to register or resolve values. Equivalently to the named interface you can
91
- # use register! and resolve! to softly resolve or forcfully register values.
92
- OtherExample::REGISTRY.resolve(KeyError)
80
+ OtherExample.registry(:errors).resolve(KeyError)
93
81
  # KeyError handler
94
82
  # => nil
83
+ OtherExample.registry(:country_codes).resolve(:germany)
84
+ # => :de
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:
93
+
94
+ ```ruby
95
+ class Nested
96
+ extend NxtRegistry
97
+
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
108
+ end
109
+ end
110
+
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
95
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'
96
164
  ```
97
165
 
166
+ *Note that this feature is also available for registries with a single level only.*
167
+
98
168
  ### Restrict attributes to a certain set
99
169
 
100
170
  Use `attrs` to restrict which attributes can be registered on a specific level.
@@ -113,7 +183,7 @@ registry :example, default: ->(value) { 'default' }
113
183
 
114
184
  ### Blocks
115
185
 
116
- When you register a block value that can be called, tt will automatically be called when you resolve the value.
186
+ When you register a block value that can be called, it will automatically be called when you resolve the value.
117
187
  If that's not what you want, you can configure your registry (on each level) not to call blocks directly by defining `call false`
118
188
 
119
189
  ```ruby
@@ -124,7 +194,7 @@ end
124
194
 
125
195
  ### Memoize
126
196
 
127
- Values are memoized per default. Switch it off with `default false`
197
+ Values are memoized per default. Switch it off with `memoize: false`
128
198
 
129
199
  ```ruby
130
200
  registry :example, memoize: false do
@@ -141,7 +211,8 @@ registry.resolve(:one)
141
211
 
142
212
  ### Resolver
143
213
 
144
- You can register a resolver block if you want to lay hands on your values after they have been resolved.
214
+ You can register a resolver block if you want to lay hands on your values after they have been resolved.
215
+ A resolver can be anything that implements `:call` to which the value is passed.
145
216
 
146
217
  ```ruby
147
218
  registry :example do
@@ -155,9 +226,10 @@ registry.resolve(:one)
155
226
 
156
227
  ### Transform keys
157
228
 
158
- NxtRegistry uses a plain ruby hash to store values internally. Per default all keys used are transformed with `&:to_s`.
159
- 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`
160
- 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 }`
161
233
 
162
234
  ```ruby
163
235
  registry :example do
@@ -172,7 +244,7 @@ registry.resolve('BOMBSHELL')
172
244
  ### Customize registry errors
173
245
 
174
246
  You can also customize what kind of errors are being raised in case a of a key was not registered or was already registered.
175
- by providing values for `raise_key_already_registered_error` and `raise_key_not_registered_error`
247
+ by providing blocks or a handler responding to :call for `on_key_already_registered` and `on_key_already_registered`
176
248
 
177
249
  ## Development
178
250
 
@@ -1,18 +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"
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'
9
9
 
10
10
  module NxtRegistry
11
11
  def registry(name, **options, &config)
12
- Registry.new(name, **options, &config)
12
+ build_registry(Registry, name, **options, &config)
13
13
  end
14
14
 
15
15
  def recursive_registry(name, **options, &config)
16
- 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 ||= {}
17
42
  end
18
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
- def initialize(name, **options, &config)
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,44 +155,43 @@ 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
170
 
137
- on_key_already_registered && on_key_already_registered.call(key) if store[key] && raise
171
+ on_key_already_registered && on_key_already_registered.call(key) if store[key] && raise_on_key_already_registered
138
172
 
139
173
  store[key] = value
140
174
  end
141
175
 
142
- def __resolve(key, raise: true)
176
+ def __resolve(key, raise_on_key_not_registered: true)
143
177
  key = transformed_key(key)
144
178
 
145
179
  value = if is_leaf?
146
- if store[key]
180
+ if store.key?(key)
147
181
  store.fetch(key)
148
182
  else
149
- if default.is_a?(Blank)
150
- return unless raise
183
+ if is_a_blank?(default)
184
+ return unless raise_on_key_not_registered
151
185
 
152
186
  on_key_not_registered && on_key_not_registered.call(key)
153
187
  else
154
- value = resolve_default
188
+ value = resolve_default(key)
155
189
  return value unless memoize
156
190
 
157
191
  store[key] ||= value
158
192
  end
159
193
  end
160
194
  else
161
- # Call nested registry builder when we are not a leaf
162
195
  store[key] ||= default.call
163
196
  end
164
197
 
@@ -176,29 +209,37 @@ module NxtRegistry
176
209
  end
177
210
 
178
211
  def define_interface
179
- define_singleton_method name do |key = Blank.new, value = Blank.new|
180
- 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)
181
220
 
182
221
  key = transformed_key(key)
183
222
 
184
- if value.is_a?(Blank)
223
+ if is_a_blank?(value)
185
224
  resolve(key)
186
225
  else
187
226
  register(key, value)
188
227
  end
189
228
  end
190
229
 
191
- define_singleton_method "#{name}!" do |key = Blank.new, value = Blank.new|
192
- 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)
193
232
 
194
233
  key = transformed_key(key)
195
234
 
196
- if value.is_a?(Blank)
235
+ if is_a_blank?(value)
197
236
  resolve!(key)
198
237
  else
199
238
  register!(key, value)
200
239
  end
201
240
  end
241
+
242
+ self.interface_defined = true
202
243
  end
203
244
 
204
245
  def setup_defaults(options)
@@ -207,6 +248,7 @@ module NxtRegistry
207
248
  @call = options.fetch(:call) { true }
208
249
  @resolver = options.fetch(:resolver, false)
209
250
  @transform_keys = options.fetch(:transform_keys) { ->(key) { key.to_s } }
251
+ @accessor = options.fetch(:accessor) { name }
210
252
 
211
253
  @on_key_already_registered = options.fetch(:on_key_already_registered) { ->(key) { raise_key_already_registered_error(key) } }
212
254
  @on_key_not_registered = options.fetch(:on_key_not_registered) { ->(key) { raise_key_not_registered_error(key) } }
@@ -215,10 +257,9 @@ module NxtRegistry
215
257
  def define_accessors
216
258
  %w[default memoize call resolver transform_keys on_key_already_registered on_key_not_registered].each do |attribute|
217
259
  define_singleton_method attribute do |value = Blank.new, &block|
218
- # TODO: Allowing a block does not make sense for memoize and call?!
219
260
  value = block if block
220
261
 
221
- if value.is_a?(Blank)
262
+ if is_a_blank?(value)
222
263
  instance_variable_get("@#{attribute}")
223
264
  else
224
265
  instance_variable_set("@#{attribute}", value)
@@ -237,9 +278,9 @@ module NxtRegistry
237
278
  attrs.keys.exclude?(transformed_key(key))
238
279
  end
239
280
 
240
- def resolve_default
281
+ def resolve_default(key)
241
282
  if call && default.respond_to?(:call)
242
- default.call
283
+ default.arity > 0 ? default.call(key) : default.call
243
284
  else
244
285
  default
245
286
  end
@@ -256,7 +297,7 @@ module NxtRegistry
256
297
  def transformed_key(key)
257
298
  @transformed_key ||= {}
258
299
  @transformed_key[key] ||= begin
259
- if transform_keys && !key.is_a?(Blank)
300
+ if transform_keys && !is_a_blank?(key)
260
301
  transform_keys.call(key)
261
302
  else
262
303
  key
@@ -269,5 +310,21 @@ module NxtRegistry
269
310
  @store = original.send(:store).deep_dup
270
311
  @options = original.send(:options).deep_dup
271
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
272
329
  end
273
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.1.5"
2
+ VERSION = "0.3.2"
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.1.5
4
+ version: 0.3.2
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-03-02 00:00:00.000000000 Z
14
+ date: 2020-09-30 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activesupport
@@ -85,15 +85,19 @@ 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: []
92
93
  files:
94
+ - ".circleci/config.yml"
95
+ - ".editorconfig"
93
96
  - ".gitignore"
94
97
  - ".rakeTasks"
95
98
  - ".rspec"
96
99
  - ".travis.yml"
100
+ - CHANGELOG.md
97
101
  - Gemfile
98
102
  - Gemfile.lock
99
103
  - LICENSE.txt
@@ -105,9 +109,9 @@ files:
105
109
  - lib/nxt_registry/attribute.rb
106
110
  - lib/nxt_registry/blank.rb
107
111
  - lib/nxt_registry/errors.rb
108
- - lib/nxt_registry/nested_registry_builder.rb
109
112
  - lib/nxt_registry/recursive_registry.rb
110
113
  - lib/nxt_registry/registry.rb
114
+ - lib/nxt_registry/registry_builder.rb
111
115
  - lib/nxt_registry/version.rb
112
116
  - nxt_registry.gemspec
113
117
  homepage: https://github.com/nxt-insurance