methodchain 0.1.0 → 0.2.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 +34 -16
- data/doc/created.rid +1 -1
- data/doc/fr_method_index.html +5 -4
- data/pkg/methodchain-0.1.0.gem +0 -0
- data/rakefile +1 -1
- data/spec/methodchain_spec.rb +63 -23
- metadata +2 -3
- data/spec/not_included.rb +0 -11
- data/spec/then_else.rb +0 -11
data/README
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
== Summary
|
2
|
-
methodchain - ruby helpers for method chaining: tap, then, else
|
2
|
+
methodchain - ruby helpers for method chaining: chain, tap, then, else
|
3
3
|
Easy ways to navigate around nil without creating local variables.
|
4
4
|
|
5
5
|
== Author and License
|
6
6
|
Copyright (c) 2008 Greg Weber, http://gregweber.info
|
7
7
|
Licensed under the MIT license
|
8
8
|
|
9
|
-
==
|
9
|
+
== Examples
|
10
10
|
==== tap
|
11
11
|
if you don't already know about this method, look it up on the net. The tap included here allows message sending.
|
12
12
|
|
@@ -17,38 +17,56 @@ NEW WAY
|
|
17
17
|
|
18
18
|
==== #then and #else
|
19
19
|
OLD WAY
|
20
|
+
|
20
21
|
name = person ? person.name : nil
|
21
22
|
|
22
23
|
NEW WaY
|
24
|
+
|
23
25
|
name = person.then {|p| p.name}
|
24
26
|
|
25
27
|
not a huge savings. But sometimes the person variable is actually a function call, and then we must save it in a variable first.
|
26
28
|
|
27
29
|
OLD WAY
|
30
|
+
|
28
31
|
location = Location.find(:first, ...)
|
29
32
|
@phone = location && location.phone
|
30
33
|
|
31
34
|
NEW WaY
|
35
|
+
|
32
36
|
@phone = Location.find(:first, ...).then {phone}
|
33
|
-
|
37
|
+
|
38
|
+
here we have reduced a line of code and removed a local variable
|
39
|
+
#then and #else can return a default value instead of evaluating a block
|
40
|
+
'a'.then('b') #=> 'b'
|
41
|
+
nil.then('b').else('c') #=> 'c'
|
34
42
|
|
43
|
+
=== #chain
|
35
44
|
OLD WAY
|
36
|
-
|
37
|
-
|
38
|
-
else
|
39
|
-
'fail'
|
40
|
-
end
|
45
|
+
|
46
|
+
customer && customer.order && customer.order.id
|
41
47
|
|
42
48
|
NEW WaY
|
43
|
-
customer.then {order}.then {id == new_customer_id}.then('success').else('fail')
|
44
49
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
+
customer.chain(:order, :id)
|
51
|
+
|
52
|
+
note that this is equivalent to
|
53
|
+
|
54
|
+
customer.then {order}.then {id}
|
55
|
+
|
56
|
+
=== chain - Custom guards and multiple argumentes
|
57
|
+
OLD WAY - guarding against zero
|
58
|
+
|
59
|
+
result = if value == 0 then value else
|
60
|
+
tmp = calc(value)
|
61
|
+
|
62
|
+
if tmp == 0 then tmp else
|
63
|
+
more_calc(tmp, 20)
|
64
|
+
end
|
50
65
|
end
|
51
66
|
|
67
|
+
NEW WAY
|
68
|
+
value.chain(:calc, [:more_calc, 20]) {|s| s == 0 }
|
69
|
+
|
52
70
|
== Usage
|
53
71
|
require 'rubygems'
|
54
72
|
|
@@ -64,8 +82,8 @@ not_included will load the MethodChain module without including it anywhere.
|
|
64
82
|
Already have your own version of tap? use the module-import gem to decide what to include
|
65
83
|
|
66
84
|
== Implementation
|
67
|
-
* There are no proxy objects
|
68
|
-
* A helper method called self_eval is also exposed. This method allows the two different block forms {|p| p.name} and {name}, where the second form is called using instance_eval.
|
85
|
+
* There are no proxy objects and no use of method_missing- these are simply function calls, so it should be fast.
|
86
|
+
* A helper method called self_eval is also exposed. This method allows the two different block forms {|p| p.name} and {name}, where the first form yields self and the second form is called using instance_eval.
|
69
87
|
|
70
88
|
== Install
|
71
89
|
gem install methodchain
|
data/doc/created.rid
CHANGED
@@ -1 +1 @@
|
|
1
|
-
Sun, 09 Mar 2008
|
1
|
+
Sun, 09 Mar 2008 15:08:53 -0500
|
data/doc/fr_method_index.html
CHANGED
@@ -20,10 +20,11 @@
|
|
20
20
|
<div id="index">
|
21
21
|
<h1 class="section-bar">Methods</h1>
|
22
22
|
<div id="index-entries">
|
23
|
-
<a href="classes/MethodChain.html#
|
24
|
-
<a href="classes/MethodChain.html#
|
25
|
-
<a href="classes/MethodChain.html#
|
26
|
-
<a href="classes/MethodChain.html#
|
23
|
+
<a href="classes/MethodChain.html#M000001">chain (MethodChain)</a><br />
|
24
|
+
<a href="classes/MethodChain.html#M000004">else (MethodChain)</a><br />
|
25
|
+
<a href="classes/MethodChain.html#M000002">self_eval (MethodChain)</a><br />
|
26
|
+
<a href="classes/MethodChain.html#M000005">tap (MethodChain)</a><br />
|
27
|
+
<a href="classes/MethodChain.html#M000003">then (MethodChain)</a><br />
|
27
28
|
</div>
|
28
29
|
</div>
|
29
30
|
</body>
|
Binary file
|
data/rakefile
CHANGED
@@ -42,7 +42,7 @@ require 'rake/gempackagetask'
|
|
42
42
|
spec = Gem::Specification.new do |s|
|
43
43
|
s.name = project
|
44
44
|
s.rubyforge_project = project
|
45
|
-
s.version = "0.
|
45
|
+
s.version = "0.2.0"
|
46
46
|
s.author = "Greg Weber"
|
47
47
|
s.email = "greg@gregweber.info"
|
48
48
|
s.homepage = "http://projects.gregweber.info/#{project}"
|
data/spec/methodchain_spec.rb
CHANGED
@@ -1,36 +1,44 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../lib/methodchain'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
vals.each do |val|
|
9
|
-
val.send(opp).should == val
|
10
|
-
val.send(opp,'aye').should == val
|
11
|
-
val.send(opp,'aye') {|a,b,c| a}.should == val
|
12
|
-
val.send(opp) {|a,b,c| a}.should == val
|
3
|
+
describe "#chain" do
|
4
|
+
it "should return self when no arguments are given" do
|
5
|
+
[nil,'a'].each do |var|
|
6
|
+
var.chain.should == var
|
7
|
+
var.chain {fail}.should == var
|
13
8
|
end
|
14
9
|
end
|
10
|
+
it "should send symbols" do
|
11
|
+
[[]].chain(:flatten).should == []
|
12
|
+
end
|
13
|
+
it "should send procs" do
|
14
|
+
[[]].chain(:flatten, lambda{|arr| arr.push('a')}).should == ['a']
|
15
|
+
[[]].chain(:flatten, lambda{ push('a') }).should == ['a']
|
16
|
+
end
|
17
|
+
it "should send an array as a message with arguments" do
|
18
|
+
[['a']].chain(:flatten, lambda{|arr| arr.push('b')}, [:join, ' ']).should == 'a b'
|
19
|
+
end
|
15
20
|
|
16
|
-
it "
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
+
it "should guard the chain against nil and false" do
|
22
|
+
nil.chain(:foo,:bar,:baz).should == nil
|
23
|
+
false.chain(:foo,:bar,:baz).should == false
|
24
|
+
[].chain(:flatten!,:not_defined).should == nil
|
25
|
+
[].chain(:flatten!, lambda{|arr| arr.push('a')}).should == nil
|
26
|
+
lambda{"foo".chain(:to_s,:not_defined)}.should raise_error(NoMethodError)
|
21
27
|
end
|
28
|
+
it "should allow custom guards with blocks" do
|
29
|
+
nil.chain {nil?}.should == nil
|
30
|
+
'a'.chain {nil?}.should == 'a'
|
31
|
+
nil.chain(:to_s) {nil?}.should == ''
|
32
|
+
'a'.chain(lambda{fail}) {nil?}.should == 'a'
|
22
33
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
34
|
+
nil.chain {is_a?(String)}.should == nil
|
35
|
+
'a'.chain {is_a?(String)}.should == 'a'
|
36
|
+
nil.chain(lambda{fail}) {is_a?(String)}.should == nil
|
37
|
+
'a'.chain(:upcase) {is_a?(String)}.should == 'A'
|
27
38
|
end
|
28
39
|
end
|
29
40
|
|
30
|
-
describe
|
31
|
-
test_then_else('a',true)
|
32
|
-
test_then_else(nil,false)
|
33
|
-
|
41
|
+
describe "#tap" do
|
34
42
|
it "#tap should yield self to a block and return self if block has one argument" do
|
35
43
|
[true,false,'a'].each do |o|
|
36
44
|
o.tap {|s| s.should == o }.should == o
|
@@ -58,3 +66,35 @@ describe Object do
|
|
58
66
|
[1, 2, 3, 4, 5].tap.should == [1, 2, 3, 4, 5]
|
59
67
|
end
|
60
68
|
end
|
69
|
+
|
70
|
+
def test_then_else *vals
|
71
|
+
bool = !!vals.first
|
72
|
+
same,opp = bool ? [:then,:else] : [:else,:then]
|
73
|
+
|
74
|
+
it "should return self if self evaluates to #{!bool}" do
|
75
|
+
vals.each do |val|
|
76
|
+
val.send(opp).should == val
|
77
|
+
val.send(opp,'aye').should == val
|
78
|
+
val.send(opp,'aye') {|a,b,c| a}.should == val
|
79
|
+
val.send(opp) {|a,b,c| a}.should == val
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
it "if self evaluates to #{bool} ##{same} should yield self to a block if one is given, and return that block's value" do
|
84
|
+
vals.each do |val|
|
85
|
+
val.send(same) {|v| v.should == val; 'foo'}.should == 'foo'
|
86
|
+
val.send(same,1) {|v| v.should == val; 'foo'}.should == 'foo'
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should validate arguments if self evaluates to #{bool}" do
|
91
|
+
vals.each {|val| lambda{val.send(same)}.should raise_error(ArgumentError)}
|
92
|
+
vals.each {|val| lambda{val.send(same){|a,b|}}.should raise_error(ArgumentError)}
|
93
|
+
vals.each {|val| lambda{val.send(same){|a,*b|}}.should raise_error(ArgumentError)}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "#then,#else" do
|
98
|
+
test_then_else('a',true)
|
99
|
+
test_then_else(nil,false)
|
100
|
+
end
|
metadata
CHANGED
@@ -3,7 +3,7 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: methodchain
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
6
|
+
version: 0.2.0
|
7
7
|
date: 2008-03-09 00:00:00 -06:00
|
8
8
|
summary: convenience methods for method chaining
|
9
9
|
require_paths:
|
@@ -48,8 +48,7 @@ files:
|
|
48
48
|
- pkg/methodchain-0.0.1.gem
|
49
49
|
- pkg/methodchain-0.0.3.gem
|
50
50
|
- pkg/methodchain-0.0.5.gem
|
51
|
-
-
|
52
|
-
- spec/then_else.rb
|
51
|
+
- pkg/methodchain-0.1.0.gem
|
53
52
|
- spec/methodchain_spec.rb
|
54
53
|
- README
|
55
54
|
test_files: []
|
data/spec/not_included.rb
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
# test optional imports
|
2
|
-
|
3
|
-
describe "requiring not_included" do
|
4
|
-
it "should not import methods into Object" do
|
5
|
-
require File.dirname(__FILE__) + '/../lib/methodchain/not_included'
|
6
|
-
Object.new.should_not respond_to(:tap)
|
7
|
-
Object.new.should_not respond_to(:then)
|
8
|
-
Object.new.should_not respond_to(:else)
|
9
|
-
MethodChain.should be_kind_of(Module)
|
10
|
-
end
|
11
|
-
end
|
data/spec/then_else.rb
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
# test optional imports
|
2
|
-
|
3
|
-
describe "requiring not_tap" do
|
4
|
-
it "should not import tap into Object" do
|
5
|
-
require File.dirname(__FILE__) + '/../lib/methodchain/then_else'
|
6
|
-
MethodChain.should be_kind_of(Module)
|
7
|
-
Object.new.should_not respond_to(:tap)
|
8
|
-
Object.new.should respond_to(:then)
|
9
|
-
Object.new.should respond_to(:else)
|
10
|
-
end
|
11
|
-
end
|