Project

raki

0.0
The project is in a healthy, maintained state
Raki enables chaining of objects. It is based on the definition of an interface and some builders. Chained Rakis must conforms to the Raki definition.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies
 Project Readme

Raki

Gem Version GEM Downloads

The Raki specification enables a kind of piping objects.

The composing is done by Raki::Chain and Raki::Builder.

Installation

As usual:

# Gemfile
gem "raki"

and run "bundle install".

Specification

A Raki is a Ruby object (not a class) that responds to "call". It takes exactly one argument, a Hash, and returns a result, again a Hash.

Rakis are stackable due to the generality of its argument and result.

Sometimes it is expected that a Raki delivers an array of strings as part of the result. The convention is that this array is accessed as "result[:body]".

Simple Raki

A simple Raki (a proc/lambda can be a Raki):

raki = ->(hsh) { {body: ["Hello World!"]} }

and a little more complex:

raki = ->(hsh) { {body: ["Hi #{hsh[:name]!", "Nice to meet you."] } }

Middleware

A Raki::Middleware is a Raki that calls another Raki enabling "before" and "after" code, i.e. operations around the second Raki.

A Raki middleware is ready to be stacked.

A sample for a Raki middleware:

# already included in "gem raki"
module Raki
  class Middleware
    def initialize(app)
      @app = app
    end
  end
end


# your sample
class SampleMiddleware < Raki::Middleware
  def call(env)
    # do something before
    result = @app.call(env) # if @app
    # do something after
    result[:body] << "My grain of salt."
    result
  end
end

Composing

Raki::Chain

Raki::Chain chains Rakis. In particular, it will forward the result of a previous Raki as the argument of the next one. The argument for the first Raki is the arguent of the "call". The return value is the result of the last Raki.

A sample:

class Cl < Raki::Base
  def call(env)
    env + @args.first
  end
end

proca = ->(env) { env + "a" }
app = Raki::Chain.new do
  add Cl, "C"
  add proca
  add { |env| env + "b" }
  add ->(env) { env + "c" }
end

app.call("") # --> "Cabc"

Raki::Builder

Raki::Builder chains Raki::Middleware. In particular, the "@app" is initialized for each middleware. The last middleware "@app" is initialized to "nil".

It is expected that each middleware takes care to call the next one.

A sample:

class MW < Raki::Middleware
  def call(env)
    result = env + @args.first
    return result unless @app

    @app.call(result)
  end
end

app = Raki::Builder.new do
  add MW, "a"
  add MW, "b"
end

app.call("") # --> "ab"

Recommendations

Implement a Raki as idempotent, i.e. same arguments delivers same results.

It is always a good idea to avoid side-effects.

Frozen arguments may avoid some strange behaviour.

Miscellaneous

Heavily inspired by Rack.

Copyright (c) 2020-2023 Dittmar Krall (www.matiq.com), released under the MIT license.