boc 0.4.2-java

Sign up to get free protection for your applications and to get access to all the features.
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