Skip to content
Transform Ruby objects in functional style
Branch: master
Clone or download
Type Name Latest commit message Commit time
Failed to load latest commit information.
lib Bump version 1.0.3 Dec 1, 2018
rakelib Clean rubocop warnings May 21, 2015
.gitignore Add /vendor/ to .gitignore Mar 24, 2015
.rspec Avoid circular require and enable warnings Jun 1, 2015
.rubocop.yml RegexpLiteral/MaxSlashes option is no longer supported May 21, 2015
.rubocop_todo.yml rubocop Apr 16, 2015
.travis.yml Update ruby versions Dec 1, 2018 Update CHANGELOG [skip ci] Dec 1, 2018
Gemfile Mutant requires Ruby 2.5+ Dec 1, 2018
Guardfile rubocop Apr 16, 2015
LICENSE.txt Remove link to Gemnasium [skip ci] Dec 1, 2018
Rakefile Add gem tasks [skip ci] Dec 1, 2018
transproc.gemspec Set minimal ruby version to 2.3 Dec 1, 2018


Gem Version Build Status Code Climate Test Coverage Inline docs

Transproc is a small library that allows you to compose procs into a functional pipeline using left-to-right function composition.

The approach came from Functional Programming, where simple functions are composed into more complex functions in order to transform some data. It works like |> in Elixir or >> in F#.

transproc provides a mechanism to define and compose transformations, along with a number of built-in transformations.

It's currently used as the data mapping backend in Ruby Object Mapper.


Add this line to your application's Gemfile:

gem 'transproc'

And then execute:

$ bundle

Or install it yourself as:

$ gem install transproc


Simple transformations are defined as easy as:

increment => (data) { data + 1 })
increment[1] # => 2

It's easy to compose transformations:

to_string =
(increment >> to_string)[1] => '2'

It's easy to pass additional arguments to transformations:

append => (value, suffix) { value + suffix })
append_bar = append.with('_bar')
append_bar['foo'] # => foo_bar

Or even accept another transformation as an argument:

map_array => (array, fn) { })
map_array.with(to_string).call([1, 2, 3]) # => ['1', '2', '3']

To improve this low-level definition, you can use class methods with Transproc::Registry:

M = do
  extend Transproc::Registry

  def self.to_string(value)

  def self.map_array(array, fn)
M[:map_array, M[:to_string]].([1, 2, 3]) # => ['1', '2', '3']

Built-in transformations

transproc comes with a lot of built-in functions. They come in the form of modules with class methods, which you can import into a registry:

You can import everything with:

module T
  extend Transproc::Registry

  import Transproc::Coercions
  import Transproc::ArrayTransformations
  import Transproc::HashTransformations
  import Transproc::ClassTransformations
  import Transproc::ProcTransformations
  import Transproc::Conditional
  import Transproc::Recursion
T[:to_string].call(:abc) # => 'abc'

Or import selectively with:

module T
  extend Transproc::Registry

  import :to_string, from: Transproc::Coercions, as: :stringify
T[:stringify].call(:abc) # => 'abc'
# => Transproc::FunctionNotFoundError: No registered function T[:to_string]


Transformer is a class-level DSL for composing transformation pipelines, for example:

T = do
  map_array do
    rename_keys user_name: :name
    nest :address, [:city, :street, :zipcode]
    { 'user_name' => 'Jane',
      'city' => 'NYC',
      'street' => 'Street 1',
      'zipcode' => '123'
# => [{:name=>"Jane", :address=>{:city=>"NYC", :street=>"Street 1", :zipcode=>"123"}}]

It converts every method call to its corresponding transformation, and joins these transformations into a transformation pipeline (a transproc).

Transproc Example Usage

require 'json'
require 'transproc/all'

# create your own local registry for transformation functions
module Functions
  extend Transproc::Registry

# import necessary functions from other transprocs...
module Functions
  # import all singleton methods from a module/class
  import Transproc::HashTransformations
  import Transproc::ArrayTransformations

# ...or from any external library
require 'inflecto'
module Functions
  # import only necessary singleton methods from a module/class
  # and rename them locally
  import :camelize, from: Inflecto, as: :camel_case

def t(*args)

# use imported transformation
transformation = t(:camel_case) 'i_am_a_camel'
# => "IAmACamel"

transformation = t(:map_array, (
  t(:symbolize_keys).>> t(:rename_keys, user_name: :user)
  )).>> t(:wrap, :address, [:city, :street, :zipcode])
    { 'user_name' => 'Jane',
      'city' => 'NYC',
      'street' => 'Street 1',
      'zipcode' => '123' }
# => [{:user=>"Jane", :address=>{:city=>"NYC", :street=>"Street 1", :zipcode=>"123"}}]

# define your own composable transformation easily
transformation = t(-> v { JSON.dump(v) }) 'Jane')
# => "{\"name\":\"Jane\"}"

# ...or add it to registered functions via singleton method of the registry
module Functions
  # ...

  def self.load_json(v)

# ...or add it to registered functions via .register method
Functions.register(:load_json) { |v| JSON.load(v) }

transformation = t(:load_json) >> t(:map_array, t(:symbolize_keys))'[{"name":"Jane"}]')
# => [{ :name => "Jane" }]


This project is inspired by the work of following people:


  1. Fork it ( )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request
You can’t perform that action at this time.