funtools 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/funtools/cons.rb +92 -0
- data/lib/funtools/pattern-matching.rb +26 -11
- data/lib/funtools.rb +2 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0faa0f3d082df30457dbd13eae82d9d78b582cda
|
4
|
+
data.tar.gz: ea596071898a6e7eca90869cc3b31fba9165c8b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5397fff059b62f1b280866424d72fcb28724ca691246cd7f350a0c0439b889dc0bcc57e31a4131b0b775400da0a348c00fad2028409e491fa44dc777cf6b1875
|
7
|
+
data.tar.gz: 510345cfabb0889d1debd002ac34624309358e040d02132824e97ebba5f59bd77347baa78550a9edd79664ecfb8b993e92a09b213850993e9efcda21fa6821ca
|
@@ -0,0 +1,92 @@
|
|
1
|
+
class Object
|
2
|
+
# Public: Wrap Cons.new to construct a new Cons cell.
|
3
|
+
#
|
4
|
+
# left - Any Object to be the left element of the cell.
|
5
|
+
# right - Any Object to be the right element of the cell.
|
6
|
+
#
|
7
|
+
# Returns a Cons cell.
|
8
|
+
def cons(left, right)
|
9
|
+
Cons.new(left, right)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Public: Construct a list of nested Cons cells.
|
13
|
+
#
|
14
|
+
# first - Any Object to be the leftmost element of the list.
|
15
|
+
# second - Any Object to be the second element of the list (default: nil).
|
16
|
+
# rest - Any number of Objects to serve as elements in the list.
|
17
|
+
#
|
18
|
+
# Returns a list (nested Cons cells).
|
19
|
+
def list(first, second = nil, *rest)
|
20
|
+
set = (rest.empty? && second.nil?) ? [] : rest + [nil]
|
21
|
+
([first, second] + set).reverse.reduce { |c, e| Cons.new(e, c) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class Cons
|
26
|
+
include Enumerable
|
27
|
+
|
28
|
+
attr_reader :car, :cdr
|
29
|
+
|
30
|
+
alias :head :car
|
31
|
+
alias :tail :cdr
|
32
|
+
|
33
|
+
# Public: Create a Cons cell.
|
34
|
+
#
|
35
|
+
# left - Any Object to be the left element of the cell.
|
36
|
+
# right - Any Object to be the right element of the cell.
|
37
|
+
def initialize(left, right)
|
38
|
+
@car = left
|
39
|
+
@cdr = right
|
40
|
+
end
|
41
|
+
|
42
|
+
# Public: Iterate through each element of a Cons cell/list. Note that Cons
|
43
|
+
# cells will be yielded without inspecting their contents if they are in the
|
44
|
+
# left position of a parent Cons cell.
|
45
|
+
#
|
46
|
+
# Yields each element.
|
47
|
+
def each(&block)
|
48
|
+
block.(car)
|
49
|
+
right = cdr
|
50
|
+
|
51
|
+
while right
|
52
|
+
if right.is_a?(Cons)
|
53
|
+
if [right.car, right.cdr].grep(Cons).any? || right.cdr.nil?
|
54
|
+
block.(right.car)
|
55
|
+
right = right.cdr
|
56
|
+
else
|
57
|
+
block.(right)
|
58
|
+
right = nil
|
59
|
+
end
|
60
|
+
else
|
61
|
+
block.(right) unless right.nil?
|
62
|
+
right = nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Public: Determine whether two Cons cells/lists are equivalent.
|
68
|
+
#
|
69
|
+
# other - Object to be compared against.
|
70
|
+
#
|
71
|
+
# Returns true or false.
|
72
|
+
def ==(other)
|
73
|
+
return false unless other.is_a?(Cons)
|
74
|
+
to_a == other.to_a
|
75
|
+
end
|
76
|
+
|
77
|
+
# Public: Produce a string representation of a Cons cell/list.
|
78
|
+
#
|
79
|
+
# Returns a String.
|
80
|
+
def inspect
|
81
|
+
last = nil
|
82
|
+
r = [1].cycle.reduce([self]) do |c,_|
|
83
|
+
break c if c == last
|
84
|
+
last = c
|
85
|
+
c.flatten.map do |e|
|
86
|
+
e.is_a?(Cons) ? ['(', e.to_a.zip([' '].cycle).flatten[0..-2], ')'] :
|
87
|
+
e.nil? ? 'nil' : e
|
88
|
+
end
|
89
|
+
end.map(&:to_s).join
|
90
|
+
end
|
91
|
+
alias :to_s :inspect
|
92
|
+
end
|
@@ -7,20 +7,31 @@ class Object
|
|
7
7
|
#
|
8
8
|
# Returns nothing.
|
9
9
|
def defpattern(sym)
|
10
|
+
match = ->(a, b) do
|
11
|
+
if([a,b].map { |o| o.is_a?(Enumerable) && a.class == b.class }.all?)
|
12
|
+
raise ArgumentError unless a.length == b.length
|
13
|
+
|
14
|
+
zipped = a.is_a?(Hash) ? a.sort.zip(b.sort) : a.zip(b)
|
15
|
+
|
16
|
+
zipped.reduce(true) do |c, e|
|
17
|
+
c && match.(*e)
|
18
|
+
end
|
19
|
+
else
|
20
|
+
a.nil? || a == b
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
10
24
|
old_method = self.class.method(sym) if self.class.method_defined?(:sym)
|
11
25
|
patterns = []
|
12
26
|
self.class.send(:define_method, sym) do |*l, &b|
|
13
27
|
patterns << ->(*n) do
|
14
28
|
->(*m) do
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
unless e.reject { |e| e[0].nil? || e[0]==e[1] }.any?
|
20
|
-
instance_exec(*flat_n, &b)
|
21
|
-
end
|
29
|
+
if m.length == n.length
|
30
|
+
e = m.zip(n)
|
31
|
+
raise NoMatch if e.reject { |e| match.(*e) }.any?
|
32
|
+
instance_exec(*n, &b)
|
22
33
|
end
|
23
|
-
end.(l
|
34
|
+
end.(*l)
|
24
35
|
end
|
25
36
|
end
|
26
37
|
|
@@ -36,10 +47,14 @@ class Object
|
|
36
47
|
message ||= :define_singleton_method
|
37
48
|
self.send(message, sym) do |*args|
|
38
49
|
patterns.each do |pattern|
|
39
|
-
|
40
|
-
|
50
|
+
begin
|
51
|
+
return instance_exec(*args, &pattern)
|
52
|
+
rescue NoMatch
|
53
|
+
end
|
41
54
|
end
|
42
|
-
|
55
|
+
instance_exec { raise NoMatch }
|
43
56
|
end
|
44
57
|
end
|
45
58
|
end
|
59
|
+
|
60
|
+
class NoMatch < ArgumentError; end
|
data/lib/funtools.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: funtools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tina Wuest
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-10-16 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Tools to assist in programming in a more functional style
|
14
14
|
email: tina@wuest.me
|
@@ -18,6 +18,7 @@ extra_rdoc_files: []
|
|
18
18
|
files:
|
19
19
|
- lib/funtools.rb
|
20
20
|
- lib/funtools/composition.rb
|
21
|
+
- lib/funtools/cons.rb
|
21
22
|
- lib/funtools/pattern-matching.rb
|
22
23
|
- lib/funtools/recursion.rb
|
23
24
|
homepage: https://gitlab.com/wuest/funtools
|