funkr 0.0.21 → 0.0.22
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/.travis.yml +1 -0
- data/Rakefile +9 -0
- data/funkr.gemspec +1 -0
- data/lib/funkr/adt/adt.rb +14 -9
- data/lib/funkr/adt/matcher.rb +1 -0
- data/lib/funkr/categories.rb +3 -0
- data/lib/funkr/extensions/array.rb +30 -21
- data/lib/funkr/extensions/hash.rb +53 -0
- data/lib/funkr/extensions.rb +1 -0
- data/lib/funkr/types/maybe.rb +25 -18
- data/lib/funkr/types/simple_record.rb +8 -10
- data/lib/funkr/version.rb +1 -1
- data/lib/funkr.rb +2 -1
- data/test/test_container.rb +17 -0
- data/test/test_extensions.rb +63 -0
- data/test/test_hash.rb +13 -0
- data/test/test_maybe.rb +73 -0
- data/test/test_simple_records.rb +25 -0
- metadata +42 -43
- data/test/tests.rb +0 -136
data/.travis.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm: 1.9.2
|
data/Rakefile
CHANGED
data/funkr.gemspec
CHANGED
@@ -18,4 +18,5 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
19
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
20
|
s.require_paths = ["lib"]
|
21
|
+
s.add_development_dependency 'rake', '~> 0.9.2'
|
21
22
|
end
|
data/lib/funkr/adt/adt.rb
CHANGED
@@ -1,25 +1,30 @@
|
|
1
1
|
require "funkr/adt/matcher"
|
2
2
|
|
3
3
|
module Funkr
|
4
|
+
|
5
|
+
# Very rought Algebraic Data Types. A class inheriting from ADT can
|
6
|
+
# declare constructors with #adt
|
4
7
|
class ADT
|
5
8
|
|
6
9
|
def initialize(const, *data)
|
7
10
|
@const, @data = const, data
|
8
11
|
end
|
9
|
-
|
12
|
+
|
13
|
+
# Declare ADT constructors, for example :
|
14
|
+
# class Maybe < ADT; adt :just, :nothing; end
|
10
15
|
def self.adt(*constructs)
|
11
16
|
build_adt(constructs)
|
12
17
|
build_matcher(constructs)
|
13
18
|
end
|
14
19
|
|
15
|
-
def self.match_method=(method)
|
16
|
-
@match_method = method
|
17
|
-
end
|
18
|
-
|
19
|
-
self.match_method = :safe
|
20
|
-
|
21
20
|
def self.matcher; @matcher; end
|
22
21
|
|
22
|
+
# Match your ADT against its constructors, for example :
|
23
|
+
# a = Maybe.just("hello")
|
24
|
+
# a.match do |on|
|
25
|
+
# on.just{|x| puts x}
|
26
|
+
# on.nothing{ }
|
27
|
+
# end
|
23
28
|
def match
|
24
29
|
m = self.class.matcher.new(normal_form)
|
25
30
|
yield m
|
@@ -27,10 +32,10 @@ module Funkr
|
|
27
32
|
end
|
28
33
|
|
29
34
|
def to_s
|
30
|
-
format("%s%s%s",
|
35
|
+
format("{%s%s%s}",
|
31
36
|
@const,
|
32
37
|
@data.any? ? " : " : "",
|
33
|
-
@data.map(&:inspect).join(" ") )
|
38
|
+
@data.map(&:inspect).join(", ") )
|
34
39
|
end
|
35
40
|
|
36
41
|
private
|
data/lib/funkr/adt/matcher.rb
CHANGED
data/lib/funkr/categories.rb
CHANGED
@@ -1,62 +1,71 @@
|
|
1
1
|
require 'funkr/categories'
|
2
2
|
|
3
|
+
# Extends array (as list) capabilities
|
3
4
|
class Array
|
4
|
-
|
5
|
+
|
5
6
|
include Funkr::Categories
|
6
|
-
|
7
|
+
|
7
8
|
class << self
|
8
9
|
def unit(e); self.new([e]); end
|
9
10
|
alias pure unit
|
10
11
|
def mzero; self.new(); end
|
11
12
|
end
|
12
|
-
|
13
|
+
|
13
14
|
### Categories
|
14
|
-
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
|
16
|
+
# Array is already a functor with its correct map implementation
|
17
|
+
|
18
|
+
|
19
|
+
# Array can be made an applicative functor, for example :
|
20
|
+
# f = Array.curry_lift_proc{|x,y| x + y}
|
21
|
+
# f.apply([0,4]).apply([5,7]) => [5, 7, 9, 11]
|
22
|
+
# f.apply([0,4]).apply([]) => []
|
19
23
|
include Applicative
|
20
24
|
extend Applicative::ClassMethods
|
21
|
-
|
25
|
+
|
22
26
|
def apply(to)
|
23
27
|
map do |f|
|
24
28
|
to.map{ |t| f.call(t)}
|
25
29
|
end.flatten(1)
|
26
30
|
end
|
27
|
-
|
31
|
+
|
32
|
+
# Array is Alternative whith empty? being zero
|
28
33
|
include Alternative
|
29
|
-
|
34
|
+
|
35
|
+
# [].or_else{[5]} => [5]
|
30
36
|
def or_else(&block)
|
31
37
|
if empty? then yield
|
32
38
|
else self end
|
33
39
|
end
|
34
|
-
|
35
|
-
|
40
|
+
|
41
|
+
|
42
|
+
# Array is a monoid with mplus = (+) and mzero = []
|
36
43
|
include Monoid
|
37
44
|
extend Monoid::ClassMethods
|
38
|
-
|
45
|
+
|
46
|
+
# [5].mplus([6]) => [5,6]
|
39
47
|
def mplus(m_y)
|
40
48
|
self + m_y
|
41
49
|
end
|
42
|
-
|
43
|
-
|
50
|
+
|
51
|
+
|
52
|
+
# Array is also a monad
|
44
53
|
include Monad
|
45
54
|
extend Monad::ClassMethods
|
46
|
-
|
55
|
+
|
47
56
|
def bind(&block)
|
48
57
|
self.map(&block).flatten(1)
|
49
58
|
end
|
50
|
-
|
59
|
+
|
51
60
|
def self.box(value)
|
52
61
|
if value.nil? then self.mzero
|
53
62
|
else self.unit(value) end
|
54
63
|
end
|
55
|
-
|
64
|
+
|
56
65
|
def unbox()
|
57
66
|
if self.empty? then nil
|
58
67
|
else self.first end
|
59
68
|
end
|
60
|
-
|
61
|
-
|
69
|
+
|
70
|
+
|
62
71
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'funkr/categories'
|
3
|
+
|
4
|
+
# Extends Hash capabilities
|
5
|
+
class Hash
|
6
|
+
|
7
|
+
# maps function over hash values
|
8
|
+
def map_v # &block
|
9
|
+
h = Hash.new(self.default)
|
10
|
+
self.each{|k,v| h[k] = yield(v)}
|
11
|
+
return h
|
12
|
+
end
|
13
|
+
|
14
|
+
# maps function over hash keys
|
15
|
+
def map_k # &block
|
16
|
+
h = Hash.new(self.default)
|
17
|
+
self.each{|k,v| h[yield(k)] = v}
|
18
|
+
return h
|
19
|
+
end
|
20
|
+
|
21
|
+
# maps function over hash keys and values. Block should take
|
22
|
+
# 2 parameters, and should return a 2 elements array.
|
23
|
+
def map_kv # &block
|
24
|
+
h = Hash.new(self.default)
|
25
|
+
self.each do |k,v|
|
26
|
+
nk, nv = yield(k,v)
|
27
|
+
h[nk] = nv
|
28
|
+
end
|
29
|
+
return h
|
30
|
+
end
|
31
|
+
|
32
|
+
include Funkr::Categories
|
33
|
+
|
34
|
+
class << self
|
35
|
+
def mzero; self.new(); end
|
36
|
+
end
|
37
|
+
|
38
|
+
### Categories
|
39
|
+
|
40
|
+
# Hash is a functor via map_v, but unfortunatly a dumb map method is
|
41
|
+
# already defined by the enumerable module, and is kept for
|
42
|
+
# compatibility
|
43
|
+
|
44
|
+
|
45
|
+
# Hash is a monoid if values type is a monoid
|
46
|
+
include Monoid
|
47
|
+
extend Monoid::ClassMethods
|
48
|
+
|
49
|
+
def mplus(m_y)
|
50
|
+
self.merge(m_y){|k, v1, v2| v1.mplus(v2)}
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/lib/funkr/extensions.rb
CHANGED
data/lib/funkr/types/maybe.rb
CHANGED
@@ -4,25 +4,32 @@ require 'funkr/categories'
|
|
4
4
|
module Funkr
|
5
5
|
module Types
|
6
6
|
class Maybe < ADT
|
7
|
-
|
7
|
+
|
8
8
|
include Funkr::Categories
|
9
|
-
|
9
|
+
|
10
10
|
adt :just, :nothing
|
11
|
-
|
11
|
+
|
12
12
|
### Categories
|
13
|
-
|
13
|
+
|
14
14
|
include Functor
|
15
|
-
|
15
|
+
|
16
16
|
def map(&block)
|
17
17
|
self.match do |on|
|
18
18
|
on.just {|v| self.class.just(yield(v))}
|
19
19
|
on.nothing { self }
|
20
20
|
end
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
|
+
# Maybe can be made an applicative functor, for example :
|
24
|
+
# f = Maybe.curry_lift_proc{|x,y| x + y}
|
25
|
+
# a = Maybe.just(3)
|
26
|
+
# b = Maybe.just(4)
|
27
|
+
# c = Maybe.nothing
|
28
|
+
# f.apply(a).apply(b) => Just 7
|
29
|
+
# f.apply(a).apply(c) => Nothing
|
23
30
|
include Applicative
|
24
31
|
extend Applicative::ClassMethods
|
25
|
-
|
32
|
+
|
26
33
|
def apply(to)
|
27
34
|
self.match do |f_on|
|
28
35
|
f_on.just do |f|
|
@@ -34,20 +41,20 @@ module Funkr
|
|
34
41
|
f_on.nothing { self }
|
35
42
|
end
|
36
43
|
end
|
37
|
-
|
44
|
+
|
38
45
|
include Alternative
|
39
|
-
|
46
|
+
|
40
47
|
def or_else(&block)
|
41
48
|
self.match do |on|
|
42
49
|
on.just {|v| self}
|
43
50
|
on.nothing { yield }
|
44
51
|
end
|
45
52
|
end
|
46
|
-
|
47
|
-
|
53
|
+
|
54
|
+
|
48
55
|
include Monoid
|
49
56
|
extend Monoid::ClassMethods
|
50
|
-
|
57
|
+
|
51
58
|
def mplus(m_y)
|
52
59
|
self.match do |x_on|
|
53
60
|
x_on.nothing { m_y }
|
@@ -59,18 +66,18 @@ module Funkr
|
|
59
66
|
end
|
60
67
|
end
|
61
68
|
end
|
62
|
-
|
63
|
-
|
69
|
+
|
70
|
+
|
64
71
|
include Monad
|
65
72
|
extend Monad::ClassMethods
|
66
|
-
|
73
|
+
|
67
74
|
def bind(&block)
|
68
75
|
self.match do |on|
|
69
76
|
on.just {|v| yield(v)}
|
70
77
|
on.nothing {self}
|
71
78
|
end
|
72
79
|
end
|
73
|
-
|
80
|
+
|
74
81
|
def unbox(default=nil)
|
75
82
|
self.match do |on|
|
76
83
|
on.just {|v| v }
|
@@ -83,7 +90,7 @@ module Funkr
|
|
83
90
|
alias pure just
|
84
91
|
alias mzero nothing
|
85
92
|
end
|
86
|
-
|
93
|
+
|
87
94
|
def self.box(value)
|
88
95
|
if value.nil? then self.nothing
|
89
96
|
else self.just(value) end
|
@@ -94,7 +101,7 @@ module Funkr
|
|
94
101
|
# a list of all the Just values.
|
95
102
|
def self.concat(maybes)
|
96
103
|
maybes.inject([]) do |a, e|
|
97
|
-
e.match do |on|
|
104
|
+
e.match do |on|
|
98
105
|
on.just{|v| a + [v]}
|
99
106
|
on.nothing{ a }
|
100
107
|
end
|
@@ -62,20 +62,18 @@ module Funkr
|
|
62
62
|
|
63
63
|
def to_s; @key_vals.to_s; end
|
64
64
|
|
65
|
-
|
66
|
-
|
67
|
-
private
|
65
|
+
private
|
68
66
|
|
69
|
-
|
70
|
-
|
71
|
-
|
67
|
+
def rebuild_array
|
68
|
+
self.replace(@key_vals.values)
|
69
|
+
end
|
72
70
|
|
73
|
-
|
74
|
-
|
71
|
+
def check_keys(keys)
|
72
|
+
unless keys.all?{|k| @allowed_keys.include?(k)} then
|
75
73
|
raise "#{self.class.to_s} forbidden key in update"
|
74
|
+
end
|
76
75
|
end
|
77
|
-
end
|
78
|
-
|
79
76
|
|
77
|
+
end
|
80
78
|
end
|
81
79
|
end
|
data/lib/funkr/version.rb
CHANGED
data/lib/funkr.rb
CHANGED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'funkr/types/container'
|
3
|
+
|
4
|
+
class TestContainer < Test::Unit::TestCase
|
5
|
+
C = Funkr::Types::Container
|
6
|
+
|
7
|
+
def test_comparable
|
8
|
+
# assert_equal(C.new('foo'), C.new('foo'))
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_container
|
12
|
+
c = C.new("Value")
|
13
|
+
assert_equal("Value", c.unbox)
|
14
|
+
assert_equal("eulaV", c.map(&:reverse).unbox)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'funkr/extensions'
|
3
|
+
|
4
|
+
class TestExtensions < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_array_full_lift
|
7
|
+
a = [1,2,3]
|
8
|
+
b = [10,20,30]
|
9
|
+
f = Array.full_lift_proc{|x,y| x + y}
|
10
|
+
assert_equal([11, 21, 31, 12, 22, 32, 13, 23, 33], f.call(a,b))
|
11
|
+
assert_equal([], f.call(a,[]))
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_array_monad
|
15
|
+
a = [1,2,3]
|
16
|
+
b = [10,20,30]
|
17
|
+
assert_equal([11, 21, 31, 12, 22, 32, 13, 23, 33],
|
18
|
+
a.bind do |x|
|
19
|
+
b.bind do |y|
|
20
|
+
Array.unit(x + y)
|
21
|
+
end
|
22
|
+
end)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_span
|
26
|
+
assert_equal([[1, 2, 4], [5, 7, 5, 8, 2, 10]],
|
27
|
+
[1,2,4,5,7,5,8,2,10].span{|x| x < 5})
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_group_seq_by
|
31
|
+
assert_equal([[1], [2, 4], [5, 7, 5], [8, 2, 10]],
|
32
|
+
[1,2,4,5,7,5,8,2,10].group_seq_by{|x| x % 2})
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_groups_of
|
36
|
+
assert_equal([[1, 2, 4, 5], [7, 5, 8, 2], [10]],
|
37
|
+
[1,2,4,5,7,5,8,2,10].groups_of(4))
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_sliding_groups_of
|
41
|
+
assert_equal([[1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6],
|
42
|
+
[5, 6, 7], [6, 7, 8], [7, 8, 9], [8, 9, 10]],
|
43
|
+
(1..10).to_a.sliding_groups_of(3))
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_seq_index
|
47
|
+
assert_equal(30, (0..100).to_a.seq_index([30,31,32]))
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_diff_with
|
51
|
+
a = [ {:v => 1}, {:v => 2}, {:v => 3}, {:v => 2}, {:v => 3} ]
|
52
|
+
b = [ {:v => 2}, {:v => 3}, {:v => 4}, {:v => 3}, {:v => 4} ]
|
53
|
+
assert_equal([[{:v=>1}], [{:v=>2}, {:v=>3}], [{:v=>4}]],
|
54
|
+
a.diff_with(b){|x,y| x[:v] == y[:v]})
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_make_uniq_by
|
58
|
+
a = [ {:v => 1}, {:v => 2}, {:v => 3}, {:v => 2}, {:v => 3}, {:v => 1} ]
|
59
|
+
assert_equal([{:v=>1}, {:v=>2}, {:v=>3}],
|
60
|
+
a.make_uniq_by{|x,y| x[:v] == y[:v]})
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
data/test/test_hash.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'funkr/extensions/hash'
|
3
|
+
|
4
|
+
class TestHash < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_map_v
|
7
|
+
assert_equal( {a: 2, b: 3},
|
8
|
+
{a: 1, b: 2}.map_v{|v| v + 1} )
|
9
|
+
h = Hash.new(:patate)
|
10
|
+
assert_equal( :patate, h.map_v{|x| x + 1}[:foo] )
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
data/test/test_maybe.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'funkr/types/maybe'
|
3
|
+
require 'funkr/extensions'
|
4
|
+
|
5
|
+
class TestMaybe < Test::Unit::TestCase
|
6
|
+
|
7
|
+
M = Funkr::Types::Maybe
|
8
|
+
|
9
|
+
def j(v)
|
10
|
+
M.just(v)
|
11
|
+
end
|
12
|
+
|
13
|
+
def n
|
14
|
+
M.nothing
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_map
|
18
|
+
assert_equal(j(6), j(5).map{|v| v+1 })
|
19
|
+
assert_equal(n, j(5).map{|v| v+1})
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_curry_lift
|
23
|
+
f = M.curry_lift_proc{|x,y| x + y}
|
24
|
+
assert_equal(j(8), f.apply(j(5)).apply(j(3)))
|
25
|
+
assert_equal(n, f.apply(j(5)).apply(n))
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_or_else
|
29
|
+
assert_equal(j(10), n.or_else{j(10)})
|
30
|
+
assert_equal(j(4), j(4).or_else{j(2)})
|
31
|
+
# assert_nothing_raised(j(2).or_else{raise 'should not be raised'})
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_full_lift
|
35
|
+
f = M.full_lift_proc{|x,y| x + y}
|
36
|
+
assert_equal(j(6), f.call(j(4),j(2)))
|
37
|
+
assert_equal(n, f.call(j(1),n))
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_lift_with
|
41
|
+
assert_equal(j(7), M.lift_with(j(4),j(3)){|x,y| x + y})
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_mconcat
|
45
|
+
assert_equal(j(60), M.mconcat([j(10), j(20), n, j(30)]))
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_concat
|
49
|
+
assert_equal([10,20,30], M.concat([j(10), j(20), n, j(30)]))
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_comparisons
|
53
|
+
assert_equal(j(0), j(5) <=> j(5))
|
54
|
+
assert_equal(j(-1), j(5) <=> j(7))
|
55
|
+
assert_equal(j(1), j(2) <=> j(1))
|
56
|
+
assert_equal(j(true), j(3) < j(7))
|
57
|
+
assert_equal(n, j(4) <=> n)
|
58
|
+
assert_equal(n, n <=> j(2))
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_unbox
|
62
|
+
assert_equal(5, j(5).unbox)
|
63
|
+
assert_equal(5, j(5).unbox(2))
|
64
|
+
assert_equal(nil, n.unbox)
|
65
|
+
assert_equal(2, n.unbox(2))
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_box
|
69
|
+
assert_equal(j(5), M.box(5))
|
70
|
+
assert_equal(n, M.box(nil))
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'funkr/types/simple_record'
|
3
|
+
|
4
|
+
class TestSimpleRecords < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_simple_records
|
7
|
+
r = Funkr::Types::SimpleRecord.new(name: "Paul", age: 27, city: "Rennes")
|
8
|
+
name, age, city = r
|
9
|
+
assert_equal("Paul", name)
|
10
|
+
assert_equal(27, age)
|
11
|
+
assert_equal("Rennes", city)
|
12
|
+
name, age, city = r.with(age: 28, city: "Trouville")
|
13
|
+
assert_equal("Paul", name)
|
14
|
+
assert_equal(28, age)
|
15
|
+
assert_equal("Trouville", city)
|
16
|
+
|
17
|
+
r.name = "Paul R"
|
18
|
+
assert_equal("Paul R", r.name)
|
19
|
+
|
20
|
+
r.update!(name: "Paul")
|
21
|
+
n, _x, _y = r
|
22
|
+
assert_equal("Paul", n)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
metadata
CHANGED
@@ -1,34 +1,37 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: funkr
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 0
|
8
|
-
- 21
|
9
|
-
version: 0.0.21
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.22
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Paul Rivier
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
12
|
+
date: 2011-10-14 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake
|
16
|
+
requirement: &15155260 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.9.2
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *15155260
|
25
|
+
description: ! '[EXPERIMENTAL] Some functionnal constructs for ruby, like ADT, functors,
|
26
|
+
monads'
|
27
|
+
email:
|
23
28
|
- paul (dot) r (dot) ml (at) gmail (dot) com
|
24
29
|
executables: []
|
25
|
-
|
26
30
|
extensions: []
|
27
|
-
|
28
31
|
extra_rdoc_files: []
|
29
|
-
|
30
|
-
files:
|
32
|
+
files:
|
31
33
|
- .gitignore
|
34
|
+
- .travis.yml
|
32
35
|
- Gemfile
|
33
36
|
- Rakefile
|
34
37
|
- funkr.gemspec
|
@@ -46,44 +49,40 @@ files:
|
|
46
49
|
- lib/funkr/extensions/array.rb
|
47
50
|
- lib/funkr/extensions/enumerable.rb
|
48
51
|
- lib/funkr/extensions/fixnum.rb
|
52
|
+
- lib/funkr/extensions/hash.rb
|
49
53
|
- lib/funkr/types.rb
|
50
54
|
- lib/funkr/types/container.rb
|
51
55
|
- lib/funkr/types/failable.rb
|
52
56
|
- lib/funkr/types/maybe.rb
|
53
57
|
- lib/funkr/types/simple_record.rb
|
54
58
|
- lib/funkr/version.rb
|
55
|
-
- test/
|
56
|
-
|
59
|
+
- test/test_container.rb
|
60
|
+
- test/test_extensions.rb
|
61
|
+
- test/test_hash.rb
|
62
|
+
- test/test_maybe.rb
|
63
|
+
- test/test_simple_records.rb
|
57
64
|
homepage: http://github.com/paul-r-ml/funkr
|
58
65
|
licenses: []
|
59
|
-
|
60
66
|
post_install_message:
|
61
67
|
rdoc_options: []
|
62
|
-
|
63
|
-
require_paths:
|
68
|
+
require_paths:
|
64
69
|
- lib
|
65
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
71
|
none: false
|
67
|
-
requirements:
|
68
|
-
- -
|
69
|
-
- !ruby/object:Gem::Version
|
70
|
-
|
71
|
-
|
72
|
-
version: "0"
|
73
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
77
|
none: false
|
75
|
-
requirements:
|
76
|
-
- -
|
77
|
-
- !ruby/object:Gem::Version
|
78
|
-
|
79
|
-
- 0
|
80
|
-
version: "0"
|
78
|
+
requirements:
|
79
|
+
- - ! '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
81
82
|
requirements: []
|
82
|
-
|
83
83
|
rubyforge_project: funkr
|
84
|
-
rubygems_version: 1.
|
84
|
+
rubygems_version: 1.8.10
|
85
85
|
signing_key:
|
86
86
|
specification_version: 3
|
87
|
-
summary:
|
87
|
+
summary: ! '[EXPERIMENTAL] Some functionnal constructs for ruby'
|
88
88
|
test_files: []
|
89
|
-
|
data/test/tests.rb
DELETED
@@ -1,136 +0,0 @@
|
|
1
|
-
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
2
|
-
|
3
|
-
require 'rubygems'
|
4
|
-
require 'funkr'
|
5
|
-
require 'funkr/types'
|
6
|
-
require 'funkr/extensions'
|
7
|
-
|
8
|
-
include Funkr::Types
|
9
|
-
|
10
|
-
m = Maybe.just(5)
|
11
|
-
|
12
|
-
puts "\n> All different ?"
|
13
|
-
puts([1,2,3].all_different?)
|
14
|
-
puts([1,2,2,3].all_different?)
|
15
|
-
|
16
|
-
puts "\n> Maybe"
|
17
|
-
puts(m.match do |on|
|
18
|
-
on.nothing{ Maybe.nothing }
|
19
|
-
on.just{|v| Maybe.just(v + 1) }
|
20
|
-
end.to_s)
|
21
|
-
|
22
|
-
puts(m.map{|v| v+1 })
|
23
|
-
|
24
|
-
|
25
|
-
n = Maybe.nothing
|
26
|
-
|
27
|
-
puts(n.match do |on|
|
28
|
-
on.nothing{ Maybe.nothing }
|
29
|
-
on.just{|v| Maybe.just(v + 1) }
|
30
|
-
end.to_s)
|
31
|
-
|
32
|
-
|
33
|
-
puts "\n> Curry lift"
|
34
|
-
f = Maybe.curry_lift_proc{|x,y| x + y}
|
35
|
-
puts f.apply(m).apply(m)
|
36
|
-
puts f.apply(m).apply(n)
|
37
|
-
puts f.apply(m).apply(n.or_else{Maybe.just(10)})
|
38
|
-
|
39
|
-
puts "\n> Full lift"
|
40
|
-
f = Maybe.full_lift_proc{|x,y| x + y}
|
41
|
-
puts f.call(m,m)
|
42
|
-
puts f.call(m,n)
|
43
|
-
|
44
|
-
puts "\n> Lift with"
|
45
|
-
puts Maybe.lift_with(m,m){|x,y| x + y}
|
46
|
-
|
47
|
-
puts "\n> mconcat"
|
48
|
-
puts Maybe.mconcat([Maybe.just(10),
|
49
|
-
Maybe.just(20),
|
50
|
-
Maybe.nothing,
|
51
|
-
Maybe.just(30)])
|
52
|
-
|
53
|
-
puts "\n> concat"
|
54
|
-
puts Maybe.concat([ Maybe.just(10),
|
55
|
-
Maybe.just(20),
|
56
|
-
Maybe.nothing,
|
57
|
-
Maybe.just(30) ]).inspect
|
58
|
-
|
59
|
-
puts "\n> Comparisons"
|
60
|
-
puts(m <=> m)
|
61
|
-
puts(m <=> (m.map{|v| v+1}))
|
62
|
-
puts(m < (m.map{|v| v+1}))
|
63
|
-
puts(m <=> n)
|
64
|
-
|
65
|
-
puts "\n> Boxing and unboxing"
|
66
|
-
puts m.unbox.inspect
|
67
|
-
puts n.unbox.inspect
|
68
|
-
puts (Maybe.box(12)).unbox.inspect
|
69
|
-
puts (Maybe.box(nil)).unbox.inspect
|
70
|
-
|
71
|
-
puts "\n> Containers"
|
72
|
-
c = Container.new("Value")
|
73
|
-
puts c.unbox
|
74
|
-
puts c.map(&:reverse)
|
75
|
-
|
76
|
-
a = [1,2,3]
|
77
|
-
b = [10,20,30]
|
78
|
-
|
79
|
-
puts "\n> Array full lift"
|
80
|
-
f = Array.full_lift_proc{|x,y| x + y}
|
81
|
-
puts f.call(a,b).inspect
|
82
|
-
puts f.call(a,[]).inspect
|
83
|
-
|
84
|
-
puts "\n> Array monad"
|
85
|
-
puts(a.bind do |x|
|
86
|
-
b.bind do |y|
|
87
|
-
Array.unit(x + y)
|
88
|
-
end
|
89
|
-
end.inspect)
|
90
|
-
|
91
|
-
|
92
|
-
puts "\n> span"
|
93
|
-
puts([1,2,4,5,7,5,8,2,10].span{|x| x < 5}.inspect)
|
94
|
-
|
95
|
-
puts "\n> group_seq_by"
|
96
|
-
puts([1,2,4,5,7,5,8,2,10].group_seq_by{|x| x % 2}.inspect)
|
97
|
-
|
98
|
-
puts "\n> groups_of"
|
99
|
-
puts([1,2,4,5,7,5,8,2,10].groups_of(4).inspect)
|
100
|
-
|
101
|
-
puts "\n> sliding_groups_of"
|
102
|
-
puts((1..10).to_a.sliding_groups_of(3).inspect)
|
103
|
-
|
104
|
-
puts "\n> seq_index (30)"
|
105
|
-
puts((0..100).to_a.seq_index([30,31,32]))
|
106
|
-
|
107
|
-
puts "\n> diff_with"
|
108
|
-
a = [ {:v => 1}, {:v => 2}, {:v => 3}, {:v => 2}, {:v => 3} ]
|
109
|
-
b = [ {:v => 2}, {:v => 3}, {:v => 4}, {:v => 3}, {:v => 4} ]
|
110
|
-
puts(a.diff_with(b){|x,y| x[:v] == y[:v]}.inspect)
|
111
|
-
|
112
|
-
puts "\n> make_uniq_by"
|
113
|
-
a = [ {:v => 1}, {:v => 2}, {:v => 3}, {:v => 2}, {:v => 3}, {:v => 1} ]
|
114
|
-
puts(a.make_uniq_by{|x,y| x[:v] == y[:v]}.inspect)
|
115
|
-
|
116
|
-
|
117
|
-
puts "\n> SimpleRecords"
|
118
|
-
r = SimpleRecord.new(name: "Paul", age: 27, city: "Rennes")
|
119
|
-
puts r.to_s
|
120
|
-
name, age, city = r
|
121
|
-
puts format("%s is %s and lives in %s", name, age, city)
|
122
|
-
name, age, city = r.with(age: 28, city: "Trouville")
|
123
|
-
puts format("%s is now %s and lives in %s", name, age, city)
|
124
|
-
puts format("%s is back to %s and really lives in %s", r.name, r.age, r.city)
|
125
|
-
r.name = "Paul R"
|
126
|
-
puts r.to_s
|
127
|
-
r.update!(name: "Paul")
|
128
|
-
n, _x, _y = r
|
129
|
-
puts n
|
130
|
-
|
131
|
-
class Person < SimpleRecord; fields :name, :age, :city; end
|
132
|
-
r = Person.new(name: "Paul", age: 27, city: "Rennes")
|
133
|
-
puts r.to_s
|
134
|
-
x = Person.new(name: "Paul", age: 27, city: "Rennes", genre: "Male") rescue "Forbidden"
|
135
|
-
y = Person.new(name: "Paul", age: 27) rescue "Forbidden"
|
136
|
-
|