binding_ninja 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +66 -0
- data/benchmark.rb +38 -0
- data/ext/binding_ninja/binding_ninja.c +42 -7
- data/lib/binding_ninja.rb +30 -0
- data/lib/binding_ninja/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 57eeb87ad943b9ab0093e5cbbd33ee92891a2180
|
4
|
+
data.tar.gz: 1a5246c9bdb73a8b83ed7f01c5f61c6882df4349
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1fadddaa3dd7b0f6cb31bbb9c1f531f4777ec83315b843fe7655cbcf49399ba3ae8e50e3a7288f6637d30e082374d9965d97ef36d073fe2ff24dd49bef57bacc
|
7
|
+
data.tar.gz: f7c154b4bc8de3a28e39c02ec4dd2645e82724839e843bdd9d71b6ab3af7891c5aa545d52c2274ce1cc7b8ec694fdb20d6ccfb7c97566552d951d03add4ffd4f
|
data/README.md
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
# BindingNinja
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/binding_ninja.svg)](https://badge.fury.io/rb/binding_ninja)
|
2
3
|
[![Build Status](https://travis-ci.org/joker1007/binding_ninja.svg?branch=master)](https://travis-ci.org/joker1007/binding_ninja)
|
3
4
|
|
4
5
|
This is method wrapper for passing binding of method caller implcitly.
|
6
|
+
And this is lightweight alternative of [binding_of_caller](https://github.com/banister/binding_of_caller)
|
5
7
|
|
6
8
|
## Installation
|
7
9
|
|
@@ -64,6 +66,70 @@ Foo.new.foo2(1, 2)
|
|
64
66
|
`:if` option can accept Proc object and Symbol object.
|
65
67
|
If option accepts a proc or symbol, uses result of evaluating the proc or method named by the symbol.
|
66
68
|
|
69
|
+
## Compare to binding_of_caller
|
70
|
+
```ruby
|
71
|
+
require "benchmark/ips"
|
72
|
+
require "binding_ninja"
|
73
|
+
require "binding_of_caller"
|
74
|
+
|
75
|
+
class Foo
|
76
|
+
extend BindingNinja
|
77
|
+
|
78
|
+
auto_inject_binding def foo1(b)
|
79
|
+
b.local_variables
|
80
|
+
end
|
81
|
+
|
82
|
+
def foo2
|
83
|
+
binding.of_caller(1).local_variables
|
84
|
+
end
|
85
|
+
|
86
|
+
def foo3(b)
|
87
|
+
b.local_variables
|
88
|
+
end
|
89
|
+
auto_inject_binding :foo3, if: :enable_auto_inject_binding?
|
90
|
+
|
91
|
+
def enable_auto_inject_binding?
|
92
|
+
true
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
foo = Foo.new
|
97
|
+
|
98
|
+
p foo.foo1
|
99
|
+
p foo.foo2
|
100
|
+
p foo.foo3
|
101
|
+
|
102
|
+
Benchmark.ips do |x|
|
103
|
+
x.report("binding_ninja") { foo.foo1 }
|
104
|
+
x.report("binding_ninja_with_condition") { foo.foo3 }
|
105
|
+
x.report("binding_of_caller") { foo.foo2 }
|
106
|
+
|
107
|
+
x.compare!
|
108
|
+
end
|
109
|
+
```
|
110
|
+
|
111
|
+
```
|
112
|
+
Warming up --------------------------------------
|
113
|
+
binding_ninja 106.598k i/100ms
|
114
|
+
binding_ninja_with_condition
|
115
|
+
49.660k i/100ms
|
116
|
+
binding_of_caller 6.799k i/100ms
|
117
|
+
Calculating -------------------------------------
|
118
|
+
binding_ninja 1.351M (± 0.4%) i/s - 6.822M in 5.051283s
|
119
|
+
binding_ninja_with_condition
|
120
|
+
566.555k (± 0.3%) i/s - 2.880M in 5.083895s
|
121
|
+
binding_of_caller 69.968k (± 0.8%) i/s - 353.548k in 5.053337s
|
122
|
+
|
123
|
+
Comparison:
|
124
|
+
binding_ninja: 1350619.1 i/s
|
125
|
+
binding_ninja_with_condition: 566555.1 i/s - 2.38x slower
|
126
|
+
binding_of_caller: 69968.2 i/s - 19.30x slower
|
127
|
+
|
128
|
+
```
|
129
|
+
|
130
|
+
13x - 16x faster than binding_of_caller.
|
131
|
+
And binding_ninja has very simple code base.
|
132
|
+
|
67
133
|
## Development
|
68
134
|
|
69
135
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/benchmark.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require "benchmark/ips"
|
2
|
+
require "binding_ninja"
|
3
|
+
require "binding_of_caller"
|
4
|
+
|
5
|
+
class Foo
|
6
|
+
extend BindingNinja
|
7
|
+
|
8
|
+
auto_inject_binding def foo1(b)
|
9
|
+
b.local_variables
|
10
|
+
end
|
11
|
+
|
12
|
+
def foo2
|
13
|
+
binding.of_caller(1).local_variables
|
14
|
+
end
|
15
|
+
|
16
|
+
def foo3(b)
|
17
|
+
b.local_variables
|
18
|
+
end
|
19
|
+
auto_inject_binding :foo3, if: :enable_auto_inject_binding?
|
20
|
+
|
21
|
+
def enable_auto_inject_binding?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
foo = Foo.new
|
27
|
+
|
28
|
+
p foo.foo1
|
29
|
+
p foo.foo2
|
30
|
+
p foo.foo3
|
31
|
+
|
32
|
+
Benchmark.ips do |x|
|
33
|
+
x.report("binding_ninja") { foo.foo1 }
|
34
|
+
x.report("binding_ninja_with_condition") { foo.foo3 }
|
35
|
+
x.report("binding_of_caller") { foo.foo2 }
|
36
|
+
|
37
|
+
x.compare!
|
38
|
+
end
|
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
VALUE rb_mBindingNinja;
|
4
4
|
static VALUE auto_inject_binding_invoke(int argc, VALUE *argv, VALUE self);
|
5
|
+
static VALUE auto_inject_binding_invoke_without_cond(int argc, VALUE *argv, VALUE self);
|
6
|
+
static VALUE auto_inject_binding_invoke_stub(int argc, VALUE *argv, VALUE self);
|
5
7
|
|
6
8
|
static ID options_id;
|
7
9
|
|
@@ -13,6 +15,8 @@ auto_inject_binding(int argc, VALUE *argv, VALUE mod)
|
|
13
15
|
static ID keyword_ids[1];
|
14
16
|
VALUE extensions, ext_mod, method_sym, options, opt, cond;
|
15
17
|
|
18
|
+
cond = Qundef;
|
19
|
+
|
16
20
|
if (!keyword_ids[0]) {
|
17
21
|
keyword_ids[0] = rb_intern("if");
|
18
22
|
}
|
@@ -21,11 +25,11 @@ auto_inject_binding(int argc, VALUE *argv, VALUE mod)
|
|
21
25
|
extensions_id = rb_intern("@auto_inject_binding_extensions");
|
22
26
|
}
|
23
27
|
|
24
|
-
if (
|
25
|
-
options =
|
28
|
+
if (rb_ivar_defined(mod, options_id)) {
|
29
|
+
options = rb_ivar_get(mod, options_id);
|
26
30
|
} else {
|
27
31
|
options = rb_hash_new();
|
28
|
-
|
32
|
+
rb_ivar_set(mod, options_id, options);
|
29
33
|
}
|
30
34
|
|
31
35
|
rb_scan_args(argc, argv, "1:", &method_sym, &opt);
|
@@ -51,7 +55,18 @@ auto_inject_binding(int argc, VALUE *argv, VALUE mod)
|
|
51
55
|
if (rb_mod_include_p(mod, ext_mod) == Qfalse) {
|
52
56
|
rb_prepend_module(mod, ext_mod);
|
53
57
|
}
|
54
|
-
|
58
|
+
|
59
|
+
if (cond == Qundef) {
|
60
|
+
rb_define_method_id(ext_mod, mid, auto_inject_binding_invoke_without_cond, -1);
|
61
|
+
} else if (rb_obj_is_proc(cond) || SYMBOL_P(cond)) {
|
62
|
+
rb_define_method_id(ext_mod, mid, auto_inject_binding_invoke, -1);
|
63
|
+
} else {
|
64
|
+
if (RTEST(cond)) {
|
65
|
+
rb_define_method_id(ext_mod, mid, auto_inject_binding_invoke_without_cond, -1);
|
66
|
+
} else {
|
67
|
+
rb_define_method_id(ext_mod, mid, auto_inject_binding_invoke_stub, -1);
|
68
|
+
}
|
69
|
+
}
|
55
70
|
|
56
71
|
return method_sym;
|
57
72
|
}
|
@@ -59,7 +74,7 @@ auto_inject_binding(int argc, VALUE *argv, VALUE mod)
|
|
59
74
|
static VALUE
|
60
75
|
auto_inject_binding_invoke(int argc, VALUE *argv, VALUE self)
|
61
76
|
{
|
62
|
-
VALUE method_sym, options, binding, args_ary, cond;
|
77
|
+
VALUE method_sym, ext_mod, options, binding, args_ary, cond;
|
63
78
|
static VALUE dummy_proc_args, dummy_method_arg[0];
|
64
79
|
|
65
80
|
if (!dummy_proc_args) {
|
@@ -68,7 +83,7 @@ auto_inject_binding_invoke(int argc, VALUE *argv, VALUE self)
|
|
68
83
|
}
|
69
84
|
|
70
85
|
method_sym = ID2SYM(rb_frame_this_func());
|
71
|
-
options =
|
86
|
+
options = rb_funcall(CLASS_OF(self), rb_intern("auto_inject_binding_options"), 0);
|
72
87
|
|
73
88
|
cond = rb_hash_lookup2(options, method_sym, Qtrue);
|
74
89
|
|
@@ -92,11 +107,31 @@ auto_inject_binding_invoke(int argc, VALUE *argv, VALUE self)
|
|
92
107
|
return rb_call_super(argc + 1, RARRAY_CONST_PTR(args_ary));
|
93
108
|
}
|
94
109
|
|
110
|
+
|
111
|
+
static VALUE
|
112
|
+
auto_inject_binding_invoke_without_cond(int argc, VALUE *argv, VALUE self)
|
113
|
+
{
|
114
|
+
VALUE args_ary, binding;
|
115
|
+
args_ary = rb_ary_new_from_values(argc, argv);
|
116
|
+
binding = rb_binding_new();
|
117
|
+
rb_ary_unshift(args_ary, binding);
|
118
|
+
return rb_call_super(argc + 1, RARRAY_CONST_PTR(args_ary));
|
119
|
+
}
|
120
|
+
|
121
|
+
static VALUE
|
122
|
+
auto_inject_binding_invoke_stub(int argc, VALUE *argv, VALUE self)
|
123
|
+
{
|
124
|
+
VALUE args_ary;
|
125
|
+
args_ary = rb_ary_new_from_values(argc, argv);
|
126
|
+
rb_ary_unshift(args_ary, Qnil);
|
127
|
+
return rb_call_super(argc + 1, RARRAY_CONST_PTR(args_ary));
|
128
|
+
}
|
129
|
+
|
95
130
|
void
|
96
131
|
Init_binding_ninja(void)
|
97
132
|
{
|
98
133
|
rb_mBindingNinja = rb_define_module("BindingNinja");
|
99
|
-
options_id = rb_intern("
|
134
|
+
options_id = rb_intern("@auto_inject_binding_options");
|
100
135
|
rb_ivar_set(rb_mBindingNinja, rb_intern("@auto_inject_binding_extensions"), rb_hash_new());
|
101
136
|
rb_define_private_method(rb_mBindingNinja, "auto_inject_binding", auto_inject_binding, -1);
|
102
137
|
}
|
data/lib/binding_ninja.rb
CHANGED
@@ -2,4 +2,34 @@ require "binding_ninja/version"
|
|
2
2
|
require "binding_ninja/binding_ninja"
|
3
3
|
|
4
4
|
module BindingNinja
|
5
|
+
def auto_inject_binding_options
|
6
|
+
{}
|
7
|
+
end
|
8
|
+
|
9
|
+
METHOD_DEFINER = ->(klass) do
|
10
|
+
unless klass.method_defined?(:auto_inject_binding_options)
|
11
|
+
options = {}
|
12
|
+
klass.class_eval do
|
13
|
+
@auto_inject_binding_options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
klass.define_singleton_method(:auto_inject_binding_options) do
|
17
|
+
super().merge(options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def inherited(klass)
|
23
|
+
super
|
24
|
+
METHOD_DEFINER.call(klass)
|
25
|
+
end
|
26
|
+
|
27
|
+
def included(klass)
|
28
|
+
super
|
29
|
+
METHOD_DEFINER.call(klass)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.extended(klass)
|
33
|
+
METHOD_DEFINER.call(klass)
|
34
|
+
end
|
5
35
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: binding_ninja
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- joker1007
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,6 +80,7 @@ files:
|
|
80
80
|
- Gemfile
|
81
81
|
- README.md
|
82
82
|
- Rakefile
|
83
|
+
- benchmark.rb
|
83
84
|
- bin/console
|
84
85
|
- bin/setup
|
85
86
|
- binding_ninja.gemspec
|
@@ -107,7 +108,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
108
|
version: '0'
|
108
109
|
requirements: []
|
109
110
|
rubyforge_project:
|
110
|
-
rubygems_version: 2.6.
|
111
|
+
rubygems_version: 2.6.13
|
111
112
|
signing_key:
|
112
113
|
specification_version: 4
|
113
114
|
summary: pass binding of method caller implicitly
|