屍術/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
gem install necromancy
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 }
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) }
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 }
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.
屍術/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
Illustrated by @chomado
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]
N = Necromancy.Category.new
ary = ('A'..'Z').to_a
(0..4).map &N > ary.method(:[]) # => ["A", "B", "C", "D", "E"]
N = Necromancy.Arrow.new
str = "foo"
lambda(&N.upcase & :capitalize & :reverse).(str) # => ["FOO", "Foo", "oof"]
N = Necromancy.Alternative.new
n = N >> N.upcase!
"foo".tap &n # => "FOO"
nil.tap &n # => nil
N = Necromancy.Alternative[:>> => :then].new
str_or_nil = ["foo", nil].sample
str_or_nil.tap &(N.then N.upcase!) # => nil or "FOO"
N = Necromancy.Alternative.hiding(:*, :**).new
(1..5).map &N ** 2 # => [1, 4, 9, 16, 25]
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]
N = Necromancy.Arrow.Alternative.hiding(:*, :**).new
[nil, 42, "foo"].map &N.is_a?(Integer) >> (N * 2 & N ** 2) | N # => [nil, [84, 1764], "foo"]