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 +18 -0
- data/Rakefile +7 -1
- data/benchmark/chainable.rb +51 -0
- data/lib/chainable.rb +4 -2
- data/spec/chainable/chain_method_spec.rb +11 -0
- metadata +2 -1
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
|
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(
|
18
|
-
name
|
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.
|
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:
|