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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 147a7fd803443d3bc56481e35023bfe25a9c6510
4
- data.tar.gz: 81b7a9752e0bc7af02b4a713e77fa0b88afa67e7
3
+ metadata.gz: 0faa0f3d082df30457dbd13eae82d9d78b582cda
4
+ data.tar.gz: ea596071898a6e7eca90869cc3b31fba9165c8b6
5
5
  SHA512:
6
- metadata.gz: 7991f402cc958d2872f038e2d48ad180224771a5488a7500744b97955b5a7db227f3b6d306bc6f13eb267391e84f6fb64ddd89ef4a8c791a2fd7bf5c1dc2b046
7
- data.tar.gz: b372da0baad485064622feceb0fecccae595a8b2273a6f20beadb61816055e7fc0daac467a0eba2577a12b7bf7ebd2f7a9a2d06aade9cc1325787ba9c856f1fd
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
- flat_m = m.flatten
16
- flat_n = n.flatten
17
- if flat_m.length == flat_n.length
18
- e = flat_m.zip(n.flatten)
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.flatten)
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
- result = instance_exec(*args, &pattern)
40
- return result unless result.nil?
50
+ begin
51
+ return instance_exec(*args, &pattern)
52
+ rescue NoMatch
53
+ end
41
54
  end
42
- nil
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
@@ -1,7 +1,8 @@
1
+ require 'funtools/cons'
1
2
  require 'funtools/recursion'
2
3
  require 'funtools/composition'
3
4
  require 'funtools/pattern-matching'
4
5
 
5
6
  module Funtools
6
- VERSION = '0.4.0'
7
+ VERSION = '0.5.0'
7
8
  end
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.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-09-14 00:00:00.000000000 Z
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