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.
@@ -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
- switch(TYPE(object))
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
- */
@@ -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
- return ruby_hash_from(tomato, object);
42
- if (object->Get(String::New("_tomato_symbol"))->IsTrue())
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
- void inspect_js(V8Tomato *tomato, Handle<Value> obj)
118
+ static VALUE ruby_unwrapped_object_from(V8Tomato *tomato, const Handle<Object> &value)
119
119
  {
120
- VALUE rbObj = ruby_value_of(tomato, obj);
121
- VALUE rbStr = rb_funcall(rbObj, rb_intern("inspect"), 0);
122
- printf("%s\n", StringValuePtr(rbStr));
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
 
@@ -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
Binary file
@@ -38,7 +38,7 @@ makefile.print <<EOF
38
38
 
39
39
  test: all
40
40
  @echo Running specs...
41
- spec -O spec/spec.opts spec
41
+ spec spec -c
42
42
 
43
43
  EOF
44
44
  end
@@ -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.2-preview3/include/ruby-1.9.1/x86_64-darwin10.4.0 -I/Users/colin/.rvm/rubies/ruby-1.9.2-preview3/include/ruby-1.9.1/ruby/backward -I/Users/colin/.rvm/rubies/ruby-1.9.2-preview3/include/ruby-1.9.1 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long -fno-common -pipe conftest.c -L. -L/Users/colin/.rvm/rubies/ruby-1.9.2-preview3/lib -L. -L/usr/local/lib -lruby.1.9.1-static -lpthread -ldl -lobjc "
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.2-preview3/include/ruby-1.9.1/x86_64-darwin10.4.0 -I/Users/colin/.rvm/rubies/ruby-1.9.2-preview3/include/ruby-1.9.1/ruby/backward -I/Users/colin/.rvm/rubies/ruby-1.9.2-preview3/include/ruby-1.9.1 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long -fno-common -pipe conftest.c -o conftest.i"
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.2-preview3/include/ruby-1.9.1/x86_64-darwin10.4.0 -I/Users/colin/.rvm/rubies/ruby-1.9.2-preview3/include/ruby-1.9.1/ruby/backward -I/Users/colin/.rvm/rubies/ruby-1.9.2-preview3/include/ruby-1.9.1 -I. -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long -fno-common -pipe -I/Users/colin/projects/gems/tomato/ext/tomato/external/build/v8/include conftest.c -o conftest.i"
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.2-preview3/include/ruby-1.9.1/x86_64-darwin10.4.0 -I/Users/colin/.rvm/rubies/ruby-1.9.2-preview3/include/ruby-1.9.1/ruby/backward -I/Users/colin/.rvm/rubies/ruby-1.9.2-preview3/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 -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long -fno-common -pipe conftest.c -L. -L/Users/colin/.rvm/rubies/ruby-1.9.2-preview3/lib -L. -L/usr/local/lib -lruby.1.9.1-static -lpthread -lpthread -ldl -lobjc "
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.2-preview3/include/ruby-1.9.1/x86_64-darwin10.4.0 -I/Users/colin/.rvm/rubies/ruby-1.9.2-preview3/include/ruby-1.9.1/ruby/backward -I/Users/colin/.rvm/rubies/ruby-1.9.2-preview3/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 -O3 -ggdb -Wextra -Wno-unused-parameter -Wno-parentheses -Wpointer-arith -Wwrite-strings -Wno-missing-field-initializers -Wshorten-64-to-32 -Wno-long-long -fno-common -pipe conftest.c -L. -L/Users/colin/.rvm/rubies/ruby-1.9.2-preview3/lib -L. -L/usr/local/lib -lpthread -lruby.1.9.1-static -lobjc -lpthread -lpthread -ldl -lobjc "
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
+ }