bindable_block 0.0.2 → 0.0.3
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/lib/bindable_block/version.rb +1 -1
- data/lib/bindable_block.rb +59 -15
- data/spec/bindable_block_spec.rb +61 -13
- metadata +2 -2
data/lib/bindable_block.rb
CHANGED
@@ -1,6 +1,54 @@
|
|
1
1
|
require "bindable_block/version"
|
2
2
|
|
3
3
|
class BindableBlock
|
4
|
+
|
5
|
+
# match args to arity, since instance_method has lambda properties
|
6
|
+
class ArgAligner
|
7
|
+
def self.align(args, instance_method)
|
8
|
+
new(args, instance_method).call
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
attr_reader :args, :parameters, :result
|
14
|
+
|
15
|
+
def initialize(args, instance_method)
|
16
|
+
@result, @args, @parameters = [], args, instance_method.parameters.map(&:first)
|
17
|
+
track_if_has_rest
|
18
|
+
parameters.delete :rest
|
19
|
+
remove_block
|
20
|
+
take num_required
|
21
|
+
parameters.delete :req
|
22
|
+
take 1 while parameters.shift && args.any?
|
23
|
+
take args.size if has_rest?
|
24
|
+
end
|
25
|
+
|
26
|
+
def num_required
|
27
|
+
parameters.count { |param| param == :req }
|
28
|
+
end
|
29
|
+
|
30
|
+
def take(n)
|
31
|
+
n.times { result << args.shift }
|
32
|
+
end
|
33
|
+
|
34
|
+
def remove_block
|
35
|
+
parameters.pop if parameters.last == :block
|
36
|
+
end
|
37
|
+
|
38
|
+
def track_if_has_rest
|
39
|
+
@has_splat = parameters.any? { |param| param == :rest }
|
40
|
+
end
|
41
|
+
|
42
|
+
def has_rest?
|
43
|
+
@has_splat
|
44
|
+
end
|
45
|
+
|
46
|
+
def call
|
47
|
+
result
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
4
52
|
def initialize(klass, &block)
|
5
53
|
@original_block = block
|
6
54
|
|
@@ -9,25 +57,11 @@ class BindableBlock
|
|
9
57
|
klass.__send__ :remove_method, method_name
|
10
58
|
end
|
11
59
|
|
12
|
-
def method_name
|
13
|
-
@method_name ||= "bindable_block_#{Time.now.to_i}_#{$$}_#{rand 1000000}"
|
14
|
-
end
|
15
|
-
|
16
|
-
def arg_size
|
17
|
-
instance_method.arity
|
18
|
-
end
|
19
|
-
|
20
60
|
attr_reader :instance_method, :original_block
|
21
61
|
|
22
62
|
def bind(target)
|
23
63
|
Proc.new do |*args, &block|
|
24
|
-
|
25
|
-
if args.size >= arg_size
|
26
|
-
args = args.take arg_size
|
27
|
-
else
|
28
|
-
args[arg_size-1] = nil
|
29
|
-
end
|
30
|
-
instance_method.bind(target).call(*args, &block)
|
64
|
+
instance_method.bind(target).call(*align(args), &block)
|
31
65
|
end
|
32
66
|
end
|
33
67
|
|
@@ -38,4 +72,14 @@ class BindableBlock
|
|
38
72
|
def to_proc
|
39
73
|
method(:call).to_proc
|
40
74
|
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def align(args)
|
79
|
+
ArgAligner.align args, instance_method
|
80
|
+
end
|
81
|
+
|
82
|
+
def method_name
|
83
|
+
@method_name ||= "bindable_block_#{Time.now.to_i}_#{$$}_#{rand 1000000}"
|
84
|
+
end
|
41
85
|
end
|
data/spec/bindable_block_spec.rb
CHANGED
@@ -23,19 +23,6 @@ describe BindableBlock do
|
|
23
23
|
block.call(3){4}.should == 10
|
24
24
|
end
|
25
25
|
|
26
|
-
it "doesn't care about arity" do
|
27
|
-
block = BindableBlock.new(klass) { |a| [a] }.bind(instance)
|
28
|
-
block.call.should == [nil]
|
29
|
-
block.call(1).should == [1]
|
30
|
-
block.call(1, 2).should == [1]
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'can take a block' do
|
34
|
-
block = BindableBlock.new(klass) { |a, &b| [a, (b&&b.call)] }.bind(instance)
|
35
|
-
block.call(1).should == [1, nil]
|
36
|
-
block.call(1){2}.should == [1, 2]
|
37
|
-
end
|
38
|
-
|
39
26
|
it 'can be passed to methods and shit' do
|
40
27
|
doubler = lambda { |&block| block.call + block.call }
|
41
28
|
doubler.call(&BindableBlock.new(klass) { 12 }).should == 24
|
@@ -50,4 +37,65 @@ describe BindableBlock do
|
|
50
37
|
# proc.define_singleton_method(:bind) { |target| bindable_block.bind target }
|
51
38
|
# proc
|
52
39
|
end
|
40
|
+
|
41
|
+
describe 'arguments' do
|
42
|
+
it 'can take a block' do
|
43
|
+
block = BindableBlock.new(klass) { |a, &b| [a, (b&&b.call)] }.bind(instance)
|
44
|
+
block.call(1).should == [1, nil]
|
45
|
+
block.call(1){2}.should == [1, 2]
|
46
|
+
end
|
47
|
+
|
48
|
+
specify "when given ordinal arguments at the start, it doesn't care about arity" do
|
49
|
+
block = BindableBlock.new(klass) { |a| [a] }.bind(instance)
|
50
|
+
block.call.should == [nil]
|
51
|
+
block.call(1).should == [1]
|
52
|
+
block.call(1, 2).should == [1]
|
53
|
+
end
|
54
|
+
|
55
|
+
specify 'when given optional args, it matches them up correctly' do
|
56
|
+
block = BindableBlock.new(klass) { |a, b=1, c=2| [a, b, c] }.bind(instance)
|
57
|
+
block.call.should == [nil, 1, 2]
|
58
|
+
block.call(:a).should == [:a, 1, 2]
|
59
|
+
block.call(:a, :b).should == [:a, :b, 2]
|
60
|
+
block.call(:a, :b, :c).should == [:a, :b, :c]
|
61
|
+
block.call(:a, :b, :c, :d).should == [:a, :b, :c]
|
62
|
+
end
|
63
|
+
|
64
|
+
specify 'splat acts as a catch all' do
|
65
|
+
block = BindableBlock.new(klass) { |a, *rest| [a, rest] }.bind(instance)
|
66
|
+
block.call.should == [nil, []]
|
67
|
+
block.call(1).should == [1, []]
|
68
|
+
block.call(1, 2).should == [1, [2]]
|
69
|
+
block.call(1, 2, 3).should == [1, [2, 3]]
|
70
|
+
end
|
71
|
+
|
72
|
+
specify "when given ordinal arguments at the end, it doesn't care about arity" do
|
73
|
+
block = BindableBlock.new(klass) { |*a, b, &c| [a, b] }.bind(instance)
|
74
|
+
block.call.should == [[], nil]
|
75
|
+
block.call(1).should == [[], 1]
|
76
|
+
block.call(1,2).should == [[1], 2]
|
77
|
+
block.call(1,2,3).should == [[1, 2], 3]
|
78
|
+
|
79
|
+
block = BindableBlock.new(klass) { |a=:a, b, c| [a, b, c] }.bind(instance)
|
80
|
+
block.call.should == [:a, nil, nil]
|
81
|
+
block.call(1).should == [:a, 1, nil]
|
82
|
+
block.call(1, 2).should == [:a, 1, 2]
|
83
|
+
block.call(1, 2, 3).should == [1, 2, 3]
|
84
|
+
block.call(1, 2, 3, 4).should == [1, 2, 3]
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
specify "when given complex arguments, it matches that shit up right" do
|
89
|
+
proc = Proc.new { |a, b, c=1, d=2, *e, f| [a,b,c,d,e,f] }
|
90
|
+
block = BindableBlock.new(klass, &proc).bind(instance)
|
91
|
+
block.call.should == proc.call
|
92
|
+
block.call(:a).should == proc.call(:a)
|
93
|
+
block.call(:a,:b).should == proc.call(:a,:b)
|
94
|
+
block.call(:a,:b,:c).should == proc.call(:a,:b,:c)
|
95
|
+
block.call(:a,:b,:c,:d).should == proc.call(:a,:b,:c,:d)
|
96
|
+
block.call(:a,:b,:c,:d,:e).should == proc.call(:a,:b,:c,:d,:e)
|
97
|
+
block.call(:a,:b,:c,:d,:e,:f).should == proc.call(:a,:b,:c,:d,:e,:f)
|
98
|
+
block.call(:a,:b,:c,:d,:e,:f,:g).should == proc.call(:a,:b,:c,:d,:e,:f,:g)
|
99
|
+
end
|
100
|
+
end
|
53
101
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bindable_block
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-06-
|
12
|
+
date: 2012-06-05 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: instance_exec can't pass block arguments through. Use a bindable block
|
15
15
|
instead.
|