Agrippa

Programming is hard. Complexity makes it harder. Agrippa helps with organizing complexity, by providing easy access to some very useful functional programming tools for otherwise stock-vanilla Ruby.

Agrippa has no external dependencies, unless you use Agrippa::Immutable, in which case you will also need the hamster gem.

Installation

Run gem install agrippa, or add gem "agrippa" to your Gemfile.

Seriously, it's a ruby gem. We all know how this works.

What the hell do you do with it?

First, read this article on reasonable programming.

Fundamentally, programming consists of only three activities: accepting data, changing data, and returning data. Programs have inputs, transformations, and outputs.

We can use this observation to help break down our methods into one of three categories. Command methods change state, transform methods change data from one form to another, and query methods return state.

In functional programming parlance, only commands are allowed to have side effects, transforms

If you have read Practical Object-Oriented Design in Ruby by Sandi Metz, then this probably sounds very familiar, but we're going to add a few extra rules to

This behavior can be applied to objects, and more importantly to

As methods or functions are the real meat of what any given program does, logic dictates that we can

  1. All methods are either query, command, or transform.

  2. Objects receive state via initialize or from command methods.

  3. Compose complex things from collections of simpler things.

State Management

require "agrippa"

class MailConfig
    include Agrippa::Mutable

    state_reader :email, :password, :use_ssl, :server

    def default_state
        { use_ssl: true }
    end
end

config = Config.new()

Agrippa provides three modules for managing state within in an object: Agrippa::Mutable, Agrippa::MutableHash, and Agrippa::Immutable.

Each of these modules implements the same interface, as they are designed to be interchangeable.

state_reader state_writer state_accessor

prefix suffix

default_state

fetch store chain

fetch and store work identical to their Hash equivalents. chain works the same as merge

initialize sets state

Agrippa::Mutable stores values in individual instance variables. This uses half the memory of Agrippa::MutableHash, but is notably slower when initializing or chaining. As the name indicates, state for Agrippa::Mutable objects is mutated in-place.

Agrippa::MutableHash stores data in a single @state hash, which is faster than Agrippa::Mutable, but consumes more memory. As all state for an object is contained in @state, serialization is dead simple. Agrippa::MutableHash also mutates the @state hash in-place.

Agrippa::Immutable works like MutableHash, but @state is provided by Hamster::Hash, and the object itself is immutable, so fetch and chain return new instances of the object, rather than the object with state mutated in-place.

state_reader state_writer state_accessor

prefix suffix

default_state

fetch store chain

fetch and store work identical to their Hash equivalents. chain works the same as merge

initialize sets state

to override setting, define a setter and call it in the initializer

Agrippa objects treat symbols and strings as identical (so, they work the same as HashWithIndifferentAccess)

Agrippa::Methods

mark_as_command mark_as_commands command_methods

Command methods are used by proxies.

Agrippa::Proxy

Delegation.

Delegation is the real core of what makes object-oriented code sing, as it enables the composition of complex behaviors from simpler objects.

Agrippa::Delegation works the same as ActiveSupport::Delegation, with a few small additions.

You can apply a

delegate to: method to: :class prefix true value suffix true value

class_delegate

delegate_command

Agrippa::State Agrippa::Maybe

Examples


Why does the name sound like a kitchen gadget?

Because you have spent too much time in Williams Sonoma, and not enough time in a library.

Agrippa is named after Marcus Vipsanius Agrippa, a Roman statesman and architect. Amongst other achievements, he was responsible for renovating the aqueducts in Rome to give all citizens, from every social class, access to the highest possible quality of water.

Contributing

When submitting pull requests, please respect the coding style of the project.