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.
@@ -1,3 +1,3 @@
1
1
  class BindableBlock
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -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
- # match args to arity, since instance_method has lambda properties
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
@@ -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.2
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-03 00:00:00.000000000 Z
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.