Skip to content

Commit

Permalink
Add support for MRI 1.8.7 and jruby
Browse files Browse the repository at this point in the history
  • Loading branch information
ConradIrwin committed Aug 11, 2012
1 parent 691c36d commit 2b24551
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 53 deletions.
2 changes: 2 additions & 0 deletions ext/extconf.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
require 'mkmf'

$CFLAGS += " -DRUBY_19" if RUBY_VERSION =~ /1.9/

extension_name = "raise_awareness"
dir_config(extension_name)
create_makefile(extension_name)
42 changes: 38 additions & 4 deletions ext/raise_awareness.c
Original file line number Diff line number Diff line change
@@ -1,18 +1,52 @@
#include "ruby.h"

static VALUE rb_mRaiseAwareness;
static VALUE argv[1];

#ifdef RUBY_19

void
raise_awareness_hook(rb_event_flag_t evflag, VALUE data, VALUE self, ID mid, VALUE klass)
{
VALUE binding = rb_funcall(self, rb_intern("binding"), 0, NULL);
rb_funcall(data, rb_intern("rescue"), 2, rb_errinfo(), binding);
VALUE binding = rb_funcall(rb_mKernel, rb_intern("binding"), 0, NULL);
rb_funcall(rb_mRaiseAwareness, rb_intern("rescue"), 2, rb_errinfo(), binding);
}

VALUE
raise_awareness_start(VALUE self)
{
rb_add_event_hook(raise_awareness_hook, RUBY_EVENT_RAISE, rb_mRaiseAwareness);
}

#else

#include "node.h"

void
raise_awareness_hook(rb_event_t event, NODE *node, VALUE self, ID mid, VALUE klass)
{
VALUE binding = rb_funcall(rb_mKernel, rb_intern("binding"), 0, NULL);
rb_funcall(rb_mRaiseAwareness, rb_intern("rescue"), 2, ruby_errinfo, binding);
}

VALUE
raise_awareness_start(VALUE self)
{
rb_add_event_hook(raise_awareness_hook, RUBY_EVENT_RAISE);
}

#endif

VALUE
raise_awareness_stop(VALUE self)
{
rb_remove_event_hook(raise_awareness_hook);
return Qnil;
}

void
Init_raise_awareness()
{
rb_mRaiseAwareness = rb_define_module("RaiseAwareness");
rb_add_event_hook(raise_awareness_hook, RUBY_EVENT_RAISE, rb_mRaiseAwareness);
rb_define_singleton_method(rb_mRaiseAwareness, "start", raise_awareness_start, 0);
rb_define_singleton_method(rb_mRaiseAwareness, "stop", raise_awareness_start, 0);
}
149 changes: 100 additions & 49 deletions lib/raise_awareness.rb
Original file line number Diff line number Diff line change
@@ -1,78 +1,129 @@
require 'rubygems'
require 'thread'
require 'pry'
if defined? Rubinius
class << Rubinius

module RaiseAwareness

class << self
attr_accessor :mutex, :listeners
end

self.mutex = Mutex.new
self.listeners = []

alias raise_with_no_awareness raise_exception
def self.listen(for_block=nil, &listen_block)

def raise_exception(exc)
bt = Rubinius::VM.backtrace(1, true).drop_while do |x|
x.variables.method.file.to_s.start_with?("kernel/")
end.first
b = Binding.setup(bt.variables, bt.variables.method, bt.constant_scope, bt.variables.self, bt)
puts "FOOO"
raise "no block given" unless listen_block || for_block
listeners << listen_block || for_block
start

RaiseAwareness.rescue(exc, b)
raise_with_no_awareness(exc)
if listen_block && for_block
begin
for_block.call
ensure
unlisten listen_block
end
end
end

def binding_of_caller(n)
bt = Rubinius::VM.backtrace(1 + n, true).first
def self.unlisten(listen_block)
listeners.delete listen_block
stop if listeners.empty?
end

b = Binding.setup(
bt.variables,
bt.variables.method,
bt.constant_scope,
bt.variables.self,
bt
)
def self.rescue(e, binding)
listeners.each do |l|
l.call(e, binding)
end
end
end

if defined? Rubinius
module RaiseAwareness
def self.start
class << Rubinius
alias raise_with_no_awareness raise_exception

def raise_exception(exc)
bt = Rubinius::VM.backtrace(1, true).drop_while do |x|
x.variables.method.file.to_s.start_with?("kernel/")
end.first
b = Binding.setup(bt.variables, bt.variables.method, bt.constant_scope, bt.variables.self, bt)

RaiseAwareness.rescue(exc, b)
raise_with_no_awareness(exc)
end
end
end

def self.stop
alias raise_exception raise_with_no_awareness
end
end
elsif defined?(JRuby)
puts "HIHIIH"
$CLASSPATH << './org/pryrepl'
java_import org.pryrepl.RaiseAwarenessEventHook

module RaiseAwareness
private
def self.start
puts "START"
JRuby.runtime.add_event_hook(hook)
end

b.instance_variable_set(:@frame_description, bt.describe)
def self.stop
JRuby.runtime.remove_event_hook(hook)
end

b
def self.hook
@hook ||= RaiseAwarenessEventHook.new(proc do |e, b|
self.rescue(e, b)
end)
end
end

else
require './ext/raise_awareness.so'
end
module RaiseAwareness
def self.listeners; @listeners ||= []; end

def self.rescue(e, binding)
listeners.each do |l|
l.call(e, binding)
end
def pryly(&block)
raised = []

puts "listening"
RaiseAwareness.listen(block) do |exception, binding|
raised << [exception, binding]
end

def self.wrap
raises = []
listeners << proc{ |e, b| raises << [e, b] }
yield
ensure
listeners.pop
e, b = *raises.last
if b
$foo = e
$bar = raises
b.eval("_ex_ = $foo")
b.eval("_raises_ = $bar")
b.pry
end
ensure
if raised.last
e, b = *raised.last
$foo = e
$bar = raised
b.eval("_ex_ = $foo")
b.eval("_raised_ = $bar")
b.pry
end
end

RaiseAwareness.wrap do
begin
pryly do

def a
begin
raise "foo"
begin
raise "foo"

rescue => e
raise "bar"
end
rescue => e
raise "bar"
end

rescue => e
"woo".wibble
rescue => e
1 / 0

end
end
a
end
__END__

Expand Down
29 changes: 29 additions & 0 deletions org/pryrepl/RaiseAwarenessEventHook.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.pryrepl;

import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.EventHook;
import org.jruby.runtime.RubyEvent;
import org.jruby.runtime.ThreadContext;
import org.jruby.RubyException;
import org.jruby.RubyBinding;
import org.jruby.RubyProc;

public class RaiseAwarenessEventHook extends EventHook {

private RubyProc proc;

public RaiseAwarenessEventHook(RubyProc proc) {
super();
this.proc = proc;
}

public boolean isInterestedInEvent(RubyEvent event) {
return event.getName().equals(RubyEvent.RAISE.getName());
}

public void eventHandler(ThreadContext context, String eventName, String file, int line, String name, IRubyObject type) {
RubyBinding binding = RubyBinding.newBinding(context.runtime, context.currentBinding());
RubyException exception = (RubyException)context.runtime.getGlobalVariables().get("$!");
proc.call(context, new IRubyObject[] {exception, binding});
}
}

0 comments on commit 2b24551

Please sign in to comment.