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.
@@ -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
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
@@ -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
@@ -0,0 +1,3 @@
1
+ # Fubby
2
+
3
+ Functional library for ruby
@@ -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
@@ -0,0 +1,7 @@
1
+ require_relative './fubby/core'
2
+ require_relative './fubby/std_lib'
3
+
4
+ class F
5
+ extend Core
6
+ extend StdLib
7
+ end
@@ -0,0 +1,6 @@
1
+ module ArrayUtils
2
+ # concat :: [a] -> [a] -> [a]
3
+ def concat
4
+ ->(a1, a2) { a1 + a2 }
5
+ end
6
+ end
@@ -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
@@ -0,0 +1,4 @@
1
+ require "minitest/autorun"
2
+ require "minitest/reporters"
3
+
4
+ Minitest::Reporters.use!(Minitest::Reporters::DefaultReporter.new)
@@ -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