methodchain 0.3.1 → 0.4.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/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