chainable 0.1.1 → 0.1.2

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.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: