fubby 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +22 -0
- data/README.md +3 -0
- data/fubby.gemspec +17 -0
- data/lib/fubby.rb +7 -0
- data/lib/fubby/array_utils.rb +6 -0
- data/lib/fubby/core.rb +62 -0
- data/lib/fubby/std_lib.rb +113 -0
- data/test/test_helper.rb +4 -0
- data/test/unit/core_test.rb +130 -0
- data/test/unit/std_lib_test.rb +46 -0
- metadata +86 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ad6780eea6f05146816180477723f9863c9d861e
|
4
|
+
data.tar.gz: 8381795af6662e96c9a84fe3669ca5b53f70b371
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a458b1f8e734bce354a079dbafa4780231f9d0e5b1aae1897a61b0f36b4ee7292acd210f5e0ae7242f18a1fa81bdcd1ab366515d44d49763a26f2b2a8678cc37
|
7
|
+
data.tar.gz: 0a115ce3487eefcfcaca1c7492756c08399bea0d1d4697bd16d37d4f1f438ca4cdb0d4496f594b4b2d396bd35793dfb2989a9655c6608dfdc3efa7097b0e10bf
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
ansi (1.5.0)
|
5
|
+
builder (3.2.2)
|
6
|
+
minitest (5.8.4)
|
7
|
+
minitest-reporters (1.1.8)
|
8
|
+
ansi
|
9
|
+
builder
|
10
|
+
minitest (>= 5.0)
|
11
|
+
ruby-progressbar
|
12
|
+
ruby-progressbar (1.7.5)
|
13
|
+
|
14
|
+
PLATFORMS
|
15
|
+
ruby
|
16
|
+
|
17
|
+
DEPENDENCIES
|
18
|
+
minitest
|
19
|
+
minitest-reporters
|
20
|
+
|
21
|
+
BUNDLED WITH
|
22
|
+
1.11.2
|
data/README.md
ADDED
data/fubby.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Gem::Specification.new do |gem|
|
2
|
+
gem.authors = ['JaredShay']
|
3
|
+
gem.email = ['jared.shay@gmail.com']
|
4
|
+
gem.description = %q{Functional library for ruby}
|
5
|
+
gem.summary = %q{Functional library for ruby}
|
6
|
+
gem.homepage = 'https://github.com/jaredshay/fubby'
|
7
|
+
|
8
|
+
gem.files = `git ls-files`.split("\n")
|
9
|
+
gem.test_files = `git ls-files -- test/*`.split("\n")
|
10
|
+
gem.name = 'fubby'
|
11
|
+
gem.require_paths = ['lib']
|
12
|
+
gem.version = '0.0.0'
|
13
|
+
gem.license = 'MIT'
|
14
|
+
|
15
|
+
gem.add_development_dependency 'miniest'
|
16
|
+
gem.add_development_dependency 'minitest-reporters'
|
17
|
+
end
|
data/lib/fubby.rb
ADDED
data/lib/fubby/core.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
module Core
|
2
|
+
# identity :: a -> a
|
3
|
+
def identity
|
4
|
+
->(x) { x }
|
5
|
+
end
|
6
|
+
|
7
|
+
# curry :: (a -> b) -> (a -> b)
|
8
|
+
def curry
|
9
|
+
_curry = ->(f, *given_args) {
|
10
|
+
->(*remaining_args) {
|
11
|
+
total_args = given_args + remaining_args
|
12
|
+
|
13
|
+
total_args.length == f.arity ? f.(*total_args) : _curry.(f, *total_args)
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
->(f) {
|
18
|
+
->(*x) {
|
19
|
+
f.arity == x.length ? f.(*x) : _curry.(f, *x)
|
20
|
+
}
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
# reduce :: a, (b -> a), [b] -> a
|
25
|
+
def reduce
|
26
|
+
curry.(->(memo, f, array) {
|
27
|
+
if memo == nil
|
28
|
+
case array.length
|
29
|
+
when 0 then nil
|
30
|
+
when 1 then array[0]
|
31
|
+
else reduce.(f.(array[0], array[1]), f, array[2..-1])
|
32
|
+
end
|
33
|
+
else
|
34
|
+
case array.length
|
35
|
+
when 0 then memo
|
36
|
+
else reduce.(f.(memo, array[0]), f, array[1..-1])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
})
|
40
|
+
end
|
41
|
+
|
42
|
+
# TODO: figure out how to notate many args. [f] isn't correct here.
|
43
|
+
# compose :: [f] -> (a -> b)
|
44
|
+
def compose
|
45
|
+
->(*f) {
|
46
|
+
_compose = ->(x, *f) {
|
47
|
+
f.length == 1 ? f[0].(x) : f[0].(_compose.(x, *f[1..-1]))
|
48
|
+
}
|
49
|
+
|
50
|
+
->(x) { _compose.(x, *f) }
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
# flip :: (a -> b) -> (a -> b)
|
55
|
+
def flip
|
56
|
+
->(f) {
|
57
|
+
->(*args) {
|
58
|
+
f.(*reverse.(args))
|
59
|
+
}
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require_relative './core.rb'
|
2
|
+
require_relative './array_utils.rb'
|
3
|
+
|
4
|
+
module StdLib
|
5
|
+
C = Class.new { extend Core }
|
6
|
+
private_constant :C
|
7
|
+
|
8
|
+
A = Class.new { extend ArrayUtils }
|
9
|
+
private_constant :A
|
10
|
+
|
11
|
+
# length :: [a] -> Number
|
12
|
+
def length
|
13
|
+
->(x) {
|
14
|
+
C.reduce.(0, ->(memo, _) { memo + 1 }, x)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
# map :: (a -> b) -> [a] -> [b]
|
19
|
+
def map
|
20
|
+
C.curry.(
|
21
|
+
->(f, x) {
|
22
|
+
fx = ->(memo, x) {
|
23
|
+
A.concat.(memo, [f.(x)])
|
24
|
+
}
|
25
|
+
|
26
|
+
C.reduce.([], fx, x)
|
27
|
+
}
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
# select :: (a -> Bool) -> [a] -> [a]
|
32
|
+
def select
|
33
|
+
C.curry.(
|
34
|
+
->(f, x) {
|
35
|
+
fx = ->(memo, x) {
|
36
|
+
f.(x) == true ? A.concat.(memo, [x]) : memo
|
37
|
+
}
|
38
|
+
|
39
|
+
C.reduce.([], fx, x)
|
40
|
+
}
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
# reject :: (a -> Bool) -> [a] -> [a]
|
45
|
+
def reject
|
46
|
+
C.curry.(->(f, x) { x - select.(f, x) })
|
47
|
+
end
|
48
|
+
|
49
|
+
# any :: (a -> Bool) -> Bool
|
50
|
+
def any
|
51
|
+
C.curry.(
|
52
|
+
->(f, x) {
|
53
|
+
fx = ->(memo, x) {
|
54
|
+
f.(x) ? true : memo
|
55
|
+
}
|
56
|
+
|
57
|
+
C.reduce.(fx, x, false)
|
58
|
+
}
|
59
|
+
)
|
60
|
+
end
|
61
|
+
|
62
|
+
# any :: (a -> Bool) -> Bool
|
63
|
+
def f_all
|
64
|
+
C.curry.(
|
65
|
+
->(f, x) {
|
66
|
+
!any.(->(x) { x == false }, map.(f, x))
|
67
|
+
}
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
# add :: Int -> Int -> Int
|
72
|
+
def add
|
73
|
+
->(x, y) { x + y }
|
74
|
+
end
|
75
|
+
|
76
|
+
# head :: [a] -> a
|
77
|
+
def head
|
78
|
+
->(x) { x[0] }
|
79
|
+
end
|
80
|
+
|
81
|
+
# reverse :: [a] -> [a]
|
82
|
+
def reverse
|
83
|
+
->(array) {
|
84
|
+
if array.empty? || length.(array) == 1
|
85
|
+
array
|
86
|
+
else
|
87
|
+
add.(reverse.(array[1..-1]), array[0])
|
88
|
+
end
|
89
|
+
}
|
90
|
+
end
|
91
|
+
|
92
|
+
# tail :: [a] -> a
|
93
|
+
def tail
|
94
|
+
C.compose.(head, reverse)
|
95
|
+
end
|
96
|
+
|
97
|
+
# TODO: figure out how to handle Strings and Chars
|
98
|
+
def str_head
|
99
|
+
->(x) { x[0] }
|
100
|
+
end
|
101
|
+
|
102
|
+
# TODO implement this without `downcase`
|
103
|
+
# downcase :: String -> String
|
104
|
+
def downcase
|
105
|
+
->(x) { x.downcase }
|
106
|
+
end
|
107
|
+
|
108
|
+
# TODO implement this without `capitalize`
|
109
|
+
# downcase :: String -> String
|
110
|
+
def upcase
|
111
|
+
->(x) { x.capitalize }
|
112
|
+
end
|
113
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
require_relative '../test_helper.rb'
|
2
|
+
require_relative '../../lib/fubby/core.rb'
|
3
|
+
|
4
|
+
class T
|
5
|
+
extend Core
|
6
|
+
end
|
7
|
+
|
8
|
+
module Test
|
9
|
+
class IdentityTest < MiniTest::Test
|
10
|
+
def test_success
|
11
|
+
assert_equal 'x', T.identity.('x')
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_fail
|
15
|
+
assert 'x' != T.identity.('y')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class CurryTest < MiniTest::Test
|
20
|
+
def test_defining_a_method_with_no_args
|
21
|
+
f = T.curry.(-> { 'x' })
|
22
|
+
|
23
|
+
assert_equal 'x', f.()
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_defining_a_method_with_one_argument
|
27
|
+
f = T.curry.(->(x) { x })
|
28
|
+
|
29
|
+
assert_equal 'x', f.('x')
|
30
|
+
assert_equal 'x', f.().('x')
|
31
|
+
assert_equal 'x', f.().().('x')
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_defining_a_method_with_two_arguments
|
35
|
+
f = T.curry.(->(x, y) { x + y })
|
36
|
+
|
37
|
+
assert_equal 3, f.(1, 2)
|
38
|
+
assert_equal 3, f.().(1, 2)
|
39
|
+
assert_equal 3, f.().().(1, 2)
|
40
|
+
assert_equal 3, f.(1).(2)
|
41
|
+
assert_equal 3, f.().(1).(2)
|
42
|
+
assert_equal 3, f.(1).().(2)
|
43
|
+
assert_equal 3, f.(1).().().(2)
|
44
|
+
assert_equal 3, f.().(1).().(2)
|
45
|
+
assert_equal 3, f.().(1).().().(2)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_defining_a_method_with_three_arguments
|
49
|
+
f = T.curry.(->(x, y, z) { x + y + z })
|
50
|
+
|
51
|
+
assert_equal 6, f.(1, 2, 3)
|
52
|
+
assert_equal 6, f.().(1, 2, 3)
|
53
|
+
assert_equal 6, f.().().(1, 2, 3)
|
54
|
+
assert_equal 6, f.(1, 2).(3)
|
55
|
+
assert_equal 6, f.().(1, 2).(3)
|
56
|
+
assert_equal 6, f.().(1, 2).().(3)
|
57
|
+
assert_equal 6, f.(1, 2).().(3)
|
58
|
+
assert_equal 6, f.(1).(2, 3)
|
59
|
+
assert_equal 6, f.().(1).(2, 3)
|
60
|
+
assert_equal 6, f.().(1).().(2, 3)
|
61
|
+
assert_equal 6, f.(1).(2).(3)
|
62
|
+
assert_equal 6, f.().(1).(2).(3)
|
63
|
+
assert_equal 6, f.().(1).().(2).(3)
|
64
|
+
assert_equal 6, f.().(1).().(2).().(3)
|
65
|
+
assert_equal 6, f.(1).().(2).(3)
|
66
|
+
assert_equal 6, f.(1).().(2).().(3)
|
67
|
+
assert_equal 6, f.(1).(2).().(3)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class ReduceTest < MiniTest::Test
|
72
|
+
def test_reducing_a_zero_element_array_with_no_memo
|
73
|
+
assert_equal nil, T.reduce.(nil, ->(x, y) { x + y }, [])
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_reducing_a_zero_element_array_with_a_memo
|
77
|
+
assert_equal 'memo', T.reduce.('memo', ->(x, y) { x + y }, [])
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_reducing_a_one_element_array_with_no_memo
|
81
|
+
assert_equal 1, T.reduce.(nil, ->(x, y) { x + y }, [1])
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_reducing_a_one_element_array_with_a_memo
|
85
|
+
assert_equal 2, T.reduce.(1, ->(x, y) { x + y }, [1])
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_reducing_a_two_element_array_with_no_memo
|
89
|
+
assert_equal 3, T.reduce.(nil, ->(x, y) { x + y }, [1, 2])
|
90
|
+
end
|
91
|
+
|
92
|
+
def test_reducing_a_two_element_array_with_a_memo
|
93
|
+
assert_equal 6, T.reduce.(1, ->(x, y) { x + y }, [2, 3])
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_reducing_a_three_element_array_with_no_memo
|
97
|
+
assert_equal 6, T.reduce.(nil, ->(x, y) { x + y }, [1, 2, 3])
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_reducing_a_three_element_array_with_a_memo
|
101
|
+
assert_equal 10, T.reduce.(1, ->(x, y) { x + y }, [2, 3, 4])
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_currying
|
105
|
+
sum = T.reduce.(nil, ->(x, y) { x + y })
|
106
|
+
|
107
|
+
assert_equal 6, sum.([1, 2, 3])
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class ComposeTest < MiniTest::Test
|
112
|
+
def test_composing_a_single_function
|
113
|
+
f = T.compose.(->(x) { x })
|
114
|
+
|
115
|
+
assert_equal 'x', f.('x')
|
116
|
+
end
|
117
|
+
|
118
|
+
def test_composing_two_functions
|
119
|
+
f = T.compose.(->(x) { x + 1 }, ->(x) { x * 2 })
|
120
|
+
|
121
|
+
assert_equal 5, f.(2)
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_composing_three_functions
|
125
|
+
f = T.compose.(->(x) { x + 1 }, ->(x) { x * 2 }, ->(x) { x + 3 })
|
126
|
+
|
127
|
+
assert_equal 11, f.(2)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require_relative '../test_helper.rb'
|
2
|
+
require_relative '../../lib/fubby/std_lib.rb'
|
3
|
+
|
4
|
+
class T
|
5
|
+
extend StdLib
|
6
|
+
end
|
7
|
+
|
8
|
+
class LengthTest < MiniTest::Test
|
9
|
+
def test_zero_length_array
|
10
|
+
assert_equal 0, T.length.([])
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_array_with_one_element
|
14
|
+
assert_equal 1, T.length.([1])
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_array_with_two_elements
|
18
|
+
assert_equal 2, T.length.(['a', 'b'])
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_array_with_three_elements
|
22
|
+
assert_equal 3, T.length.([1, 2, 3])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class MapTest < MiniTest::Test
|
27
|
+
def test_zero_length_array
|
28
|
+
assert_equal [], T.map.(->(x) { x }, [])
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_array_with_one_element
|
32
|
+
assert_equal [2], T.map.(->(x) { x + 1 }, [1])
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_currying
|
36
|
+
double = T.map.(->(x) { x * 2 })
|
37
|
+
|
38
|
+
assert_equal [2, 4], double.([1, 2])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class SelectTest < MiniTest::Test
|
43
|
+
def test_zero_length_array
|
44
|
+
assert_equal [], T.select.(->(x) { x == 1 }, [])
|
45
|
+
end
|
46
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fubby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- JaredShay
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-05-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: miniest
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest-reporters
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Functional library for ruby
|
42
|
+
email:
|
43
|
+
- jared.shay@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- Gemfile
|
49
|
+
- Gemfile.lock
|
50
|
+
- README.md
|
51
|
+
- fubby.gemspec
|
52
|
+
- lib/fubby.rb
|
53
|
+
- lib/fubby/array_utils.rb
|
54
|
+
- lib/fubby/core.rb
|
55
|
+
- lib/fubby/std_lib.rb
|
56
|
+
- test/test_helper.rb
|
57
|
+
- test/unit/core_test.rb
|
58
|
+
- test/unit/std_lib_test.rb
|
59
|
+
homepage: https://github.com/jaredshay/fubby
|
60
|
+
licenses:
|
61
|
+
- MIT
|
62
|
+
metadata: {}
|
63
|
+
post_install_message:
|
64
|
+
rdoc_options: []
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 2.5.1
|
80
|
+
signing_key:
|
81
|
+
specification_version: 4
|
82
|
+
summary: Functional library for ruby
|
83
|
+
test_files:
|
84
|
+
- test/test_helper.rb
|
85
|
+
- test/unit/core_test.rb
|
86
|
+
- test/unit/std_lib_test.rb
|