Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

44 Commits

Repository files navigation

ROP - Railway Oriented Programming in Elixir

Build statusHex versionHex downloads


Some macros to enable railsway-oriented programming in Elixir. Collected from code snippets and wrapped into a simple library for your convenience.

For more examples please check the tests here:

Sources for inspiration + copying

Installation

If available in Hex, the package can be installed as:

  1. Add rop to your list of dependencies in mix.exs:
defdepsdo[{:rop,"~> 0.5"}]end

Usage

Call

useRop

in your module. That will give you access to following macros/functions:

>>>

No need to stop pipelining in case of an error somewhere in the middle

used like: 1 |> fn1 >>> fn2 >>> fn3 >>> fn4

defmoduleTripleArrowExampledouseRopdeftagged_inc(v)doIO.puts"inc for #{v}"# sideeffect for demonstration{:ok,v+1}enddeferror_fn(_)do{:error,"I'm a bad fn!"}enddefraising_fn(_)doraise"I'm raising!"enddefresultdo1|>tagged_inc>>>tagged_inc>>>tagged_incenddeferror_resultdo1|>tagged_inc>>>tagged_inc>>>error_fn>>>tagged_incenddefraising_resultdo1|>tagged_inc>>>tagged_inc>>>raising_fn>>>tagged_incendendiex>TripleArrowExample.resultincfor1incfor2incfor3{:ok,4}### increases twice, errors and tries to increase again### notice that after errored result we don't execute any function anymore in the pipeline,### e.g. only tagged_inc before error_fn were executed.iex>TripleArrowExample.error_resultincfor1incfor2{:error,"I'm a bad fn!"}### raises... We'll fix it in a later example for try_catch!iex>TripleArrowExample.raising_resultincfor1incfor2**(RuntimeError) I'm raising!

bind

Wraps a simple function to return a tagged tuple with :ok to comply to the protocol {:ok, result}: e.g.

defmoduleBindExampledouseRopdefinc(v)dov+1enddefonly_last_pipe_tagged_result(v)dov|>inc|>bind(inc)enddefresult_fully_tagged(v)dov|>bind(inc)>>>bind(inc)>>>bind(inc)endendiex>BindExample.only_last_pipe_tagged_result(2){:ok,4}iex>BindExample.result_fully_tagged(2){:ok,5}

try_catch

Wraps raising functions to return a tagged tuple {:error, ErrorMessage} to comply with the protocol

# modified example from TripleArrowExample to handle raising functionsdefmoduleTryCatchExampledouseRopdeftagged_inc(v)doIO.puts"inc for #{v}"# sideeffect for demonstration{:ok,v+1}enddefraising_fn(_)doraise"I'm raising!"enddefresultdo1|>tagged_inc>>>tagged_inc>>>tagged_incenddefraising_result_wrapped(v)dov|>tagged_inc>>>tagged_inc>>>try_catch(raising_fn)>>>tagged_incendendiex>TryCatchExample.raising_result_wrapped(1)incfor1incfor2{:error,%RuntimeError{message: "I'm raising!"}}

tee

Like a similar Unix utility it does some work and returns the input. See tee (command), Unix.

defmoduleTeeExampledouseRopdeftagged_inc(v)doIO.puts"inc for #{v}"# sideeffect for demonstration{:ok,v+1}enddefcalc(v)dov|>tee(tagged_inc)>>>tee(tagged_inc)>>>tee(tagged_inc)endend# notice how the incremented value is not passed through the pipeline,# but just the original argument `1`iex>TeeExample.calc(1)incfor1incfor1incfor1_{:ok,1}

ok

A simple utility function to extract the value from {:ok, result} tuple and to raise the error in {:error, ErrorStruct}.

defmoduleOkExampledouseRopdefok_resultdo{:ok,1}|>okenddeferror_resultdo{:error,%ArithmeticError{}}|>okenddefany_value_resultdo"bad value"|>okendendiex>OkExample.ok_result1iex>OkExample.error_result**(ArithmeticError) bad argument inarithmeticexpression(rop) lib/rop.ex:70: Rop.ok/1iex>OkExample.any_value_result**(RuntimeError)badvalue(rop) lib/rop.ex:71: Rop.ok/1

Background information

Some discussions about Railsway programming:

Code (Railsway Programming)

Code (Monads)

Altenatives

About

Railway Oriented Programming in Elixir

Resources

Stars

20 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages