{"id":13879196,"url":"https://github.com/nxt-insurance/nxt_registry","last_synced_at":"2025-05-08T21:13:28.444Z","repository":{"id":36936290,"uuid":"230161268","full_name":"nxt-insurance/nxt_registry","owner":"nxt-insurance","description":"A simple registry to implement the container pattern","archived":false,"fork":false,"pushed_at":"2025-04-22T00:01:46.000Z","size":106,"stargazers_count":17,"open_issues_count":12,"forks_count":0,"subscribers_count":14,"default_branch":"master","last_synced_at":"2025-05-08T21:12:55.050Z","etag":null,"topics":["container","registry","ruby","ruby-on-rails"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nxt-insurance.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-25T22:44:44.000Z","updated_at":"2024-06-11T21:13:27.000Z","dependencies_parsed_at":"2024-10-26T04:50:30.826Z","dependency_job_id":"c052c48f-4531-48db-8097-0310079b87f0","html_url":"https://github.com/nxt-insurance/nxt_registry","commit_stats":{"total_commits":56,"total_committers":5,"mean_commits":11.2,"dds":0.625,"last_synced_commit":"3baff945af69a7826556d3f4197fd431db3efedc"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nxt-insurance%2Fnxt_registry","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nxt-insurance%2Fnxt_registry/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nxt-insurance%2Fnxt_registry/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nxt-insurance%2Fnxt_registry/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nxt-insurance","download_url":"https://codeload.github.com/nxt-insurance/nxt_registry/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253149617,"owners_count":21861739,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["container","registry","ruby","ruby-on-rails"],"created_at":"2024-08-06T08:02:13.104Z","updated_at":"2025-05-08T21:13:28.415Z","avatar_url":"https://github.com/nxt-insurance.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"[![CircleCI](https://circleci.com/gh/nxt-insurance/nxt_registry.svg?style=svg)](https://circleci.com/gh/nxt-insurance/nxt_registry)\n\n# NxtRegistry\n\n`NxtRegistry` is a simple container that allows you to register and resolve values in nested structures.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'nxt_registry'\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install nxt_registry\n\n## Usage\n\n### Simple use case\n\n## Instance Level\n\nIf you simply need a single global instance of a registry include `NxtRegistry::Singleton`:    \n\n```ruby\nclass Example\n  include NxtRegistry::Singleton\n  \n  registry do\n    register(:ruby, 'Stone')\n    register(:python, 'Snake')\n    register(:javascript, 'undefined')\n  end\nend\n\nExample.resolve(:ruby) # =\u003e 'Stone'\n```\n\nAlternatively you can simply create instances of `NxtRegistry::Registry`:\n\n```ruby\nregistry = NxtRegistry::Registry.new do\n  register(:andy, 'Andy')\n  register(:anthony, 'Anthony')\n  register(:aki, 'Aki')\nend\n\nregistry.resolve(:aki) # =\u003e 'Aki'\n\n```\n\n## Class Level\n\nYou can also add registries on the class level simply by extending your class with `NxtRegistry`\n\n```ruby\nclass OtherExample\n  extend NxtRegistry\n \n  registry(:errors) do\n    register(KeyError, -\u003e(error) { puts 'KeyError handler' } )\n    register(ArgumentError, -\u003e(error) { puts 'ArgumentError handler' } )\n  end\n\n  registry(:country_codes) do\n    register(:germany, :de)\n    register(:england, :uk)\n    register(:france, :fr)\n  end \nend\n\nOtherExample.registry(:errors).resolve(KeyError)\n# KeyError handler\n# =\u003e nil\nOtherExample.registry(:country_codes).resolve(:germany)\n# =\u003e :de\n```\n\n## Register Patterns\n\nYou can also register values with patterns as keys. Non pattern keys are always evaluated first and then patterns \nwill be tried to match by definition sequence.  \n\n```ruby\nclass Example\n  extend NxtRegistry\n  \n  registry :status_codes do\n    register(/\\A4\\d{2}\\z/, 'Client errors')\n    register(/\\A5.*\\z/, 'Server errors')\n    register('422', 'Unprocessable Entity')\n    register(:'503', 'Internal Server Error')\n  end\nend\n\nExample.registry(:status_codes).resolve('503') # =\u003e \"Internal Server Error\"\nExample.registry(:status_codes).resolve(503) # =\u003e \"Internal Server Error\"\nExample.registry(:status_codes).resolve(422) # =\u003e \"Unprocessable Entity\"\nExample.registry(:status_codes).resolve(404) # =\u003e \"Client Errors\"\n```\n\n### Readers\n\nAccess your defined registries with the `registry(:country_code)` method.\n\n### Nesting registries\n\nYou can also simply nest registries like so:\n\n```ruby\nclass Nested\n  extend NxtRegistry\n\n  registry :developers do\n    register(:frontend) do\n      register(:igor, 'Igor')\n      register(:ben, 'Ben')\n    end\n    \n    register(:backend) do\n      register(:rapha, 'Rapha')\n      register(:aki, 'Aki')\n    end\n  end\nend\n\nNested.registry(:developers).resolve(:frontend, :igor)\n# =\u003e 'Igor'\n```\n\n#### Inherit options in nested registries\n\n```ruby\nclass Nested\n  extend NxtRegistry\n  \n  registry :developers, default: 'options can be inherited' do\n    register(:frontend, inherit_options: true) do\n      register(:igor, 'Igor')\n      register(:ben, 'Ben')\n    end\n  end\nend\n\nNested.registry(:developers).resolve(:frontend, :blank)\n# =\u003e 'options can be inherited'\n```\n\n### Defining specific nesting levels of a registry\n\nAnother feature of `NxtRegistry` is that you can define the nesting levels for a registry. Levels allow you to dynamically \nregister values within the defined levels. This means that on any level the registry will resolve to another registry and \nyou can register values into a deeply nested structure.  \n\n```ruby\nclass Layer\n  extend NxtRegistry\n  \n  registry :from do\n    level :to do\n      level :via\n    end  \n  end\nend\n\n# On every upper level every resolve returns a registry \nLayer.registry(:from) # =\u003e Registry[from]\nLayer.registry(:from).resolve(:munich) # =\u003e Registry[to] -\u003e {}\nLayer.registry(:from).resolve(:amsterdam) # =\u003e Registry[to] -\u003e {}\nLayer.registry(:from).resolve(:any_key) # =\u003e Registry[to] -\u003e {}\nLayer.registry(:from).resolve(:munich, :amsterdam) # =\u003e Registry[via] -\u003e {}\n\n# Register a value on the bottom level\nLayer.registry(:from).resolve(:munich, :amsterdam).register(:train, -\u003e { 'train' })\n# Resolve the complete path \nLayer.registry(:from).resolve(:munich, :amsterdam, :train) #  =\u003e 'train'\n``` \n\nFor registries with multiple levels the normal syntax for registering and resolving becomes quite weird and unreadable. This is why\nevery registry can be accessed through it's name or a custom accessor. The above example then can be simplified as follows.\n\n```ruby\nclass Layer\n  extend NxtRegistry\n  \n  registry :path, accessor: :from do # registry named path, can be accessed with .from(...)\n    level :to do\n      level :via\n    end  \n  end\nend\n\n# Register a value\nLayer.registry(:path).from(:munich).to(:amsterdam).via(:train, -\u003e { 'train' })\n# Resolve the complete path\nLayer.registry(:path).from(:munich).to(:amsterdam).via(:train) #  =\u003e 'train'\n```\n\n*Note that this feature is also available for registries with a single level only.*\n\n### Restrict keys to a certain set\n\nUse `allowed_keys` to restrict which keys can be registered on a specific level.\n\n```ruby\nregistry :example, allowed_keys: %w[one two three]\n```\n\n### Require a certain set of keys to be registered\n\nUse `required_keys` to enforce a certain set of keys to be registered on a specific level. This is especially helpful\nif you use registries in multiple places and you want to ensure they all register the same set of keys. \n\n```ruby\nregistry :example, required_keys: %w[one two three]\n```\n\n### Default values\n\nUse `default` to register a default value that will be resolved in case an attribute was not registered.\n\n```ruby\nregistry :example, default: -\u003e(value) { 'default' }\n```\n\n### Blocks\n\nWhen you register a block value that can be called, it will automatically be called when you resolve the value. \nIf that's not what you want, you can configure your registry (on each level) not to call blocks directly by defining `call false`\n\n```ruby\nregistry :example, call: false do\n  register(:one, -\u003e(value) { 'Not called when resolved' } )\nend\n```\n\n### Memoize\n\nValues are memoized per default. Switch it off with `memoize: false`\n\n```ruby\nregistry :example, memoize: false do\n  register(:one, -\u003e { Time.current } )\nend\n\nregistry.resolve(:one)\n# =\u003e 2020-01-02 23:56:15 +0100\nregistry.resolve(:one)\n# =\u003e 2020-01-02 23:56:17 +0100\nregistry.resolve(:one)\n# =\u003e 2020-01-02 23:56:18 +0100\n```\n\n**IMPORTANT**: whenever you want your value to be evaluated anew every time it is resolved, you should always wrap it in a lambda.\n\nFor example, if you're resolving an ENV variable you should do it this way:\n\n```ruby\nregistry :example do\n  register(:env_variable, -\u003e { ENV['FEATURE_FLAG'] })\nend\n```\n\nIn this case config can be reloaded on the fly, and tests can also overwrite feature flags, for example.\n\n### Resolve callbacks\n\nYou can hook into the before and after resolver callbacks in case you need to lay hands on your values\nbefore and / or after resolving. A callback can be anything that implements `:call` to which the value is passed.  \n\n```ruby\nregistry :example do\n  key_resolver -\u003e(key) { key.strip }\n  resolver -\u003e(value) { value.upcase }\n  \n  register(:input, 'output')\nend\n\nregistry.resolve('  input   ')\n# =\u003e 'OUTPUT'\n```\n\n### Transform keys\n\n`NxtRegistry` uses a plain ruby hash to store values internally. Per default all keys used are transformed with `\u0026:to_s`.\nThus you can use symbols or strings to register and resolve values. If it's not what you want, switch it off with \n`transform_keys false` or define your own key transformer by assigning a block to transform_keys: \n`transform_keys -\u003e(key) { key.upcase }`\n\n```ruby\nregistry :example do\n  transform_keys -\u003e(key) { key.to_s.downcase }\n  register(:bombshell, 'hanna')\nend\n\nregistry.resolve('BOMBSHELL')\n# =\u003e 'hanna'\n```\n\n### Customize registry errors\n\nYou can also customize what kind of errors are being raised in case a of a key was not registered or was already registered.\nby providing blocks or a handler responding to :call for `on_key_already_registered` and `on_key_already_registered`\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/nxt_registry.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnxt-insurance%2Fnxt_registry","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnxt-insurance%2Fnxt_registry","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnxt-insurance%2Fnxt_registry/lists"}