andand 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,3 +8,5 @@
8
8
  * tap is now a synonym for me
9
9
  * 4 minor enhancement
10
10
  * Object#dont
11
+ * 5 bug fix
12
+ * Plays well with other patch-artists
@@ -57,8 +57,11 @@ end
57
57
  module AndAnd
58
58
 
59
59
  class BlankSlate
60
- instance_methods.reject { |m| m =~ /^__/ }.each { |m| undef_method m }
60
+ def self.wipe
61
+ instance_methods.reject { |m| m =~ /^__/ }.each { |m| undef_method m }
62
+ end
61
63
  def initialize(me)
64
+ BlankSlate.wipe
62
65
  @me = me
63
66
  end
64
67
  end
@@ -2,7 +2,7 @@ module Andand #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 1
4
4
  MINOR = 2
5
- TINY = 0
5
+ TINY = 1
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
File without changes
File without changes
File without changes
@@ -33,7 +33,7 @@
33
33
  <h1>Object#andand</h1>
34
34
  <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/andand"; return false'>
35
35
  <p>Get Version</p>
36
- <a href="http://rubyforge.org/projects/andand" class="numbers">1.2.0</a>
36
+ <a href="http://rubyforge.org/projects/andand" class="numbers">1.2.1</a>
37
37
  </div>
38
38
  <h1>&#x2192; &#8216;andand&#8217;</h1>
39
39
 
@@ -44,11 +44,25 @@
44
44
  <p><em>Object#andand</em> lets us write:</p>
45
45
 
46
46
 
47
- <pre>
48
- @phone = Location.find(:first, ...elided... ).andand.phone
49
- </pre>And get a <em>guarded method invocation</em> or <em>safe navigation method</em>. This snippet performs a <code>.find</code> on the Location class, then sends <code>.phone</code> to the result <em>if the result is not nil</em>. If the result is nil, then the expression returns nil without throwing a NoMethodError.
47
+ <p><pre class='syntax'>
48
+ <span class="attribute">@phone</span> <span class="punct">=</span> <span class="constant">Location</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="symbol">:first</span><span class="punct">,</span> <span class="punct">...</span><span class="ident">elided</span><span class="punct">...</span> <span class="punct">).</span><span class="ident">andand</span><span class="punct">.</span><span class="ident">phone</span>
49
+ </pre>And get a <em>guarded method invocation</em> or <em>safe navigation method</em>. This snippet performs a <code>.find</code> on the Location class, then sends <code>.phone</code> to the result <em>if the result is not nil</em>. If the result is nil, then the expression returns nil without throwing a NoMethodError.</p>
50
50
 
51
- <p>We also get an enhanced Object#tap method.</p>
51
+
52
+ <p>As Dejan Simic <a href="http://rors.org/2008/3/18/andand">put it</a>:</p>
53
+
54
+
55
+ <p>Why would you want to write this:</p>
56
+
57
+
58
+ <p><pre class='syntax'>
59
+ <span class="ident">entry</span><span class="punct">.</span><span class="ident">at</span><span class="punct">('</span><span class="string">description</span><span class="punct">')</span> <span class="punct">&amp;&amp;</span> <span class="ident">entry</span><span class="punct">.</span><span class="ident">at</span><span class="punct">('</span><span class="string">description</span><span class="punct">').</span><span class="ident">inner_text</span>
60
+ </pre>when you can write this:</p>
61
+
62
+
63
+ <p><pre class='syntax'>
64
+ <span class="ident">entry</span><span class="punct">.</span><span class="ident">at</span><span class="punct">('</span><span class="string">description</span><span class="punct">').</span><span class="ident">andand</span><span class="punct">.</span><span class="ident">inner_text</span>
65
+ </pre>Why indeed! As a bonus, install andand and you will also receive an enhanced Object#tap method, <em>at no extra charge</em>!</p>
52
66
 
53
67
 
54
68
  <h2>Installing</h2>
@@ -66,29 +80,52 @@
66
80
  <p>Ruby programmers are familiar with the two <em>guarded assignment</em> operators <code>&#38;&#38;=</code> and <code>||=</code>. The typical use for them is when you have a variable that might be nil. For example:</p>
67
81
 
68
82
 
69
- <pre>
70
- first_name &#38;&#38;= @first_name.trim
71
- @phone ||= '612-777-9311'
72
- </pre>You are trimming the first name provided it isn’t nil, and you are assigning ‘612-777-9311’ to the phone if it <em>is</em> nil (or false, but that isn’t important right now). The other day we were discussing the guards and we agreed that we wished there was a <em>guarded method invocation</em> operator. Here’s an example of when you would use it:
83
+ <p><pre class='syntax'>
84
+ <span class="ident">first_name</span> <span class="punct">&amp;&amp;=</span> <span class="attribute">@first_name</span><span class="punct">.</span><span class="ident">trim</span>
85
+ <span class="attribute">@phone</span> <span class="punct">||=</span> <span class="punct">'</span><span class="string">612-777-9311</span><span class="punct">'</span>
86
+ </pre>You are trimming the first name provided it isn’t nil, and you are assigning ‘612-777-9311’ to the phone if it <em>is</em> nil (or false, but that isn’t important right now). The other day we were discussing the guards and we agreed that we wished there was a <em>guarded method invocation</em> operator. Here’s an example of when you would use it:</p>
87
+
88
+
89
+ <p><pre class='syntax'>
90
+ <span class="attribute">@phone</span> <span class="punct">=</span> <span class="constant">Location</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="symbol">:first</span><span class="punct">,</span> <span class="punct">...</span><span class="ident">elided</span><span class="punct">...</span> <span class="punct">)&amp;&amp;.</span><span class="ident">phone</span>
91
+ </pre>Meaning, search the location table for the first record matching some criteria, and if you find a location, get its phone. If you don’t, get nil. (Groovy provides this exact functionality, although Groovy uses <code>?.</code> instead of <code>&#38;&#38;.</code>) However, <code>&#38;&#38;.</code> won’t work because <code>&#38;&#38;.</code> is not a real Ruby operator.</p>
73
92
 
74
- <pre>
75
- @phone = Location.find(:first, ...elided... )&#38;&#38;.phone
76
- </pre>Meaning, search the location table for the first record matching some criteria, and if you find a location, get its phone. If you don’t, get nil. (Groovy provides this exact functionality, although Groovy uses <code>?.</code> instead of <code>&#38;&#38;.</code>) However, <code>&#38;&#38;.</code> won’t work because <code>&#38;&#38;.</code> is not a real Ruby operator.
77
93
 
78
94
  <p>Object#andand let&rsquo;s us write:</p>
79
95
 
80
96
 
81
- <pre>
82
- @phone = Location.find(:first, ...elided... ).andand.phone
83
- </pre>And get the same effect as:
97
+ <p><pre class='syntax'>
98
+ <span class="attribute">@phone</span> <span class="punct">=</span> <span class="constant">Location</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="symbol">:first</span><span class="punct">,</span> <span class="punct">...</span><span class="ident">elided</span><span class="punct">...</span> <span class="punct">).</span><span class="ident">andand</span><span class="punct">.</span><span class="ident">phone</span>
99
+ </pre>And get the same effect as:</p>
100
+
101
+
102
+ <p><pre class='syntax'>
103
+ <span class="attribute">@phone</span> <span class="punct">=</span> <span class="punct">-&gt;(</span><span class="ident">loc</span><span class="punct">){</span> <span class="ident">loc</span> <span class="punct">&amp;&amp;</span> <span class="ident">loc</span><span class="punct">.</span><span class="ident">phone</span> <span class="punct">}.</span><span class="ident">call</span><span class="punct">(</span><span class="constant">Location</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="symbol">:first</span><span class="punct">,</span> <span class="punct">...</span><span class="ident">elided</span><span class="punct">...</span> <span class="punct">))</span>
104
+ </pre>Note that because you accept any method using Ruby’s method invocation syntax, you can accept methods with parameters and/or blocks:</p>
105
+
106
+
107
+ <p><pre class='syntax'>
108
+ <span class="ident">list_of_lists</span><span class="punct">.</span><span class="ident">detect</span> <span class="punct">{</span> <span class="punct">...</span><span class="ident">elided</span><span class="punct">...</span> <span class="punct">}.</span><span class="ident">andand</span><span class="punct">.</span><span class="ident">inject</span><span class="punct">(</span><span class="number">42</span><span class="punct">)</span> <span class="punct">{</span> <span class="punct">...</span><span class="ident">elided</span> <span class="punct">...</span> <span class="punct">}</span>
109
+ </pre>Object#andand emphasizes syntactic regularity: the goal was to make an <code>&#38;&#38;.</code> operation that worked like <code>&#38;&#38;=</code>. <code>&#38;&#38;=</code> looks just like normal assignment, you can use any expression on the <span class="caps">RHS</span>, only the semantics are different. The andand method also works just like a normal method invocation, only the semantics are modified.</p>
110
+
111
+
112
+ <h3>Use andand to simplify your regular expression matching and extraction</h3>
113
+
114
+
115
+ <p>Do you ever find yourself wanting to extract a single value from a string using a regular expression? For example, Ruby&#8217;s Tempfile class creates paths to files that end in .pid.n (where pid is your process id and n is some number). Do you have a path that might be a tempfile and you want to obtain the base name?</p>
84
116
 
85
- <pre>
86
- @phone = -&gt;(loc){ loc &#38;&#38; loc.phone }.call(Location.find(:first, ...elided... ))
87
- </pre>Note that because you accept any method using Ruby’s method invocation syntax, you can accept methods with parameters and/or blocks:
88
117
 
89
- <pre>
90
- list_of_lists.detect { ...elided... }.andand.inject(42) { ...elided ... }
91
- </pre>Object#andand emphasizes syntactic regularity: the goal was to make an <code>&#38;&#38;.</code> operation that worked like <code>&#38;&#38;=</code>. <code>&#38;&#38;=</code> looks just like normal assignment, you can use any expression on the <span class="caps">RHS</span>, only the semantics are different. The andand method also works just like a normal method invocation, only the semantics are modified.
118
+ <p>Do you currently retrieve the MatchData object, check if it is nil, and get the first matching group if it isn&#8217;t? How about:</p>
119
+
120
+
121
+ <p><pre class='syntax'>
122
+ <span class="ident">require</span> <span class="punct">'</span><span class="string">tempfile</span><span class="punct">'</span>
123
+ <span class="ident">path</span> <span class="punct">=</span> <span class="constant">Tempfile</span><span class="punct">.</span><span class="ident">new</span><span class="punct">('</span><span class="string">foo.bar</span><span class="punct">').</span><span class="ident">path</span>
124
+ <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">/var/folders/UZ/UZyZsbVPEWqC7tTXrQBYGU+++TI/-Tmp-/foo.bar.1280.0</span><span class="punct">&quot;</span>
125
+ <span class="ident">path</span><span class="punct">.</span><span class="ident">match</span><span class="punct">('</span><span class="string">/([^/]+)\.[0-9]+\.[0-9]+$</span><span class="punct">').</span><span class="ident">andand</span><span class="punct">[</span><span class="number">1</span><span class="punct">]</span>
126
+ <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">foo.bar</span><span class="punct">&quot;</span>
127
+ </pre>With <code>.andand[1]</code>, you extract the group in the regular expression safely: if the expression matches, you get the group. If the expression fails to match, you get nil. Which is what you want, isn&#8217;t it? The contents of the group if the expression matches? Why should you need more than one line for something so simple?</p>
128
+
92
129
 
93
130
  <h3>Enhanced Object#tap</h3>
94
131
 
@@ -96,47 +133,62 @@ list_of_lists.detect { ...elided... }.andand.inject(42) { ...elided ... }
96
133
  <p>Ruby 1.9 introduces <a href="http://moonbase.rydia.net/mental/blog/programming/eavesdropping-on-expressions">Object#tap</a>. This library implements Object#tap for Ruby 1.8 <strong>and</strong> enhances it. As in Ruby 1.9, you can call <code>.tap</code> with a block:</p>
97
134
 
98
135
 
99
- <pre>
100
- blah.sort.grep( /foo/ ).tap { |xs| p xs }.map { |x| x.blah }
101
- </pre> But like its sibling <code>.andand</code>, you can now call <code>.tap</code> with a method as well:
136
+ <p><pre class='syntax'>
137
+ <span class="ident">blah</span><span class="punct">.</span><span class="ident">sort</span><span class="punct">.</span><span class="ident">grep</span><span class="punct">(</span> <span class="punct">/</span><span class="regex">foo</span><span class="punct">/</span> <span class="punct">).</span><span class="ident">tap</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">xs</span><span class="punct">|</span> <span class="ident">p</span> <span class="ident">xs</span> <span class="punct">}.</span><span class="ident">map</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">x</span><span class="punct">|</span> <span class="ident">x</span><span class="punct">.</span><span class="ident">blah</span> <span class="punct">}</span>
138
+ </pre> But like its sibling <code>.andand</code>, you can now call <code>.tap</code> with a method as well:</p>
139
+
140
+
141
+ <p><pre class='syntax'>
142
+ <span class="punct">[</span><span class="number">1</span><span class="punct">,</span> <span class="number">2</span><span class="punct">,</span> <span class="number">3</span><span class="punct">,</span> <span class="number">4</span><span class="punct">,</span> <span class="number">5</span><span class="punct">].</span><span class="ident">tap</span><span class="punct">.</span><span class="ident">pop</span><span class="punct">.</span><span class="ident">map</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">n</span><span class="punct">|</span> <span class="ident">n</span> <span class="punct">*</span> <span class="number">2</span> <span class="punct">}</span>
143
+ <span class="punct">=&gt;</span> <span class="punct">[</span><span class="number">2</span><span class="punct">,</span> <span class="number">4</span><span class="punct">,</span> <span class="number">6</span><span class="punct">,</span> <span class="number">8</span><span class="punct">]</span>
144
+ </pre></p>
102
145
 
103
- <pre>
104
- [1, 2, 3, 4, 5].tap.pop.map { |n| n * 2 }
105
- =&gt; [2, 4, 6, 8]
106
- </pre>
107
146
 
108
147
  <h3>Doctor, it hurts when I do that</h3>
109
148
 
110
149
 
111
- <p><strong>Don&#8217;t do that!</strong></p>
150
+ <p><em>So don&#8217;t do that!</em></p>
112
151
 
113
152
 
114
153
  <p>The popular use case for Object#tap is poor man&#8217;s debugging:</p>
115
154
 
116
155
 
117
- <pre>
118
- blah.sort.grep( /foo/ ).tap { |xs| p xs }.map { |x| x.blah }
119
- </pre>Perhaps you want to remove the tap, you can delete it:
156
+ <p><pre class='syntax'>
157
+ <span class="ident">blah</span><span class="punct">.</span><span class="ident">sort</span><span class="punct">.</span><span class="ident">grep</span><span class="punct">(</span> <span class="punct">/</span><span class="regex">foo</span><span class="punct">/</span> <span class="punct">).</span><span class="ident">tap</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">xs</span><span class="punct">|</span> <span class="ident">p</span> <span class="ident">xs</span> <span class="punct">}.</span><span class="ident">map</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">x</span><span class="punct">|</span> <span class="ident">x</span><span class="punct">.</span><span class="ident">blah</span> <span class="punct">}</span>
158
+ </pre>Perhaps you want to remove the tap, you can delete it:</p>
159
+
160
+
161
+ <p><pre class='syntax'>
162
+ <span class="ident">blah</span><span class="punct">.</span><span class="ident">sort</span><span class="punct">.</span><span class="ident">grep</span><span class="punct">(</span> <span class="punct">/</span><span class="regex">foo</span><span class="punct">/</span> <span class="punct">).</span><span class="ident">map</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">x</span><span class="punct">|</span> <span class="ident">x</span><span class="punct">.</span><span class="ident">blah</span> <span class="punct">}</span>
163
+ </pre>Or, you can change it to <code>.dont</code>:</p>
164
+
120
165
 
121
- <pre>
122
- blah.sort.grep( /foo/ ).tap { |xs| p xs }.map { |x| x.blah }
123
- </pre>Or, you can change it to <code>.dont</code>:
166
+ <p><pre class='syntax'>
167
+ <span class="ident">blah</span><span class="punct">.</span><span class="ident">sort</span><span class="punct">.</span><span class="ident">grep</span><span class="punct">(</span> <span class="punct">/</span><span class="regex">foo</span><span class="punct">/</span> <span class="punct">).</span><span class="ident">dont</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">xs</span><span class="punct">|</span> <span class="ident">p</span> <span class="ident">xs</span> <span class="punct">}.</span><span class="ident">map</span> <span class="punct">{</span> <span class="punct">|</span><span class="ident">x</span><span class="punct">|</span> <span class="ident">x</span><span class="punct">.</span><span class="ident">blah</span> <span class="punct">}</span>
168
+ </pre>Like <code>.andand</code> and <code>.tap</code>, <code>.dont</code> works with arbitrary methods, not just blocks:</p>
124
169
 
125
- <pre>
126
- blah.sort.grep( /foo/ ).dont { |xs| p xs }.map { |x| x.blah }
127
- </pre>Like <code>.andand</code> and <code>.tap</code>, <code>.dont</code> works with arbitrary methods, not just blocks:
128
170
 
129
- <pre>
130
- (1..10).to_a.reverse!
131
- =&gt; [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
132
- (1..10).dont.to_a.reverse!
133
- =&gt; [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
134
- </pre>
171
+ <p><pre class='syntax'>
172
+ <span class="punct">(</span><span class="number">1</span><span class="punct">..</span><span class="number">10</span><span class="punct">).</span><span class="ident">to_a</span><span class="punct">.</span><span class="ident">reverse!</span>
173
+ <span class="punct">=&gt;</span> <span class="punct">[</span><span class="number">10</span><span class="punct">,</span> <span class="number">9</span><span class="punct">,</span> <span class="number">8</span><span class="punct">,</span> <span class="number">7</span><span class="punct">,</span> <span class="number">6</span><span class="punct">,</span> <span class="number">5</span><span class="punct">,</span> <span class="number">4</span><span class="punct">,</span> <span class="number">3</span><span class="punct">,</span> <span class="number">2</span><span class="punct">,</span> <span class="number">1</span><span class="punct">]</span>
174
+ <span class="punct">(</span><span class="number">1</span><span class="punct">..</span><span class="number">10</span><span class="punct">).</span><span class="ident">to_a</span><span class="punct">.</span><span class="ident">dont</span><span class="punct">.</span><span class="ident">reverse!</span>
175
+ <span class="punct">=&gt;</span> <span class="punct">[</span><span class="number">1</span><span class="punct">,</span> <span class="number">2</span><span class="punct">,</span> <span class="number">3</span><span class="punct">,</span> <span class="number">4</span><span class="punct">,</span> <span class="number">5</span><span class="punct">,</span> <span class="number">6</span><span class="punct">,</span> <span class="number">7</span><span class="punct">,</span> <span class="number">8</span><span class="punct">,</span> <span class="number">9</span><span class="punct">,</span> <span class="number">10</span><span class="punct">]</span>
176
+ </pre></p>
177
+
135
178
 
136
179
  <h2>A little more background</h2>
137
180
 
138
181
 
139
- <p><a href="http://weblog.raganwald.com/2008/01/objectandand-objectme-in-ruby.html">Object#andand &#38; Object#me in Ruby</a> explains the original motivations, as well as providing links to similar implementations you may want to consider. A few people have pointed out that Object#andand is similar to Haskell&#8217;s <code>Maybe</code> monad. <a href="http://blog.pretheory.com/arch/2008/02/the_maybe_monad_in_ruby.php">The Maybe Monad in Ruby</a> is a good introduction for Ruby programmers.</p>
182
+ <p><a href="http://weblog.raganwald.com/2008/01/objectandand-objectme-in-ruby.html">Object#andand &#38; Object#me in Ruby</a> explains the original motivations, as well as providing links to similar implementations you may want to consider. A few people have pointed out that Object#andand is similar to Haskell&#8217;s Maybe monad. <a href="http://blog.pretheory.com/arch/2008/02/the_maybe_monad_in_ruby.php">The Maybe Monad in Ruby</a> is a good introduction for Ruby programmers.</p>
183
+
184
+
185
+ <h2>That&#8217;s cool, but&hellip;</h2>
186
+
187
+
188
+ <p>No problem, I get that andand isn&#8217;t exactly what you need. Have a look at the <a href="http://ick.rubyforge.org">Invocation Construction Kit</a> or &#8220;Ick.&#8221; The Ick gem <em>generalizes</em> #andand and #tap: Ick provides four useful ways to block-structure your code, the methods #let, #returning, #inside, and #my. Ick also includes four quasi-monadic invocations, #maybe, #please, #tee, and #fork.</p>
189
+
190
+
191
+ <p><a href="http://ick.rubyforge.org">Ick</a> provides abstractions for building your own invocations, so you can branch out and build some of your own abstractions with Ick&#8217;s building blocks.</p>
140
192
 
141
193
 
142
194
  <h2>How to submit patches</h2>
@@ -165,12 +217,14 @@ list_of_lists.detect { ...elided... }.andand.inject(42) { ...elided ... }
165
217
 
166
218
  <p>Comments are welcome. Send an email to <a href="mailto:raganwald+rubyforge@gmail.com">Reginald Braithwaite</a>.</p>
167
219
  <p class="coda">
168
- <a href="http://weblog.raganwald.com">Reginald Braithwaite</a>, 15th February 2008<br>
220
+ <a href="http://weblog.raganwald.com">Reginald Braithwaite</a>, 6th April 2008<br>
169
221
  Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
170
222
  </p>
171
223
  </div>
172
224
 
173
225
  <!-- insert site tracking codes here, like Google Urchin -->
174
226
 
227
+ <div style="visibility: hidden"><script type="text/javascript" src="http://pub44.bravenet.com/counter/code.php?id=404723&usernum=3754613835&cpv=2"></script></div>
228
+
175
229
  </body>
176
230
  </html>
@@ -6,11 +6,21 @@ h2. What
6
6
 
7
7
  _Object#andand_ lets us write:
8
8
 
9
- <pre>
9
+ <pre syntax="ruby">
10
10
  @phone = Location.find(:first, ...elided... ).andand.phone
11
11
  </pre>And get a _guarded method invocation_ or _safe navigation method_. This snippet performs a @.find@ on the Location class, then sends @.phone@ to the result _if the result is not nil_. If the result is nil, then the expression returns nil without throwing a NoMethodError.
12
12
 
13
- We also get an enhanced Object#tap method.
13
+ As Dejan Simic "put it":http://rors.org/2008/3/18/andand:
14
+
15
+ Why would you want to write this:
16
+
17
+ <pre syntax="ruby">
18
+ entry.at('description') && entry.at('description').inner_text
19
+ </pre>when you can write this:
20
+
21
+ <pre syntax="ruby">
22
+ entry.at('description').andand.inner_text
23
+ </pre>Why indeed! As a bonus, install andand and you will also receive an enhanced Object#tap method, _at no extra charge_!
14
24
 
15
25
  h2. Installing
16
26
 
@@ -22,70 +32,90 @@ h3. Object#andand
22
32
 
23
33
  Ruby programmers are familiar with the two _guarded assignment_ operators @&&=@ and @||=@. The typical use for them is when you have a variable that might be nil. For example:
24
34
 
25
- <pre>
35
+ <pre syntax="ruby">
26
36
  first_name &&= @first_name.trim
27
37
  @phone ||= '612-777-9311'
28
38
  </pre>You are trimming the first name provided it isn’t nil, and you are assigning ‘612-777-9311’ to the phone if it _is_ nil (or false, but that isn’t important right now). The other day we were discussing the guards and we agreed that we wished there was a _guarded method invocation_ operator. Here’s an example of when you would use it:
29
39
 
30
- <pre>
40
+ <pre syntax="ruby">
31
41
  @phone = Location.find(:first, ...elided... )&&.phone
32
42
  </pre>Meaning, search the location table for the first record matching some criteria, and if you find a location, get its phone. If you don’t, get nil. (Groovy provides this exact functionality, although Groovy uses @?.@ instead of @&&.@) However, @&&.@ won’t work because @&&.@ is not a real Ruby operator.
33
43
 
34
44
  Object#andand let&rsquo;s us write:
35
45
 
36
- <pre>
46
+ <pre syntax="ruby">
37
47
  @phone = Location.find(:first, ...elided... ).andand.phone
38
48
  </pre>And get the same effect as:
39
49
 
40
- <pre>
50
+ <pre syntax="ruby">
41
51
  @phone = ->(loc){ loc && loc.phone }.call(Location.find(:first, ...elided... ))
42
52
  </pre>Note that because you accept any method using Ruby’s method invocation syntax, you can accept methods with parameters and/or blocks:
43
53
 
44
- <pre>
54
+ <pre syntax="ruby">
45
55
  list_of_lists.detect { ...elided... }.andand.inject(42) { ...elided ... }
46
56
  </pre>Object#andand emphasizes syntactic regularity: the goal was to make an @&&.@ operation that worked like @&&=@. @&&=@ looks just like normal assignment, you can use any expression on the RHS, only the semantics are different. The andand method also works just like a normal method invocation, only the semantics are modified.
47
57
 
58
+ h3. Use andand to simplify your regular expression matching and extraction
59
+
60
+ Do you ever find yourself wanting to extract a single value from a string using a regular expression? For example, Ruby's Tempfile class creates paths to files that end in .pid.n (where pid is your process id and n is some number). Do you have a path that might be a tempfile and you want to obtain the base name?
61
+
62
+ Do you currently retrieve the MatchData object, check if it is nil, and get the first matching group if it isn't? How about:
63
+
64
+ <pre syntax="ruby">
65
+ require 'tempfile'
66
+ path = Tempfile.new('foo.bar').path
67
+ => "/var/folders/UZ/UZyZsbVPEWqC7tTXrQBYGU+++TI/-Tmp-/foo.bar.1280.0"
68
+ path.match('/([^/]+)\.[0-9]+\.[0-9]+$').andand[1]
69
+ => "foo.bar"
70
+ </pre>With @.andand[1]@, you extract the group in the regular expression safely: if the expression matches, you get the group. If the expression fails to match, you get nil. Which is what you want, isn't it? The contents of the group if the expression matches? Why should you need more than one line for something so simple?
71
+
48
72
  h3. Enhanced Object#tap
49
73
 
50
74
  Ruby 1.9 introduces "Object#tap":http://moonbase.rydia.net/mental/blog/programming/eavesdropping-on-expressions. This library implements Object#tap for Ruby 1.8 *and* enhances it. As in Ruby 1.9, you can call @.tap@ with a block:
51
75
 
52
- <pre>
76
+ <pre syntax="ruby">
53
77
  blah.sort.grep( /foo/ ).tap { |xs| p xs }.map { |x| x.blah }
54
78
  </pre> But like its sibling @.andand@, you can now call @.tap@ with a method as well:
55
79
 
56
- <pre>
80
+ <pre syntax="ruby">
57
81
  [1, 2, 3, 4, 5].tap.pop.map { |n| n * 2 }
58
82
  => [2, 4, 6, 8]
59
83
  </pre>
60
84
 
61
85
  h3. Doctor, it hurts when I do that
62
86
 
63
- *Don't do that!*
87
+ _So don't do that!_
64
88
 
65
89
  The popular use case for Object#tap is poor man's debugging:
66
90
 
67
- <pre>
91
+ <pre syntax="ruby">
68
92
  blah.sort.grep( /foo/ ).tap { |xs| p xs }.map { |x| x.blah }
69
93
  </pre>Perhaps you want to remove the tap, you can delete it:
70
94
 
71
- <pre>
72
- blah.sort.grep( /foo/ ).tap { |xs| p xs }.map { |x| x.blah }
95
+ <pre syntax="ruby">
96
+ blah.sort.grep( /foo/ ).map { |x| x.blah }
73
97
  </pre>Or, you can change it to @.dont@:
74
98
 
75
- <pre>
99
+ <pre syntax="ruby">
76
100
  blah.sort.grep( /foo/ ).dont { |xs| p xs }.map { |x| x.blah }
77
101
  </pre>Like @.andand@ and @.tap@, @.dont@ works with arbitrary methods, not just blocks:
78
102
 
79
- <pre>
103
+ <pre syntax="ruby">
80
104
  (1..10).to_a.reverse!
81
105
  => [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
82
- (1..10).dont.to_a.reverse!
106
+ (1..10).to_a.dont.reverse!
83
107
  => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
84
108
  </pre>
85
109
 
86
110
  h2. A little more background
87
111
 
88
- "Object#andand & Object#me in Ruby":http://weblog.raganwald.com/2008/01/objectandand-objectme-in-ruby.html explains the original motivations, as well as providing links to similar implementations you may want to consider. A few people have pointed out that Object#andand is similar to Haskell's @Maybe@ monad. "The Maybe Monad in Ruby":http://blog.pretheory.com/arch/2008/02/the_maybe_monad_in_ruby.php is a good introduction for Ruby programmers.
112
+ "Object#andand & Object#me in Ruby":http://weblog.raganwald.com/2008/01/objectandand-objectme-in-ruby.html explains the original motivations, as well as providing links to similar implementations you may want to consider. A few people have pointed out that Object#andand is similar to Haskell's Maybe monad. "The Maybe Monad in Ruby":http://blog.pretheory.com/arch/2008/02/the_maybe_monad_in_ruby.php is a good introduction for Ruby programmers.
113
+
114
+ h2. That's cool, but&hellip;
115
+
116
+ No problem, I get that andand isn't exactly what you need. Have a look at the "Invocation Construction Kit":http://ick.rubyforge.org or "Ick." The Ick gem _generalizes_ #andand and #tap: Ick provides four useful ways to block-structure your code, the methods #let, #returning, #inside, and #my. Ick also includes four quasi-monadic invocations, #maybe, #please, #tee, and #fork.
117
+
118
+ "Ick":http://ick.rubyforge.org provides abstractions for building your own invocations, so you can branch out and build some of your own abstractions with Ick's building blocks.
89
119
 
90
120
  h2. How to submit patches
91
121
 
@@ -103,5 +133,4 @@ h2. Shout Out
103
133
 
104
134
  h2. Contact
105
135
 
106
- Comments are welcome. Send an email to "Reginald Braithwaite":mailto:raganwald+rubyforge@gmail.com.
107
-
136
+ Comments are welcome. Send an email to "Reginald Braithwaite":mailto:raganwald+rubyforge@gmail.com.
@@ -44,5 +44,7 @@
44
44
 
45
45
  <!-- insert site tracking codes here, like Google Urchin -->
46
46
 
47
+ <div style="visibility: hidden"><script type="text/javascript" src="http://pub44.bravenet.com/counter/code.php?id=404723&usernum=3754613835&cpv=2"></script></div>
48
+
47
49
  </body>
48
50
  </html>
metadata CHANGED
@@ -1,34 +1,31 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.0
3
- specification_version: 1
4
2
  name: andand
5
3
  version: !ruby/object:Gem::Version
6
- version: 1.2.0
7
- date: 2008-02-15 00:00:00 -05:00
8
- summary: adds guarded method invocation to Ruby
9
- require_paths:
10
- - lib
11
- email:
12
- - reg@braythwayt.com
13
- homepage: http://andand.rubyforge.org
14
- rubyforge_project: andand
15
- description: adds guarded method invocation to Ruby
16
- autorequire:
17
- default_executable:
18
- bindir: bin
19
- has_rdoc: true
20
- required_ruby_version: !ruby/object:Gem::Version::Requirement
21
- requirements:
22
- - - ">"
23
- - !ruby/object:Gem::Version
24
- version: 0.0.0
25
- version:
4
+ version: 1.2.1
26
5
  platform: ruby
27
- signing_key:
28
- cert_chain:
29
- post_install_message:
30
6
  authors:
31
7
  - Reginald Braithwaite
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-07-10 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: adds guarded method invocation to Ruby
17
+ email:
18
+ - reg@braythwayt.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files:
24
+ - History.txt
25
+ - License.txt
26
+ - Manifest.txt
27
+ - README.txt
28
+ - website/index.txt
32
29
  files:
33
30
  - History.txt
34
31
  - License.txt
@@ -54,23 +51,33 @@ files:
54
51
  - website/javascripts/rounded_corners_lite.inc.js
55
52
  - website/stylesheets/screen.css
56
53
  - website/template.rhtml
57
- test_files:
58
- - test/test_andand.rb
59
- - test/test_helper.rb
54
+ has_rdoc: true
55
+ homepage: http://andand.rubyforge.org
56
+ post_install_message:
60
57
  rdoc_options:
61
58
  - --main
62
59
  - README.txt
63
- extra_rdoc_files:
64
- - History.txt
65
- - License.txt
66
- - Manifest.txt
67
- - README.txt
68
- - website/index.txt
69
- executables: []
70
-
71
- extensions: []
72
-
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: "0"
67
+ version:
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: "0"
73
+ version:
73
74
  requirements: []
74
75
 
75
- dependencies: []
76
-
76
+ rubyforge_project: andand
77
+ rubygems_version: 1.2.0
78
+ signing_key:
79
+ specification_version: 2
80
+ summary: adds guarded method invocation to Ruby
81
+ test_files:
82
+ - test/test_andand.rb
83
+ - test/test_helper.rb