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 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
- == Example
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
- here we have reduced a line of code and removed a local variable
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
- if(customer && customer.order && customer.order.id == new_customer_id)
37
- 'success'
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
- Here we have removed one call to order and reduced the code to a one-liner. There is also an equivalent block form
46
- customer.then {order}.then {id == new_customer_id}.then do |o|
47
- 'success'
48
- end.else do
49
- 'fail'
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, these are simply function calls, so it should be fast.
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 12:16:13 -0500
1
+ Sun, 09 Mar 2008 15:08:53 -0500
@@ -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#M000003">else (MethodChain)</a><br />
24
- <a href="classes/MethodChain.html#M000001">self_eval (MethodChain)</a><br />
25
- <a href="classes/MethodChain.html#M000004">tap (MethodChain)</a><br />
26
- <a href="classes/MethodChain.html#M000002">then (MethodChain)</a><br />
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.1.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}"
@@ -1,36 +1,44 @@
1
1
  require File.dirname(__FILE__) + '/../lib/methodchain'
2
2
 
3
- def test_then_else *vals
4
- bool = !!vals.first
5
- same,opp = bool ? [:then,:else] : [:else,:then]
6
-
7
- it "should return self if self evaluates to #{!bool}" do
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 "if self evaluates to #{bool} ##{same} should yield self to a block if one is given, and return that block's value" do
17
- vals.each do |val|
18
- val.send(same) {|v| v.should == val; 'foo'}.should == 'foo'
19
- val.send(same,1) {|v| v.should == val; 'foo'}.should == 'foo'
20
- end
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
- it "should validate arguments if self evaluates to #{bool}" do
24
- vals.each {|val| lambda{val.send(same)}.should raise_error(ArgumentError)}
25
- vals.each {|val| lambda{val.send(same){|a,b|}}.should raise_error(ArgumentError)}
26
- vals.each {|val| lambda{val.send(same){|a,*b|}}.should raise_error(ArgumentError)}
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 Object do
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.1.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
- - spec/not_included.rb
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