#include "v8_ref.h" #include "v8_cast.h" #include "v8_context.h" #include "v8_errors.h" #include "v8_macros.h" using namespace v8; VALUE rb_cV8Context; UNWRAPPER(Context); /* V8::Context methods */ static VALUE rb_v8_context_enter(VALUE self); /* * call-seq: * V8::Context.new => new_context * * Returns new V8 context. * */ static VALUE rb_v8_context_new(VALUE self) { HandleScope scope; Persistent<Context> context(Context::New()); VALUE ref = v8_ref_new(self, context); rb_v8_context_enter(ref); rb_iv_set(ref, "@errors", rb_ary_new()); context.Dispose(); return ref; } /* * call-seq: * cxt.enter => true or false * cxt.enter { |cxt| ... } => nil * * Enters to context. Returns <code>true</code> when enter action has * been performed. If current context is already entered then returns * <code>false</code>. * * If block passed then context enters only for block execution, and * exits imidietely after that. * */ static VALUE rb_v8_context_enter(VALUE self) { HandleScope scope; Handle<Context> context = unwrap(self); VALUE entered = Qfalse; if (Context::GetEntered() != context) { context->Enter(); entered = Qtrue; } if (rb_block_given_p()) { rb_yield(self); context->Exit(); return Qnil; } return entered; } /* * call-seq: * cxt.eval(source, filename) => result * cxt.evaluate(source, filename) => result * * Evaluates given JavaScript code within current context. * * cxt = V8::Context.new * cxt.evaluate("1+1", "script.js") # => 2 * cxt.evaluate("var a=1", "<eval>") # => 1 * cxt.evaluate("var b=a+1", "<eval>") # => 2 * */ static VALUE rb_v8_context_evaluate(VALUE self, VALUE source, VALUE filename) { HandleScope scope; Local<String> _source(String::Cast(*to_v8(source))); Local<String> _filename(String::Cast(*to_v8(filename))); rb_v8_context_enter(self); rb_iv_set(self, "@error", Qfalse); TryCatch try_catch; Local<Script> script = Script::Compile(_source, _filename); if (!try_catch.HasCaught()) { Local<Value> result = script->Run(); if (!try_catch.HasCaught()) { return to_ruby(result); } } return rb_v8_error_new3(try_catch); } /* * call-seq: * cxt.prototype => obj * * Returns prototype object of current context. * */ VALUE rb_v8_context_prototype(VALUE self) { HandleScope scope; Handle<Object> proto(Object::Cast(*unwrap(self)->Global()->GetPrototype())); return to_ruby(proto); } /* * call-seq: * cxt.global => value * * Returns global object for this context. * */ static VALUE rb_v8_context_global(VALUE self) { HandleScope scope; Handle<Value> global = unwrap(self)->Global(); return to_ruby(global); } /* * call-seq: * cxt.entered? => true or false * * Returns <code>true</code> when this context is entered. * */ static VALUE rb_v8_context_entered_p(VALUE self) { HandleScope scope; return unwrap(self) == Context::GetEntered() ? Qtrue : Qfalse; } /* * call-seq: * cxt.exit => nil * * Exits from context. * */ static VALUE rb_v8_context_exit(VALUE self) { HandleScope scope; Handle<Context> context; if (Context::InContext()) { context->Exit(); } return Qnil; } /* * call-seq: * V8::Context.exit_all! => nil * * Exits from all entered context. * */ static VALUE rb_v8_context_exit_all_bang(VALUE klass) { HandleScope scope; while (Context::InContext()) { Context::GetEntered()->Exit(); } return Qnil; } /* V8::Context class initializer. */ void Init_V8_Context() { rb_cV8Context = rb_define_class_under(rb_mV8, "Context", rb_cObject); rb_define_singleton_method(rb_cV8Context, "new", RUBY_METHOD_FUNC(rb_v8_context_new), 0); rb_define_singleton_method(rb_cV8Context, "exit_all!", RUBY_METHOD_FUNC(rb_v8_context_exit_all_bang), 0); rb_define_method(rb_cV8Context, "evaluate", RUBY_METHOD_FUNC(rb_v8_context_evaluate), 2); rb_define_method(rb_cV8Context, "eval", RUBY_METHOD_FUNC(rb_v8_context_evaluate), 2); rb_define_method(rb_cV8Context, "prototype", RUBY_METHOD_FUNC(rb_v8_context_prototype), 0); rb_define_method(rb_cV8Context, "global", RUBY_METHOD_FUNC(rb_v8_context_global), 0); rb_define_method(rb_cV8Context, "enter", RUBY_METHOD_FUNC(rb_v8_context_enter), 0); rb_define_method(rb_cV8Context, "exit", RUBY_METHOD_FUNC(rb_v8_context_exit), 0); rb_define_method(rb_cV8Context, "entered?", RUBY_METHOD_FUNC(rb_v8_context_entered_p), 0); rb_define_attr(rb_cV8Context, "error", 1, 0); rb_define_attr(rb_cV8Context, "errors", 1, 0); }