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 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
- #then and #else can return a default value instead of evaluating a block
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('&quot;', '"').gsub('&gt;','>')}</coderay>")
92
+ ex.swap("<coderay lang='ruby'>#{ex.inner_html.gsub('&quot;', '"').gsub('&gt;','>').gsub('&lt;', '<')}</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.3.1"
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, 17 Mar 2008 08:17:16 -0500
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, otherwise
52
- # evaluate the block or return the default argument
53
- def then default=nil, &block
54
- if self
55
- block_given? ? (yield_or_eval(&block)) : (default || (fail \
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
- self
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
- # the inverse of then
63
- def else arg=nil, &block
64
- if self
65
- self
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
- block_given? ? (yield_or_eval(&block)) : (arg || (fail \
68
- ArgumentError, "#else must be called with an argument or a bloc"))
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
@@ -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 "should validate arguments if self evaluates to #{bool}" do
112
- vals.each {|val| lambda{val.send(same)}.should raise_error(ArgumentError)}
113
- vals.each {|val| lambda{val.send(same){|a,b|}}.should raise_error(ArgumentError)}
114
- vals.each {|val| lambda{val.send(same){|a,*b|}}.should raise_error(ArgumentError)}
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.3.1
7
- date: 2008-03-17 00:00:00 -05:00
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