tomato 0.0.1.prealpha1 → 0.0.1.prealpha2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +115 -31
- data/Rakefile +1 -0
- data/VERSION +1 -1
- data/ext/tomato/Makefile +32 -37
- data/ext/tomato/binding_methods.cpp +47 -20
- data/ext/tomato/binding_methods.h +8 -0
- data/ext/tomato/binding_methods.o +0 -0
- data/ext/tomato/conversions_to_js.cpp +15 -61
- data/ext/tomato/conversions_to_js.o +0 -0
- data/ext/tomato/conversions_to_rb.cpp +31 -8
- data/ext/tomato/conversions_to_rb.o +0 -0
- data/ext/tomato/depend +2 -1
- data/ext/tomato/errors.o +0 -0
- data/ext/tomato/extconf.rb +1 -1
- data/ext/tomato/mkmf.log +5 -5
- data/ext/tomato/object_chain.cpp +241 -0
- data/ext/tomato/object_chain.o +0 -0
- data/ext/tomato/tomato.bundle +0 -0
- data/ext/tomato/tomato.cpp +22 -2
- data/ext/tomato/tomato.h +5 -1
- data/ext/tomato/tomato.o +0 -0
- data/ext/tomato/v8.o +0 -0
- data/lib/tomato.rb +104 -2
- data/pkg/tomato-0.0.1.prealpha1.gem +0 -0
- data/spec/lib/bound_class_spec.rb +48 -0
- data/spec/lib/bound_methods_spec.rb +20 -0
- data/spec/lib/bound_object_spec.rb +33 -0
- data/spec/lib/conversions_spec.rb +16 -37
- data/t.rb +6 -0
- data/tomato.gemspec +14 -3
- metadata +30 -6
@@ -0,0 +1,8 @@
|
|
1
|
+
#ifndef BINDING_METHODS_H
|
2
|
+
#define BINDING_METHODS_H
|
3
|
+
|
4
|
+
extern Handle<Value> bound_method(const Arguments& args);
|
5
|
+
extern int store_rb_message(const Arguments &args, V8Tomato **out_tomato, VALUE *out_receiver, ID *out_method_id);
|
6
|
+
extern void store_args(V8Tomato *tomato, VALUE rbargs, const Arguments &args);
|
7
|
+
|
8
|
+
#endif//BINDING_METHODS_H
|
Binary file
|
@@ -4,6 +4,7 @@ static Handle<Value> js_array_from(V8Tomato *tomato, VALUE value);
|
|
4
4
|
static Handle<Value> js_hash_from(V8Tomato *tomato, VALUE value);
|
5
5
|
static Handle<Value> js_symbol_to_string(const Arguments& args);
|
6
6
|
static Handle<Value> js_symbol_from(VALUE value);
|
7
|
+
static Handle<Value> js_date_from(VALUE value);
|
7
8
|
|
8
9
|
Handle<Value> js_value_of(V8Tomato *tomato, VALUE value)
|
9
10
|
{
|
@@ -32,6 +33,16 @@ Handle<Value> js_value_of(V8Tomato *tomato, VALUE value)
|
|
32
33
|
else return js_symbol_from(value);
|
33
34
|
//return String::New(rb_id2name(SYM2ID(value)));
|
34
35
|
};
|
36
|
+
|
37
|
+
/* take care of some JS types that aren't reflected above */
|
38
|
+
if (rb_funcall(value, rb_intern("kind_of?"), 1, rb_const_get(rb_cObject, rb_intern("Date"))) == Qtrue ||
|
39
|
+
rb_funcall(value, rb_intern("kind_of?"), 1, rb_const_get(rb_cObject, rb_intern("Time"))) == Qtrue ||
|
40
|
+
rb_funcall(value, rb_intern("kind_of?"), 1, rb_const_get(rb_cObject, rb_intern("DateTime"))) == Qtrue ||
|
41
|
+
rb_funcall(value, rb_intern("kind_of?"), 1, rb_const_get(rb_const_get(rb_cObject, rb_intern("ActiveSupport")), rb_intern("TimeWithZone"))) == Qtrue)
|
42
|
+
{
|
43
|
+
return js_date_from(value);
|
44
|
+
}
|
45
|
+
|
35
46
|
return inspect_rb(value);
|
36
47
|
}
|
37
48
|
|
@@ -112,66 +123,9 @@ Handle<Value> inspect_rb(VALUE value)
|
|
112
123
|
return String::New(StringValuePtr(string));
|
113
124
|
}
|
114
125
|
|
115
|
-
|
116
|
-
Handle<Value> v8_value_of(V8Tomato *tomato, VALUE object)
|
126
|
+
Handle<Value> js_date_from(VALUE value)
|
117
127
|
{
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
case T_NIL :
|
122
|
-
case T_OBJECT :
|
123
|
-
//case T_CLASS :
|
124
|
-
//case T_MODULE :
|
125
|
-
case T_FLOAT :
|
126
|
-
case T_STRING :
|
127
|
-
case T_REGEXP :
|
128
|
-
case T_ARRAY :
|
129
|
-
case T_HASH :
|
130
|
-
//case T_STRUCT :
|
131
|
-
case T_BIGNUM :
|
132
|
-
case T_FIXNUM :
|
133
|
-
//case T_COMPLEX :
|
134
|
-
//case T_RATIONAL:
|
135
|
-
//case T_FILE :
|
136
|
-
case T_TRUE :
|
137
|
-
case T_FALSE :
|
138
|
-
//case T_DATA :
|
139
|
-
case T_SYMBOL :
|
140
|
-
symbol_from(object)
|
141
|
-
break;
|
142
|
-
default: string_from(object);
|
143
|
-
};
|
144
|
-
}
|
145
|
-
*/
|
146
|
-
/*
|
147
|
-
if (result->IsUndefined()) { return ID2SYM(rb_intern("undefined")); }
|
148
|
-
if (result->IsNull()) { return Qnil; }
|
149
|
-
if (result->IsTrue()) { return Qtrue; }
|
150
|
-
if (result->IsFalse()) { return Qfalse; }
|
151
|
-
if (result->IsString()) { return ruby_string_from(result); }
|
152
|
-
if (result->IsFunction()) { return ruby_string_from(result); }
|
153
|
-
if (result->IsArray()) { Handle<Array> array = Handle<Array>::Cast(result); return ruby_array_from(tomato, array); }
|
154
|
-
if (result->IsNumber()) { return ruby_numeric_from(result); }
|
155
|
-
if (result->IsDate()) { return ruby_date_from(result); }
|
156
|
-
|
157
|
-
|
158
|
-
if (result->IsObject())
|
159
|
-
{
|
160
|
-
Handle<Value> json = tomato->context->Global()->Get(String::New("JSON"));
|
161
|
-
if (json->IsObject())
|
162
|
-
{
|
163
|
-
Handle<Value> stringify = Handle<Object>::Cast(json)->Get(String::New("stringify"));
|
164
|
-
if (stringify->IsFunction())
|
165
|
-
{
|
166
|
-
String::Utf8Value str(Handle<Function>::Cast(stringify)->Call(
|
167
|
-
Handle<Object>::Cast(json),
|
168
|
-
1,
|
169
|
-
&result
|
170
|
-
));
|
171
|
-
return rb_str_new2(ToCString(str));
|
172
|
-
}
|
173
|
-
}
|
174
|
-
}
|
175
|
-
return Qnil;
|
128
|
+
VALUE ival = rb_funcall(value, rb_intern("to_f"), 0);
|
129
|
+
double time = NUM2DBL(ival) * 1000.0;
|
130
|
+
return Date::New(time);
|
176
131
|
}
|
177
|
-
*/
|
Binary file
|
@@ -5,6 +5,7 @@ static VALUE ruby_numeric_from(const Handle<Value> &number);
|
|
5
5
|
static VALUE ruby_date_from(const Handle<Value> &date);
|
6
6
|
static VALUE ruby_string_from(const Handle<Value> &value);
|
7
7
|
static VALUE ruby_symbol_from(const Handle<Object> &value);
|
8
|
+
static VALUE ruby_unwrapped_object_from(V8Tomato *tomato, const Handle<Object> &value);
|
8
9
|
static VALUE ruby_object_from(V8Tomato *tomato, Handle<Value> result);
|
9
10
|
static VALUE ruby_hash_from(V8Tomato *tomato, const Handle<Object> &object);
|
10
11
|
|
@@ -37,10 +38,9 @@ static VALUE ruby_object_from(V8Tomato *tomato, Handle<Value> result)
|
|
37
38
|
{
|
38
39
|
Handle<Object> object = Handle<Object>::Cast(result);
|
39
40
|
|
40
|
-
if (object->Get(String::New("_tomato_hash"))->IsTrue())
|
41
|
-
|
42
|
-
if (object->Get(String::New("
|
43
|
-
return ruby_symbol_from(object);
|
41
|
+
if (object->Get(String::New("_tomato_hash"))->IsTrue()) return ruby_hash_from(tomato, object);
|
42
|
+
if (object->Get(String::New("_tomato_symbol"))->IsTrue()) return ruby_symbol_from(object);
|
43
|
+
if (object->Get(String::New("_tomato_ruby_wrapper"))->IsTrue()) return ruby_unwrapped_object_from(tomato, object);
|
44
44
|
}
|
45
45
|
|
46
46
|
/* Call Javascript's JSON.stringify(object) method. If that can't be done for any reason, return nil. */
|
@@ -115,10 +115,33 @@ static VALUE ruby_numeric_from(const Handle<Value> &number)
|
|
115
115
|
return DBL2NUM(number->NumberValue());
|
116
116
|
}
|
117
117
|
|
118
|
-
|
118
|
+
static VALUE ruby_unwrapped_object_from(V8Tomato *tomato, const Handle<Object> &value)
|
119
119
|
{
|
120
|
-
VALUE
|
121
|
-
|
122
|
-
|
120
|
+
VALUE receivers = rb_funcall2(tomato->rb_instance, rb_intern("receivers"), 0, 0);
|
121
|
+
int len = RARRAY_LEN(receivers);
|
122
|
+
int index = value->Get(String::New("_tomato_receiver_index"))->Int32Value();
|
123
|
+
if (len <= index)
|
124
|
+
return Qnil;
|
125
|
+
return *(RARRAY_PTR(receivers)+index);
|
126
|
+
}
|
127
|
+
|
128
|
+
Handle<Value> inspect_js(V8Tomato *tomato, Handle<Value> obj)
|
129
|
+
{
|
130
|
+
/* Call Javascript's JSON.stringify(object) method. If that can't be done for any reason, return an error. */
|
131
|
+
Handle<Value> json = tomato->context->Global()->Get(String::New("JSON"));
|
132
|
+
if (json->IsObject())
|
133
|
+
{
|
134
|
+
Handle<Value> stringify = Handle<Object>::Cast(json)->Get(String::New("stringify"));
|
135
|
+
if (stringify->IsFunction())
|
136
|
+
{
|
137
|
+
String::Utf8Value str(Handle<Function>::Cast(stringify)->Call(
|
138
|
+
Handle<Object>::Cast(json),
|
139
|
+
1,
|
140
|
+
&obj
|
141
|
+
));
|
142
|
+
return String::New(ToCString(str));
|
143
|
+
}
|
144
|
+
}
|
145
|
+
return ThrowException(String::New("Could not JSONify the object"));
|
123
146
|
}
|
124
147
|
|
Binary file
|
data/ext/tomato/depend
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
-
binding_methods.o: binding_methods.cpp tomato.h
|
1
|
+
binding_methods.o: binding_methods.cpp tomato.h binding_methods.h
|
2
2
|
conversions_to_js.o: conversions_to_js.cpp tomato.h
|
3
3
|
conversions_to_rb.o: conversions_to_rb.cpp tomato.h
|
4
4
|
errors.o: errors.cpp tomato.h
|
5
|
+
object_chain.o: object_chain.cpp tomato.h binding_methods.h
|
5
6
|
tomato.o: tomato.cpp tomato.h
|
6
7
|
v8.o: v8.cpp tomato.h
|
data/ext/tomato/errors.o
CHANGED
Binary file
|
data/ext/tomato/extconf.rb
CHANGED
data/ext/tomato/mkmf.log
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
find_header: checking for v8.h in /Users/colin/projects/gems/tomato/ext/tomato/external/build/v8/include... -------------------- yes
|
2
2
|
|
3
|
-
"gcc -o conftest -I/Users/colin/.rvm/rubies/ruby-1.9.
|
3
|
+
"gcc -o conftest -I/Users/colin/.rvm/rubies/ruby-1.9.1-p378/include/ruby-1.9.1/i386-darwin10.4.0 -I/Users/colin/.rvm/rubies/ruby-1.9.1-p378/include/ruby-1.9.1/ruby/backward -I/Users/colin/.rvm/rubies/ruby-1.9.1-p378/include/ruby-1.9.1 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -O2 -g -Wall -Wno-parentheses -fno-common -pipe -fno-common conftest.c -L. -L/Users/colin/.rvm/rubies/ruby-1.9.1-p378/lib -L. -L/usr/local/lib -lruby-static -lpthread -ldl -lobjc "
|
4
4
|
checked program was:
|
5
5
|
/* begin */
|
6
6
|
1: #include "ruby.h"
|
@@ -8,7 +8,7 @@ checked program was:
|
|
8
8
|
3: int main() {return 0;}
|
9
9
|
/* end */
|
10
10
|
|
11
|
-
"gcc -E -I/Users/colin/.rvm/rubies/ruby-1.9.
|
11
|
+
"gcc -E -I/Users/colin/.rvm/rubies/ruby-1.9.1-p378/include/ruby-1.9.1/i386-darwin10.4.0 -I/Users/colin/.rvm/rubies/ruby-1.9.1-p378/include/ruby-1.9.1/ruby/backward -I/Users/colin/.rvm/rubies/ruby-1.9.1-p378/include/ruby-1.9.1 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -O2 -g -Wall -Wno-parentheses -fno-common -pipe -fno-common conftest.c -o conftest.i"
|
12
12
|
conftest.c:3:16: error: v8.h: No such file or directory
|
13
13
|
checked program was:
|
14
14
|
/* begin */
|
@@ -17,7 +17,7 @@ checked program was:
|
|
17
17
|
3: #include <v8.h>
|
18
18
|
/* end */
|
19
19
|
|
20
|
-
"gcc -E -I/Users/colin/.rvm/rubies/ruby-1.9.
|
20
|
+
"gcc -E -I/Users/colin/.rvm/rubies/ruby-1.9.1-p378/include/ruby-1.9.1/i386-darwin10.4.0 -I/Users/colin/.rvm/rubies/ruby-1.9.1-p378/include/ruby-1.9.1/ruby/backward -I/Users/colin/.rvm/rubies/ruby-1.9.1-p378/include/ruby-1.9.1 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -O2 -g -Wall -Wno-parentheses -fno-common -pipe -fno-common -I/Users/colin/projects/gems/tomato/ext/tomato/external/build/v8/include conftest.c -o conftest.i"
|
21
21
|
checked program was:
|
22
22
|
/* begin */
|
23
23
|
1: #include "ruby.h"
|
@@ -29,7 +29,7 @@ checked program was:
|
|
29
29
|
|
30
30
|
have_library: checking for main() in -lpthread... -------------------- yes
|
31
31
|
|
32
|
-
"gcc -o conftest -I/Users/colin/.rvm/rubies/ruby-1.9.
|
32
|
+
"gcc -o conftest -I/Users/colin/.rvm/rubies/ruby-1.9.1-p378/include/ruby-1.9.1/i386-darwin10.4.0 -I/Users/colin/.rvm/rubies/ruby-1.9.1-p378/include/ruby-1.9.1/ruby/backward -I/Users/colin/.rvm/rubies/ruby-1.9.1-p378/include/ruby-1.9.1 -I. -I/Users/colin/projects/gems/tomato/ext/tomato/external/build/v8/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -O2 -g -Wall -Wno-parentheses -fno-common -pipe -fno-common conftest.c -L. -L/Users/colin/.rvm/rubies/ruby-1.9.1-p378/lib -L. -L/usr/local/lib -lruby-static -lpthread -lpthread -ldl -lobjc "
|
33
33
|
checked program was:
|
34
34
|
/* begin */
|
35
35
|
1: #include "ruby.h"
|
@@ -43,7 +43,7 @@ checked program was:
|
|
43
43
|
|
44
44
|
have_library: checking for main() in -lobjc... -------------------- yes
|
45
45
|
|
46
|
-
"gcc -o conftest -I/Users/colin/.rvm/rubies/ruby-1.9.
|
46
|
+
"gcc -o conftest -I/Users/colin/.rvm/rubies/ruby-1.9.1-p378/include/ruby-1.9.1/i386-darwin10.4.0 -I/Users/colin/.rvm/rubies/ruby-1.9.1-p378/include/ruby-1.9.1/ruby/backward -I/Users/colin/.rvm/rubies/ruby-1.9.1-p378/include/ruby-1.9.1 -I. -I/Users/colin/projects/gems/tomato/ext/tomato/external/build/v8/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -O2 -g -Wall -Wno-parentheses -fno-common -pipe -fno-common conftest.c -L. -L/Users/colin/.rvm/rubies/ruby-1.9.1-p378/lib -L. -L/usr/local/lib -lpthread -lruby-static -lobjc -lpthread -lpthread -ldl -lobjc "
|
47
47
|
checked program was:
|
48
48
|
/* begin */
|
49
49
|
1: #include "ruby.h"
|
@@ -0,0 +1,241 @@
|
|
1
|
+
#include "tomato.h"
|
2
|
+
#include "binding_methods.h"
|
3
|
+
|
4
|
+
static VALUE create_new(VALUE args);
|
5
|
+
static v8::Handle<v8::Value> ruby_class_constructor(const Arguments &args);
|
6
|
+
static Handle<Value> bind_methods(Local<Object> js, VALUE rb, V8Tomato *tomato);
|
7
|
+
static Handle<Value> bound_getter(Local<String> property, const AccessorInfo &info);
|
8
|
+
static void bound_setter(Local<String> property, Local<Value> value, const AccessorInfo &info);
|
9
|
+
static VALUE protected_get(VALUE args);
|
10
|
+
static VALUE protected_set(VALUE args);
|
11
|
+
|
12
|
+
VALUE fTomato_bind_class(VALUE self, VALUE receiver_index, VALUE chain)
|
13
|
+
{
|
14
|
+
V8Tomato *tomato;
|
15
|
+
Data_Get_Struct(self, V8Tomato, tomato);
|
16
|
+
|
17
|
+
HandleScope handle_scope;
|
18
|
+
Context::Scope context_scope(tomato->context);
|
19
|
+
VALUE js_class_name = rb_ary_pop(chain);
|
20
|
+
// This is kind of a misnomer. We're creating a JavaScript function ("method") to stand in for
|
21
|
+
// the Ruby class. So the method_name has to be the Ruby class name. Consider: "new" is not a
|
22
|
+
// method in JS -- it's a keyword.
|
23
|
+
Handle<String> method_name = String::New(StringValuePtr(js_class_name));
|
24
|
+
Handle<Value> parent = find_or_create_object_chain(tomato, chain);
|
25
|
+
|
26
|
+
if (parent->IsObject())
|
27
|
+
{
|
28
|
+
Handle<Object> object = Handle<Object>::Cast(parent);
|
29
|
+
Handle<Function> function = FunctionTemplate::New(ruby_class_constructor)->GetFunction();
|
30
|
+
|
31
|
+
function->Set(String::New("_tomato"), External::New(tomato));
|
32
|
+
function->Set(String::New("_tomato_receiver_index"), Int32::New(FIX2INT(receiver_index)));
|
33
|
+
function->SetName(method_name);
|
34
|
+
|
35
|
+
Handle<Value> current_value = object->Get(method_name);
|
36
|
+
if (current_value->IsObject())
|
37
|
+
{
|
38
|
+
// we're about to overwrite an object. First clone any of its registered functions.
|
39
|
+
Handle<Object> current = Handle<Object>::Cast(current_value);
|
40
|
+
Local<Array> properties = current->GetPropertyNames();
|
41
|
+
int length = properties->Length();
|
42
|
+
for (int i = 0; i < length; i++)
|
43
|
+
{
|
44
|
+
Local<Value> property = properties->Get(i);
|
45
|
+
String::Utf8Value stra(inspect_js(tomato, property));
|
46
|
+
String::Utf8Value str(inspect_js(tomato, current->Get(property)));
|
47
|
+
function->Set(property, current->Get(property));
|
48
|
+
}
|
49
|
+
}
|
50
|
+
object->Set(method_name, function);
|
51
|
+
return Qtrue;
|
52
|
+
}
|
53
|
+
return Qfalse;
|
54
|
+
}
|
55
|
+
|
56
|
+
v8::Handle<v8::Value> ruby_class_constructor(const Arguments &args)
|
57
|
+
{
|
58
|
+
// throw if called without `new'
|
59
|
+
if (!args.IsConstructCall())
|
60
|
+
return ThrowException(String::New("Cannot call constructor as function"));
|
61
|
+
|
62
|
+
// we get the method ID and then call it, so that any C++ destructors that need to fire before
|
63
|
+
// we do so, can.
|
64
|
+
VALUE receiver;
|
65
|
+
ID rb_method_id;
|
66
|
+
V8Tomato *tomato;
|
67
|
+
int code = store_rb_message(args, &tomato, &receiver, &rb_method_id);
|
68
|
+
switch(code)
|
69
|
+
{
|
70
|
+
case -1: return ThrowException(String::New("Error: _tomato is not an object (BUG: please report)"));
|
71
|
+
case -2: return ThrowException(String::New("Error: _tomato_receiver_index is not an Int32 (BUG: please report)"));
|
72
|
+
case -3: return ThrowException(String::New("Error: _tomato_receiver_index is greater than @receivers.length (BUG: please report)"));
|
73
|
+
};
|
74
|
+
|
75
|
+
VALUE rbargs = rb_ary_new2(1+args.Length());
|
76
|
+
rb_ary_store(rbargs, 0, receiver);
|
77
|
+
store_args(tomato, rbargs, args);
|
78
|
+
|
79
|
+
int error;
|
80
|
+
VALUE result = rb_protect(create_new, rbargs, &error);
|
81
|
+
if(error)
|
82
|
+
{
|
83
|
+
return ThrowException(js_error_from(rb_gv_get("$!")));
|
84
|
+
}
|
85
|
+
|
86
|
+
Local<Object> holder = args.Holder();
|
87
|
+
holder->Set(String::New("_tomato_ruby_wrapper"), Boolean::New(true), DontEnum);
|
88
|
+
holder->Set(String::New("_tomato_receiver_index"),
|
89
|
+
Int32::New(FIX2INT(rb_funcall(tomato->rb_instance, rb_intern("receiver_index"), 1, result))), DontEnum);
|
90
|
+
return bind_methods(holder, result, tomato);
|
91
|
+
}
|
92
|
+
|
93
|
+
Handle<Value> bind_methods(Local<Object> js, VALUE rb, V8Tomato *tomato)
|
94
|
+
{
|
95
|
+
VALUE methods = rb_funcall(rb, rb_intern("public_methods"), 0);
|
96
|
+
int receiver_index = FIX2INT(rb_funcall(tomato->rb_instance, rb_intern("receiver_index"), 1, rb));
|
97
|
+
|
98
|
+
HandleScope handle_scope;
|
99
|
+
Context::Scope context_scope(tomato->context);
|
100
|
+
Handle<String> method_name;
|
101
|
+
js->Set(String::New("_tomato"), External::New(tomato));
|
102
|
+
for (int i = 0; i < RARRAY_LEN(methods); i++)
|
103
|
+
{
|
104
|
+
method_name = String::New(StringValuePtr(*(RARRAY_PTR(methods)+i)));
|
105
|
+
Handle<Function> function = FunctionTemplate::New(bound_method)->GetFunction();
|
106
|
+
|
107
|
+
function->Set(String::New("_tomato"), External::New(tomato));
|
108
|
+
function->Set(String::New("_tomato_receiver_index"), Int32::New(receiver_index));
|
109
|
+
function->SetName(method_name);
|
110
|
+
|
111
|
+
js->Set(method_name, function);
|
112
|
+
js->SetAccessor(method_name, bound_getter, bound_setter);
|
113
|
+
}
|
114
|
+
return js;
|
115
|
+
}
|
116
|
+
|
117
|
+
static VALUE protected_get(VALUE args)
|
118
|
+
{
|
119
|
+
VALUE receiver = *(RARRAY_PTR(args));
|
120
|
+
VALUE method = *(RARRAY_PTR(args)+1);
|
121
|
+
return rb_funcall2(receiver, SYM2ID(method), 0, 0);
|
122
|
+
}
|
123
|
+
|
124
|
+
static VALUE protected_set(VALUE args)
|
125
|
+
{
|
126
|
+
VALUE receiver = *(RARRAY_PTR(args));
|
127
|
+
VALUE method = *(RARRAY_PTR(args)+1);
|
128
|
+
VALUE value = *(RARRAY_PTR(args)+2);
|
129
|
+
|
130
|
+
method = rb_funcall(method, rb_intern("to_s"), 0);
|
131
|
+
method = rb_funcall(method, rb_intern("+"), 1, rb_str_new2("="));
|
132
|
+
return rb_funcall2(receiver, rb_intern(StringValuePtr(method)), 1, &value);
|
133
|
+
return Qnil;
|
134
|
+
}
|
135
|
+
|
136
|
+
static Handle<Value> bound_getter(Local<String> property, const AccessorInfo &info)
|
137
|
+
{
|
138
|
+
int error;
|
139
|
+
Local<Object> self = info.Holder();
|
140
|
+
|
141
|
+
// pull the binding data from the function (stored there by fTomato_bind_method)
|
142
|
+
Local<Value> v8_tomato = self->Get(String::New("_tomato"));
|
143
|
+
Local<Value> v8_receiver_index = self->Get(String::New("_tomato_receiver_index"));
|
144
|
+
|
145
|
+
// make sure the data is what we expect it to be
|
146
|
+
if (!v8_tomato->IsExternal()) return ThrowException(String::New("_tomato is not an external! (bug: please report)"));
|
147
|
+
if (!v8_receiver_index->IsInt32()) return ThrowException(String::New("_tomato_receiver_index is not an Int32! (bug: please report)"));
|
148
|
+
|
149
|
+
// find the tomato
|
150
|
+
V8Tomato *tomato = (V8Tomato *)Local<External>::Cast(v8_tomato)->Value();
|
151
|
+
|
152
|
+
// find the receiver index, and make sure it's a valid index
|
153
|
+
int receiver_index = v8_receiver_index->Int32Value();
|
154
|
+
VALUE receivers = rb_iv_get(tomato->rb_instance, "@receivers"); //rb_funcall(tomato->rb_instance, rb_intern("receivers"));
|
155
|
+
if (RARRAY_LEN(receivers) < receiver_index) return ThrowException(String::New("_tomato_receiver_index is too small! (bug: please report)"));
|
156
|
+
|
157
|
+
// get the receiver
|
158
|
+
VALUE receiver = (RARRAY_PTR(receivers)[receiver_index]);
|
159
|
+
|
160
|
+
VALUE args = rb_ary_new();
|
161
|
+
String::Utf8Value property_name(property);
|
162
|
+
rb_ary_push(args, receiver);
|
163
|
+
rb_ary_push(args, ID2SYM(rb_intern(ToCString(property_name))));
|
164
|
+
VALUE result = rb_protect(protected_get, args, &error);
|
165
|
+
if (error)
|
166
|
+
return ThrowException(js_error_from(rb_gv_get("$!")));
|
167
|
+
return js_value_of(tomato, result);
|
168
|
+
}
|
169
|
+
|
170
|
+
static void bound_setter(Local<String> property, Local<Value> value, const AccessorInfo &info)
|
171
|
+
{
|
172
|
+
int error;
|
173
|
+
Local<Object> self = info.Holder();
|
174
|
+
|
175
|
+
// pull the binding data from the function (stored there by fTomato_bind_method)
|
176
|
+
Local<Value> v8_tomato = self->Get(String::New("_tomato"));
|
177
|
+
Local<Value> v8_receiver_index = self->Get(String::New("_tomato_receiver_index"));
|
178
|
+
|
179
|
+
// make sure the data is what we expect it to be
|
180
|
+
if (!v8_tomato->IsExternal()) { ThrowException(String::New("_tomato is not an external! (bug: please report)")); return; }
|
181
|
+
if (!v8_receiver_index->IsInt32()) { ThrowException(String::New("_tomato_receiver_index is not an Int32! (bug: please report)")); return; }
|
182
|
+
|
183
|
+
// find the tomato
|
184
|
+
V8Tomato *tomato = (V8Tomato *)Local<External>::Cast(v8_tomato)->Value();
|
185
|
+
|
186
|
+
// find the receiver index, and make sure it's a valid index
|
187
|
+
int receiver_index = v8_receiver_index->Int32Value();
|
188
|
+
VALUE receivers = rb_iv_get(tomato->rb_instance, "@receivers"); //rb_funcall(tomato->rb_instance, rb_intern("receivers"));
|
189
|
+
if (RARRAY_LEN(receivers) < receiver_index) { ThrowException(String::New("_tomato_receiver_index is too small! (bug: please report)")); return; }
|
190
|
+
|
191
|
+
// get the receiver
|
192
|
+
VALUE receiver = (RARRAY_PTR(receivers)[receiver_index]);
|
193
|
+
|
194
|
+
VALUE args = rb_ary_new();
|
195
|
+
String::Utf8Value property_name(property);
|
196
|
+
rb_ary_push(args, receiver);
|
197
|
+
rb_ary_push(args, ID2SYM(rb_intern(ToCString(property_name))));
|
198
|
+
rb_ary_push(args, ruby_value_of(tomato, value));
|
199
|
+
rb_protect(protected_set, args, &error);
|
200
|
+
if (error)
|
201
|
+
ThrowException(js_error_from(rb_gv_get("$!")));
|
202
|
+
}
|
203
|
+
|
204
|
+
static VALUE create_new(VALUE args)
|
205
|
+
{
|
206
|
+
VALUE receiver = rb_ary_shift(args);
|
207
|
+
VALUE result = rb_funcall2(receiver, rb_intern("new"), RARRAY_LEN(args), RARRAY_PTR(args));
|
208
|
+
return result;
|
209
|
+
}
|
210
|
+
|
211
|
+
Handle<Value> find_or_create_object_chain(V8Tomato *tomato, VALUE chain)
|
212
|
+
{
|
213
|
+
Handle<Value> value = tomato->context->Global();
|
214
|
+
if (value->IsObject())
|
215
|
+
{
|
216
|
+
Handle<Object> object = Handle<Object>::Cast(value);
|
217
|
+
if (chain != Qnil)
|
218
|
+
{
|
219
|
+
int len = RARRAY_LEN(chain);
|
220
|
+
VALUE *items = RARRAY_PTR(chain);
|
221
|
+
|
222
|
+
for (int i = 0; i < len; i++)
|
223
|
+
{
|
224
|
+
Handle<String> object_name = String::New(StringValuePtr(items[i]));
|
225
|
+
value = object->Get(object_name);
|
226
|
+
if (value->IsObject())
|
227
|
+
{
|
228
|
+
object = Handle<Object>::Cast(value);
|
229
|
+
}
|
230
|
+
else
|
231
|
+
{
|
232
|
+
Handle<Object> new_object = Object::New();
|
233
|
+
object->Set(object_name, new_object);
|
234
|
+
object = new_object;
|
235
|
+
}
|
236
|
+
}
|
237
|
+
}
|
238
|
+
return object;
|
239
|
+
}
|
240
|
+
return value;
|
241
|
+
}
|