functor 0.3.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
data/doc/HISTORY CHANGED
@@ -1,3 +1,4 @@
1
1
  0.1 - Initial implemention of Functor class.
2
2
  0.2 - Added method dispatch, to_proc support, tests.
3
- 0.3 - Added support for guards and redefinition.
3
+ 0.3 - Added support for guards and redefinition.
4
+ 0.3.1 - Made thread-safe and added ability to call base class functors.
data/doc/README CHANGED
@@ -1,4 +1,8 @@
1
- Functor provides pattern-based function and method dispatch for Ruby. To use it in a class:
1
+ Functor provides pattern-based function and method dispatch for Ruby, originally inspired by Topher Cyll's multi gem.
2
+
3
+ = Method Functors
4
+
5
+ To use it in a class:
2
6
 
3
7
  class Repeater
4
8
  attr_accessor :times
@@ -11,29 +15,33 @@ Functor provides pattern-based function and method dispatch for Ruby. To use it
11
15
  r.times = 5
12
16
  r.repeat( 5 ) # => 25
13
17
  r.repeat( "-" ) # => "- - - - -"
14
- r.repeat( 7.3 ) # => RuntimeError!
18
+ r.repeat( 7.3 ) # => ArgumentError!
15
19
 
16
- Warning: This defines a class instance variable @__functors behind the scenes as a side-effect. Also, although inheritance works within a functor method, super does not. To call the parent method, you need to call it explicitly using the #functors class method, like this:
20
+ Warning: This defines a class instance variable <tt>@__functors</tt> behind the scenes as a side-effect. Also, although inheritance works within a functor method, super does not. To call the parent method, you need to call it explicitly using the <tt>#functors</tt> class method, like this:
17
21
 
18
22
  A.functors[ :foo ].apply( self, 'bar' )
19
23
 
24
+ = Stand-Alone Functors
25
+
20
26
  You can also define Functor objects directly:
21
27
 
22
28
  fib = Functor.new do
23
29
  given( 0 ) { 0 }
24
30
  given( 1 ) { 1 }
25
- given( 2..10000 ) { |n| self.call( n - 1 ) + self.call( n - 2 ) }
31
+ given( Integer ) { |n| self.call( n - 1 ) + self.call( n - 2 ) }
26
32
  end
27
33
 
28
34
  You can use functors directly with functions taking a block like this:
29
35
 
30
36
  [ *0..10 ].map( &fib ) # => [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
31
37
 
32
- You can explicitly bind self using #bind:
38
+ You can call a functor as a method using #apply:
33
39
 
34
- fun.bind( obj )
40
+ fun.apply( obj, 7 )
35
41
 
36
- which is actually how the method dispatch is implemented.
42
+ which is actually how the method functors are implemented.
43
+
44
+ = Pattern Matching
37
45
 
38
46
  Arguments are matched first using === and then ==, so anything that supports these methods can be matched against. In addition, you may pass "guards," any object that responds to #call and which take and object (the argument) and return true or false. This allows you to do things like this:
39
47
 
@@ -42,4 +50,22 @@ Arguments are matched first using === and then ==, so anything that supports the
42
50
  given( lambda { |x| x % 2 == 1 } ) { 'silver' }
43
51
  end
44
52
 
45
- which will return "white" and "silver" alternately for a sequence of numbers.
53
+ which will return "white" and "silver" alternately for a sequence of numbers.
54
+
55
+ = Precedence
56
+
57
+ Precedence is defined in order of declaration: first-come, first-serve, aka FIFO. Thus, you need to be careful in how you define your functor. The Fibonacci example above would not work properly if the Integer pattern was given first. That said, it is possible to redefine earlier cases, which, in effect, "demotes" it, as if it had not been declared before. So the following will work properly:
58
+
59
+ fib = Functor.new do
60
+ given( Integer ) { |n| raise "this would start an infinite loop ..." }
61
+ given( 0 ) { 0 }
62
+ given( 1 ) { 1 }
63
+ # but this will "demote" the Integer pattern and now it will work ...
64
+ given( Integer ) { |n| self.call( n - 1 ) + self.call( n - 2 ) }
65
+ end
66
+
67
+ This isn't perfect, but it is very easy to predict, simple to implement, and reasonably fast, which other approaches (such as implementing a precedence scheme) are not.
68
+
69
+ = Credits And Support
70
+
71
+ Functor was written by Dan Yoder, Matthew King, and Lawrence Pit. Send email to dan at zeraweb.com for support or questions.
@@ -0,0 +1,207 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>Class: Functor</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
+ <link rel="stylesheet" href=".././rdoc-style.css" type="text/css" media="screen" />
12
+ <script type="text/javascript">
13
+ // <![CDATA[
14
+
15
+ function popupCode( url ) {
16
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
+ }
18
+
19
+ function toggleCode( id ) {
20
+ if ( document.getElementById )
21
+ elem = document.getElementById( id );
22
+ else if ( document.all )
23
+ elem = eval( "document.all." + id );
24
+ else
25
+ return false;
26
+
27
+ elemStyle = elem.style;
28
+
29
+ if ( elemStyle.display != "block" ) {
30
+ elemStyle.display = "block"
31
+ } else {
32
+ elemStyle.display = "none"
33
+ }
34
+
35
+ return true;
36
+ }
37
+
38
+ // Make codeblocks hidden by default
39
+ document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
+
41
+ // ]]>
42
+ </script>
43
+
44
+ </head>
45
+ <body>
46
+
47
+
48
+
49
+ <div id="classHeader">
50
+ <table class="header-table">
51
+ <tr class="top-aligned-row">
52
+ <td><strong>Class</strong></td>
53
+ <td class="class-name-in-header">Functor</td>
54
+ </tr>
55
+ <tr class="top-aligned-row">
56
+ <td><strong>In:</strong></td>
57
+ <td>
58
+ <a href="../files/lib/functor_rb.html">
59
+ lib/functor.rb
60
+ </a>
61
+ <br />
62
+ </td>
63
+ </tr>
64
+
65
+ <tr class="top-aligned-row">
66
+ <td><strong>Parent:</strong></td>
67
+ <td>
68
+ <a href="Object.html">
69
+ Object
70
+ </a>
71
+ </td>
72
+ </tr>
73
+ </table>
74
+ </div>
75
+ <!-- banner header -->
76
+
77
+ <div id="bodyContent">
78
+
79
+
80
+
81
+ <div id="contextContent">
82
+
83
+
84
+
85
+ </div>
86
+
87
+ <div id="method-list">
88
+ <h3 class="section-bar">Methods</h3>
89
+
90
+ <div class="name-list">
91
+ <a href="#M000003">apply</a>&nbsp;&nbsp;
92
+ <a href="#M000004">call</a>&nbsp;&nbsp;
93
+ <a href="#M000002">given</a>&nbsp;&nbsp;
94
+ <a href="#M000001">new</a>&nbsp;&nbsp;
95
+ <a href="#M000005">to_proc</a>&nbsp;&nbsp;
96
+ </div>
97
+ </div>
98
+
99
+ </div>
100
+
101
+
102
+ <!-- if includes -->
103
+
104
+ <div id="section">
105
+
106
+ <div id="class-list">
107
+ <h3 class="section-bar">Classes and Modules</h3>
108
+
109
+ Module <a href="Functor/Method.html" class="link">Functor::Method</a><br />
110
+
111
+ </div>
112
+
113
+
114
+
115
+
116
+
117
+
118
+
119
+ <!-- if method_list -->
120
+ <div id="methods">
121
+ <h3 class="section-bar">Public Class methods</h3>
122
+
123
+ <div id="method-M000001" class="method-detail">
124
+ <a name="M000001"></a>
125
+
126
+ <div class="method-heading">
127
+ <a href="Functor.src/M000001.html" target="Code" class="method-signature"
128
+ onclick="popupCode('Functor.src/M000001.html');return false;">
129
+ <span class="method-name">new</span><span class="method-args">( &amp;block )</span>
130
+ </a>
131
+ </div>
132
+
133
+ <div class="method-description">
134
+ </div>
135
+ </div>
136
+
137
+ <h3 class="section-bar">Public Instance methods</h3>
138
+
139
+ <div id="method-M000003" class="method-detail">
140
+ <a name="M000003"></a>
141
+
142
+ <div class="method-heading">
143
+ <a href="Functor.src/M000003.html" target="Code" class="method-signature"
144
+ onclick="popupCode('Functor.src/M000003.html');return false;">
145
+ <span class="method-name">apply</span><span class="method-args">( object, *args, &amp;block )</span>
146
+ </a>
147
+ </div>
148
+
149
+ <div class="method-description">
150
+ </div>
151
+ </div>
152
+
153
+ <div id="method-M000004" class="method-detail">
154
+ <a name="M000004"></a>
155
+
156
+ <div class="method-heading">
157
+ <a href="Functor.src/M000004.html" target="Code" class="method-signature"
158
+ onclick="popupCode('Functor.src/M000004.html');return false;">
159
+ <span class="method-name">call</span><span class="method-args">( *args, &amp;block )</span>
160
+ </a>
161
+ </div>
162
+
163
+ <div class="method-description">
164
+ </div>
165
+ </div>
166
+
167
+ <div id="method-M000002" class="method-detail">
168
+ <a name="M000002"></a>
169
+
170
+ <div class="method-heading">
171
+ <a href="Functor.src/M000002.html" target="Code" class="method-signature"
172
+ onclick="popupCode('Functor.src/M000002.html');return false;">
173
+ <span class="method-name">given</span><span class="method-args">( *pattern, &amp;action )</span>
174
+ </a>
175
+ </div>
176
+
177
+ <div class="method-description">
178
+ </div>
179
+ </div>
180
+
181
+ <div id="method-M000005" class="method-detail">
182
+ <a name="M000005"></a>
183
+
184
+ <div class="method-heading">
185
+ <a href="Functor.src/M000005.html" target="Code" class="method-signature"
186
+ onclick="popupCode('Functor.src/M000005.html');return false;">
187
+ <span class="method-name">to_proc</span><span class="method-args">()</span>
188
+ </a>
189
+ </div>
190
+
191
+ <div class="method-description">
192
+ </div>
193
+ </div>
194
+
195
+
196
+ </div>
197
+
198
+
199
+ </div>
200
+
201
+
202
+ <div id="validator-badges">
203
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
204
+ </div>
205
+
206
+ </body>
207
+ </html>
@@ -0,0 +1,18 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html>
7
+ <head>
8
+ <title>new (Functor)</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
11
+ </head>
12
+ <body class="standalone-code">
13
+ <pre> <span class="ruby-comment cmt"># File lib/functor.rb, line 31</span>
14
+ 31: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">initialize</span><span class="ruby-identifier">initialize</span><span class="ruby-identifier">initialize</span>( <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span> )
15
+ 32: <span class="ruby-ivar">@rules</span> = [] ; <span class="ruby-identifier">instance_eval</span>( <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span> ) <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">block_given?</span>
16
+ 33: <span class="ruby-keyword kw">end</span></pre>
17
+ </body>
18
+ </html>
@@ -0,0 +1,19 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html>
7
+ <head>
8
+ <title>given (Functor)</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
11
+ </head>
12
+ <body class="standalone-code">
13
+ <pre> <span class="ruby-comment cmt"># File lib/functor.rb, line 35</span>
14
+ 35: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">given</span>( <span class="ruby-operator">*</span><span class="ruby-identifier">pattern</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">action</span> )
15
+ 36: <span class="ruby-ivar">@rules</span>.<span class="ruby-identifier">delete_if</span> { <span class="ruby-operator">|</span><span class="ruby-identifier">p</span>,<span class="ruby-identifier">a</span><span class="ruby-operator">|</span> <span class="ruby-identifier">p</span> <span class="ruby-operator">==</span> <span class="ruby-identifier">pattern</span> }
16
+ 37: <span class="ruby-ivar">@rules</span> <span class="ruby-operator">&lt;&lt;</span> [ <span class="ruby-identifier">pattern</span>, <span class="ruby-identifier">action</span> ]
17
+ 38: <span class="ruby-keyword kw">end</span></pre>
18
+ </body>
19
+ </html>
@@ -0,0 +1,18 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html>
7
+ <head>
8
+ <title>apply (Functor)</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
11
+ </head>
12
+ <body class="standalone-code">
13
+ <pre> <span class="ruby-comment cmt"># File lib/functor.rb, line 40</span>
14
+ 40: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">apply</span>( <span class="ruby-identifier">object</span>, <span class="ruby-operator">*</span><span class="ruby-identifier">args</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span> )
15
+ 41: <span class="ruby-identifier">object</span>.<span class="ruby-identifier">instance_exec</span>( <span class="ruby-operator">*</span><span class="ruby-identifier">args</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">match</span>( <span class="ruby-operator">*</span><span class="ruby-identifier">args</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span> ) )
16
+ 42: <span class="ruby-keyword kw">end</span></pre>
17
+ </body>
18
+ </html>
@@ -0,0 +1,19 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html>
7
+ <head>
8
+ <title>call (Functor)</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
11
+ </head>
12
+ <body class="standalone-code">
13
+ <pre> <span class="ruby-comment cmt"># File lib/functor.rb, line 44</span>
14
+ 44: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">call</span>( <span class="ruby-operator">*</span><span class="ruby-identifier">args</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span> )
15
+ 45: <span class="ruby-identifier">args</span>.<span class="ruby-identifier">push</span>( <span class="ruby-identifier">block</span> ) <span class="ruby-keyword kw">if</span> <span class="ruby-identifier">block_given?</span>
16
+ 46: <span class="ruby-identifier">match</span>( <span class="ruby-operator">*</span><span class="ruby-identifier">args</span>, <span class="ruby-operator">&amp;</span><span class="ruby-identifier">block</span> ).<span class="ruby-identifier">call</span>( <span class="ruby-operator">*</span><span class="ruby-identifier">args</span> )
17
+ 47: <span class="ruby-keyword kw">end</span></pre>
18
+ </body>
19
+ </html>
@@ -0,0 +1,16 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html>
7
+ <head>
8
+ <title>to_proc (Functor)</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
11
+ </head>
12
+ <body class="standalone-code">
13
+ <pre> <span class="ruby-comment cmt"># File lib/functor.rb, line 49</span>
14
+ 49: <span class="ruby-keyword kw">def</span> <span class="ruby-identifier">to_proc</span> ; <span class="ruby-identifier">lambda</span> { <span class="ruby-operator">|</span><span class="ruby-operator">*</span><span class="ruby-identifier">args</span><span class="ruby-operator">|</span> <span class="ruby-keyword kw">self</span>.<span class="ruby-identifier">call</span>( <span class="ruby-operator">*</span><span class="ruby-identifier">args</span> ) } ; <span class="ruby-keyword kw">end</span></pre>
15
+ </body>
16
+ </html>
@@ -0,0 +1,131 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
5
+
6
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
7
+ <head>
8
+ <title>Module: Functor::Method</title>
9
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
10
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
11
+ <link rel="stylesheet" href="../.././rdoc-style.css" type="text/css" media="screen" />
12
+ <script type="text/javascript">
13
+ // <![CDATA[
14
+
15
+ function popupCode( url ) {
16
+ window.open(url, "Code", "resizable=yes,scrollbars=yes,toolbar=no,status=no,height=150,width=400")
17
+ }
18
+
19
+ function toggleCode( id ) {
20
+ if ( document.getElementById )
21
+ elem = document.getElementById( id );
22
+ else if ( document.all )
23
+ elem = eval( "document.all." + id );
24
+ else
25
+ return false;
26
+
27
+ elemStyle = elem.style;
28
+
29
+ if ( elemStyle.display != "block" ) {
30
+ elemStyle.display = "block"
31
+ } else {
32
+ elemStyle.display = "none"
33
+ }
34
+
35
+ return true;
36
+ }
37
+
38
+ // Make codeblocks hidden by default
39
+ document.writeln( "<style type=\"text/css\">div.method-source-code { display: none }</style>" )
40
+
41
+ // ]]>
42
+ </script>
43
+
44
+ </head>
45
+ <body>
46
+
47
+
48
+
49
+ <div id="classHeader">
50
+ <table class="header-table">
51
+ <tr class="top-aligned-row">
52
+ <td><strong>Module</strong></td>
53
+ <td class="class-name-in-header">Functor::Method</td>
54
+ </tr>
55
+ <tr class="top-aligned-row">
56
+ <td><strong>In:</strong></td>
57
+ <td>
58
+ <a href="../../files/lib/functor_rb.html">
59
+ lib/functor.rb
60
+ </a>
61
+ <br />
62
+ </td>
63
+ </tr>
64
+
65
+ </table>
66
+ </div>
67
+ <!-- banner header -->
68
+
69
+ <div id="bodyContent">
70
+
71
+
72
+
73
+ <div id="contextContent">
74
+
75
+
76
+
77
+ </div>
78
+
79
+ <div id="method-list">
80
+ <h3 class="section-bar">Methods</h3>
81
+
82
+ <div class="name-list">
83
+ <a href="#M000006">included</a>&nbsp;&nbsp;
84
+ </div>
85
+ </div>
86
+
87
+ </div>
88
+
89
+
90
+ <!-- if includes -->
91
+
92
+ <div id="section">
93
+
94
+
95
+
96
+
97
+
98
+
99
+
100
+
101
+ <!-- if method_list -->
102
+ <div id="methods">
103
+ <h3 class="section-bar">Public Class methods</h3>
104
+
105
+ <div id="method-M000006" class="method-detail">
106
+ <a name="M000006"></a>
107
+
108
+ <div class="method-heading">
109
+ <a href="Method.src/M000006.html" target="Code" class="method-signature"
110
+ onclick="popupCode('Method.src/M000006.html');return false;">
111
+ <span class="method-name">included</span><span class="method-args">( k )</span>
112
+ </a>
113
+ </div>
114
+
115
+ <div class="method-description">
116
+ </div>
117
+ </div>
118
+
119
+
120
+ </div>
121
+
122
+
123
+ </div>
124
+
125
+
126
+ <div id="validator-badges">
127
+ <p><small><a href="http://validator.w3.org/check/referer">[Validate]</a></small></p>
128
+ </div>
129
+
130
+ </body>
131
+ </html>