jbarnette-johnson 1.0.0.200806240111
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +5 -0
- data/MANIFEST +385 -0
- data/MINGW32.mk +124 -0
- data/README.rdoc +51 -0
- data/Rakefile +166 -0
- data/bin/johnson +107 -0
- data/cross-compile.txt +38 -0
- data/ext/spidermonkey/context.c +122 -0
- data/ext/spidermonkey/context.h +19 -0
- data/ext/spidermonkey/conversions.c +286 -0
- data/ext/spidermonkey/conversions.h +18 -0
- data/ext/spidermonkey/debugger.c +208 -0
- data/ext/spidermonkey/debugger.h +9 -0
- data/ext/spidermonkey/extconf.rb +25 -0
- data/ext/spidermonkey/extensions.c +37 -0
- data/ext/spidermonkey/extensions.h +12 -0
- data/ext/spidermonkey/global.c +40 -0
- data/ext/spidermonkey/global.h +11 -0
- data/ext/spidermonkey/idhash.c +16 -0
- data/ext/spidermonkey/idhash.h +8 -0
- data/ext/spidermonkey/immutable_node.c.erb +522 -0
- data/ext/spidermonkey/immutable_node.h +22 -0
- data/ext/spidermonkey/jroot.h +187 -0
- data/ext/spidermonkey/js_land_proxy.c +609 -0
- data/ext/spidermonkey/js_land_proxy.h +20 -0
- data/ext/spidermonkey/ruby_land_proxy.c +537 -0
- data/ext/spidermonkey/ruby_land_proxy.h +17 -0
- data/ext/spidermonkey/runtime.c +304 -0
- data/ext/spidermonkey/runtime.h +25 -0
- data/ext/spidermonkey/spidermonkey.c +20 -0
- data/ext/spidermonkey/spidermonkey.h +29 -0
- data/js/johnson/browser.js +9 -0
- data/js/johnson/browser/env.js +687 -0
- data/js/johnson/browser/jquery.js +3444 -0
- data/js/johnson/browser/xmlsax.js +1564 -0
- data/js/johnson/browser/xmlw3cdom.js +4189 -0
- data/js/johnson/cli.js +30 -0
- data/js/johnson/prelude.js +80 -0
- data/js/johnson/template.js +29 -0
- data/lib/hoe.rb +748 -0
- data/lib/johnson.rb +46 -0
- data/lib/johnson/cli.rb +7 -0
- data/lib/johnson/cli/options.rb +56 -0
- data/lib/johnson/error.rb +4 -0
- data/lib/johnson/nodes.rb +7 -0
- data/lib/johnson/nodes/binary_node.rb +64 -0
- data/lib/johnson/nodes/for.rb +14 -0
- data/lib/johnson/nodes/for_in.rb +12 -0
- data/lib/johnson/nodes/function.rb +13 -0
- data/lib/johnson/nodes/list.rb +27 -0
- data/lib/johnson/nodes/node.rb +68 -0
- data/lib/johnson/nodes/ternary_node.rb +20 -0
- data/lib/johnson/parser.rb +21 -0
- data/lib/johnson/parser/syntax_error.rb +13 -0
- data/lib/johnson/runtime.rb +55 -0
- data/lib/johnson/spidermonkey/context.rb +10 -0
- data/lib/johnson/spidermonkey/debugger.rb +67 -0
- data/lib/johnson/spidermonkey/immutable_node.rb +280 -0
- data/lib/johnson/spidermonkey/js_land_proxy.rb +62 -0
- data/lib/johnson/spidermonkey/mutable_tree_visitor.rb +233 -0
- data/lib/johnson/spidermonkey/ruby_land_proxy.rb +52 -0
- data/lib/johnson/spidermonkey/runtime.rb +94 -0
- data/lib/johnson/version.rb +4 -0
- data/lib/johnson/visitable.rb +16 -0
- data/lib/johnson/visitors.rb +4 -0
- data/lib/johnson/visitors/dot_visitor.rb +167 -0
- data/lib/johnson/visitors/ecma_visitor.rb +315 -0
- data/lib/johnson/visitors/enumerating_visitor.rb +115 -0
- data/lib/johnson/visitors/sexp_visitor.rb +172 -0
- data/lib/rails/init.rb +37 -0
- data/test/assets/index.html +38 -0
- data/test/assets/jquery_test.html +186 -0
- data/test/helper.rb +58 -0
- data/test/johnson/browser_test.rb +38 -0
- data/test/johnson/conversions/array_test.rb +32 -0
- data/test/johnson/conversions/boolean_test.rb +17 -0
- data/test/johnson/conversions/callable_test.rb +34 -0
- data/test/johnson/conversions/file_test.rb +15 -0
- data/test/johnson/conversions/nil_test.rb +20 -0
- data/test/johnson/conversions/number_test.rb +34 -0
- data/test/johnson/conversions/regexp_test.rb +24 -0
- data/test/johnson/conversions/string_test.rb +26 -0
- data/test/johnson/conversions/struct_test.rb +15 -0
- data/test/johnson/conversions/symbol_test.rb +19 -0
- data/test/johnson/conversions/thread_test.rb +24 -0
- data/test/johnson/error_test.rb +9 -0
- data/test/johnson/extensions_test.rb +56 -0
- data/test/johnson/nodes/array_literal_test.rb +57 -0
- data/test/johnson/nodes/array_node_test.rb +26 -0
- data/test/johnson/nodes/binary_node_test.rb +61 -0
- data/test/johnson/nodes/bracket_access_test.rb +16 -0
- data/test/johnson/nodes/delete_test.rb +11 -0
- data/test/johnson/nodes/do_while_test.rb +12 -0
- data/test/johnson/nodes/dot_accessor_test.rb +15 -0
- data/test/johnson/nodes/export_test.rb +9 -0
- data/test/johnson/nodes/for_test.rb +54 -0
- data/test/johnson/nodes/function_test.rb +71 -0
- data/test/johnson/nodes/if_test.rb +41 -0
- data/test/johnson/nodes/import_test.rb +13 -0
- data/test/johnson/nodes/label_test.rb +19 -0
- data/test/johnson/nodes/object_literal_test.rb +110 -0
- data/test/johnson/nodes/return_test.rb +16 -0
- data/test/johnson/nodes/semi_test.rb +8 -0
- data/test/johnson/nodes/switch_test.rb +55 -0
- data/test/johnson/nodes/ternary_test.rb +25 -0
- data/test/johnson/nodes/throw_test.rb +9 -0
- data/test/johnson/nodes/try_node_test.rb +59 -0
- data/test/johnson/nodes/typeof_test.rb +11 -0
- data/test/johnson/nodes/unary_node_test.rb +23 -0
- data/test/johnson/nodes/void_test.rb +11 -0
- data/test/johnson/nodes/while_test.rb +26 -0
- data/test/johnson/nodes/with_test.rb +10 -0
- data/test/johnson/prelude_test.rb +56 -0
- data/test/johnson/runtime_test.rb +46 -0
- data/test/johnson/spidermonkey/context_test.rb +21 -0
- data/test/johnson/spidermonkey/immutable_node_test.rb +34 -0
- data/test/johnson/spidermonkey/js_land_proxy_test.rb +236 -0
- data/test/johnson/spidermonkey/ruby_land_proxy_test.rb +225 -0
- data/test/johnson/spidermonkey/runtime_test.rb +17 -0
- data/test/johnson/version_test.rb +13 -0
- data/test/johnson/visitors/dot_visitor_test.rb +39 -0
- data/test/johnson/visitors/enumerating_visitor_test.rb +12 -0
- data/test/johnson_test.rb +16 -0
- data/test/jquery_units/test.js +27 -0
- data/test/jquery_units/test_helper.js +197 -0
- data/test/jquery_units/units/ajax.js +795 -0
- data/test/jquery_units/units/core.js +1563 -0
- data/test/jquery_units/units/event.js +299 -0
- data/test/jquery_units/units/fx.js +427 -0
- data/test/jquery_units/units/offset.js +112 -0
- data/test/jquery_units/units/selector.js +224 -0
- data/test/jspec/helper.js +7 -0
- data/test/jspec/jspec.js +192 -0
- data/test/jspec/simple_spec.js +68 -0
- data/test/parser_test.rb +276 -0
- data/todo/.keep +0 -0
- metadata +501 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
#ifndef JOHNSON_SPIDERMONKEY_JS_LAND_PROXY_H
|
2
|
+
#define JOHNSON_SPIDERMONKEY_JS_LAND_PROXY_H
|
3
|
+
|
4
|
+
#include "spidermonkey.h"
|
5
|
+
#include "runtime.h"
|
6
|
+
|
7
|
+
bool js_value_is_proxy(JohnsonRuntime* runtime, jsval maybe_proxy);
|
8
|
+
VALUE unwrap_js_land_proxy(JohnsonRuntime* runtime, jsval proxy);
|
9
|
+
JSBool make_js_land_proxy(JohnsonRuntime* runtime, VALUE value, jsval* retval);
|
10
|
+
|
11
|
+
#include "node.h"
|
12
|
+
typedef struct {
|
13
|
+
VALUE klass, rklass;
|
14
|
+
VALUE recv;
|
15
|
+
ID id, oid;
|
16
|
+
int safe_level;
|
17
|
+
NODE *body;
|
18
|
+
} METHOD;
|
19
|
+
|
20
|
+
#endif
|
@@ -0,0 +1,537 @@
|
|
1
|
+
#include "ruby_land_proxy.h"
|
2
|
+
#include "conversions.h"
|
3
|
+
|
4
|
+
DECLARE_RUBY_WRAPPER(rb_call_super, int argc; const VALUE* argv)
|
5
|
+
DEFINE_RUBY_WRAPPER(rb_call_super, rb_call_super, ARGLIST2(argc, argv))
|
6
|
+
|
7
|
+
DECLARE_RUBY_WRAPPER(rb_yield, VALUE v)
|
8
|
+
DEFINE_RUBY_WRAPPER(rb_yield, rb_yield, ARGLIST1(v))
|
9
|
+
|
10
|
+
static VALUE proxy_class = Qnil;
|
11
|
+
|
12
|
+
static inline JSBool get_jsval_for_proxy(RubyLandProxy* proxy, jsval* jv)
|
13
|
+
{
|
14
|
+
*jv = (jsval)(proxy->key);
|
15
|
+
return JS_TRUE;
|
16
|
+
}
|
17
|
+
|
18
|
+
static VALUE call_js_function_value(JohnsonRuntime* runtime, jsval target, jsval function, int argc, VALUE* argv)
|
19
|
+
{
|
20
|
+
JSContext * context = johnson_get_current_context(runtime);
|
21
|
+
PREPARE_RUBY_JROOTS(context, argc + 2);
|
22
|
+
|
23
|
+
JROOT(target);
|
24
|
+
JROOT(function);
|
25
|
+
|
26
|
+
assert(JSVAL_IS_OBJECT(target));
|
27
|
+
|
28
|
+
jsval args[argc];
|
29
|
+
jsval result;
|
30
|
+
|
31
|
+
int i;
|
32
|
+
for(i = 0; i < argc; ++i)
|
33
|
+
{
|
34
|
+
JCHECK(convert_to_js(runtime, argv[i], &(args[i])));
|
35
|
+
JROOT(args[i]);
|
36
|
+
}
|
37
|
+
|
38
|
+
JCHECK(JS_CallFunctionValue(context,
|
39
|
+
JSVAL_TO_OBJECT(target), function, (unsigned) argc, args, &result));
|
40
|
+
|
41
|
+
JRETURN_RUBY(CONVERT_TO_RUBY(runtime, result));
|
42
|
+
}
|
43
|
+
|
44
|
+
/*
|
45
|
+
* call-seq:
|
46
|
+
* [](name)
|
47
|
+
*
|
48
|
+
* Returns the property with +name+.
|
49
|
+
*/
|
50
|
+
static VALUE
|
51
|
+
get(VALUE self, VALUE name)
|
52
|
+
{
|
53
|
+
RubyLandProxy* proxy;
|
54
|
+
Data_Get_Struct(self, RubyLandProxy, proxy);
|
55
|
+
|
56
|
+
JSContext * context = johnson_get_current_context(proxy->runtime);
|
57
|
+
PREPARE_RUBY_JROOTS(context, 1);
|
58
|
+
|
59
|
+
jsval proxy_value;
|
60
|
+
JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
|
61
|
+
JROOT(proxy_value);
|
62
|
+
|
63
|
+
jsval js_value;
|
64
|
+
|
65
|
+
switch(TYPE(name)) {
|
66
|
+
case T_FIXNUM:
|
67
|
+
JCHECK(JS_GetElement(context,
|
68
|
+
JSVAL_TO_OBJECT(proxy_value), NUM2INT(name), &js_value));
|
69
|
+
break;
|
70
|
+
default:
|
71
|
+
Check_Type(name, T_STRING);
|
72
|
+
JCHECK(JS_GetProperty(context,
|
73
|
+
JSVAL_TO_OBJECT(proxy_value), StringValueCStr(name), &js_value));
|
74
|
+
break;
|
75
|
+
}
|
76
|
+
|
77
|
+
JRETURN_RUBY(CONVERT_TO_RUBY(proxy->runtime, js_value));
|
78
|
+
}
|
79
|
+
|
80
|
+
/*
|
81
|
+
* call-seq:
|
82
|
+
* []=(name,value)
|
83
|
+
*
|
84
|
+
* Sets the property with +name+ to +value+.
|
85
|
+
*/
|
86
|
+
static VALUE
|
87
|
+
set(VALUE self, VALUE name, VALUE value)
|
88
|
+
{
|
89
|
+
RubyLandProxy* proxy;
|
90
|
+
Data_Get_Struct(self, RubyLandProxy, proxy);
|
91
|
+
JSContext * context = johnson_get_current_context(proxy->runtime);
|
92
|
+
|
93
|
+
PREPARE_RUBY_JROOTS(context, 2);
|
94
|
+
|
95
|
+
jsval proxy_value;
|
96
|
+
JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
|
97
|
+
JROOT(proxy_value);
|
98
|
+
|
99
|
+
jsval js_value;
|
100
|
+
JCHECK(convert_to_js(proxy->runtime, value, &js_value));
|
101
|
+
|
102
|
+
JROOT(js_value);
|
103
|
+
|
104
|
+
switch(TYPE(name)) {
|
105
|
+
case T_FIXNUM:
|
106
|
+
JCHECK(JS_SetElement(context,
|
107
|
+
JSVAL_TO_OBJECT(proxy_value), NUM2INT(name), &js_value));
|
108
|
+
break;
|
109
|
+
default:
|
110
|
+
Check_Type(name, T_STRING);
|
111
|
+
JCHECK(JS_SetProperty(context,
|
112
|
+
JSVAL_TO_OBJECT(proxy_value), StringValueCStr(name), &js_value));
|
113
|
+
break;
|
114
|
+
}
|
115
|
+
|
116
|
+
JRETURN_RUBY(value);
|
117
|
+
}
|
118
|
+
|
119
|
+
/*
|
120
|
+
* call-seq:
|
121
|
+
* function?
|
122
|
+
*
|
123
|
+
* Returns <code>true</code> if this is a function.
|
124
|
+
*/
|
125
|
+
static VALUE
|
126
|
+
function_p(VALUE self)
|
127
|
+
{
|
128
|
+
RubyLandProxy* proxy;
|
129
|
+
Data_Get_Struct(self, RubyLandProxy, proxy);
|
130
|
+
JSContext * context = johnson_get_current_context(proxy->runtime);
|
131
|
+
PREPARE_RUBY_JROOTS(context, 1);
|
132
|
+
jsval proxy_value;
|
133
|
+
JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
|
134
|
+
JROOT(proxy_value);
|
135
|
+
JRETURN_RUBY(JS_TypeOfValue(context, proxy_value) == JSTYPE_FUNCTION ? Qtrue : Qfalse);
|
136
|
+
}
|
137
|
+
|
138
|
+
/*
|
139
|
+
* call-seq:
|
140
|
+
* respond_to?(symbol)
|
141
|
+
*
|
142
|
+
* Returns <code>true</code> if _obj_ responds to given method.
|
143
|
+
*/
|
144
|
+
static VALUE
|
145
|
+
respond_to_p(VALUE self, VALUE sym)
|
146
|
+
{
|
147
|
+
RubyLandProxy* proxy;
|
148
|
+
Data_Get_Struct(self, RubyLandProxy, proxy);
|
149
|
+
|
150
|
+
JSContext * context = johnson_get_current_context(proxy->runtime);
|
151
|
+
PREPARE_RUBY_JROOTS(context, 2);
|
152
|
+
|
153
|
+
char* name = rb_id2name(SYM2ID(sym));
|
154
|
+
|
155
|
+
// assignment is always okay
|
156
|
+
if (name[strlen(name) - 1] == '=')
|
157
|
+
JRETURN_RUBY(Qtrue);
|
158
|
+
|
159
|
+
jsval proxy_value;
|
160
|
+
JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
|
161
|
+
JROOT(proxy_value);
|
162
|
+
|
163
|
+
JSObject *obj;
|
164
|
+
JSBool found;
|
165
|
+
|
166
|
+
JCHECK(JS_ValueToObject(context, proxy_value, &obj));
|
167
|
+
JROOT(obj);
|
168
|
+
|
169
|
+
JCHECK(JS_HasProperty(context, obj, name, &found));
|
170
|
+
|
171
|
+
JRETURN_RUBY(found ? Qtrue : CALL_RUBY_WRAPPER(rb_call_super, 1, &sym));
|
172
|
+
}
|
173
|
+
|
174
|
+
/*
|
175
|
+
* call-seq:
|
176
|
+
* native_call(global, *args)
|
177
|
+
*
|
178
|
+
* Call as a function with given +global+ using *args.
|
179
|
+
*/
|
180
|
+
static VALUE
|
181
|
+
native_call(int argc, VALUE* argv, VALUE self)
|
182
|
+
{
|
183
|
+
// FIXME: This should really call super#native_call.
|
184
|
+
if (!function_p(self))
|
185
|
+
rb_raise(rb_eRuntimeError, "This Johnson::SpiderMonkey::RubyLandProxy isn't a function.");
|
186
|
+
|
187
|
+
if (argc < 1)
|
188
|
+
rb_raise(rb_eArgError, "Target object required");
|
189
|
+
|
190
|
+
RubyLandProxy* proxy;
|
191
|
+
Data_Get_Struct(self, RubyLandProxy, proxy);
|
192
|
+
JSContext * context = johnson_get_current_context(proxy->runtime);
|
193
|
+
|
194
|
+
PREPARE_RUBY_JROOTS(context, 1);
|
195
|
+
|
196
|
+
jsval proxy_value;
|
197
|
+
JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
|
198
|
+
JROOT(proxy_value);
|
199
|
+
|
200
|
+
jsval global;
|
201
|
+
JCHECK(convert_to_js(proxy->runtime, argv[0], &global));
|
202
|
+
|
203
|
+
JRETURN_RUBY(call_js_function_value(proxy->runtime, global, proxy_value, argc - 1, &(argv[1])));
|
204
|
+
}
|
205
|
+
|
206
|
+
static void
|
207
|
+
destroy_id_array(JSContext* context, void* data)
|
208
|
+
{
|
209
|
+
JS_DestroyIdArray(context, (JSIdArray*)data);
|
210
|
+
}
|
211
|
+
|
212
|
+
/*
|
213
|
+
* call-seq:
|
214
|
+
* each { |obj| block }
|
215
|
+
*
|
216
|
+
* Calls <em>block</em> with each item in the collection.
|
217
|
+
*/
|
218
|
+
static VALUE
|
219
|
+
each(VALUE self)
|
220
|
+
{
|
221
|
+
RubyLandProxy* proxy;
|
222
|
+
Data_Get_Struct(self, RubyLandProxy, proxy);
|
223
|
+
JSContext * context = johnson_get_current_context(proxy->runtime);
|
224
|
+
|
225
|
+
PREPARE_RUBY_JROOTS(context, 5);
|
226
|
+
|
227
|
+
jsval proxy_value;
|
228
|
+
JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
|
229
|
+
JROOT(proxy_value);
|
230
|
+
|
231
|
+
JSObject* value = JSVAL_TO_OBJECT(proxy_value);
|
232
|
+
JROOT(value);
|
233
|
+
|
234
|
+
// arrays behave like you'd expect, indexes in order
|
235
|
+
if (JS_IsArrayObject(context, value))
|
236
|
+
{
|
237
|
+
jsuint length;
|
238
|
+
JCHECK(JS_GetArrayLength(context, value, &length));
|
239
|
+
|
240
|
+
jsuint i = 0;
|
241
|
+
for (i = 0; i < length; ++i)
|
242
|
+
{
|
243
|
+
jsval element;
|
244
|
+
JCHECK(JS_GetElement(context, value, (signed) i, &element));
|
245
|
+
CALL_RUBY_WRAPPER(rb_yield, convert_to_ruby(proxy->runtime, element));
|
246
|
+
}
|
247
|
+
}
|
248
|
+
else
|
249
|
+
{
|
250
|
+
// not an array? behave like each on Hash; yield [key, value]
|
251
|
+
JSIdArray* ids = JS_Enumerate(context, value);
|
252
|
+
JCHECK(ids);
|
253
|
+
|
254
|
+
JCLEANUP(destroy_id_array, ids);
|
255
|
+
|
256
|
+
int i;
|
257
|
+
for (i = 0; i < ids->length; ++i)
|
258
|
+
{
|
259
|
+
jsval js_key, js_value;
|
260
|
+
|
261
|
+
JCHECK(JS_IdToValue(context, ids->vector[i], &js_key));
|
262
|
+
JROOT(js_key);
|
263
|
+
|
264
|
+
if (JSVAL_IS_STRING(js_key))
|
265
|
+
{
|
266
|
+
// regular properties have string keys
|
267
|
+
JCHECK(JS_GetProperty(context, value,
|
268
|
+
JS_GetStringBytes(JSVAL_TO_STRING(js_key)), &js_value));
|
269
|
+
}
|
270
|
+
else
|
271
|
+
{
|
272
|
+
// it's a numeric property, use array access
|
273
|
+
JCHECK(JS_GetElement(context, value,
|
274
|
+
JSVAL_TO_INT(js_key), &js_value));
|
275
|
+
}
|
276
|
+
JROOT(js_value);
|
277
|
+
|
278
|
+
VALUE key = CONVERT_TO_RUBY(proxy->runtime, js_key);
|
279
|
+
VALUE value = CONVERT_TO_RUBY(proxy->runtime, js_value);
|
280
|
+
|
281
|
+
CALL_RUBY_WRAPPER(rb_yield, rb_ary_new3(2, key, value));
|
282
|
+
|
283
|
+
JUNROOT(js_value);
|
284
|
+
JUNROOT(js_key);
|
285
|
+
}
|
286
|
+
}
|
287
|
+
|
288
|
+
JRETURN_RUBY(self);
|
289
|
+
}
|
290
|
+
|
291
|
+
/*
|
292
|
+
* call-seq:
|
293
|
+
* length
|
294
|
+
*
|
295
|
+
* Returns the length of the collection.
|
296
|
+
*/
|
297
|
+
static VALUE
|
298
|
+
length(VALUE self)
|
299
|
+
{
|
300
|
+
RubyLandProxy* proxy;
|
301
|
+
Data_Get_Struct(self, RubyLandProxy, proxy);
|
302
|
+
JSContext * context = johnson_get_current_context(proxy->runtime);
|
303
|
+
|
304
|
+
PREPARE_RUBY_JROOTS(context, 2);
|
305
|
+
|
306
|
+
jsval proxy_value;
|
307
|
+
JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
|
308
|
+
JROOT(proxy_value);
|
309
|
+
|
310
|
+
JSObject* value = JSVAL_TO_OBJECT(proxy_value);
|
311
|
+
JROOT(value);
|
312
|
+
|
313
|
+
if (JS_IsArrayObject(context, value))
|
314
|
+
{
|
315
|
+
jsuint length;
|
316
|
+
JCHECK(JS_GetArrayLength(context, value, &length));
|
317
|
+
|
318
|
+
JRETURN_RUBY(INT2FIX(length));
|
319
|
+
}
|
320
|
+
else
|
321
|
+
{
|
322
|
+
JSIdArray* ids = JS_Enumerate(context, value);
|
323
|
+
JCHECK(ids);
|
324
|
+
VALUE length = INT2FIX(ids->length);
|
325
|
+
|
326
|
+
JS_DestroyIdArray(context, ids);
|
327
|
+
|
328
|
+
JRETURN_RUBY(length);
|
329
|
+
}
|
330
|
+
}
|
331
|
+
|
332
|
+
/*
|
333
|
+
* call-seq:
|
334
|
+
* runtime
|
335
|
+
*
|
336
|
+
* Returns runtime.
|
337
|
+
*/
|
338
|
+
static VALUE
|
339
|
+
runtime(VALUE self)
|
340
|
+
{
|
341
|
+
RubyLandProxy* proxy;
|
342
|
+
Data_Get_Struct(self, RubyLandProxy, proxy);
|
343
|
+
return (VALUE)JS_GetRuntimePrivate(proxy->runtime->js);
|
344
|
+
}
|
345
|
+
|
346
|
+
/*
|
347
|
+
* call-seq:
|
348
|
+
* function_property?(name)
|
349
|
+
*
|
350
|
+
* Returns <code>true</code> if +name+ is a function property.
|
351
|
+
*/
|
352
|
+
static VALUE
|
353
|
+
function_property_p(VALUE self, VALUE name)
|
354
|
+
{
|
355
|
+
Check_Type(name, T_STRING);
|
356
|
+
|
357
|
+
RubyLandProxy* proxy;
|
358
|
+
Data_Get_Struct(self, RubyLandProxy, proxy);
|
359
|
+
JSContext * context = johnson_get_current_context(proxy->runtime);
|
360
|
+
|
361
|
+
PREPARE_RUBY_JROOTS(context, 2);
|
362
|
+
|
363
|
+
jsval proxy_value;
|
364
|
+
JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
|
365
|
+
JROOT(proxy_value);
|
366
|
+
|
367
|
+
jsval js_value;
|
368
|
+
|
369
|
+
JCHECK(JS_GetProperty(context,
|
370
|
+
JSVAL_TO_OBJECT(proxy_value), StringValueCStr(name), &js_value));
|
371
|
+
|
372
|
+
JROOT(js_value);
|
373
|
+
|
374
|
+
JSType type = JS_TypeOfValue(context, js_value);
|
375
|
+
|
376
|
+
JRETURN_RUBY(type == JSTYPE_FUNCTION ? Qtrue : Qfalse);
|
377
|
+
}
|
378
|
+
|
379
|
+
/*
|
380
|
+
* call-seq:
|
381
|
+
* call_function_property(name, arguments)
|
382
|
+
*
|
383
|
+
* Calls function +name+ with +arguments+.
|
384
|
+
*/
|
385
|
+
static VALUE
|
386
|
+
call_function_property(int argc, VALUE* argv, VALUE self)
|
387
|
+
{
|
388
|
+
RubyLandProxy* proxy;
|
389
|
+
Data_Get_Struct(self, RubyLandProxy, proxy);
|
390
|
+
JSContext * context = johnson_get_current_context(proxy->runtime);
|
391
|
+
|
392
|
+
if (argc < 1)
|
393
|
+
rb_raise(rb_eArgError, "Function name required");
|
394
|
+
|
395
|
+
PREPARE_RUBY_JROOTS(context, 2);
|
396
|
+
|
397
|
+
jsval proxy_value;
|
398
|
+
JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
|
399
|
+
JROOT(proxy_value);
|
400
|
+
|
401
|
+
jsval function;
|
402
|
+
|
403
|
+
JCHECK(JS_GetProperty(context,
|
404
|
+
JSVAL_TO_OBJECT(proxy_value), StringValueCStr(argv[0]), &function));
|
405
|
+
|
406
|
+
JROOT(function);
|
407
|
+
|
408
|
+
JSType funtype = JS_TypeOfValue(context, function);
|
409
|
+
|
410
|
+
// should never be anything but a function
|
411
|
+
if (funtype != JSTYPE_FUNCTION)
|
412
|
+
JERROR("Specified property \"%s\" isn't a function.", StringValueCStr(argv[0]));
|
413
|
+
|
414
|
+
JRETURN_RUBY(call_js_function_value(proxy->runtime, proxy_value, function, argc - 1, &(argv[1])));
|
415
|
+
}
|
416
|
+
|
417
|
+
/*
|
418
|
+
* call-seq:
|
419
|
+
* to_s
|
420
|
+
*
|
421
|
+
* Converts object to a string.
|
422
|
+
*/
|
423
|
+
static VALUE to_s(VALUE self)
|
424
|
+
{
|
425
|
+
RubyLandProxy* proxy;
|
426
|
+
Data_Get_Struct(self, RubyLandProxy, proxy);
|
427
|
+
JSContext * context = johnson_get_current_context(proxy->runtime);
|
428
|
+
|
429
|
+
PREPARE_RUBY_JROOTS(context, 1);
|
430
|
+
|
431
|
+
jsval proxy_value;
|
432
|
+
JCHECK(get_jsval_for_proxy(proxy, &proxy_value));
|
433
|
+
JROOT(proxy_value);
|
434
|
+
|
435
|
+
JSString* str = JS_ValueToString(context, proxy_value);
|
436
|
+
JRETURN_RUBY(convert_js_string_to_ruby(proxy->runtime, str));
|
437
|
+
}
|
438
|
+
|
439
|
+
///////////////////////////////////////////////////////////////////////////
|
440
|
+
//// INFRASTRUCTURE BELOW HERE ////////////////////////////////////////////
|
441
|
+
///////////////////////////////////////////////////////////////////////////
|
442
|
+
|
443
|
+
static void finalize(RubyLandProxy* proxy)
|
444
|
+
{
|
445
|
+
// could get finalized after the context has been freed
|
446
|
+
if (proxy->runtime && proxy->runtime->jsids)
|
447
|
+
{
|
448
|
+
// remove this proxy from the OID map
|
449
|
+
jsval proxy_value;
|
450
|
+
get_jsval_for_proxy(proxy, &proxy_value);
|
451
|
+
JS_HashTableRemove(proxy->runtime->jsids, (void *)proxy_value);
|
452
|
+
}
|
453
|
+
|
454
|
+
if (proxy->runtime)
|
455
|
+
{
|
456
|
+
// remove our GC handle on the JS value
|
457
|
+
JS_RemoveRootRT(proxy->runtime->js, &(proxy->key));
|
458
|
+
}
|
459
|
+
|
460
|
+
free(proxy);
|
461
|
+
}
|
462
|
+
|
463
|
+
bool ruby_value_is_proxy(VALUE maybe_proxy)
|
464
|
+
{
|
465
|
+
return proxy_class == CLASS_OF(maybe_proxy);
|
466
|
+
}
|
467
|
+
|
468
|
+
JSBool unwrap_ruby_land_proxy(JohnsonRuntime* runtime, VALUE wrapped, jsval* retval)
|
469
|
+
{
|
470
|
+
JSContext * context = johnson_get_current_context(runtime);
|
471
|
+
assert(ruby_value_is_proxy(wrapped));
|
472
|
+
|
473
|
+
PREPARE_JROOTS(context, 0);
|
474
|
+
|
475
|
+
RubyLandProxy* proxy;
|
476
|
+
Data_Get_Struct(wrapped, RubyLandProxy, proxy);
|
477
|
+
|
478
|
+
JCHECK(get_jsval_for_proxy(proxy, retval));
|
479
|
+
JRETURN;
|
480
|
+
}
|
481
|
+
|
482
|
+
VALUE make_ruby_land_proxy(JohnsonRuntime* runtime, jsval value, const char const* root_name)
|
483
|
+
{
|
484
|
+
VALUE id = (VALUE)JS_HashTableLookup(runtime->jsids, (void *)value);
|
485
|
+
|
486
|
+
if (id)
|
487
|
+
{
|
488
|
+
// if we already have a proxy, return it
|
489
|
+
return id;
|
490
|
+
}
|
491
|
+
else
|
492
|
+
{
|
493
|
+
// otherwise make one and cache it
|
494
|
+
RubyLandProxy* our_proxy;
|
495
|
+
VALUE proxy = Data_Make_Struct(proxy_class, RubyLandProxy, 0, finalize, our_proxy);
|
496
|
+
|
497
|
+
JSContext * context = johnson_get_current_context(runtime);
|
498
|
+
|
499
|
+
PREPARE_RUBY_JROOTS(context, 1);
|
500
|
+
JROOT(value);
|
501
|
+
|
502
|
+
our_proxy->runtime = runtime;
|
503
|
+
our_proxy->key = (void *)value;
|
504
|
+
|
505
|
+
// root the value for JS GC and lookups
|
506
|
+
JCHECK(JS_AddNamedRootRT(runtime->js, &(our_proxy->key), root_name));
|
507
|
+
|
508
|
+
// put the proxy OID in the id map
|
509
|
+
JCHECK(JS_HashTableAdd(runtime->jsids, (void *)value, (void *)proxy));
|
510
|
+
|
511
|
+
JRETURN_RUBY(proxy);
|
512
|
+
}
|
513
|
+
}
|
514
|
+
|
515
|
+
void init_Johnson_SpiderMonkey_Proxy(VALUE spidermonkey)
|
516
|
+
{
|
517
|
+
/* HACK: These comments are *only* to make RDoc happy.
|
518
|
+
VALUE johnson = rb_define_module("Johnson");
|
519
|
+
VALUE spidermonkey = rb_define_module_under(johnson, "SpiderMonkey");
|
520
|
+
*/
|
521
|
+
|
522
|
+
/* RubyLandProxy class. */
|
523
|
+
proxy_class = rb_define_class_under(spidermonkey, "RubyLandProxy", rb_cObject);
|
524
|
+
|
525
|
+
rb_define_method(proxy_class, "[]", get, 1);
|
526
|
+
rb_define_method(proxy_class, "[]=", set, 2);
|
527
|
+
rb_define_method(proxy_class, "function?", function_p, 0);
|
528
|
+
rb_define_method(proxy_class, "respond_to?", respond_to_p, 1);
|
529
|
+
rb_define_method(proxy_class, "each", each, 0);
|
530
|
+
rb_define_method(proxy_class, "length", length, 0);
|
531
|
+
rb_define_method(proxy_class, "to_s", to_s, 0);
|
532
|
+
|
533
|
+
rb_define_private_method(proxy_class, "native_call", native_call, -1);
|
534
|
+
rb_define_private_method(proxy_class, "runtime", runtime, 0);
|
535
|
+
rb_define_private_method(proxy_class, "function_property?", function_property_p, 1);
|
536
|
+
rb_define_private_method(proxy_class, "call_function_property", call_function_property, -1);
|
537
|
+
}
|