methodchain 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +32 -4
- data/Rakefile +2 -2
- data/doc/created.rid +1 -1
- data/lib/methodchain/not-included.rb +48 -13
- data/spec/methodchain_spec.rb +57 -8
- metadata +2 -2
data/README
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
== Summary
|
2
|
-
methodchain - ruby helpers for method chaining: chain, tap, then, else
|
2
|
+
methodchain - ruby helpers for method chaining: chain, tap, then, else, and, or
|
3
3
|
Easy ways to navigate around nil without creating local variables.
|
4
4
|
|
5
5
|
== Author and License
|
@@ -14,6 +14,8 @@ Licensed under the MIT license
|
|
14
14
|
|
15
15
|
==== new way
|
16
16
|
name = person.then {|p| p.name}
|
17
|
+
# or
|
18
|
+
name = person.then {name}
|
17
19
|
|
18
20
|
not a huge savings. But sometimes the person variable is actually a function call, and then we must save it in a variable first.
|
19
21
|
|
@@ -29,10 +31,36 @@ not a huge savings. But sometimes the person variable is actually a function cal
|
|
29
31
|
@phone = find(:first).then {phone} # => nil
|
30
32
|
|
31
33
|
We have reduced a line of code and removed a local variable.
|
32
|
-
|
34
|
+
##else is the opposite of #then, and the two methods can be used together
|
35
|
+
|
36
|
+
'a'.then{'b'} #=> 'b'
|
37
|
+
nil.then{'b'}.else{'c'} #=> 'c'
|
38
|
+
|
39
|
+
==== message sending
|
40
|
+
The normal conditional for ##then and ##else is self
|
41
|
+
|
42
|
+
if self # inside MethodChain#then
|
43
|
+
# evaluate block
|
44
|
+
end
|
45
|
+
|
46
|
+
##then and ##else allow message sending as the conditional. See more examples of message sending with the MethodChain#chain examples below
|
47
|
+
|
48
|
+
"not empty".then(:empty?) {"N/A"} # => "not empty"
|
49
|
+
"".then(:empty?) {"N/A"} # => "N/A"
|
50
|
+
|
51
|
+
=== ##and, ##or
|
52
|
+
==== old way
|
53
|
+
Return a default value or the original value depending on whether multiple conditions are met
|
54
|
+
Person = Struct.new(:phone )
|
55
|
+
blank = Person.new('') # or {:phone => nil}
|
56
|
+
blank.phone && (not blank.phone.empty?) ? blank.phone : "N/A" # => "N/A"
|
57
|
+
p = Person.new('123')
|
58
|
+
p.phone && (not p.phone.empty?) ? p.phone : "N/A" # => "123"
|
59
|
+
|
60
|
+
==== new way
|
61
|
+
blank.phone.and {not empty?} || "N/A" # => "N/A"
|
62
|
+
p.phone.and {not empty?} || "N/A" # => "123"
|
33
63
|
|
34
|
-
'a'.then('b') #=> 'b'
|
35
|
-
nil.then('b').else('c') #=> 'c'
|
36
64
|
|
37
65
|
=== ##tap
|
38
66
|
if you don't already know about this method, look it up on the net. The tap included here allows message sending.
|
data/Rakefile
CHANGED
@@ -89,7 +89,7 @@ namespace :readme do
|
|
89
89
|
doc.at('#description').search('pre').each do |ex|
|
90
90
|
#select {|elem| elem.inner_html =~ /class |module /}.each do |ex|
|
91
91
|
# add coderay and undo what rdoc has done in the example code
|
92
|
-
ex.swap("<coderay lang='ruby'>#{ex.inner_html.gsub('"', '"').gsub('>','>')}</coderay>")
|
92
|
+
ex.swap("<coderay lang='ruby'>#{ex.inner_html.gsub('"', '"').gsub('>','>').gsub('<', '<')}</coderay>")
|
93
93
|
end
|
94
94
|
puts doc.at('#description').to_html
|
95
95
|
end
|
@@ -134,7 +134,7 @@ require 'rake/gempackagetask'
|
|
134
134
|
spec = Gem::Specification.new do |s|
|
135
135
|
s.name = project
|
136
136
|
s.rubyforge_project = project
|
137
|
-
s.version = "0.
|
137
|
+
s.version = "0.4.0"
|
138
138
|
s.author = "Greg Weber"
|
139
139
|
s.email = "greg@gregweber.info"
|
140
140
|
s.homepage = "http://projects.gregweber.info/#{project}"
|
data/doc/created.rid
CHANGED
@@ -1 +1 @@
|
|
1
|
-
Mon,
|
1
|
+
Mon, 24 Mar 2008 13:06:03 -0500
|
@@ -48,24 +48,59 @@ public
|
|
48
48
|
(send_as_function (messages.shift)).chain(*messages, &guard)
|
49
49
|
end
|
50
50
|
|
51
|
-
# return self if self evaluates to false,
|
52
|
-
#
|
53
|
-
def then
|
54
|
-
if
|
55
|
-
|
56
|
-
ArgumentError, "#then must be called with an argument or a block"))
|
51
|
+
# return self if self or a guard evaluates to false,
|
52
|
+
# otherwise return the evaluation of the block
|
53
|
+
def then *guards, &block
|
54
|
+
if guards.empty?
|
55
|
+
return self if not self
|
57
56
|
else
|
58
|
-
|
57
|
+
guards.each do |cond|
|
58
|
+
return self if not send_as_function(cond)
|
59
|
+
end
|
59
60
|
end
|
61
|
+
|
62
|
+
block_given? ? yield_or_eval(&block) : self
|
63
|
+
end
|
64
|
+
|
65
|
+
# return self if self or a guard evaluates to true
|
66
|
+
# otherwise return the evaluation of the block
|
67
|
+
def else *guards, &block
|
68
|
+
if guards.empty?
|
69
|
+
return self if self
|
70
|
+
else
|
71
|
+
guards.each do |cond|
|
72
|
+
return self if send_as_function(cond)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
block_given? ? yield_or_eval(&block) : self
|
60
77
|
end
|
61
78
|
|
62
|
-
#
|
63
|
-
|
64
|
-
|
65
|
-
|
79
|
+
# with no guards, is equivalent to self && yield_or_eval(&block) && self
|
80
|
+
# same as: <tt>self.then(*guards, &block) && self</tt>
|
81
|
+
def and *guards, &block
|
82
|
+
if guards.empty?
|
83
|
+
return self if not self
|
66
84
|
else
|
67
|
-
|
68
|
-
|
85
|
+
guards.each do |cond|
|
86
|
+
return self if not send_as_function(cond)
|
87
|
+
end
|
69
88
|
end
|
89
|
+
|
90
|
+
block_given? ? (yield_or_eval(&block) && self) : self
|
91
|
+
end
|
92
|
+
|
93
|
+
# with no guards, is equivalent to <tt>self || (yield_or_eval(&block) && self)</tt>
|
94
|
+
# same as: <tt>self.else(*guards, &block) && self</tt>
|
95
|
+
def or *guards, &block
|
96
|
+
if guards.empty?
|
97
|
+
return self if self
|
98
|
+
else
|
99
|
+
guards.each do |cond|
|
100
|
+
return self if send_as_function(cond)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
block_given? ? yield_or_eval(&block) : self
|
70
105
|
end
|
71
106
|
end
|
data/spec/methodchain_spec.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../lib/methodchain'
|
2
2
|
|
3
|
+
#TODO
|
4
|
+
# test message sending with #and and #or
|
5
|
+
|
3
6
|
describe "#chain" do
|
4
7
|
it "should return self when no arguments or just a block are given" do
|
5
8
|
[nil,'a'].each do |var|
|
@@ -88,30 +91,76 @@ describe "#tap" do
|
|
88
91
|
end
|
89
92
|
end
|
90
93
|
|
94
|
+
describe "Object#and" do
|
95
|
+
it "should return self or a value that evaluates to false" do
|
96
|
+
[true,'testing'].each do |val|
|
97
|
+
val.and {false}.should == false
|
98
|
+
val.and {'a'}.should == val
|
99
|
+
end
|
100
|
+
[false,nil].each do |val|
|
101
|
+
val.and {false}.should == val
|
102
|
+
val.and {nil}.should == val
|
103
|
+
val.and {true}.should == val
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe "Object#or" do
|
109
|
+
it "should return self or a value that evaluates to false" do
|
110
|
+
[true,'testing'].each do |val|
|
111
|
+
val.or {false}.should == val
|
112
|
+
val.or {'a'}.should == val
|
113
|
+
end
|
114
|
+
[false,nil].each do |val|
|
115
|
+
val.or {false}.should == false
|
116
|
+
val.or {nil}.should == nil
|
117
|
+
val.or {true}.should == true
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
91
121
|
def test_then_else *vals
|
92
122
|
bool = !!vals.first
|
93
123
|
same,opp = bool ? [:then,:else] : [:else,:then]
|
94
124
|
|
95
|
-
it "should return self if self evaluates to #{!bool}" do
|
125
|
+
it "should return self if no conditions are given and self evaluates to #{!bool}" do
|
96
126
|
vals.each do |val|
|
97
127
|
val.send(opp).should == val
|
98
|
-
val.send(opp,'aye').should == val
|
99
|
-
val.send(opp,'aye') {|a,b,c| a}.should == val
|
100
128
|
val.send(opp) {|a,b,c| a}.should == val
|
101
129
|
end
|
102
130
|
end
|
103
131
|
|
132
|
+
it "should return self if no block is given" do
|
133
|
+
vals.each do |val|
|
134
|
+
val.send(same, proc{self}).should == val
|
135
|
+
val.send(same, proc{not self}).should == val
|
136
|
+
val.send(opp, proc{self}).should == val
|
137
|
+
val.send(opp, proc{not self}).should == val
|
138
|
+
|
139
|
+
lambda{val.send(same, proc{fail})}.should raise_error
|
140
|
+
lambda{val.send(opp, proc{fail})}.should raise_error
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
104
144
|
it "if self evaluates to #{bool} ##{same} should yield self to a block if one is given, and return that block's value" do
|
105
145
|
vals.each do |val|
|
106
146
|
val.send(same) {|v| v.should == val; 'foo'}.should == 'foo'
|
107
|
-
val.send(same,1) {|v| v.should == val; 'foo'}.should == 'foo'
|
108
147
|
end
|
109
148
|
end
|
110
149
|
|
111
|
-
it "
|
112
|
-
vals.each
|
113
|
-
|
114
|
-
|
150
|
+
it "if self evaluates to #{!bool} ##{opp} should yield self to a block if one is given, and return that block's value" do
|
151
|
+
vals.each do |val|
|
152
|
+
val.send(opp) {|v| v.should == val; 'foo'}.should == val
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should test conditions" do
|
157
|
+
vals.each do |val|
|
158
|
+
val.send(same, proc{self}) {"test"}.should == "test"
|
159
|
+
val.send(same, proc{not self}) {fail}.should == val
|
160
|
+
|
161
|
+
val.send(opp, proc{self}) {fail}.should == val
|
162
|
+
val.send(opp, proc{not self}) {"test"}.should == "test"
|
163
|
+
end
|
115
164
|
end
|
116
165
|
end
|
117
166
|
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: methodchain
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2008-03-
|
6
|
+
version: 0.4.0
|
7
|
+
date: 2008-03-24 00:00:00 -05:00
|
8
8
|
summary: convenience methods for method chaining
|
9
9
|
require_paths:
|
10
10
|
- lib
|