Revised by Piotr Solnica and Andy Holland
Lately, I have been playing around and contributing to the great ecosystem of dry-rb, first of all, I have to say the community is absolutely fantastic, super supportive and eager to welcome many new contributors.
Yesterday I decided to start playing around with a gem call dry-web-roda this small framework aims to provide an alternative to building web apps using ruby, with the use of small libraries such as dry-view, dry-container, dry-transaction, roda, rom and many more; the help you build clearer, flexible and more maintainable code.
The post tries to create a bridge for Rails Developers and encourage them to try these new alternatives, that will bring joy and fresh concepts for building web apps with ruby.
After installing the gem we can create a sample app by typing
dry-web-roda new github_stalker --arch=flat- this will create the file structure.
├── bin ├── config ├── db ├── lib │ ├── github_stalker │ │ └── views │ └── persistence │ ├── commands │ └── relations ├── log ├── spec │ └── support │ └── db ├── system │ ├── boot │ └── github_stalker ├── transactions └── web ├── routes └── templates └── layouts
At first the structure is quite different from what we are used to in a typical Rails app, but I will try my best to explain it.
First, the system folder is where all the configuration lives, we can think of them as our initializers, this will be the entry point of our application. There are many small libraries involved to make everything work, that I can not go into detail in just one post, I will try cover all of them in a series of posts.
│ ├── monitor.rb
│ ├── rom.rb
│ └── view.rb
We will start with
application.rb, this file contains all the configuration regarding
container and plugins to be use with
require "dry/web/roda/application" require_relative "container" module GithubStalker class Application < Dry::Web::Roda::Application configure do |config| config.container = Container config.routes = "web/routes".freeze end opts[:root] = Pathname(__FILE__).join("../..").realpath.dirname use Rack::Session::Cookie, key: "github_stalker.session", secret: GithubStalker::Container.settings.session_secret plugin :csrf, raise: true plugin :flash plugin :dry_view route do |r| r.multi_route r.root do r.view "welcome" end end load_routes! end end
What is a container? I’m going to bring the words from the official website
dry-container is a simple, thread-safe container, intended to be one half of the implementation of an IoC container or how I understand it a container “gives you access to the objects that make up your application”.
Roda (the router) is a Routing Tree Web Toolkit I will not go into much detail since I’m really new to it.
Following is the
import.rb, which in my opinion is where all the magic happens, thanks to
dry-auto_inject. This holds the configuration for loading the files for our application, more or less like
auto_load_path of Rails, but only using ruby methods and variables
require "dry/web/umbrella" require_relative "settings" module GithubStalker class Container < Dry::Web::Umbrella configure do config.name = :github_stalker config.default_namespace = "github_stalker" config.settings_loader = GithubStalker::Settings config.listeners = true config.auto_register = %w[ lib/github_stalker ] end load_paths! "lib", "system" def self.settings config.settings end end end
At first sight, we see some configuration for name, namespace and some
auto_register, this will register all the files inside our
lib/github_stalker folder in your container, following the convention from the file structure, so for example
├── lib ├── github_stalker ├── github │ ├── client.rb # will register inside our container under the name github.client │ ├── fetch_gists.rb # github.fetch_gists │ └── fetch_info.rb # github.fetch_info └── users └── validate_input.rb # users.validate_input
And thanks to
dry-auto_inject, all these files will be lazily loaded as required, making it really efficient.
require "github_stalker/import" module GithubStalker module Github class FetchGists include GithubStalker::Import['github.client'] # at the instance level we will have access to `client` def call(input) client.gists(input) end end end end
Well I think this post is getting too long and I don’t want to take more of your time. Thank you for reading it. I will keep creating more posts explaining the rest of the structure and libraries involved in
dry-rb - they are great and bring a fresh view in the ruby world.
All the above example were taken from an example app I built using
dry-web-roda if you want to check the code please follow this repo
If you have any thoughts or questions, please share and I’ll be happy to answer in the comments.