boc 0.4.2-java

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/ext/boc/boc.c ADDED
@@ -0,0 +1,136 @@
1
+ #include "ruby.h"
2
+
3
+ VALUE
4
+ rb_funcall_passing_block(VALUE recv, ID mid, int argc, const VALUE *argv) ;
5
+
6
+ static VALUE cBoc ;
7
+
8
+ static VALUE basic_object_method_sym ;
9
+
10
+ struct dispatch_args
11
+ {
12
+ int argc ;
13
+ VALUE* argv ;
14
+ VALUE self ;
15
+ ID method_id ;
16
+ } ;
17
+
18
+ static VALUE
19
+ begin_section( VALUE data )
20
+ {
21
+ struct dispatch_args* dargs = (struct dispatch_args*)data ;
22
+
23
+ return rb_funcall_passing_block(
24
+ dargs->self,
25
+ dargs->method_id,
26
+ dargs->argc,
27
+ dargs->argv) ;
28
+ }
29
+
30
+ static VALUE
31
+ ensure_section( VALUE unused )
32
+ {
33
+ rb_ary_pop(
34
+ rb_funcall(
35
+ cBoc,
36
+ rb_intern("stack"),
37
+ 0)) ;
38
+
39
+ return Qnil ;
40
+ }
41
+
42
+ static VALUE
43
+ dispatch_common( VALUE method_sym, int argc, VALUE *argv, VALUE self )
44
+ {
45
+ struct dispatch_args dargs ;
46
+
47
+ dargs.argc = argc ;
48
+ dargs.argv = argv ;
49
+ dargs.self = self ;
50
+
51
+ dargs.method_id =
52
+ rb_to_id(
53
+ rb_str_plus(
54
+ rb_sym_to_s(method_sym),
55
+ rb_str_new2("__impl"))) ;
56
+
57
+ rb_ary_push(
58
+ rb_funcall(
59
+ cBoc,
60
+ rb_intern("stack"),
61
+ 0),
62
+ rb_binding_new()) ;
63
+
64
+ return rb_ensure(
65
+ begin_section,
66
+ (VALUE)&dargs,
67
+ ensure_section,
68
+ Qnil) ;
69
+ }
70
+
71
+ static VALUE
72
+ dispatch_normal( int argc, VALUE *argv, VALUE self )
73
+ {
74
+ return dispatch_common(
75
+ rb_funcall(
76
+ self,
77
+ rb_intern("__method__"),
78
+ 0),
79
+ argc,
80
+ argv,
81
+ self) ;
82
+ }
83
+
84
+ static VALUE
85
+ dispatch_basic_object(int argc, VALUE *argv, VALUE self)
86
+ {
87
+ return dispatch_common(
88
+ basic_object_method_sym,
89
+ argc,
90
+ argv,
91
+ self) ;
92
+ }
93
+
94
+ static VALUE
95
+ enable_ext( VALUE self, VALUE klass, VALUE method_sym )
96
+ {
97
+ rb_define_method(
98
+ klass,
99
+ RSTRING_PTR(rb_sym_to_s(method_sym)),
100
+ dispatch_normal,
101
+ -1) ;
102
+
103
+ return Qnil ;
104
+ }
105
+
106
+ static VALUE
107
+ enable_basic_object_ext( VALUE self, VALUE klass, VALUE method_sym )
108
+ {
109
+ basic_object_method_sym = method_sym ;
110
+
111
+ rb_define_method(
112
+ klass,
113
+ RSTRING_PTR(rb_sym_to_s(method_sym)),
114
+ dispatch_basic_object,
115
+ -1) ;
116
+
117
+ return Qnil ;
118
+ }
119
+
120
+ void
121
+ Init_boc()
122
+ {
123
+ cBoc = rb_define_module("Boc") ;
124
+
125
+ rb_define_singleton_method(
126
+ cBoc,
127
+ "enable_ext",
128
+ enable_ext,
129
+ 2) ;
130
+
131
+ rb_define_singleton_method(
132
+ cBoc,
133
+ "enable_basic_object_ext",
134
+ enable_basic_object_ext,
135
+ 2) ;
136
+ }
@@ -0,0 +1,2 @@
1
+ require 'mkmf'
2
+ create_makefile('boc')
@@ -0,0 +1,111 @@
1
+ package boc ;
2
+
3
+ import org.jruby.Ruby ;
4
+ import org.jruby.RubyModule ;
5
+ import org.jruby.RubyBinding ;
6
+ import org.jruby.RubySymbol ;
7
+ import org.jruby.RubyClass ;
8
+ import org.jruby.anno.JRubyMethod ;
9
+ import org.jruby.exceptions.RaiseException ;
10
+ import org.jruby.runtime.Arity ;
11
+ import org.jruby.runtime.Block ;
12
+ import org.jruby.runtime.ThreadContext ;
13
+ import org.jruby.runtime.callback.Callback ;
14
+ import org.jruby.runtime.builtin.IRubyObject ;
15
+ import org.jruby.runtime.load.BasicLibraryService ;
16
+
17
+ public class BocService implements BasicLibraryService
18
+ {
19
+ static RubyModule s_boc ;
20
+ static RubyClass s_removed_error ;
21
+
22
+ public boolean basicLoad( Ruby ruby )
23
+ {
24
+ s_boc = ruby.defineModule("Boc") ;
25
+
26
+ s_boc.getSingletonClass().
27
+ defineAnnotatedMethods(SingletonMethods.class) ;
28
+
29
+ s_removed_error = ruby.defineClassUnder(
30
+ "InformationRemovedError",
31
+ ruby.getException(),
32
+ ruby.getException().getAllocator(),
33
+ s_boc) ;
34
+
35
+ return true ;
36
+ }
37
+
38
+ public static class SingletonMethods
39
+ {
40
+ @JRubyMethod( name = "enable_ext", alias = {"enable_basic_object_ext"} )
41
+ public static IRubyObject
42
+ s_enable_ext( IRubyObject recv, IRubyObject klass, IRubyObject sym )
43
+ {
44
+ String method_name = ((RubySymbol)sym).toString() ;
45
+
46
+ ((RubyModule)klass).defineMethod(
47
+ method_name,
48
+ new Dispatcher(method_name + "__impl")) ;
49
+
50
+ return recv.getRuntime().getNil() ;
51
+ }
52
+ }
53
+
54
+ public static class Dispatcher implements Callback
55
+ {
56
+ String m_impl ;
57
+
58
+ public Dispatcher( String impl )
59
+ {
60
+ m_impl = impl ;
61
+ }
62
+
63
+ public IRubyObject
64
+ execute( IRubyObject recv, IRubyObject[] args, Block block )
65
+ {
66
+ Ruby ruby = recv.getRuntime() ;
67
+ ThreadContext context = ruby.getCurrentContext() ;
68
+ IRubyObject stack = s_boc.callMethod(context, "stack") ;
69
+
70
+ stack.callMethod(
71
+ context,
72
+ "push",
73
+ RubyBinding.newBinding(ruby, context.previousBinding())) ;
74
+
75
+ try
76
+ {
77
+ return recv.callMethod(context, m_impl, args, block) ;
78
+ }
79
+ catch( java.lang.NullPointerException e )
80
+ {
81
+ throw new RaiseException(
82
+ ruby, s_removed_error, s_error_msg, true) ;
83
+ }
84
+ finally
85
+ {
86
+ stack.callMethod(context, "pop") ;
87
+ }
88
+ }
89
+
90
+ public Arity getArity()
91
+ {
92
+ return Arity.OPTIONAL ;
93
+ }
94
+ }
95
+
96
+ static String s_error_msg = "\n" +
97
+ "\n" +
98
+ "__________________________________________________________________\n" +
99
+ "Boc (binding of caller) failed because JRuby removed the necessary\n" +
100
+ "information. To prevent this from happening, pass the following\n" +
101
+ "command-line flag to jruby:\n" +
102
+ "\n" +
103
+ " -J-Djruby.astInspector.enabled=false\n" +
104
+ "\n" +
105
+ "Alternatively, place a do-nothing block somewhere in the caller:\n" +
106
+ "\n" +
107
+ " p { }\n" +
108
+ " # ...your code...\n" +
109
+ "\n" +
110
+ "==================================================================\n" ;
111
+ }
data/lib/boc.rb ADDED
@@ -0,0 +1,108 @@
1
+ require 'boc/boc'
2
+
3
+ module Boc
4
+ #
5
+ # :singleton-method: enable
6
+ # :call-seq: enable(klass, method_name)
7
+ #
8
+ # Enable <code>Boc.value</code> for the given instance method.
9
+ #
10
+ # class A
11
+ # def f
12
+ # p eval("x", Boc.value)
13
+ # end
14
+ #
15
+ # def self.g
16
+ # p eval("x", Boc.value)
17
+ # end
18
+ # end
19
+ #
20
+ # Boc.enable A, :f
21
+ # Boc.enable A.singleton_class, :g
22
+ #
23
+ # x = 33
24
+ # A.new.f # => 33
25
+ # A.g # => 33
26
+ #
27
+
28
+ #
29
+ # <code>Boc.value</code> was called outside of an
30
+ # <code>enable</code>d method.
31
+ #
32
+ class NotEnabledError < StandardError
33
+ end
34
+
35
+ #
36
+ # The method given to <code>Boc.enable</code> appears to have been
37
+ # already enabled.
38
+ #
39
+ class AlreadyEnabledError < StandardError
40
+ end
41
+
42
+ class << self
43
+ #
44
+ # Returns the binding of the caller. May only be used within an
45
+ # <code>enable</code>d method.
46
+ #
47
+ def value
48
+ if stack.empty?
49
+ raise NotEnabledError, "Boc.value called outside of an enabled method"
50
+ end
51
+ stack.last
52
+ end
53
+
54
+ [:enable, :enable_basic_object].each do |def_method|
55
+ define_method def_method do |klass, method_name|
56
+ MODULE_EVAL.bind(klass).call do
57
+ visibility = Boc.visibility klass, method_name
58
+
59
+ impl = "#{method_name}__impl"
60
+ Boc.check_enabled klass, method_name, impl
61
+
62
+ Boc.no_warn { alias_method impl, method_name }
63
+ Boc.send "#{def_method}_ext", klass, method_name
64
+
65
+ send visibility, method_name
66
+ public impl # needs to work with rb_funcall_passing_block
67
+ end
68
+ end
69
+ end
70
+
71
+ def stack #:nodoc:
72
+ Thread.current[:_boc_stack] ||= []
73
+ end
74
+
75
+ #
76
+ # squelch alias warnings
77
+ #
78
+ def no_warn #:nodoc:
79
+ prev = $VERBOSE
80
+ $VERBOSE = nil
81
+ begin
82
+ yield
83
+ ensure
84
+ $VERBOSE = prev
85
+ end
86
+ end
87
+
88
+ def visibility(klass, method_name) #:nodoc:
89
+ if klass.public_instance_methods.include?(method_name)
90
+ :public
91
+ elsif klass.protected_instance_methods.include?(method_name)
92
+ :protected
93
+ else
94
+ :private
95
+ end
96
+ end
97
+
98
+ def check_enabled(klass, method_name, impl) #:nodoc:
99
+ if klass.method_defined?(impl) or klass.private_method_defined?(impl)
100
+ raise AlreadyEnabledError,
101
+ "Boc.enable: refusing to overwrite `#{impl}' -- " <<
102
+ "method `#{method_name}' appears to be already enabled"
103
+ end
104
+ end
105
+ end
106
+
107
+ MODULE_EVAL = Module.instance_method(:module_eval) #:nodoc:
108
+ end
@@ -0,0 +1,11 @@
1
+ #
2
+ # compatibility with the old-style Binding.of_caller from 1.8
3
+ #
4
+
5
+ require 'boc'
6
+
7
+ class Binding
8
+ def self.of_caller
9
+ yield Boc.value
10
+ end
11
+ end
data/lib/boc/boc.jar ADDED
Binary file
@@ -0,0 +1,3 @@
1
+ module Boc
2
+ VERSION = "0.4.2"
3
+ end
@@ -0,0 +1,209 @@
1
+ require_relative 'main'
2
+
3
+ class BasicTest < BocTest
4
+ MEMO = {}
5
+
6
+ def setup
7
+ MEMO.clear
8
+ end
9
+
10
+ class A
11
+ def f(y, z)
12
+ MEMO[:x] = eval("x", Boc.value)
13
+ MEMO[:y] = y
14
+ MEMO[:z] = z
15
+ 66
16
+ end
17
+
18
+ def g
19
+ x = 33
20
+ f(44, 55)
21
+ end
22
+ end
23
+
24
+ def test_basic
25
+ assert_raises Boc::NotEnabledError do
26
+ Boc.value
27
+ end
28
+
29
+ Boc.enable A, :f
30
+
31
+ assert_nil MEMO[:x]
32
+ assert_nil MEMO[:y]
33
+ assert_nil MEMO[:z]
34
+
35
+ assert_equal 66, A.new.g
36
+
37
+ assert_equal 33, MEMO[:x]
38
+ assert_equal 44, MEMO[:y]
39
+ assert_equal 55, MEMO[:z]
40
+
41
+ assert_raises Boc::NotEnabledError do
42
+ Boc.value
43
+ end
44
+ end
45
+
46
+ class B
47
+ def foo(*args, &block)
48
+ MEMO[:args] = args
49
+ MEMO[:block] = block
50
+ eval("u", Boc.value) ;
51
+ end
52
+
53
+ def bar
54
+ u = 66
55
+ foo(77, 88) { |s| s + "zzz" }
56
+ end
57
+ end
58
+
59
+ def test_explicit_block
60
+ Boc.enable B, :foo
61
+
62
+ assert_nil MEMO[:args]
63
+ assert_nil MEMO[:block]
64
+
65
+ assert_equal 66, B.new.bar
66
+ assert_equal [77, 88], MEMO[:args]
67
+ assert_equal "zoozzz", MEMO[:block].call("zoo")
68
+ end
69
+
70
+ class C
71
+ def foo(*args)
72
+ MEMO[:args] = args
73
+ MEMO[:yield_result] = yield "moo"
74
+ eval("u", Boc.value) ;
75
+ end
76
+
77
+ def bar
78
+ u = 66
79
+ foo(77, 88) { |s| s + "zzz" }
80
+ end
81
+ end
82
+
83
+ def test_implicit_block
84
+ Boc.enable C, :foo
85
+
86
+ assert_nil MEMO[:args]
87
+ assert_nil MEMO[:yield_result]
88
+
89
+ assert_equal 66, C.new.bar
90
+ assert_equal [77, 88], MEMO[:args]
91
+ assert_equal "moozzz", MEMO[:yield_result]
92
+ end
93
+
94
+ module R
95
+ def self.factorial_of_x
96
+ x = eval("x", Boc.value) -
97
+ if caller.grep(/#{__method__}/).size == (RUBY_ENGINE == "jruby" ? 0 : 1)
98
+ 0
99
+ else
100
+ 1
101
+ end
102
+
103
+ if x == 0
104
+ 1
105
+ else
106
+ x*factorial_of_x
107
+ end
108
+ end
109
+ end
110
+
111
+ def test_recursive
112
+ Boc.enable R.singleton_class, :factorial_of_x
113
+
114
+ x = 5
115
+ assert_equal 120, R.factorial_of_x
116
+ x = 4
117
+ assert_equal 24, R.factorial_of_x
118
+ x = 1
119
+ assert_equal 1, R.factorial_of_x
120
+ x = 0
121
+ assert_equal 1, R.factorial_of_x
122
+ end
123
+
124
+ def test_basic_object
125
+ begin
126
+ BasicObject.module_eval do
127
+ def zoofoo
128
+ ::Kernel.eval("z", ::Boc.value)
129
+ end
130
+ end
131
+
132
+ Boc.enable_basic_object BasicObject, :zoofoo
133
+ z = 77
134
+ assert_equal 77, BasicObject.new.zoofoo
135
+ ensure
136
+ BasicObject.module_eval do
137
+ remove_method :zoofoo
138
+ end
139
+ end
140
+ end
141
+
142
+ class D
143
+ public
144
+ def f ; end
145
+
146
+ protected
147
+ def g ; end
148
+
149
+ private
150
+ def h ; end
151
+ end
152
+
153
+ def test_visibility
154
+ Boc.enable D, :f
155
+ Boc.enable D, :g
156
+ Boc.enable D, :h
157
+
158
+ assert D.public_instance_methods.include?(:f)
159
+ assert D.protected_instance_methods.include?(:g)
160
+ assert D.private_instance_methods.include?(:h)
161
+
162
+ D.new.f
163
+ D.new.instance_eval { g }
164
+ D.new.instance_eval { h }
165
+ end
166
+
167
+ class K
168
+ def f(bind)
169
+ eval("self", bind)
170
+ end
171
+
172
+ def self.g
173
+ self.new.f(binding)
174
+ end
175
+ end
176
+
177
+ def test_self_control
178
+ Boc.enable K, :f
179
+ assert_equal K, K.g
180
+ end
181
+
182
+ class L
183
+ def f
184
+ eval("self", Boc.value)
185
+ end
186
+
187
+ def self.g
188
+ self.new.f
189
+ end
190
+ end
191
+
192
+ def test_self
193
+ Boc.enable L, :f
194
+ assert_equal L, L.g
195
+ end
196
+
197
+ class K
198
+ def k
199
+ end
200
+ end
201
+
202
+ def test_double_enable
203
+ Boc.enable K, :k
204
+ error = assert_raises Boc::AlreadyEnabledError do
205
+ Boc.enable K, :k
206
+ end
207
+ assert_match(/method `k'.*already/, error.message)
208
+ end
209
+ end