{"id":30371263,"url":"https://github.com/eliav-lavi/dawn","last_synced_at":"2025-10-06T23:21:09.657Z","repository":{"id":59152770,"uuid":"202766978","full_name":"eliav-lavi/dawn","owner":"eliav-lavi","description":"An Instances Container for Ruby","archived":false,"fork":false,"pushed_at":"2020-04-05T21:04:47.000Z","size":30,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-27T16:57:33.644Z","etag":null,"topics":["container","dependency-injection","rails","ruby"],"latest_commit_sha":null,"homepage":null,"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/eliav-lavi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-08-16T16:56:56.000Z","updated_at":"2020-04-05T21:04:49.000Z","dependencies_parsed_at":"2022-09-13T11:01:18.630Z","dependency_job_id":null,"html_url":"https://github.com/eliav-lavi/dawn","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/eliav-lavi/dawn","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eliav-lavi%2Fdawn","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eliav-lavi%2Fdawn/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eliav-lavi%2Fdawn/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eliav-lavi%2Fdawn/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eliav-lavi","download_url":"https://codeload.github.com/eliav-lavi/dawn/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eliav-lavi%2Fdawn/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278693684,"owners_count":26029569,"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","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["container","dependency-injection","rails","ruby"],"created_at":"2025-08-20T05:21:21.609Z","updated_at":"2025-10-06T23:21:09.651Z","avatar_url":"https://github.com/eliav-lavi.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Dawn: An Instances Container for Ruby\n[![Gem Version](https://badge.fury.io/rb/dawn.svg)](https://badge.fury.io/rb/dawn)\n[![Maintainability](https://api.codeclimate.com/v1/badges/e7246fe169a534491e50/maintainability)](https://codeclimate.com/github/eliav-lavi/dawn/maintainability)\n[![Build Status](https://travis-ci.org/eliav-lavi/dawn.svg?branch=master)](https://travis-ci.org/eliav-lavi/dawn)\n\n`Dawn` is a simple and intuitive instances container for Ruby. It was born out of the need to reference existing application instances in Rails controllers, without having to re-initialize them upon each controller call or using the singleton pattern; however, while `Dawn` can be used in a Rails app, it may fit any Ruby application that is built with dependency injection in mind.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'dawn'\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install dawn\n\n## Usage\n\n`Dawn` allows you to build a container of namespaces which are registered with instances. Upon the booting stages of your application, you might want to initialize instances of classes which serve different purposes (e.g. `ChargeCreationService` for handling the complexity of creating a new charge in your system), accross different business domains. That way you can reference those instances later, when requests start arriving at your application, without having re-initialize those instances each time. This idea also allows you to build your app as a hierarchical tree of dependnecies, as will be demonstrated later.\n\nYou can build a `Dawn` container with multiple namespaces, each namespace having a unique name and containing several instances:\n\n```ruby\n# Assuming instance_a and instance_b were just initialized:\nfoo_namespace_request = Dawn::Namespace::Request.new(name: :foo) do |namespace|\n  namespace\n    .set(key: :instance_a, instance: instance_a)\n    .set(key: :instance_b, instance: instance_b)\nend\n\nCONTAINER = Dawn::Container.build([foo_namespace_request])\n```\nNote: the block passed to `Dawn::Namespace::Request#new` only gets evaluated once used within `Dawn::Container.build`.\n\nLater, you may fetch instances from the container:\n```ruby\nCONTAINER.fetch(namespace: foo, key: :instance_a)\n```\n\n\u003cimg src=\"https://i.imgur.com/GFEKDlh.png\" width=\"25%\" height=\"25%\"\u003e\n\n### Dependency Injection Based Applications\nSince `Dawn` was created to support the development of dependency injection based application, I will briefly discuss this topic in this section. Usage in Rails will be clearer hence.\n\nCrafting your application as such that is based on a nested tree of injected dependencies has many benefits that has been described in many writings before. That is, in contrary to an opposing design choice, which is fairly common in the Ruby eco-system, in which dependencies are hard coded. The following example demonstrates this in a nutshell.\n\nAssuming some `FooService` class:\n\n```ruby\nclass FooService\n  def call\n    # Return some value / do something\n  end\nend\n```\n\nWe can use it as a dependency in another class, `BarService` in two ways. Either directly, as an hard-coded dependency:\n```ruby\nclass BarService\n  def call\n    FooService.new.call\n  end\nend\n```\n\nOr as injected dependency:\n```ruby\nclass BarService\n  def self.build\n    foo_service = FooService.new\n    new(foo_service: foo_service)\n  end\n\n  def initialize(foo_service:)\n    @foo_service = foo_service\n  end\n\n  def call\n    @foo_service.call\n  end\nend\n```\n\nThis is just a single level of dependency, real-life application are often much more nested.\nNotice that I did mentioned `FooService` in an hard-coded fashion, in my `.build` method, but that is just a helper method to get the common usage of `BarService` instances and its not on the instant scope, but on the class scope. I can pass anything I want to `BarService#initialize`.\n\nI urge you to read more about dependency injection, but the advantages of the latter approach are numerous! From testing to code reusability, dependency injection is a real thing, and it doesn't have to be complex or scary at all.\n\n### Usage In Rails\nOne problem that sometimes  emerges is that we don't have control of everything in our application, and the most prominent example is if we are building our application on top of Rails. When Rails receives a request to a certain route, it will find the controller which is registered with this route **and will initialize a new instance of that controller with the parameters of the request as the instance variable `@param`**. This pattern is the complete opposite of dependency injection based design, but we have nothing to do about it (other than not using Rails, which is not always a choice we can make).\nWhile we cannot change this behaviour of Rails - a new controller instance will be created upon each request - we can choose to stop this pattern right there, and use pre-initialized instances from there on. This is where `Dawn` becomes really helpful.\n\nFor example, let's assume some `ChargesController`, whose `#create` method needs to pass request's data to some `ChargeCreationService`. Usually, the implementation would look like this:\n```ruby\nclass ChargesController \u003c ApplicationController\n  def create\n    ChargeCreationService.new.call(params[:charge])\n\n    # Note: In this manner, ChargeCreationService instances have no members / instance variables.\n    # Some people also do the following, which might feel slicker at first:\n    # ChargeCreationService.new(params[:charge]).call\n    # Honestly, assuming ChargeCreationService has dependencies of it's own, both feel wrong to me.\n  end\nend\n```\n\nWith `Dawn` we can do this:\n```ruby\nclass ChargesController \u003c ApplicationController\n  def create\n    # Assuming we initialized a proper Dawn container in the initialization stages of our application, and assigned it the the global const CONTAINER:\n\n    service = CONTAINER.fetch(namespace: :charges, key: :creation_service)\n    service.call(params[:charge])\n  end\nend\n```\n\nRails offers the `after_initialize` hook that you can use in `application.rb` - this is a proper place to initialize your `Dawn::Container`. In the previous example, I have referenced it from the top level contsant `CONTAINER`, which could be assigned there. See [here](https://guides.rubyonrails.org/configuring.html#rails-general-configuration) for more info on `after_initialize`.\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## Feature Requests\n\nDawn is open for changes and requests!\nIf you have an idea, a question or some need, feel free to contact me here or at eliavlavi@gmail.com.\n\n## Contributing\n\n1. Fork it ( https://github.com/eliav-lavi/dawn/fork )\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## 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%2Feliav-lavi%2Fdawn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feliav-lavi%2Fdawn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feliav-lavi%2Fdawn/lists"}