andand 1.0.1 → 1.1.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.
- data/History.txt +3 -1
- data/lib/andand.rb +2 -0
- data/lib/andand/version.rb +2 -2
- data/website/index.html +65 -10
- data/website/index.txt +53 -10
- data/website/template.rhtml +1 -1
- metadata +2 -2
data/History.txt
CHANGED
data/lib/andand.rb
CHANGED
data/lib/andand/version.rb
CHANGED
data/website/index.html
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
<link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
|
6
6
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
7
7
|
<title>
|
8
|
-
andand
|
8
|
+
Object#andand
|
9
9
|
</title>
|
10
10
|
<script src="javascripts/rounded_corners_lite.inc.js" type="text/javascript"></script>
|
11
11
|
<style>
|
@@ -30,10 +30,10 @@
|
|
30
30
|
<body>
|
31
31
|
<div id="main">
|
32
32
|
|
33
|
-
<h1>andand</h1>
|
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.0
|
36
|
+
<a href="http://rubyforge.org/projects/andand" class="numbers">1.1.0</a>
|
37
37
|
</div>
|
38
38
|
<h1>→ ‘andand’</h1>
|
39
39
|
|
@@ -41,6 +41,16 @@
|
|
41
41
|
<h2>What</h2>
|
42
42
|
|
43
43
|
|
44
|
+
<p><em>Object#andand</em> lets us write:</p>
|
45
|
+
|
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.
|
50
|
+
|
51
|
+
<p>We also get an enhanced Object#tap method.</p>
|
52
|
+
|
53
|
+
|
44
54
|
<h2>Installing</h2>
|
45
55
|
|
46
56
|
|
@@ -50,22 +60,67 @@
|
|
50
60
|
<h2>The basics</h2>
|
51
61
|
|
52
62
|
|
63
|
+
<h3>Object#andand</h3>
|
64
|
+
|
65
|
+
|
66
|
+
<p>Ruby programmers are familiar with the two <em>guarded assignment</em> operators <code>&&=</code> and <code>||=</code>. The typical use for them is when you have a variable that might be nil. For example:</p>
|
67
|
+
|
68
|
+
|
69
|
+
<pre>
|
70
|
+
first_name &&= @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:
|
73
|
+
|
74
|
+
<pre>
|
75
|
+
@phone = Location.find(:first, ...elided... )&&.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>&&.</code>) However, <code>&&.</code> won’t work because <code>&&.</code> is not a real Ruby operator.
|
77
|
+
|
78
|
+
<p>Object#andand let’s us write:</p>
|
79
|
+
|
80
|
+
|
81
|
+
<pre>
|
82
|
+
@phone = Location.find(:first, ...elided... ).andand.phone
|
83
|
+
</pre>And get the same effect as:
|
84
|
+
|
85
|
+
<pre>
|
86
|
+
@phone = ->(loc){ loc && 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
|
+
|
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>&&.</code> operation that worked like <code>&&=</code>. <code>&&=</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.
|
92
|
+
|
93
|
+
<h3>Enhanced Object#tap</h3>
|
94
|
+
|
95
|
+
|
96
|
+
<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
|
+
|
98
|
+
|
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:
|
102
|
+
|
103
|
+
<pre>
|
104
|
+
[1, 2, 3, 4, 5].tap.pop.map { |n| n * 2 }
|
105
|
+
=> [2, 4, 6, 8]
|
106
|
+
</pre>
|
107
|
+
|
53
108
|
<h2>Demonstration of usage</h2>
|
54
109
|
|
55
110
|
|
56
|
-
<
|
111
|
+
<p>See above.</p>
|
57
112
|
|
58
113
|
|
59
|
-
<
|
114
|
+
<h2>A little more background</h2>
|
60
115
|
|
61
116
|
|
62
|
-
<p><
|
117
|
+
<p><a href="http://weblog.raganwald.com/2008/01/objectandand-objectme-in-ruby.html">Object#andand & Object#me in Ruby</a></p>
|
63
118
|
|
64
119
|
|
65
120
|
<h2>How to submit patches</h2>
|
66
121
|
|
67
122
|
|
68
|
-
<p>Read the <a href="http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/">8 steps for fixing other people’s code</a
|
123
|
+
<p>Read the <a href="http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/">8 steps for fixing other people’s code</a>.</p>
|
69
124
|
|
70
125
|
|
71
126
|
<p>The trunk repository is <code>svn://rubyforge.org/var/svn/andand/trunk</code> for anonymous access.</p>
|
@@ -74,15 +129,15 @@
|
|
74
129
|
<h2>License</h2>
|
75
130
|
|
76
131
|
|
77
|
-
<p>This code is free to use under the terms of the <span class="caps">MIT</span> license
|
132
|
+
<p>This code is free to use under the terms of the <a href="http://en.wikipedia.org/wiki/MIT_License"><span class="caps">MIT</span> license</a>.</p>
|
78
133
|
|
79
134
|
|
80
135
|
<h2>Contact</h2>
|
81
136
|
|
82
137
|
|
83
|
-
<p>Comments are welcome. Send an email to <a href="mailto:
|
138
|
+
<p>Comments are welcome. Send an email to <a href="mailto:raganwald+rubyforge@gmail.com">Reginald Braithwaite</a>.</p>
|
84
139
|
<p class="coda">
|
85
|
-
<a href="
|
140
|
+
<a href="http://weblog.raganwald.com">Reginald Braithwaite</a>, 10th February 2008<br>
|
86
141
|
Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
|
87
142
|
</p>
|
88
143
|
</div>
|
data/website/index.txt
CHANGED
@@ -1,10 +1,16 @@
|
|
1
|
-
h1. andand
|
1
|
+
h1. Object#andand
|
2
2
|
|
3
3
|
h1. → 'andand'
|
4
4
|
|
5
|
-
|
6
5
|
h2. What
|
7
6
|
|
7
|
+
_Object#andand_ lets us write:
|
8
|
+
|
9
|
+
<pre>
|
10
|
+
@phone = Location.find(:first, ...elided... ).andand.phone
|
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
|
+
|
13
|
+
We also get an enhanced Object#tap method.
|
8
14
|
|
9
15
|
h2. Installing
|
10
16
|
|
@@ -12,28 +18,65 @@ h2. Installing
|
|
12
18
|
|
13
19
|
h2. The basics
|
14
20
|
|
21
|
+
h3. Object#andand
|
15
22
|
|
16
|
-
|
23
|
+
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
|
+
|
25
|
+
<pre>
|
26
|
+
first_name &&= @first_name.trim
|
27
|
+
@phone ||= '612-777-9311'
|
28
|
+
</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
|
+
|
30
|
+
<pre>
|
31
|
+
@phone = Location.find(:first, ...elided... )&&.phone
|
32
|
+
</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
|
+
|
34
|
+
Object#andand let’s us write:
|
17
35
|
|
36
|
+
<pre>
|
37
|
+
@phone = Location.find(:first, ...elided... ).andand.phone
|
38
|
+
</pre>And get the same effect as:
|
18
39
|
|
40
|
+
<pre>
|
41
|
+
@phone = ->(loc){ loc && loc.phone }.call(Location.find(:first, ...elided... ))
|
42
|
+
</pre>Note that because you accept any method using Ruby’s method invocation syntax, you can accept methods with parameters and/or blocks:
|
43
|
+
|
44
|
+
<pre>
|
45
|
+
list_of_lists.detect { ...elided... }.andand.inject(42) { ...elided ... }
|
46
|
+
</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
|
+
|
48
|
+
h3. Enhanced Object#tap
|
49
|
+
|
50
|
+
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
|
+
|
52
|
+
<pre>
|
53
|
+
blah.sort.grep( /foo/ ).tap { |xs| p xs }.map { |x| x.blah }
|
54
|
+
</pre> But like its sibling @.andand@, you can now call @.tap@ with a method as well:
|
55
|
+
|
56
|
+
<pre>
|
57
|
+
[1, 2, 3, 4, 5].tap.pop.map { |n| n * 2 }
|
58
|
+
=> [2, 4, 6, 8]
|
59
|
+
</pre>
|
60
|
+
|
61
|
+
h2. Demonstration of usage
|
19
62
|
|
20
|
-
|
63
|
+
See above.
|
21
64
|
|
22
|
-
|
65
|
+
h2. A little more background
|
23
66
|
|
24
|
-
|
67
|
+
"Object#andand & Object#me in Ruby":http://weblog.raganwald.com/2008/01/objectandand-objectme-in-ruby.html
|
25
68
|
|
26
69
|
h2. How to submit patches
|
27
70
|
|
28
|
-
Read the "8 steps for fixing other people's code":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code
|
71
|
+
Read the "8 steps for fixing other people's code":http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/.
|
29
72
|
|
30
|
-
The trunk repository is
|
73
|
+
The trunk repository is @svn://rubyforge.org/var/svn/andand/trunk@ for anonymous access.
|
31
74
|
|
32
75
|
h2. License
|
33
76
|
|
34
|
-
This code is free to use under the terms of the MIT license.
|
77
|
+
This code is free to use under the terms of the "MIT license":http://en.wikipedia.org/wiki/MIT_License.
|
35
78
|
|
36
79
|
h2. Contact
|
37
80
|
|
38
|
-
Comments are welcome. Send an email to "
|
81
|
+
Comments are welcome. Send an email to "Reginald Braithwaite":mailto:raganwald+rubyforge@gmail.com.
|
39
82
|
|
data/website/template.rhtml
CHANGED
@@ -37,7 +37,7 @@
|
|
37
37
|
</div>
|
38
38
|
<%= body %>
|
39
39
|
<p class="coda">
|
40
|
-
<a href="
|
40
|
+
<a href="http://weblog.raganwald.com">Reginald Braithwaite</a>, <%= modified.pretty %><br>
|
41
41
|
Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
|
42
42
|
</p>
|
43
43
|
</div>
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: andand
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 1.0
|
7
|
-
date: 2008-02-
|
6
|
+
version: 1.1.0
|
7
|
+
date: 2008-02-10 00:00:00 -05:00
|
8
8
|
summary: adds guarded method invocation to Ruby
|
9
9
|
require_paths:
|
10
10
|
- lib
|