Project

necromancy

0.01
No commit activity in last 3 years
No release in over 3 years
Necromancy conjures up the functional code.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

>= 0
 Project Readme

屍術/Necromancy

屍術/Necromancy conjures up the functional code.

require 'necromancy'
N = Necromancy.new

# [:foo, :bar, :baz].map{|s| s.to_s }.map{|s| s.upcase }
[:foo, :bar, :baz].map &N.to_s . upcase

# [:foo, :hoge, :bar, :fuga].select{|s| s.to_s.length > 3} # => [:hoge, :fuga]
[:foo, :hoge, :bar, :fuga].select &N.to_s . length > 3

Installation

gem install necromancy

Features

Function composition

Every messages to instance of Necromancy are function composition by default. that is left-to-right composition.

N.f.g == ->(o) { :g.to_proc(:f.to_proc(o)) } == ->(o) { o.f.g }

Application with arguments

If a message was called with some argument given, their arguments are given into that function each time.

N.f(x) == ->(o) { :f.to_proc(o, x) } == ->(o) { o.f(x) }

Rich extensions

If you want, you can use extensions by clojuring up the evil spirit.

M = Necromancy.Alternative.new
M.x | M.y == ->(o) { o.x || o.y }

No core extensions

Open classes is evil unless that is need really! 屍術/Necromancy isn't. All methods are defining at local modules, and you can call their methods by sending some messages to a Necromancy object.

Influenced by Haskell

屍術/Necromancy influenced by Haskell. Practically, the library provides Haskell's syntax for Ruby.

require 'necromancy'
N = Necromancy.Alternative.new

f = lambda(&N >> N + 1)
f.(42)  # => 43
f.(nil) # => nil
import Control.Applicative

f n = (+1) <$> n
f (Just 42) -- Just 43
f Nothing   -- Nothing

img/rbhs.png

Illustrated by @chomado

Examples

Simple function composition

First, you create a Necromancy object. it is immutable, you can save it to any variable you like. for example, that is constant, global varibale, instance variable, class variable, local variable, etc.

N = Necromancy.new

After, you send some message to N when you need to write a simple block.

(1..5).map &N ** 2 # => [1, 4, 9, 16, 25]

Function composition

N = Necromancy.Category.new
ary = ('A'..'Z').to_a
(0..4).map &N > ary.method(:[]) # => ["A", "B", "C", "D", "E"]

Multiple accessing to attribtues

N = Necromancy.Arrow.new
str = "foo"
lambda(&N.upcase & :capitalize & :reverse).(str) # => ["FOO", "Foo", "oof"]

Maybe evaluating

N = Necromancy.Alternative.new
n = N >> N.upcase!
"foo".tap &n # => "FOO"
nil.tap &n # => nil

Alias importation

N = Necromancy.Alternative[:>> => :then].new
str_or_nil = ["foo", nil].sample
str_or_nil.tap &(N.then N.upcase!) # => nil or "FOO"

Hiding importation

N = Necromancy.Alternative.hiding(:*, :**).new
(1..5).map &N ** 2 # => [1, 4, 9, 16, 25]

Specifying importation

N = Necromancy.Alternative(:>>).new
str_or_nil = ["foo", nil].sample
str_or_nil.tap &N >> N.upcase! # => nil or "FOO"
(1..5).map &N ** 2 # => [1, 4, 9, 16, 25]

Multiple module importation

N = Necromancy.Arrow.Alternative.hiding(:*, :**).new
[nil, 42, "foo"].map &N.is_a?(Integer) >> (N * 2 & N ** 2) | N # => [nil, [84, 1764], "foo"]