chainable 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -50,6 +50,12 @@ Example:
50
50
  end
51
51
 
52
52
  end
53
+
54
+ # or chain multiple methods at once
55
+ chain_method :foo, :bar do
56
+ super.to_s
57
+ end
58
+
53
59
  end
54
60
 
55
61
  f = Foo.new
@@ -66,6 +72,18 @@ Of course you can do this with any class (or module):
66
72
  end
67
73
  end
68
74
 
75
+ Note that there is a speed advantage when using chain_method without a block
76
+ and doing a "def", since chain_method will use define_method if a block is
77
+ given, which produces slower methods (but makes the method a real closure).
78
+
79
+ == Benchmark
80
+ chain_method tends do produce slightly faster methods than alias_method_chain:
81
+ user system total real
82
+ chainable (define_method) 0.160000 0.010000 0.170000 ( 0.183363)
83
+ chainable (def & eval) 0.170000 0.010000 0.180000 ( 0.177084)
84
+ alias_method_chain (define_method) 0.570000 0.030000 0.600000 ( 0.607330)
85
+ alias_method_chain (def & eval) 0.170000 0.020000 0.190000 ( 0.190048)
86
+
69
87
  == Installation
70
88
  Add github gems, if you haven't already:
71
89
  gem sources -a http://gems.github.com
data/Rakefile CHANGED
@@ -1,3 +1,9 @@
1
1
  require 'spec/rake/spectask'
2
2
 
3
- Spec::Rake::SpecTask.new { |t| t.spec_files = FileList['spec/**/*.rb'] }
3
+ Spec::Rake::SpecTask.new do |t|
4
+ t.spec_files = FileList['spec/**/*.rb']
5
+ t.spec_opts << "-fs"
6
+ end
7
+
8
+ desc "Run benchmark"
9
+ task(:benchmark) { load "benchmark/chainable.rb" }
@@ -0,0 +1,51 @@
1
+ require "benchmark"
2
+ require "lib/chainable"
3
+ require "active_support"
4
+
5
+ class BenchmarkChain
6
+ CHAIN_LENGTH = 1000
7
+ CALL_TIMES = 1000
8
+ class << self
9
+ def bm1(x)
10
+ obj = new
11
+ x.report("#{@name} (define_method)") { CALL_TIMES.times { obj.bm1 } }
12
+ end
13
+ def bm2(x)
14
+ obj = new
15
+ x.report("#{@name} (def & eval)") { CALL_TIMES.times { obj.bm2 } }
16
+ end
17
+ end
18
+ define_method(:bm1) { }
19
+ def bm2; end
20
+ end
21
+
22
+ class BenchmarkChainable < BenchmarkChain
23
+ @name = "chainable"
24
+ CHAIN_LENGTH.times do
25
+ chain_method(:bm1) { super }
26
+ chain_method(:bm2)
27
+ def bm2; super; end
28
+ end
29
+ end
30
+
31
+ class BenchmarkAliasMethodChain < BenchmarkChain
32
+ @name = "alias_method_chain"
33
+ CHAIN_LENGTH.times do |i|
34
+ method_without = "bm1_without_#{i}"
35
+ define_method("bm1_with_#{i}") { send(method_without) }
36
+ alias_method_chain :bm1, i.to_s
37
+ eval "def bm2_with_#{i}; bm2_without_#{i}; end"
38
+ alias_method_chain :bm2, i.to_s
39
+ end
40
+ end
41
+
42
+ def bench(x, klass)
43
+ obj = klass.new
44
+ end
45
+
46
+ Benchmark.bmbm do |x|
47
+ BenchmarkChainable.bm1(x)
48
+ BenchmarkAliasMethodChain.bm1(x)
49
+ BenchmarkChainable.bm2(x)
50
+ BenchmarkAliasMethodChain.bm2(x)
51
+ end
data/lib/chainable.rb CHANGED
@@ -14,8 +14,9 @@ module Chainable
14
14
  # Maybe that is not what you want, as methods defined by def tend to be
15
15
  # faster. If that is the case, simply don't pass the block and call def
16
16
  # after chain_method instead.
17
- def chain_method(name, &block)
18
- name = name.to_s
17
+ def chain_method(*names, &block)
18
+ raise ArgumentError, "no method name given" if names.empty?
19
+ name = names.shift.to_s
19
20
  if instance_methods(false).include? name
20
21
  begin
21
22
  code = Ruby2Ruby.translate self, name
@@ -27,6 +28,7 @@ module Chainable
27
28
  end
28
29
  block ||= Proc.new { super }
29
30
  define_method(name, &block)
31
+ chain_method(*names, &block) unless names.empty?
30
32
  end
31
33
 
32
34
  # If you define a method inside a block passed to auto_chain, chain_method
@@ -60,6 +60,17 @@ describe Chainable do
60
60
  @an_instance.to_i.should == @original_results["to_i"] + 20
61
61
  end
62
62
 
63
+ it "should allow passing multiple method names to chain_method" do
64
+ @a_class.class_eval do
65
+ chain_method :random, :foo2
66
+ chain_method(:foo, :to_i) { super.to_s }
67
+ end
68
+ @an_instance.random.should == @original_results["random"]
69
+ @an_instance.foo2.should == @original_results["foo2"]
70
+ @an_instance.foo.should == @original_results["foo"].to_s
71
+ @an_instance.to_i.should == @original_results["to_i"].to_s
72
+ end
73
+
63
74
  it "should keep inheritance intact" do
64
75
  a_module = Module.new do
65
76
  define_method(:inspect) { "some inspect result" }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chainable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Haase
@@ -29,6 +29,7 @@ files:
29
29
  - lib/chainable.rb
30
30
  - spec/chainable/auto_chain_spec.rb
31
31
  - spec/chainable/chain_method_spec.rb
32
+ - benchmark/chainable.rb
32
33
  has_rdoc: true
33
34
  homepage: http://rkh.github.com/chainable
34
35
  post_install_message: