nxt_registry 0.1.4 → 0.3.1

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: 5c121a45cf6ff43b4428e50ed93d3c22b7aff832fb46c93641c39bedbd139faa
4
- data.tar.gz: bd8a2f07655578d9441e9b238ae2b400b31327ad0b66e8b1dbaeadd72e67bde1
3
+ metadata.gz: 121af631fa49f89d2b47599adcf3122401409299f65d755f7ba3cb418734cdf4
4
+ data.tar.gz: e6d94a93edf4bb250186242e5892f0dcda7df9c71c23be5a4b8ddca5420eed0d
5
5
  SHA512:
6
- metadata.gz: 18ddc690ff5a48be4874dcc9d1c48ccc44b68db20f107ebf6877938ee9da15240e04c4c438002f3ab59a01106597a407ca46bd6a5602caba5022706a9d0e44de
7
- data.tar.gz: a6bb26cd86e220b4cf5b20bb4d87e58b0f8e789a428ec032b3c86394d4ec57a2d026254f78649bdab2ac0e30276b230e78eaf88de7f03b6f8b6716133a7873b7
6
+ metadata.gz: b0601a25a8325fe3fb21f2cfdf25e8710c3b219c135999fea2bc0bc325713bf3f20f321f4aadbdffcc50f4d03557c0fc4ba1008d52efe69e3f38400e4dfdf0b9
7
+ data.tar.gz: 770c75ffca22aa1c7de4af1de955abf2044d9dca121b566e277f5d0fd637e41bc58231ae1edfd38a11af69279c05928f001e98561edae77edd060499bcf9bdf4
@@ -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
data/.rakeTasks CHANGED
@@ -4,4 +4,4 @@ You are allowed to:
4
4
  1. Remove rake task
5
5
  2. Add existing rake tasks
6
6
  To add existing rake tasks automatically delete this file and reload the project.
7
- --><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Build nxt_registry-0.1.0.gem into the pkg directory" fullCmd="build" taksId="build" /><RakeTask description="Remove any temporary products" fullCmd="clean" taksId="clean" /><RakeTask description="Remove any generated files" fullCmd="clobber" taksId="clobber" /><RakeTask description="Build and install nxt_registry-0.1.0.gem into system gems" fullCmd="install" taksId="install" /><RakeGroup description="" fullCmd="" taksId="install"><RakeTask description="Build and install nxt_registry-0.1.0.gem into system gems without network access" fullCmd="install:local" taksId="local" /></RakeGroup><RakeTask description="Create tag v0.1.0 and build and push nxt_registry-0.1.0.gem to TODO: Set to 'http://mygemserver.com'" fullCmd="release[remote]" taksId="release[remote]" /><RakeTask description="Run RSpec code examples" fullCmd="spec" taksId="spec" /><RakeTask description="" fullCmd="default" taksId="default" /><RakeTask description="" fullCmd="release" taksId="release" /><RakeGroup description="" fullCmd="" taksId="release"><RakeTask description="" fullCmd="release:guard_clean" taksId="guard_clean" /><RakeTask description="" fullCmd="release:rubygem_push" taksId="rubygem_push" /><RakeTask description="" fullCmd="release:source_control_push" taksId="source_control_push" /></RakeGroup></RakeGroup></Settings>
7
+ --><RakeGroup description="" fullCmd="" taksId="rake"><RakeTask description="Build nxt_registry-0.1.4.gem into the pkg directory" fullCmd="build" taksId="build" /><RakeTask description="Remove any temporary products" fullCmd="clean" taksId="clean" /><RakeTask description="Remove any generated files" fullCmd="clobber" taksId="clobber" /><RakeTask description="Build and install nxt_registry-0.1.4.gem into system gems" fullCmd="install" taksId="install" /><RakeGroup description="" fullCmd="" taksId="install"><RakeTask description="Build and install nxt_registry-0.1.4.gem into system gems without network access" fullCmd="install:local" taksId="local" /></RakeGroup><RakeTask description="Create tag v0.1.4 and build and push nxt_registry-0.1.4.gem to https://rubygems.org" fullCmd="release[remote]" taksId="release[remote]" /><RakeTask description="Run RSpec code examples" fullCmd="spec" taksId="spec" /><RakeTask description="" fullCmd="default" taksId="default" /><RakeTask description="" fullCmd="release" taksId="release" /><RakeGroup description="" fullCmd="" taksId="release"><RakeTask description="" fullCmd="release:guard_clean" taksId="guard_clean" /><RakeTask description="" fullCmd="release:rubygem_push" taksId="rubygem_push" /><RakeTask description="" fullCmd="release:source_control_push" taksId="source_control_push" /></RakeGroup></RakeGroup></Settings>
@@ -0,0 +1,37 @@
1
+ # v0.3.1 2020-09-23
2
+
3
+ - Allow to define custom accessors for registries
4
+
5
+ # v0.3.0 2020-09-10
6
+
7
+ ### Breaking Changes
8
+
9
+ - Toggled interface for resolve(!) and register(!)
10
+ - Allow to register values in nested registries
11
+ - Rename nested method into level
12
+ - Provide registry readers
13
+ - Remove Singleton extension
14
+ - Allow to resolve paths
15
+ - Pass key to default block when it takes an argument
16
+
17
+ [Compare v0.2.1...v0.3.0](https://github.com/nxt-insurance/nxt_registry/compare/v0.2.1...v0.3.0)
18
+
19
+ # v0.2.1 2020-08-14
20
+
21
+ ### Fixed
22
+
23
+ - Fixed Registry#fetch to raise key error in case of missing key
24
+
25
+ [Compare v0.2.0...v0.2.1](https://github.com/nxt-insurance/nxt_registry/compare/v0.2.0...v0.2.1)
26
+
27
+
28
+ # v0.2.0 2020-07-24
29
+
30
+ ### Added
31
+
32
+ - [internal] Added NxtRegistry::Singleton
33
+ - Added NxtRegistry::Singleton interface
34
+ - Make name optional and have object_id.to_s as default name
35
+ - Fix readme
36
+
37
+ [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.4)
4
+ nxt_registry (0.3.1)
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.5)
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)
26
- rake (10.5.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
+ 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.0)
32
- rspec-support (~> 3.9.0)
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
- rspec-mocks (3.9.0)
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.0)
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
@@ -49,8 +51,9 @@ DEPENDENCIES
49
51
  bundler (~> 2.0)
50
52
  nxt_registry!
51
53
  pry
52
- rake (~> 10.0)
54
+ rake (~> 12)
53
55
  rspec (~> 3.0)
56
+ rspec_junit_formatter
54
57
 
55
58
  BUNDLED WITH
56
- 2.0.2
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
- configure(&config)
15
+ configure(&config) if block_given? || parent
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
158
+ attr_reader :namespace, :parent, :config, :store, :options, :accessor
125
159
  attr_accessor :is_leaf
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,24 +209,28 @@ 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
+ raise_invalid_accessor_name(accessor) if respond_to?(accessor)
213
+ accessor_with_bang = "#{accessor}!"
214
+ raise_invalid_accessor_name(accessor_with_bang) if respond_to?(accessor_with_bang)
215
+
216
+ define_singleton_method accessor do |key = Blank.new, value = Blank.new|
217
+ return self if is_a_blank?(key)
181
218
 
182
219
  key = transformed_key(key)
183
220
 
184
- if value.is_a?(Blank)
221
+ if is_a_blank?(value)
185
222
  resolve(key)
186
223
  else
187
224
  register(key, value)
188
225
  end
189
226
  end
190
227
 
191
- define_singleton_method "#{name}!" do |key = Blank.new, value = Blank.new|
192
- return self if key.is_a?(Blank)
228
+ define_singleton_method accessor_with_bang do |key = Blank.new, value = Blank.new|
229
+ return self if is_a_blank?(key)
193
230
 
194
231
  key = transformed_key(key)
195
232
 
196
- if value.is_a?(Blank)
233
+ if is_a_blank?(value)
197
234
  resolve!(key)
198
235
  else
199
236
  register!(key, value)
@@ -207,6 +244,7 @@ module NxtRegistry
207
244
  @call = options.fetch(:call) { true }
208
245
  @resolver = options.fetch(:resolver, false)
209
246
  @transform_keys = options.fetch(:transform_keys) { ->(key) { key.to_s } }
247
+ @accessor = options.fetch(:accessor) { name }
210
248
 
211
249
  @on_key_already_registered = options.fetch(:on_key_already_registered) { ->(key) { raise_key_already_registered_error(key) } }
212
250
  @on_key_not_registered = options.fetch(:on_key_not_registered) { ->(key) { raise_key_not_registered_error(key) } }
@@ -215,10 +253,9 @@ module NxtRegistry
215
253
  def define_accessors
216
254
  %w[default memoize call resolver transform_keys on_key_already_registered on_key_not_registered].each do |attribute|
217
255
  define_singleton_method attribute do |value = Blank.new, &block|
218
- # TODO: Allowing a block does not make sense for memoize and call?!
219
256
  value = block if block
220
257
 
221
- if value.is_a?(Blank)
258
+ if is_a_blank?(value)
222
259
  instance_variable_get("@#{attribute}")
223
260
  else
224
261
  instance_variable_set("@#{attribute}", value)
@@ -237,9 +274,9 @@ module NxtRegistry
237
274
  attrs.keys.exclude?(transformed_key(key))
238
275
  end
239
276
 
240
- def resolve_default
277
+ def resolve_default(key)
241
278
  if call && default.respond_to?(:call)
242
- default.call
279
+ default.arity > 0 ? default.call(key) : default.call
243
280
  else
244
281
  default
245
282
  end
@@ -256,7 +293,7 @@ module NxtRegistry
256
293
  def transformed_key(key)
257
294
  @transformed_key ||= {}
258
295
  @transformed_key[key] ||= begin
259
- if transform_keys && !key.is_a?(Blank)
296
+ if transform_keys && !is_a_blank?(key)
260
297
  transform_keys.call(key)
261
298
  else
262
299
  key
@@ -269,5 +306,21 @@ module NxtRegistry
269
306
  @store = original.send(:store).deep_dup
270
307
  @options = original.send(:options).deep_dup
271
308
  end
309
+
310
+ def build_namespace
311
+ parent ? name.to_s.prepend("#{parent.send(:namespace)}.") : name.to_s
312
+ end
313
+
314
+ def raise_register_argument_error
315
+ raise ArgumentError, 'Either provide a key value pair or a block to register'
316
+ end
317
+
318
+ def is_a_blank?(value)
319
+ value.is_a?(Blank)
320
+ end
321
+
322
+ def raise_invalid_accessor_name(name)
323
+ raise ArgumentError, "#{self} already implements a method named: #{name}. Please choose a different accessor name"
324
+ end
272
325
  end
273
326
  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.4"
2
+ VERSION = "0.3.1"
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"
@@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
35
35
  spec.add_dependency "activesupport"
36
36
 
37
37
  spec.add_development_dependency "bundler", "~> 2.0"
38
- spec.add_development_dependency "rake", "~> 10.0"
38
+ spec.add_development_dependency "rake", "~> 12"
39
39
  spec.add_development_dependency "rspec", "~> 3.0"
40
40
  spec.add_development_dependency "pry"
41
41
  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.1.4
4
+ version: 0.3.1
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-01-15 00:00:00.000000000 Z
14
+ date: 2020-09-25 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activesupport
@@ -47,14 +47,14 @@ dependencies:
47
47
  requirements:
48
48
  - - "~>"
49
49
  - !ruby/object:Gem::Version
50
- version: '10.0'
50
+ version: '12'
51
51
  type: :development
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
55
  - - "~>"
56
56
  - !ruby/object:Gem::Version
57
- version: '10.0'
57
+ version: '12'
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rspec
60
60
  requirement: !ruby/object:Gem::Requirement
@@ -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
@@ -132,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
136
  - !ruby/object:Gem::Version
133
137
  version: '0'
134
138
  requirements: []
135
- rubygems_version: 3.0.6
139
+ rubygems_version: 3.0.3
136
140
  signing_key:
137
141
  specification_version: 4
138
142
  summary: nxt_registry is a simple implementation of the container pattern