Alki (AL-kai) is a Dependency Injection framework for Ruby. Alki is designed to help organize and scale your project, so you can focus on the important stuff. It can be used alongside frameworks such as Ruby on Rails.
Some high level features:
-
Easily manage objects and dependencies
-
Enables writing reusable and testable code
-
Requires no annotations, mixins, or other changes to your code.
-
Developer console (built on pry)
-
Automatic code reloading
-
Powerful DSL toolkit
-
Extensible
Installation
Add this line to your application’s Gemfile:
gem 'alki'
And then execute:
$ bundle
Or install it yourself as:
$ gem install alki
Introduction
Note
|
Full "todo" example can be found here |
Alki simplifies project organization by pulling out all of the "connective tissue" that connects our classes and modules together, and puts them into a special object called an Assembly.
There are many ways to use Assemblies, but the most common is to have a single Assembly for a project. For example, if you hade a "todo" command line utility project that you wanted to use Alki with, all you would need to do to create an Assembly is add this file.
require 'alki'
Alki.project_assembly!
This will create a module called Todo
that is an empty assembly:
$ bundle exec irb -Ilib
2.4.0 :001 > require 'todo'
=> true
2.4.0 :002 > todo = Todo.new
=> #<Todo:21964520>
Defining Elements
Adding things to the assembly requires an assembly definition file. By convention this is
named config/assembly.rb
and is built using a simple DSL. There are
a handful of different element types in Assemblies. Below are a few of the
most common. Full documentation of the DSL can be found at alki.io.
Elements can refer to other elements, and can be defined in any order.
Alki do
group :settings do <b class="conum">(1)</b>
set(:home) { ENV['HOME'] } <b class="conum">(2)</b>
set(:db_path) { ENV['TODO_DB_PATH'] || File.join(home,'.todo_db') }
set :prompt, 'todo> '
end
service :interface do <b class="conum">(3)</b>
require 'todo/readline_interface'
Todo::ReadlineInterface.new settings.prompt, handler
end
service :handler do
require 'todo/command_handler'
Todo::CommandHandler.new db
end
service :db do
require 'todo/store_db'
Todo::StoreDb.new file_store
end
service :file_store do
require 'todo/json_file_store'
Todo::JsonFileStore.new settings.db_path
end
end
-
group
allows bundling together subelements (and which can be moved to their own files) -
set
defines simple values -
service
defines our main application objects
Any element can be accessed directly from the assembly object.
$ bundle exec irb -Ilib
2.4.0 :001 > require 'todo'
=> true
2.4.0 :002 > todo = Todo.new
=> #<Todo:21964520>
2.4.0 :003 > todo.interface.run
> ?
All commands can be shortened to their first letters
print
add <description>
edit <id> <description>
complete <id>
uncomplete <id>
remove <id>
move <from> <to>
quit
The 'alki-console' tool can also be used to quickly work with assemblies.
Add gem 'alki-console'
to your Gemfile and run bundle --binstubs
.
$ bin/alki-console
todo> settings.prompt
=> 'todo> '
Creating an executable
Read more about creating executables with Alki here.
In the todo example, it’s a CLI utility so it requires an executable. The executable just needs to require the main project file, create a new instance of the assembly, and call a method on a service.
require 'todo'
Todo.new.interface.run
Splitting up the Assembly configuration
As a project grows, it’s helpful to be able to split out parts of the Assembly configuration into multiple files.
This can be accomplished with the load
method in the DSL,
which will load the named file and add it the elements
defined in it as a group in the assembly.
For example, it’s common to split out application settings into a separate config file.
Alki do
set(:home) { ENV['HOME'] }
set(:db_path) { ENV['TODO_DB_PATH'] || File.join(home,'.todo_db') }
set :prompt, 'todo> '
end
Alki do
load :settings
service :interface do
require 'todo/readline_interface'
Todo::ReadlineInterface.new settings.prompt, handler
end
...
end
Further Documentation
Authors
Written by Matt Edlefsen