fubby 0.0.0
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.
- 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
|