binding_ninja 0.2.3-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b66d0731f1c2fe0136ba3a23ce1cb9f655ac06725b5b95aed488f0f4377e88f9
4
+ data.tar.gz: e666c029b27565e1e4d5d9b9cbc68bb3e2133a0e0be34c865df6e8e69fd670a4
5
+ SHA512:
6
+ metadata.gz: 8380b55a908470485b0234415421fd86ee05fd0668c68ab6079c82124eb9d71d3e4a3c10bfbc466ed913fffb603f27c586345a12415d4b04037a6739542176d7
7
+ data.tar.gz: c0abe947390250d3cd211c0db58d0efbcbd9496503eb5c38791e184dd1037ef035d8b8cba073fec50a9617282ebb5be33402f68f47032a6899721801d11dc121
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ lib/binding_ninja/binding_ninja.jar
16
+
17
+ # rspec failure tracking
18
+ .rspec_status
19
+ .ruby-version
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,8 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.5.5
5
+ - 2.6.3
6
+ - jruby-9.2.6.0
7
+ - jruby-9.2.7.0
8
+ before_install: gem install bundler -v 2.0.1
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in binding_ninja.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 joker1007
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,145 @@
1
+ # BindingNinja
2
+ [![Gem Version](https://badge.fury.io/rb/binding_ninja.svg)](https://badge.fury.io/rb/binding_ninja)
3
+ [![Build Status](https://travis-ci.org/joker1007/binding_ninja.svg?branch=master)](https://travis-ci.org/joker1007/binding_ninja)
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)
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'binding_ninja'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install binding_ninja
23
+
24
+ ## Usage
25
+
26
+ ```ruby
27
+ class Foo
28
+ extend BindingNinja
29
+
30
+ def foo(binding, arg1, arg2)
31
+ p binding
32
+ p arg1
33
+ p arg2
34
+ end
35
+ auto_inject_binding :foo
36
+
37
+ def foo2(binding, arg1, arg2)
38
+ p binding
39
+ p arg1
40
+ p arg2
41
+ end
42
+ auto_inject_binding :foo2, if: ENV["ENABLE_BINDING_NINJA"]
43
+ # or
44
+ auto_inject_binding :foo2, if: ->(obj) { obj.enable_auto_inject_binding? }
45
+ # or
46
+ auto_inject_binding :foo2, if: :enable_auto_inject_binding?
47
+
48
+ def enable_auto_inject_binding?
49
+ true
50
+ end
51
+ end
52
+
53
+ Foo.new.foo(1, 2)
54
+ # => <Binding of toplevel>
55
+ # => 1
56
+ # => 2
57
+
58
+ # if ENABLE_BINDING_NINJA environment variable is nil or false,
59
+ # binding arguments is nil.
60
+ Foo.new.foo2(1, 2)
61
+ # => nil
62
+ # => 1
63
+ # => 2
64
+ ```
65
+
66
+ `:if` option can accept Proc object and Symbol object.
67
+ If option accepts a proc or symbol, uses result of evaluating the proc or method named by the symbol.
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
+
133
+ ## Development
134
+
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.
136
+
137
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
138
+
139
+ ## Contributing
140
+
141
+ Bug reports and pull requests are welcome on GitHub at https://github.com/joker1007/binding_ninja.
142
+
143
+ ## License
144
+
145
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :build => :compile
7
+
8
+ case RUBY_PLATFORM
9
+ when /java/
10
+ require 'rake/javaextensiontask'
11
+ Rake::JavaExtensionTask.new('binding_ninja') do |ext|
12
+ ext.lib_dir = "lib/binding_ninja"
13
+ ext.source_version = '1.8'
14
+ ext.target_version = '1.8'
15
+ end
16
+ else
17
+ require 'rake/extensiontask'
18
+ Rake::ExtensionTask.new("binding_ninja") do |ext|
19
+ ext.lib_dir = "lib/binding_ninja"
20
+ end
21
+ end
22
+
23
+ task :default => [:clobber, :compile, :spec]
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
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "binding_ninja"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "binding_ninja/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "binding_ninja"
8
+ spec.version = BindingNinja::VERSION
9
+ spec.authors = ["joker1007"]
10
+ spec.email = ["kakyoin.hierophant@gmail.com"]
11
+
12
+ spec.summary = %q{pass binding of method caller implicitly}
13
+ spec.description = %q{pass binding of method caller implicitly}
14
+ spec.homepage = "https://github.com/joker1007/binding_ninja"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ case RUBY_PLATFORM
25
+ when /java/
26
+ spec.platform = "java"
27
+ spec.files << "lib/binding_ninja/binding_ninja.jar"
28
+ else
29
+ spec.extensions = ["ext/binding_ninja/extconf.rb"]
30
+ end
31
+
32
+ spec.add_development_dependency "bundler", ">= 1.15"
33
+ spec.add_development_dependency "rake", "~> 10.0"
34
+ spec.add_development_dependency "rake-compiler"
35
+ spec.add_development_dependency "rspec", "~> 3.0"
36
+ end
@@ -0,0 +1,18 @@
1
+ package io.github.joker1007;
2
+
3
+ import java.io.IOException;
4
+
5
+ import org.jruby.Ruby;
6
+ import org.jruby.RubyHash;
7
+ import org.jruby.RubyModule;
8
+ import org.jruby.runtime.load.BasicLibraryService;
9
+
10
+ public class BindingNinjaService implements BasicLibraryService {
11
+ @Override
12
+ public boolean basicLoad(final Ruby runtime) throws IOException {
13
+ RubyModule bindingNinja = runtime.defineModule("BindingNinja");
14
+ bindingNinja.setInstanceVariable("@auto_inject_binding_extensions", RubyHash.newHash(runtime));
15
+ bindingNinja.defineAnnotatedMethods(RubyBindingNinja.class);
16
+ return true;
17
+ }
18
+ }
@@ -0,0 +1,154 @@
1
+ package io.github.joker1007;
2
+
3
+ import java.util.stream.Stream;
4
+ import org.jruby.anno.JRubyMethod;
5
+ import org.jruby.anno.JRubyModule;
6
+ import org.jruby.ast.util.ArgsUtil;
7
+ import org.jruby.internal.runtime.methods.JavaMethod;
8
+ import org.jruby.Ruby;
9
+ import org.jruby.RubyBasicObject;
10
+ import org.jruby.RubyBinding;
11
+ import org.jruby.RubyClass;
12
+ import org.jruby.RubyHash;
13
+ import org.jruby.RubyMethod;
14
+ import org.jruby.RubyModule;
15
+ import org.jruby.RubyProc;
16
+ import org.jruby.RubySymbol;
17
+ import org.jruby.runtime.Block;
18
+ import org.jruby.runtime.Constants;
19
+ import org.jruby.runtime.builtin.IRubyObject;
20
+ import org.jruby.runtime.Helpers;
21
+ import org.jruby.runtime.ThreadContext;
22
+ import org.jruby.runtime.Visibility;
23
+
24
+ @JRubyModule(name = "BindingNinja")
25
+ public class RubyBindingNinja {
26
+ static String OPTIONS_ID = "@auto_inject_binding_options";
27
+ static String EXTENSIONS_ID = "@auto_inject_binding_extensions";
28
+ static Integer[] jrubyVersionNums = Stream.of(Constants.VERSION.split("\\.")).map(Integer::parseInt).toArray(Integer[]::new);
29
+
30
+ @JRubyMethod(name = "auto_inject_binding", module = true, visibility = Visibility.PRIVATE, required = 1, optional = 1)
31
+ public static IRubyObject autoInjectBinding(ThreadContext context, IRubyObject recv, IRubyObject[] args) {
32
+ final Ruby runtime = context.getRuntime();
33
+
34
+ final IRubyObject extensions = runtime.getModule("BindingNinja").getInstanceVariable(EXTENSIONS_ID);
35
+ final IRubyObject methodSym = args[0];
36
+
37
+ IRubyObject ivar = ((RubyModule)recv).getInstanceVariable(OPTIONS_ID);
38
+ final IRubyObject options;
39
+ if (ivar.isTrue()) {
40
+ options = ivar;
41
+ } else {
42
+ options = RubyHash.newHash(runtime);
43
+ ((RubyModule)recv).setInstanceVariable(OPTIONS_ID, options);
44
+ }
45
+
46
+ IRubyObject extModTmp =
47
+ extensions instanceof RubyHash ?
48
+ ((RubyHash)extensions).op_aref(context, recv) :
49
+ context.nil;
50
+ if (extModTmp.isNil()) {
51
+ extModTmp = RubyModule.newModule(runtime);
52
+ ((RubyHash)extensions).op_aset(context, recv, extModTmp);
53
+ }
54
+ final RubyModule extMod = (RubyModule)extModTmp;
55
+ if (!((RubyModule)recv).hasModuleInHierarchy(extMod)) {
56
+ ((RubyModule)recv).prependModule(extMod);
57
+ }
58
+
59
+ IRubyObject cond = RubyBasicObject.UNDEF;
60
+ if (args.length == 2) {
61
+ final RubyHash kwArgs = args[1].convertToHash();
62
+ final IRubyObject[] rets = ArgsUtil.extractKeywordArgs(runtime.getCurrentContext(), kwArgs, "if");
63
+ cond = rets[0];
64
+ }
65
+
66
+ if (cond != RubyBasicObject.UNDEF) {
67
+ ((RubyHash)options).op_aset(context, methodSym, cond);
68
+ }
69
+
70
+ final String mid = methodSym.asJavaString();
71
+ if (cond == RubyBasicObject.UNDEF) {
72
+ extMod.addMethod(mid, autoInjectBindingInvokeWithoutCond(extMod, mid));
73
+ } else {
74
+ final RubyClass klass = cond.getMetaClass().getRealClass();
75
+ if (klass == runtime.getProc() || klass == runtime.getSymbol()) {
76
+ extMod.addMethod(mid, autoInjectBindingInvoke(extMod, mid));
77
+ } else if (cond.isTrue()) {
78
+ extMod.addMethod(mid, autoInjectBindingInvokeWithoutCond(extMod, mid));
79
+ } else {
80
+ extMod.addMethod(mid, autoInjectBindingInvokeStub(extMod, mid));
81
+ }
82
+ }
83
+
84
+ return methodSym;
85
+ }
86
+
87
+ private static JavaMethod autoInjectBindingInvoke(final RubyModule extMod, String name) {
88
+ return new JavaMethod(extMod, Visibility.PUBLIC, name) {
89
+ @Override
90
+ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
91
+ final IRubyObject options = Helpers.invoke(context, self.getMetaClass(), "auto_inject_binding_options");
92
+ IRubyObject cond = ((org.jruby.RubyHash)options).op_aref(context, RubySymbol.newSymbol(context.getRuntime(), name));
93
+
94
+ final RubyClass klass = cond.getMetaClass().getRealClass();
95
+ if (klass == context.getRuntime().getProc()) {
96
+ if (Math.abs(((RubyProc)cond).arity().getIntValue()) > 0) {
97
+ cond = ((RubyProc)cond).call(context, new IRubyObject[]{self});
98
+ } else {
99
+ cond = ((RubyProc)cond).call(context, new IRubyObject[]{});
100
+ }
101
+ } else if (klass == context.getRuntime().getSymbol()) {
102
+ final IRubyObject method = ((RubyBasicObject)self).method(cond);
103
+ final IRubyObject proc = ((RubyMethod) method).to_proc(context);
104
+ cond = ((RubyProc)proc).call(context, new IRubyObject[]{});
105
+ }
106
+
107
+ final IRubyObject[] unshiftedArgs = new IRubyObject[args.length + 1];
108
+ if (cond.isTrue()) {
109
+ unshiftedArgs[0] = RubyBinding.newBinding(context.getRuntime(), context.currentBinding());
110
+ } else {
111
+ unshiftedArgs[0] = context.nil;
112
+ }
113
+ System.arraycopy(args, 0, unshiftedArgs, 1, args.length);
114
+ if (jrubyVersionNums[0] >= 9 && jrubyVersionNums[1] >= 2 && jrubyVersionNums[2] >= 7) {
115
+ return Helpers.invokeSuper(context, self, clazz, name, unshiftedArgs, block);
116
+ } else {
117
+ return Helpers.invokeSuper(context, self, extMod, name, unshiftedArgs, block);
118
+ }
119
+ }
120
+ };
121
+ }
122
+
123
+ private static JavaMethod autoInjectBindingInvokeStub(final RubyModule extMod, String name) {
124
+ return new JavaMethod(extMod, Visibility.PUBLIC, name) {
125
+ @Override
126
+ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
127
+ final IRubyObject[] unshiftedArgs = new IRubyObject[args.length + 1];
128
+ unshiftedArgs[0] = context.nil;
129
+ System.arraycopy(args, 0, unshiftedArgs, 1, args.length);
130
+ if (jrubyVersionNums[0] >= 9 && jrubyVersionNums[1] >= 2 && jrubyVersionNums[2] >= 7) {
131
+ return Helpers.invokeSuper(context, self, clazz, name, unshiftedArgs, block);
132
+ } else {
133
+ return Helpers.invokeSuper(context, self, extMod, name, unshiftedArgs, block);
134
+ }
135
+ }
136
+ };
137
+ }
138
+
139
+ private static JavaMethod autoInjectBindingInvokeWithoutCond(final RubyModule extMod, String name) {
140
+ return new JavaMethod(extMod, Visibility.PUBLIC, name) {
141
+ @Override
142
+ public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
143
+ final IRubyObject[] unshiftedArgs = new IRubyObject[args.length + 1];
144
+ unshiftedArgs[0] = RubyBinding.newBinding(context.getRuntime(), context.currentBinding());
145
+ System.arraycopy(args, 0, unshiftedArgs, 1, args.length);
146
+ if (jrubyVersionNums[0] >= 9 && jrubyVersionNums[1] >= 2 && jrubyVersionNums[2] >= 7) {
147
+ return Helpers.invokeSuper(context, self, clazz, name, unshiftedArgs, block);
148
+ } else {
149
+ return Helpers.invokeSuper(context, self, extMod, name, unshiftedArgs, block);
150
+ }
151
+ }
152
+ };
153
+ }
154
+ }
@@ -0,0 +1,137 @@
1
+ #include "binding_ninja.h"
2
+
3
+ VALUE rb_mBindingNinja;
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);
7
+
8
+ static ID options_id;
9
+
10
+ static VALUE
11
+ auto_inject_binding(int argc, VALUE *argv, VALUE mod)
12
+ {
13
+ ID mid;
14
+ static ID extensions_id;
15
+ static ID keyword_ids[1];
16
+ VALUE extensions, ext_mod, method_sym, options, opt, cond;
17
+
18
+ cond = Qundef;
19
+
20
+ if (!keyword_ids[0]) {
21
+ keyword_ids[0] = rb_intern("if");
22
+ }
23
+
24
+ if (!extensions_id) {
25
+ extensions_id = rb_intern("@auto_inject_binding_extensions");
26
+ }
27
+
28
+ if (rb_ivar_defined(mod, options_id)) {
29
+ options = rb_ivar_get(mod, options_id);
30
+ } else {
31
+ options = rb_hash_new();
32
+ rb_ivar_set(mod, options_id, options);
33
+ }
34
+
35
+ rb_scan_args(argc, argv, "1:", &method_sym, &opt);
36
+ if (!NIL_P(opt)) {
37
+ rb_get_kwargs(opt, keyword_ids, 0, 1, &cond);
38
+ if (cond != Qundef) {
39
+ rb_hash_aset(options, method_sym, cond);
40
+ }
41
+ }
42
+
43
+ mid = SYM2ID(method_sym);
44
+ if (abs(rb_mod_method_arity(mod, mid)) < 1) {
45
+ rb_raise(rb_eArgError, "target method receives 1 or more arguments");
46
+ }
47
+
48
+ extensions = rb_ivar_get(rb_mBindingNinja, extensions_id);
49
+ ext_mod = rb_hash_aref(extensions, mod);
50
+ if (NIL_P(ext_mod)) {
51
+ ext_mod = rb_module_new();
52
+ rb_hash_aset(extensions, mod, ext_mod);
53
+ }
54
+
55
+ if (rb_mod_include_p(mod, ext_mod) == Qfalse) {
56
+ rb_prepend_module(mod, ext_mod);
57
+ }
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
+ }
70
+
71
+ return method_sym;
72
+ }
73
+
74
+ static VALUE
75
+ auto_inject_binding_invoke(int argc, VALUE *argv, VALUE self)
76
+ {
77
+ VALUE method_sym, ext_mod, options, binding, args_ary, cond;
78
+ static VALUE dummy_proc_args, dummy_method_arg[0];
79
+
80
+ if (!dummy_proc_args) {
81
+ dummy_proc_args = rb_ary_new();
82
+ rb_obj_freeze(dummy_proc_args);
83
+ }
84
+
85
+ method_sym = ID2SYM(rb_frame_this_func());
86
+ options = rb_funcall(CLASS_OF(self), rb_intern("auto_inject_binding_options"), 0);
87
+
88
+ cond = rb_hash_lookup2(options, method_sym, Qtrue);
89
+
90
+ if (rb_obj_is_proc(cond)) {
91
+ if (abs(rb_proc_arity(cond)) > 0) {
92
+ cond = rb_proc_call(cond, rb_ary_new_from_args(1, self));
93
+ } else {
94
+ cond = rb_proc_call(cond, dummy_proc_args);
95
+ }
96
+ } else if (SYMBOL_P(cond)) {
97
+ cond = rb_method_call(0, dummy_method_arg, rb_obj_method(self, cond));
98
+ }
99
+
100
+ args_ary = rb_ary_new_from_values(argc, argv);
101
+ if (RTEST(cond)) {
102
+ binding = rb_binding_new();
103
+ rb_ary_unshift(args_ary, binding);
104
+ } else {
105
+ rb_ary_unshift(args_ary, Qnil);
106
+ }
107
+ return rb_call_super(argc + 1, RARRAY_CONST_PTR(args_ary));
108
+ }
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
+
130
+ void
131
+ Init_binding_ninja(void)
132
+ {
133
+ rb_mBindingNinja = rb_define_module("BindingNinja");
134
+ options_id = rb_intern("@auto_inject_binding_options");
135
+ rb_ivar_set(rb_mBindingNinja, rb_intern("@auto_inject_binding_extensions"), rb_hash_new());
136
+ rb_define_private_method(rb_mBindingNinja, "auto_inject_binding", auto_inject_binding, -1);
137
+ }
@@ -0,0 +1,6 @@
1
+ #ifndef BINDING_NINJA_H
2
+ #define BINDING_NINJA_H 1
3
+
4
+ #include "ruby.h"
5
+
6
+ #endif /* BINDING_NINJA_H */
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile("binding_ninja/binding_ninja")
@@ -0,0 +1,41 @@
1
+ require "binding_ninja/version"
2
+
3
+ if /java/ =~ RUBY_PLATFORM
4
+ require_relative 'binding_ninja/binding_ninja.jar'
5
+ Java::IoGithubJoker1007::BindingNinjaService.new.basicLoad(JRuby.runtime)
6
+ else
7
+ require "binding_ninja/binding_ninja"
8
+ end
9
+
10
+ module BindingNinja
11
+ def auto_inject_binding_options
12
+ {}
13
+ end
14
+
15
+ METHOD_DEFINER = ->(klass) do
16
+ unless klass.method_defined?(:auto_inject_binding_options)
17
+ options = {}
18
+ klass.class_eval do
19
+ @auto_inject_binding_options = options
20
+ end
21
+
22
+ klass.define_singleton_method(:auto_inject_binding_options) do
23
+ super().merge(options)
24
+ end
25
+ end
26
+ end
27
+
28
+ def inherited(klass)
29
+ super
30
+ METHOD_DEFINER.call(klass)
31
+ end
32
+
33
+ def included(klass)
34
+ super
35
+ METHOD_DEFINER.call(klass)
36
+ end
37
+
38
+ def self.extended(klass)
39
+ METHOD_DEFINER.call(klass)
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module BindingNinja
2
+ VERSION = "0.2.3"
3
+ end
metadata ADDED
@@ -0,0 +1,118 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: binding_ninja
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.3
5
+ platform: java
6
+ authors:
7
+ - joker1007
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-04-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '1.15'
19
+ name: bundler
20
+ prerelease: false
21
+ type: :development
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '1.15'
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '10.0'
33
+ name: rake
34
+ prerelease: false
35
+ type: :development
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ name: rake-compiler
48
+ prerelease: false
49
+ type: :development
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.0'
61
+ name: rspec
62
+ prerelease: false
63
+ type: :development
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: pass binding of method caller implicitly
70
+ email:
71
+ - kakyoin.hierophant@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".travis.yml"
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - benchmark.rb
84
+ - bin/console
85
+ - bin/setup
86
+ - binding_ninja.gemspec
87
+ - ext/binding_ninja/BindingNinjaService.java
88
+ - ext/binding_ninja/RubyBindingNinja.java
89
+ - ext/binding_ninja/binding_ninja.c
90
+ - ext/binding_ninja/binding_ninja.h
91
+ - ext/binding_ninja/extconf.rb
92
+ - lib/binding_ninja.rb
93
+ - lib/binding_ninja/binding_ninja.jar
94
+ - lib/binding_ninja/version.rb
95
+ homepage: https://github.com/joker1007/binding_ninja
96
+ licenses:
97
+ - MIT
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubygems_version: 3.0.3
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: pass binding of method caller implicitly
118
+ test_files: []