necromancy 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rst +8 -8
- data/VERSION +1 -1
- data/examples/fizzbuzz.rb +1 -1
- data/lib/necromancy/control/alternative.rb +28 -2
- data/lib/necromancy/control/applicative.rb +35 -0
- data/lib/necromancy/control/arrow.rb +16 -0
- data/lib/necromancy/control/category.rb +18 -0
- data/lib/necromancy/control.rb +34 -9
- data/lib/necromancy/version.rb +1 -1
- data/lib/necromancy.rb +7 -0
- data/spec/examples/category_spec.rb +10 -0
- metadata +1 -1
data/README.rst
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
Necromancy
|
1
|
+
屍術/Necromancy
|
2
2
|
================================================================================
|
3
3
|
|
4
|
-
Necromancy conjures up the functional code.
|
4
|
+
*屍術/Necromancy* conjures up the functional code.
|
5
5
|
|
6
6
|
.. code:: ruby
|
7
7
|
|
@@ -20,7 +20,7 @@ Features
|
|
20
20
|
Function composition
|
21
21
|
________________________________________________________________________________
|
22
22
|
|
23
|
-
Every messages to instance of
|
23
|
+
Every messages to instance of ``Necromancy`` are function composition
|
24
24
|
by default. that is left-to-right composition.
|
25
25
|
|
26
26
|
.. code:: ruby
|
@@ -53,16 +53,16 @@ No core extensions.
|
|
53
53
|
________________________________________________________________________________
|
54
54
|
|
55
55
|
Open classes is evil unless that is need really!
|
56
|
-
Necromancy isn't. All methods are defining at local modules,
|
57
|
-
and you can call their methods by sending some messages to a Necromancy object.
|
56
|
+
*屍術/Necromancy* isn't. All methods are defining at local modules,
|
57
|
+
and you can call their methods by sending some messages to a ``Necromancy`` object.
|
58
58
|
|
59
59
|
Examples
|
60
60
|
--------------------------------------------------------------------------------
|
61
61
|
|
62
|
-
Simple
|
62
|
+
Simple function composition
|
63
63
|
________________________________________________________________________________
|
64
64
|
|
65
|
-
First, you create a
|
65
|
+
First, you create a ``Necromancy`` object.
|
66
66
|
it is immutable, you can save it to any variable you like.
|
67
67
|
for example, that is constant, global varibale, instance variable, class variable, local variable, etc.
|
68
68
|
|
@@ -76,7 +76,7 @@ After, you send some message to N when you need to write a simple block.
|
|
76
76
|
|
77
77
|
(1..5).map &N ** 2 # => [1, 4, 9, 16, 25]
|
78
78
|
|
79
|
-
Function
|
79
|
+
Function composition
|
80
80
|
________________________________________________________________________________
|
81
81
|
|
82
82
|
.. code:: ruby
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.2
|
data/examples/fizzbuzz.rb
CHANGED
@@ -8,18 +8,44 @@ module Necromancy
|
|
8
8
|
|
9
9
|
include Control::Applicative
|
10
10
|
|
11
|
+
# Tests whether the result is empty or not.
|
12
|
+
# If it is empty, {#empty?} returns the true, otherwise that returns the false.
|
13
|
+
# By default, {#empty?} returns the true, if it is nil or false.
|
11
14
|
def empty?(x, *xs)
|
12
15
|
not x
|
13
16
|
end
|
14
17
|
|
15
|
-
|
18
|
+
:empty?.tap(&method(:protected))
|
19
|
+
# protected :empty?
|
16
20
|
|
17
|
-
|
21
|
+
# Applies the result of the callable into self unless that result is empty.
|
22
|
+
# @see #empty?
|
23
|
+
# @note self :: a -> b -> c
|
24
|
+
# @param [Object] callable a -> b
|
25
|
+
# @return [Necromancy] a -> c
|
26
|
+
# @example
|
27
|
+
# require 'necromancy'
|
28
|
+
# N = Necromancy.Alternative.new
|
29
|
+
# f = lambda(&N.+ * N) # == ->(o) { :+.to_proc.(o,o) if o }
|
30
|
+
# f.(nil) # => nil
|
31
|
+
# f.("foo") # => "foofoo"
|
32
|
+
def *(callable)
|
18
33
|
str = make_evaluable_string(callable)
|
19
34
|
necromancy = "self.empty?(*(xs = (#{str}))) ? xs : (args.concat(xs); #{@necromancy})"
|
20
35
|
self.class.new(necromancy, @references.dup)
|
21
36
|
end
|
22
37
|
|
38
|
+
# Evaluates the callable, unless result of self is empty. otherwise that returns result of self.
|
39
|
+
# @see #empty?
|
40
|
+
# @note self :: a -> b
|
41
|
+
# @param [Object] callable a -> b
|
42
|
+
# @return [Necromancy] a -> b
|
43
|
+
# @example
|
44
|
+
# require 'necromancy'
|
45
|
+
# N = Necromancy.Alternative.new
|
46
|
+
# f = lambda(&N | ->(o){"foo"}) # == ->(o){ o ? o : "foo" }
|
47
|
+
# f.(nil) # => "foo"
|
48
|
+
# f.("bar") # => "var"
|
23
49
|
def |(callable)
|
24
50
|
str = make_evaluable_string(callable)
|
25
51
|
|
@@ -5,20 +5,55 @@ module Necromancy
|
|
5
5
|
|
6
6
|
module Control::Applicative; extend Control
|
7
7
|
|
8
|
+
# @note self :: a -> b -> c
|
9
|
+
# @param [Object] callable a -> b
|
10
|
+
# @return [Necromancy] a -> c
|
11
|
+
# @example
|
12
|
+
# require 'necromancy'
|
13
|
+
# N = Necromancy.Applicative.new
|
14
|
+
# f = lambda(&N.+ * N) # == ->(o) {o + o}
|
15
|
+
# f.(42) # => 84
|
8
16
|
def *(callable)
|
9
17
|
str = make_evaluable_string(callable)
|
10
18
|
self.class.new("args.concat((#{str})); #{@necromancy}", @references.dup)
|
11
19
|
end
|
12
20
|
|
21
|
+
# A variant of {#*} with the arguments reversed.
|
22
|
+
# @note self :: a -> b
|
23
|
+
# @param [Object] callable a -> b -> c
|
24
|
+
# @return [Necromancy] a -> c
|
25
|
+
# @example
|
26
|
+
# require 'necromancy'
|
27
|
+
# N = Necromancy.Applicative.new
|
28
|
+
# f = lambda(&N ** :+) # == ->(o) {o + o}
|
29
|
+
# f.(42) # => 84
|
13
30
|
def **(callable)
|
14
31
|
str = make_evaluable_string(callable)
|
15
32
|
self.class.new(str, @references.dup).__Applicative_Astarisk(self)
|
16
33
|
end
|
17
34
|
|
35
|
+
# Sequence actions, discarding the value of the callable.
|
36
|
+
# @note self :: a -> b
|
37
|
+
# @param [Object] callable a -> _
|
38
|
+
# @return [Necromancy] a -> b
|
39
|
+
# @example
|
40
|
+
# require 'necromancy'
|
41
|
+
# N = Necromancy.Applicative.new
|
42
|
+
# f = lambda(&N.succ << N.pred) # == ->(o) {o.pred; o.succ}
|
43
|
+
# f.(42) # => 43
|
18
44
|
def <<(callable)
|
19
45
|
self.class.new("args.pop; #{@necromancy}", @references.dup).__Applicative_Astarisk(callable)
|
20
46
|
end
|
21
47
|
|
48
|
+
# Sequence actions, discarding the value of self.
|
49
|
+
# @note self :: a -> _
|
50
|
+
# @param [Object] callable a -> b
|
51
|
+
# @return [Necromancy] a -> b
|
52
|
+
# @example
|
53
|
+
# require 'necromancy'
|
54
|
+
# N = Necromancy.Applicative.new
|
55
|
+
# f = lambda(&N.succ >> N.pred) # == ->(o) {o.succ; o.pred}
|
56
|
+
# f.(42) # => 41
|
22
57
|
def >>(callable)
|
23
58
|
str = make_evaluable_string(callable)
|
24
59
|
self.class.new("args.pop; #{str}", @references.dup).__Applicative_Astarisk(self)
|
@@ -8,12 +8,28 @@ module Necromancy
|
|
8
8
|
|
9
9
|
include Control::Category
|
10
10
|
|
11
|
+
# @note self :: a -> b
|
12
|
+
# @param [Object] callable a -> b'
|
13
|
+
# @return [Necromancy] a -> (b, b')
|
14
|
+
# @example
|
15
|
+
# require 'necromancy'
|
16
|
+
# N = Necromancy.Arrow.new
|
17
|
+
# f = lambda(&N.upcase & :capitalize & :reverse) # == ->(o) { [o.upcase, o.capitalize, o.reverse] }
|
18
|
+
# f.("foo") # => ["FOO", "Foo", "oof"]
|
11
19
|
def &(callable)
|
12
20
|
str = make_evaluable_string(callable)
|
13
21
|
necromancy = "(#{@necromancy}) + (#{str})"
|
14
22
|
self.class.new(necromancy, @references.dup)
|
15
23
|
end
|
16
24
|
|
25
|
+
# @note self :: a -> b
|
26
|
+
# @param [Object] callable a' -> b'
|
27
|
+
# @return [Necromancy] (a, a') -> (b, b')
|
28
|
+
# @example
|
29
|
+
# require 'necromancy'
|
30
|
+
# N = Necromancy.Arrow.new
|
31
|
+
# f = lambda(&N.to_sym * N.to_f) # == ->(a, b) { [a.to_sym, b.to_f] }
|
32
|
+
# f.("x", 42) # => [:x, 42.0]
|
17
33
|
def *(callable)
|
18
34
|
str = make_evaluable_string(callable)
|
19
35
|
necromancy = "stack << [] << args; args = stack[-1][0..-2]; stack[-2].concat((#{@necromancy})); args = [stack[-1][-1]]; stack[-2].concat((#{str})); args = stack.pop; stack.pop"
|
@@ -5,12 +5,30 @@ module Necromancy
|
|
5
5
|
|
6
6
|
module Control::Category; extend Control
|
7
7
|
|
8
|
+
# Left-to-right composition.
|
9
|
+
# @note self :: a -> b
|
10
|
+
# @param [Object] callable b -> c
|
11
|
+
# @return [Necromancy] a -> c
|
12
|
+
# @example
|
13
|
+
# require 'necromancy'
|
14
|
+
# N = Necromancy.Category.new
|
15
|
+
# f = lambda(&N.to_i > N * 2) # == ->(o) { o.to_i * 2 }
|
16
|
+
# f.('42') # => 84
|
8
17
|
def >(callable)
|
9
18
|
str = make_evaluable_string(callable)
|
10
19
|
necromancy = "args = (#{@necromancy}); #{str}"
|
11
20
|
self.class.new(necromancy, @references.dup)
|
12
21
|
end
|
13
22
|
|
23
|
+
# Right-to-left composition
|
24
|
+
# @note self :: b -> c
|
25
|
+
# @param [Object] callable a -> b
|
26
|
+
# @return [Necromancy] a -> c
|
27
|
+
# @example
|
28
|
+
# require 'necromancy'
|
29
|
+
# N = Necromancy.Category.new
|
30
|
+
# f = lambda(&N.to_i < N * 2) # == ->(o) { (o * 2).to_i }
|
31
|
+
# f.('42') # => 4242
|
14
32
|
def <(callable)
|
15
33
|
str = make_evaluable_string(callable)
|
16
34
|
necromancy = "args = (#{str}); #{@necromancy}"
|
data/lib/necromancy/control.rb
CHANGED
@@ -2,6 +2,8 @@ module Necromancy
|
|
2
2
|
|
3
3
|
module Control
|
4
4
|
|
5
|
+
# Creates a {Necromancy::Necromancy} object including the {Necromancy::Control}.
|
6
|
+
# @return [Necromancy]
|
5
7
|
def new
|
6
8
|
mod = self
|
7
9
|
Class.new(::Necromancy::Necromancy) { include mod }.new
|
@@ -14,6 +16,7 @@ module Necromancy
|
|
14
16
|
|
15
17
|
private :branch
|
16
18
|
|
19
|
+
# @deprecated
|
17
20
|
def call(*targets)
|
18
21
|
warn <<EOF
|
19
22
|
Necromancy.Hoge.() deprecated.
|
@@ -22,6 +25,7 @@ EOF
|
|
22
25
|
branch { protected *instance_methods }[*targets]
|
23
26
|
end
|
24
27
|
|
28
|
+
# @deprecated
|
25
29
|
def using(*targets)
|
26
30
|
warn <<EOF
|
27
31
|
Necromancy.Hoge.using() deprecated.
|
@@ -30,7 +34,21 @@ EOF
|
|
30
34
|
self[*targets]
|
31
35
|
end
|
32
36
|
|
33
|
-
|
37
|
+
# Reveals some methods and Creates some aliases.
|
38
|
+
# @param [Symbol] target Reveals a method of the symbol.
|
39
|
+
# @param [Hash] target Hides all methods of each key and creates aliases from each value to each key.
|
40
|
+
# @param [Array] targets A list of Symbol or Hash that will be processing as target.
|
41
|
+
# @return [Control] Processed new {Necromancy::Control} object.
|
42
|
+
# @example
|
43
|
+
# require 'necromancy'
|
44
|
+
# N = Necromancy.Alternative[:<< => :if,
|
45
|
+
# :>> => :then,
|
46
|
+
# :| => :else].new
|
47
|
+
# puts (1..100).map &( (N%15).zero? .then(proc{"FizzBuzz"}) .else \
|
48
|
+
# (N%3).zero? .then(proc{"Fizz"}) .else \
|
49
|
+
# (N%5).zero? .then(proc{"Buzz"}) .else N )
|
50
|
+
def [](target, *targets)
|
51
|
+
targets.unshift(target)
|
34
52
|
names = targets.select { |t| t.is_a? Symbol }
|
35
53
|
aliases = targets.select { |t| t.is_a? Hash }.inject(:merge) || {}
|
36
54
|
branch do
|
@@ -43,22 +61,29 @@ EOF
|
|
43
61
|
end
|
44
62
|
end
|
45
63
|
|
46
|
-
|
64
|
+
# Hides some methods.
|
65
|
+
# @param [Symbol] name Hides a method of the name.
|
66
|
+
# @param [Array] names A list of a Symbol that will be processing as name.
|
67
|
+
# @return [Control] Processed new {Necromancy::Control} object.
|
68
|
+
# @example
|
69
|
+
# require 'necromancy'
|
70
|
+
# N = Necromancy.Alternative.hiding(:*, :**).new
|
71
|
+
# ary = [1, nil, 2, nil, 3]
|
72
|
+
# ary.map &(N | proc{0}) * 10 # => [10, 0, 20, 0, 3]
|
73
|
+
def hiding(name, *names)
|
74
|
+
names.unshift(name)
|
47
75
|
branch { protected *names }
|
48
76
|
end
|
49
77
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
78
|
+
def self.extended(mod)
|
79
|
+
return unless mod.name and mod.name.start_with? self.name
|
80
|
+
mthname = mod.name.sub("#{self.name}::", '')
|
81
|
+
define_method mthname do |*args, &block|
|
55
82
|
if args.empty?
|
56
83
|
branch { include mod }
|
57
84
|
else
|
58
85
|
branch { include mod; protected *mod.instance_methods }[*args, &block]
|
59
86
|
end
|
60
|
-
else
|
61
|
-
super
|
62
87
|
end
|
63
88
|
end
|
64
89
|
end
|
data/lib/necromancy/version.rb
CHANGED
data/lib/necromancy.rb
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
# @example
|
2
|
+
# require 'necromancy'
|
3
|
+
# N = Necromancy.Alternative(:>>, :|).new
|
4
|
+
# puts (1..100).map &(N%15).zero? >> proc{"FizzBuzz"} |
|
5
|
+
# (N%3).zero? >> proc{"Fizz"} |
|
6
|
+
# (N%5).zero? >> proc{"Buzz"} |
|
7
|
+
# N
|
1
8
|
module Necromancy
|
2
9
|
|
3
10
|
require 'necromancy/version'
|
@@ -9,4 +9,14 @@ describe Necromancy::Control::Category do
|
|
9
9
|
%w(0 1 2).map(&l.to_i > "foo".method(:[])).
|
10
10
|
should == %w(0 1 2).map {|x| "foo"[x.to_i] }
|
11
11
|
end
|
12
|
+
|
13
|
+
example do
|
14
|
+
lambda(&l.to_i > l * 2).('42').
|
15
|
+
should == '42'.to_i * 2
|
16
|
+
end
|
17
|
+
|
18
|
+
example do
|
19
|
+
lambda(&l.to_i < l * 2).('42').
|
20
|
+
should == ('42' * 2).to_i
|
21
|
+
end
|
12
22
|
end
|