Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/solnic/transproc
The project was ported to dry-rb/dry-transformer
https://github.com/solnic/transproc
Last synced: 3 months ago
JSON representation
The project was ported to dry-rb/dry-transformer
- Host: GitHub
- URL: https://github.com/solnic/transproc
- Owner: solnic
- License: mit
- Archived: true
- Created: 2014-12-24T15:15:27.000Z (almost 10 years ago)
- Default Branch: master
- Last Pushed: 2019-12-28T12:29:22.000Z (almost 5 years ago)
- Last Synced: 2024-05-12T00:40:49.465Z (6 months ago)
- Language: Ruby
- Homepage:
- Size: 445 KB
- Stars: 410
- Watchers: 13
- Forks: 29
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# :warning: The project was ported to [dry-rb/dry-transformer](https://github.com/dry-rb/dry-transformer) :warning:
[gem]: https://rubygems.org/gems/transproc
[travis]: https://travis-ci.org/solnic/transproc
[codeclimate]: https://codeclimate.com/github/solnic/transproc
[coveralls]: https://coveralls.io/r/solnic/transproc
[inchpages]: https://inch-ci.org/github/solnic/transproc# Transproc
[![Gem Version](https://badge.fury.io/rb/transproc.svg)][gem]
[![Build Status](https://travis-ci.org/solnic/transproc.svg?branch=master)][travis]
[![Code Climate](https://codeclimate.com/github/solnic/transproc/badges/gpa.svg)][codeclimate]
[![Test Coverage](https://codeclimate.com/github/solnic/transproc/badges/coverage.svg)][codeclimate]
[![Inline docs](https://inch-ci.org/github/solnic/transproc.svg?branch=master)][inchpages]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](https://rom-rb.org).
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'transproc'
```And then execute:
$ bundle
Or install it yourself as:
$ gem install transproc
## Basics
Simple transformations are defined as easy as:
```ruby
increment = Transproc::Function.new(-> (data) { data + 1 })
increment[1] # => 2
```It's easy to compose transformations:
```ruby
to_string = Transproc::Function.new(:to_s.to_proc)
(increment >> to_string)[1] # => '2'
```It's easy to pass additional arguments to transformations:
```ruby
append = Transproc::Function.new(-> (value, suffix) { value + suffix })
append_bar = append.with('_bar')
append_bar['foo'] # => foo_bar
```Or even accept another transformation as an argument:
```ruby
map_array = Transproc::Function.new(-> (array, fn) { array.map(&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`:```ruby
M = Module.new do
extend Transproc::Registrydef self.to_string(value)
value.to_s
enddef self.map_array(array, fn)
array.map(&fn)
end
end
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:* [Coercions](https://www.rubydoc.info/gems/transproc/Transproc/Coercions)
* [Array transformations](https://www.rubydoc.info/gems/transproc/Transproc/ArrayTransformations)
* [Hash transformations](https://www.rubydoc.info/gems/transproc/Transproc/HashTransformations)
* [Class transformations](https://www.rubydoc.info/gems/transproc/Transproc/ClassTransformations)
* [Proc transformations](https://www.rubydoc.info/gems/transproc/Transproc/ProcTransformations)
* [Conditional](https://www.rubydoc.info/gems/transproc/Transproc/Conditional)
* [Recursion](https://www.rubydoc.info/gems/transproc/Transproc/Recursion)You can import everything with:
```ruby
module T
extend Transproc::Registryimport Transproc::Coercions
import Transproc::ArrayTransformations
import Transproc::HashTransformations
import Transproc::ClassTransformations
import Transproc::ProcTransformations
import Transproc::Conditional
import Transproc::Recursion
end
T[:to_string].call(:abc) # => 'abc'
```Or import selectively with:
```ruby
module T
extend Transproc::Registryimport :to_string, from: Transproc::Coercions, as: :stringify
end
T[:stringify].call(:abc) # => 'abc'
T[:to_string].call(:abc)
# => Transproc::FunctionNotFoundError: No registered function T[:to_string]
```### Transformer
Transformer is a class-level DSL for composing transformation pipelines,
for example:```ruby
T = Class.new(Transproc::Transformer) do
map_array do
symbolize_keys
rename_keys user_name: :name
nest :address, [:city, :street, :zipcode]
end
endT.new.call(
[
{ '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
``` ruby
require 'json'
require 'transproc/all'# create your own local registry for transformation functions
module Functions
extend Transproc::Registry
end# import necessary functions from other transprocs...
module Functions
# import all singleton methods from a module/class
import Transproc::HashTransformations
import Transproc::ArrayTransformations
end# ...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
enddef t(*args)
Functions[*args]
end# use imported transformation
transformation = t(:camel_case)transformation.call 'i_am_a_camel'
# => "IAmACamel"transformation = t(:map_array, (
t(:symbolize_keys).>> t(:rename_keys, user_name: :user)
)).>> t(:wrap, :address, [:city, :street, :zipcode])transformation.call(
[
{ '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) })transformation.call(name: 'Jane')
# => "{\"name\":\"Jane\"}"# ...or add it to registered functions via singleton method of the registry
module Functions
# ...def self.load_json(v)
JSON.load(v)
end
end# ...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))
transformation.call('[{"name":"Jane"}]')
# => [{ :name => "Jane" }]
```## Credits
This project is inspired by the work of the following people:
* [Markus Schirp](https://github.com/mbj) and [morpher](https://github.com/mbj/morpher) project
* [Josep M. Bach](https://github.com/txus) and [kleisli](https://github.com/txus/kleisli) project## Contributing
1. Fork it ( https://github.com/solnic/transproc/fork )
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