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