{"id":13805730,"url":"https://github.com/rwnx/hardwire","last_synced_at":"2026-04-08T14:32:40.879Z","repository":{"id":44672252,"uuid":"234989918","full_name":"rwnx/hardwire","owner":"rwnx","description":"A compile-time, non-intrusive dependency injection system.","archived":false,"fork":false,"pushed_at":"2025-08-27T12:23:19.000Z","size":134,"stargazers_count":23,"open_issues_count":3,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2026-02-06T00:52:30.056Z","etag":null,"topics":["crystal","dependency-injection","hacktoberfest","macros"],"latest_commit_sha":null,"homepage":"https://rwnx.github.io/hardwire/","language":"Crystal","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/rwnx.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","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":"2020-01-20T00:38:39.000Z","updated_at":"2025-08-27T12:22:08.000Z","dependencies_parsed_at":"2024-01-25T05:25:49.020Z","dependency_job_id":"9ecc0413-1303-4dc2-b8d6-0f667f18a7d5","html_url":"https://github.com/rwnx/hardwire","commit_stats":null,"previous_names":["jerometwell/hardwire"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/rwnx/hardwire","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rwnx%2Fhardwire","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rwnx%2Fhardwire/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rwnx%2Fhardwire/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rwnx%2Fhardwire/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rwnx","download_url":"https://codeload.github.com/rwnx/hardwire/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rwnx%2Fhardwire/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31559814,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"ssl_error","status_checked_at":"2026-04-08T14:31:17.202Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["crystal","dependency-injection","hacktoberfest","macros"],"created_at":"2024-08-04T01:01:04.277Z","updated_at":"2026-04-08T14:32:40.862Z","avatar_url":"https://github.com/rwnx.png","language":"Crystal","funding_links":[],"categories":["Dependency Injection"],"sub_categories":[],"readme":"# HardWire ⚡\n[![Crystal CI](https://github.com/rwnx/hardwire/workflows/Crystal%20CI/badge.svg?branch=main)](https://github.com/rwnx/hardwire/actions?query=workflow%3A%22Crystal+CI%22)\n\nA Compile-time Dependency Injection system for Crystal.\n\n## Installation\n\n1. Add the dependency to your `shard.yml`:\n\n```yaml\ndependencies:\n  hardwire:\n    github: rwnx/hardwire\n```\n\n2. Run `shards install`\n\n## Usage\n\n```crystal\nrequire \"hardwire\"\n```\n\nHardwire is designed to operate inside a container object.\nSince the resolution is compile-time (Using Macros), normally this will be a module.\n\n### Creating a container 📦\n```crystal\n# To create a new container, include `HardWire::Container`\n# This will add the macros you need to register and resolve wiring\nmodule Container\n  include HardWire::Container\n\n  # use transient/singleton to wire different lifecycles\n  # singleton dependencies will be memoized\n  # dependencies for the constructor will be resolved from the constructor automatically\n  transient Dependency\n  singleton NeedsDependency\n  scoped Webservice\n\n  # you can also register dependencies with a block instead of inspecting the constructor\n  # Your block MUST return an instance of the class you are registering\n  singleton NeedsDependency {\n    NeedsDependency.new( self.resolve Dependency )\n  }\nend\n```\n\nHardwire tries to operate with minimal modifications to other classes (unless required).\n_\"simple\"_ classes, e.g.\n  * Have a single constructor\n  * Have unique dependencies/do not require tags\n\nIf your classes match this signature, you can wire up in the container without adding anything to the classes.\n\nFor everything else, there's:\n\n### Multiple Constructors 🚧\nHardwire needs to know which constuctor function to use.\n\nAnnotate your \"Injectable\" constructor with the Hardwire::Inject annotation.\n```crystal\nclass MultipleInits\n  @[HardWire::Inject]\n  def initialize(input: String)\n    # register will inspect this method's arguments\n    # [...]\n  end\n\n  def initialize\n    # will not be used for injection\n    # [...]\n  end\nend\n```\n\n### Tags 🏷\nTo differentiate between registrations of _the same type_, use the HardWire::Tags annotation.\nTags allow you to attach additional metadata to the signature. Tags themselves are string-based, simple identifiers (/\\w+/) that allow you to resolve\na different registration of the same class.\n\n\n```crystal\n# [...]\n\n# registering a transient dependency with tag \"secret\"\ntransient String, \"secret\" {\n  \"a secret string\"\n}\n\n# registering a singleton\n# When no tags are set, it is considered the \"default\" registration\nsingleton DbService\n\n# registering a different singleton with a tag\nsingleton DbService, \"primary\"\n\n# Resolving Dependencies\nclass Resolving\n  @[Hardwire::Tags(input: \"secret\", primary_db: \"primary\")]\n  def initialize(input : String, primary_db : DbService, default_db : DbService)\n  end\nend\n```\n### Lifecycles ♽\nThere are 3 lifecycles available for registrations:\n* Singleton: The dependency is instantiated once for the lifetime of the application\n* Scoped: the dependency instantiated once for each created scope and destroyed when the scope is garbage-collected\n* Transient: the dependency is instatiated each time it is resolved\n\n#### Scopes 🔭\nTo managed scoped instances, you should create a scope object with the `.scope` macro.\n\n```crystal\n# This example will init a database DatabaseConnection for each http request\n# but all the databases will recieve the same instance of config (singleton)\n# the ScopedLogging dependency will also be instantiated once for each scope resolution\nrequire \"kemal\"\nclass Config; end\nclass ScopedLogging; end\nclass DatabaseConnection\n  def initialize(@config : Config, @logging : ScopedLogging)\n  end\nend\n\nmodule Container\n  include HardWire::Container\n\n  singleton Config\n  scoped ScopedLogging\n  scoped DatabaseConnection\nend\n\n\nget \"/\" do\n  # create a unique scope\n  scope = Container.scope\n\n  logger = scope.resolve ScopedLogging\n  db = scope.resolve DatabaseConnection\n  db.get_some_data\n\n  logger.log(\"I share a logger with the database in scope!\")\nend\n\nKemal.run\n\n```\n\n### Resolving Manually 🔨\nYou can resolve dependencies manually using the `.resolve` macro. This allows you to resolve dependencies manually with the tag string.\n\n```crystal\nmodule Container\n  include HardWire::Container\n\n  transient SecretService, \"primary\"\n  singleton DatabaseThing\nend\n\nservice = Container.resolve SecretService, \"primary\"\ndb = Container.resolve DatabaseThing\n```\n\n### Runtime Interrogation 👀\nHardwire can tell you information about the registrations at runtime, but the dependencies are _HardWired_ (See what I did there?), so they can't be changed.\n\n```crystal\nmodule Container\n  include HardWire::Container\n\n  singleton DbService\nend\n\nContainer.registered?(DbService) # true\nContainer.registered?(DbService, \"tagged\") # false\nContainer.registered?(String) # false\n```\n\n## Contributing\n\n1. Fork it (\u003chttps://github.com/rwnx/hardwire/fork\u003e)\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create a new Pull Request\n\n## Contributors\n\n- [rwnx](https://github.com/rwnx) - creator and maintainer\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frwnx%2Fhardwire","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frwnx%2Fhardwire","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frwnx%2Fhardwire/lists"}