js 0.0.1 → 2.4.1.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ext/js/bindgen/.clang-format +2 -0
- data/ext/js/bindgen/rb-js-abi-host.c +342 -0
- data/ext/js/bindgen/rb-js-abi-host.h +82 -0
- data/ext/js/bindgen/rb-js-abi-host.wit +47 -0
- data/ext/js/depend +10 -0
- data/ext/js/extconf.rb +3 -0
- data/ext/js/js-core.c +577 -0
- data/ext/witapi/bindgen/.clang-format +2 -0
- data/ext/witapi/bindgen/rb-abi-guest.c +222 -0
- data/ext/witapi/bindgen/rb-abi-guest.h +77 -0
- data/ext/witapi/bindgen/rb-abi-guest.wit +25 -0
- data/ext/witapi/depend +11 -0
- data/ext/witapi/extconf.rb +3 -0
- data/ext/witapi/witapi-core.c +325 -0
- data/js.gemspec +26 -16
- data/lib/js/array.rb +9 -0
- data/lib/js/hash.rb +8 -0
- data/lib/js/nil_class.rb +6 -0
- data/lib/js/require_remote/evaluator.rb +15 -0
- data/lib/js/require_remote/url_resolver.rb +45 -0
- data/lib/js/require_remote.rb +85 -0
- data/lib/js/version.rb +2 -2
- data/lib/js.rb +238 -3
- metadata +40 -23
- data/.gitignore +0 -17
- data/Gemfile +0 -4
- data/LICENSE.txt +0 -22
- data/README.md +0 -35
- data/Rakefile +0 -1
data/ext/js/js-core.c
ADDED
@@ -0,0 +1,577 @@
|
|
1
|
+
#include <stdlib.h>
|
2
|
+
|
3
|
+
#include "ruby.h"
|
4
|
+
|
5
|
+
#include "bindgen/rb-js-abi-host.h"
|
6
|
+
|
7
|
+
// MARK: - Ruby extension
|
8
|
+
|
9
|
+
#ifndef RBOOL
|
10
|
+
# define RBOOL(v) ((v) ? Qtrue : Qfalse)
|
11
|
+
#endif
|
12
|
+
|
13
|
+
extern VALUE rb_mKernel;
|
14
|
+
extern VALUE rb_cInteger;
|
15
|
+
extern VALUE rb_cFloat;
|
16
|
+
extern VALUE rb_cString;
|
17
|
+
extern VALUE rb_cTrueClass;
|
18
|
+
extern VALUE rb_cFalseClass;
|
19
|
+
extern VALUE rb_cProc;
|
20
|
+
|
21
|
+
// from js/js-core.c
|
22
|
+
void rb_abi_lend_object(VALUE obj);
|
23
|
+
|
24
|
+
static VALUE rb_mJS;
|
25
|
+
static VALUE rb_cJS_Object;
|
26
|
+
static VALUE rb_cJS_Error;
|
27
|
+
|
28
|
+
static ID i_to_js;
|
29
|
+
|
30
|
+
struct jsvalue {
|
31
|
+
rb_js_abi_host_js_abi_value_t abi;
|
32
|
+
};
|
33
|
+
|
34
|
+
static void jsvalue_mark(void *p) {}
|
35
|
+
|
36
|
+
static void jsvalue_free(void *p) {
|
37
|
+
struct jsvalue *ptr = p;
|
38
|
+
rb_js_abi_host_js_abi_value_free(&ptr->abi);
|
39
|
+
ruby_xfree(ptr);
|
40
|
+
}
|
41
|
+
|
42
|
+
static size_t jsvalue_memsize(const void *p) { return sizeof(struct jsvalue); }
|
43
|
+
|
44
|
+
static const rb_data_type_t jsvalue_data_type = {"jsvalue",
|
45
|
+
{
|
46
|
+
jsvalue_mark,
|
47
|
+
jsvalue_free,
|
48
|
+
jsvalue_memsize,
|
49
|
+
},
|
50
|
+
0,
|
51
|
+
0,
|
52
|
+
RUBY_TYPED_FREE_IMMEDIATELY};
|
53
|
+
static VALUE jsvalue_s_allocate(VALUE klass) {
|
54
|
+
struct jsvalue *p;
|
55
|
+
VALUE obj =
|
56
|
+
TypedData_Make_Struct(klass, struct jsvalue, &jsvalue_data_type, p);
|
57
|
+
return obj;
|
58
|
+
}
|
59
|
+
|
60
|
+
static VALUE jsvalue_s_new(rb_js_abi_host_js_abi_value_t abi) {
|
61
|
+
struct jsvalue *p;
|
62
|
+
VALUE obj = TypedData_Make_Struct(rb_cJS_Object, struct jsvalue,
|
63
|
+
&jsvalue_data_type, p);
|
64
|
+
p->abi = abi;
|
65
|
+
return obj;
|
66
|
+
}
|
67
|
+
|
68
|
+
static struct jsvalue *check_jsvalue(VALUE obj) {
|
69
|
+
return rb_check_typeddata(obj, &jsvalue_data_type);
|
70
|
+
}
|
71
|
+
|
72
|
+
#define IS_JSVALUE(obj) (rb_typeddata_is_kind_of((obj), &jsvalue_data_type))
|
73
|
+
|
74
|
+
static inline void rstring_to_abi_string(VALUE rstr,
|
75
|
+
rb_js_abi_host_string_t *abi_str) {
|
76
|
+
abi_str->len = RSTRING_LEN(rstr);
|
77
|
+
abi_str->ptr = xmalloc(abi_str->len);
|
78
|
+
memcpy(abi_str->ptr, RSTRING_PTR(rstr), abi_str->len);
|
79
|
+
}
|
80
|
+
|
81
|
+
static inline void
|
82
|
+
raise_js_error_if_failure(const rb_js_abi_host_js_abi_result_t *result) {
|
83
|
+
if (result->tag == RB_JS_ABI_HOST_JS_ABI_RESULT_FAILURE) {
|
84
|
+
VALUE js_err = jsvalue_s_new(result->val.failure);
|
85
|
+
VALUE rb_err = rb_class_new_instance(1, &js_err, rb_cJS_Error);
|
86
|
+
rb_exc_raise(rb_err);
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
/*
|
91
|
+
* call-seq:
|
92
|
+
* JS.eval(code) -> JS::Object
|
93
|
+
*
|
94
|
+
* Evaluates the given JavaScript code, returning the result as a JS::Object.
|
95
|
+
*
|
96
|
+
* p JS.eval("return 1 + 1").to_i # => 2
|
97
|
+
* p JS.eval("return new Object()").is_a?(JS.global[:Object]) # => true
|
98
|
+
*/
|
99
|
+
static VALUE _rb_js_eval_js(VALUE _, VALUE code_str) {
|
100
|
+
rb_js_abi_host_string_t abi_str;
|
101
|
+
rstring_to_abi_string(code_str, &abi_str);
|
102
|
+
rb_js_abi_host_js_abi_result_t ret;
|
103
|
+
rb_js_abi_host_eval_js(&abi_str, &ret);
|
104
|
+
raise_js_error_if_failure(&ret);
|
105
|
+
return jsvalue_s_new(ret.val.success);
|
106
|
+
}
|
107
|
+
|
108
|
+
static VALUE _rb_js_is_js(VALUE _, VALUE obj) {
|
109
|
+
if (!IS_JSVALUE(obj)) {
|
110
|
+
return Qfalse;
|
111
|
+
}
|
112
|
+
struct jsvalue *val = DATA_PTR(obj);
|
113
|
+
return RBOOL(rb_js_abi_host_is_js(val->abi));
|
114
|
+
}
|
115
|
+
|
116
|
+
/*
|
117
|
+
* call-seq:
|
118
|
+
* JS.try_convert(obj) -> JS::Object or nil
|
119
|
+
*
|
120
|
+
* Try to convert the given object to a JS::Object using <code>to_js</code>
|
121
|
+
* method. Returns <code>nil</code> if the object cannot be converted.
|
122
|
+
*
|
123
|
+
* p JS.try_convert(1) # => JS::Object
|
124
|
+
* p JS.try_convert("foo") # => JS::Object
|
125
|
+
* p JS.try_convert(Object.new) # => nil
|
126
|
+
* p JS.try_convert(JS::Object.wrap(Object.new)) # => JS::Object
|
127
|
+
*/
|
128
|
+
VALUE _rb_js_try_convert(VALUE klass, VALUE obj) {
|
129
|
+
if (_rb_js_is_js(klass, obj)) {
|
130
|
+
return obj;
|
131
|
+
} else if (rb_respond_to(obj, i_to_js)) {
|
132
|
+
return rb_funcallv(obj, i_to_js, 0, NULL);
|
133
|
+
} else {
|
134
|
+
return Qnil;
|
135
|
+
}
|
136
|
+
}
|
137
|
+
|
138
|
+
/*
|
139
|
+
* call-seq:
|
140
|
+
* JS.is_a?(js_obj, js_class) -> true or false
|
141
|
+
*
|
142
|
+
* Returns <code>true</code> if <i>js_class</i> is the instance of
|
143
|
+
* <i>js_obj</i>, otherwise returns <code>false</code>.
|
144
|
+
* Comparison is done using the <code>instanceof</code> in JavaScript.
|
145
|
+
*
|
146
|
+
* p JS.is_a?(JS.global, JS.global[:Object]) #=> true
|
147
|
+
* p JS.is_a?(JS.global, Object) #=> false
|
148
|
+
*/
|
149
|
+
static VALUE _rb_js_is_kind_of(VALUE klass, VALUE obj, VALUE c) {
|
150
|
+
if (!IS_JSVALUE(obj)) {
|
151
|
+
return Qfalse;
|
152
|
+
}
|
153
|
+
struct jsvalue *val = DATA_PTR(obj);
|
154
|
+
VALUE js_klass_v = _rb_js_try_convert(klass, c);
|
155
|
+
struct jsvalue *js_klass = DATA_PTR(js_klass_v);
|
156
|
+
return RBOOL(rb_js_abi_host_instance_of(val->abi, js_klass->abi));
|
157
|
+
}
|
158
|
+
|
159
|
+
/*
|
160
|
+
* call-seq:
|
161
|
+
* JS.global -> JS::Object
|
162
|
+
*
|
163
|
+
* Returns <code>globalThis</code> JavaScript object.
|
164
|
+
*
|
165
|
+
* p JS.global
|
166
|
+
* p JS.global[:document]
|
167
|
+
*/
|
168
|
+
static VALUE _rb_js_global_this(VALUE _) {
|
169
|
+
return jsvalue_s_new(rb_js_abi_host_global_this());
|
170
|
+
}
|
171
|
+
|
172
|
+
/*
|
173
|
+
* call-seq:
|
174
|
+
* self[prop] -> JS::Object
|
175
|
+
*
|
176
|
+
* Returns the value of the property:
|
177
|
+
* JS.global[:Object]
|
178
|
+
* JS.global[:console][:log]
|
179
|
+
*/
|
180
|
+
static VALUE _rb_js_obj_aref(VALUE obj, VALUE key) {
|
181
|
+
struct jsvalue *p = check_jsvalue(obj);
|
182
|
+
rb_js_abi_host_string_t key_abi_str;
|
183
|
+
key = rb_obj_as_string(key);
|
184
|
+
rstring_to_abi_string(key, &key_abi_str);
|
185
|
+
rb_js_abi_host_js_abi_result_t ret;
|
186
|
+
rb_js_abi_host_reflect_get(p->abi, &key_abi_str, &ret);
|
187
|
+
raise_js_error_if_failure(&ret);
|
188
|
+
return jsvalue_s_new(ret.val.success);
|
189
|
+
}
|
190
|
+
|
191
|
+
/*
|
192
|
+
* call-seq:
|
193
|
+
* self[prop] = value -> JS::Object
|
194
|
+
*
|
195
|
+
* Set a property on the object with the given value.
|
196
|
+
* Returns the value of the property:
|
197
|
+
* JS.global[:Object][:foo] = "bar"
|
198
|
+
* p JS.global[:console][:foo] # => "bar"
|
199
|
+
*/
|
200
|
+
static VALUE _rb_js_obj_aset(VALUE obj, VALUE key, VALUE val) {
|
201
|
+
struct jsvalue *p = check_jsvalue(obj);
|
202
|
+
VALUE rv = _rb_js_try_convert(rb_mJS, val);
|
203
|
+
struct jsvalue *v = check_jsvalue(rv);
|
204
|
+
rb_js_abi_host_string_t key_abi_str;
|
205
|
+
key = rb_obj_as_string(key);
|
206
|
+
rstring_to_abi_string(key, &key_abi_str);
|
207
|
+
rb_js_abi_host_js_abi_result_t ret;
|
208
|
+
rb_js_abi_host_reflect_set(p->abi, &key_abi_str, v->abi, &ret);
|
209
|
+
raise_js_error_if_failure(&ret);
|
210
|
+
rb_js_abi_host_js_abi_value_free(&ret.val.success);
|
211
|
+
RB_GC_GUARD(rv);
|
212
|
+
return val;
|
213
|
+
}
|
214
|
+
|
215
|
+
/*
|
216
|
+
* call-seq:
|
217
|
+
* js_value.strictly_eql?(other) -> boolean
|
218
|
+
*
|
219
|
+
* Performs "===" comparison, a.k.a the "Strict Equality Comparison"
|
220
|
+
* algorithm defined in the ECMAScript.
|
221
|
+
* https://262.ecma-international.org/11.0/#sec-strict-equality-comparison
|
222
|
+
*/
|
223
|
+
static VALUE _rb_js_obj_strictly_eql(VALUE obj, VALUE other) {
|
224
|
+
struct jsvalue *lhs = check_jsvalue(obj);
|
225
|
+
struct jsvalue *rhs = check_jsvalue(other);
|
226
|
+
bool result = rb_js_abi_host_js_value_strictly_equal(lhs->abi, rhs->abi);
|
227
|
+
return RBOOL(result);
|
228
|
+
}
|
229
|
+
|
230
|
+
/*
|
231
|
+
* call-seq:
|
232
|
+
* js_value.==(other) -> boolean
|
233
|
+
* js_value.eql?(other) -> boolean
|
234
|
+
*
|
235
|
+
* Performs "==" comparison, a.k.a the "Abstract Equality Comparison"
|
236
|
+
* algorithm defined in the ECMAScript.
|
237
|
+
* https://262.ecma-international.org/11.0/#sec-abstract-equality-comparison
|
238
|
+
*/
|
239
|
+
static VALUE _rb_js_obj_eql(VALUE obj, VALUE other) {
|
240
|
+
struct jsvalue *lhs = check_jsvalue(obj);
|
241
|
+
struct jsvalue *rhs = check_jsvalue(other);
|
242
|
+
bool result = rb_js_abi_host_js_value_equal(lhs->abi, rhs->abi);
|
243
|
+
return RBOOL(result);
|
244
|
+
}
|
245
|
+
|
246
|
+
/*
|
247
|
+
* :nodoc: all
|
248
|
+
*/
|
249
|
+
static VALUE _rb_js_obj_hash(VALUE obj) {
|
250
|
+
// TODO(katei): Track the JS object id in JS side as Pyodide and Swift
|
251
|
+
// JavaScriptKit do.
|
252
|
+
return Qnil;
|
253
|
+
}
|
254
|
+
|
255
|
+
/*
|
256
|
+
* call-seq:
|
257
|
+
* js_value.call(name, *args) -> JS::Object
|
258
|
+
*
|
259
|
+
* Call a JavaScript method specified by the name with the arguments.
|
260
|
+
* Returns the result of the call as a JS::Object.
|
261
|
+
* p JS.global.call(:parseInt, JS.eval("return '42'")) # => 42
|
262
|
+
* JS.global[:console].call(:log, JS.eval("return '42'")) # => undefined
|
263
|
+
*/
|
264
|
+
static VALUE _rb_js_obj_call(int argc, VALUE *argv, VALUE obj) {
|
265
|
+
struct jsvalue *p = check_jsvalue(obj);
|
266
|
+
if (argc == 0) {
|
267
|
+
rb_raise(rb_eArgError, "no method name given");
|
268
|
+
}
|
269
|
+
VALUE method = _rb_js_obj_aref(obj, argv[0]);
|
270
|
+
struct jsvalue *abi_method = check_jsvalue(method);
|
271
|
+
|
272
|
+
rb_js_abi_host_list_js_abi_value_t abi_args;
|
273
|
+
int function_arguments_count = argc;
|
274
|
+
if (!rb_block_given_p())
|
275
|
+
function_arguments_count -= 1;
|
276
|
+
|
277
|
+
abi_args.ptr =
|
278
|
+
ALLOCA_N(rb_js_abi_host_js_abi_value_t, function_arguments_count);
|
279
|
+
abi_args.len = function_arguments_count;
|
280
|
+
VALUE rv_args = rb_ary_tmp_new(function_arguments_count);
|
281
|
+
|
282
|
+
for (int i = 1; i < argc; i++) {
|
283
|
+
VALUE arg = _rb_js_try_convert(rb_mJS, argv[i]);
|
284
|
+
if (arg == Qnil) {
|
285
|
+
rb_raise(rb_eTypeError, "argument %d is not a JS::Object like object",
|
286
|
+
1 + i);
|
287
|
+
}
|
288
|
+
abi_args.ptr[i - 1] = check_jsvalue(arg)->abi;
|
289
|
+
rb_ary_push(rv_args, arg);
|
290
|
+
}
|
291
|
+
|
292
|
+
if (rb_block_given_p()) {
|
293
|
+
VALUE proc = rb_block_proc();
|
294
|
+
VALUE rb_proc = _rb_js_try_convert(rb_mJS, proc);
|
295
|
+
abi_args.ptr[function_arguments_count - 1] = check_jsvalue(rb_proc)->abi;
|
296
|
+
rb_ary_push(rv_args, rb_proc);
|
297
|
+
}
|
298
|
+
|
299
|
+
rb_js_abi_host_js_abi_result_t ret;
|
300
|
+
rb_js_abi_host_reflect_apply(abi_method->abi, p->abi, &abi_args, &ret);
|
301
|
+
raise_js_error_if_failure(&ret);
|
302
|
+
VALUE result = jsvalue_s_new(ret.val.success);
|
303
|
+
RB_GC_GUARD(rv_args);
|
304
|
+
RB_GC_GUARD(method);
|
305
|
+
return result;
|
306
|
+
}
|
307
|
+
|
308
|
+
/*
|
309
|
+
* call-seq:
|
310
|
+
* js_value.typeof -> String
|
311
|
+
*
|
312
|
+
* Returns the result string of JavaScript 'typeof' operator.
|
313
|
+
* See also JS.is_a? for 'instanceof' operator.
|
314
|
+
* p JS.global.typeof # => "object"
|
315
|
+
* p JS.eval("return 1").typeof # => "number"
|
316
|
+
* p JS.eval("return 'str'").typeof # => "string"
|
317
|
+
* p JS.eval("return undefined").typeof # => "undefined"
|
318
|
+
* p JS.eval("return null").typeof # => "object"
|
319
|
+
*/
|
320
|
+
static VALUE _rb_js_obj_typeof(VALUE obj) {
|
321
|
+
struct jsvalue *p = check_jsvalue(obj);
|
322
|
+
rb_js_abi_host_string_t ret0;
|
323
|
+
rb_js_abi_host_js_value_typeof(p->abi, &ret0);
|
324
|
+
return rb_str_new(ret0.ptr, ret0.len);
|
325
|
+
}
|
326
|
+
|
327
|
+
/*
|
328
|
+
* call-seq:
|
329
|
+
* to_s -> string
|
330
|
+
*
|
331
|
+
* Returns a printable version of +self+:
|
332
|
+
* JS.eval("return 'str'").to_s # => "str"
|
333
|
+
* JS.eval("return true").to_s # => "true"
|
334
|
+
* JS.eval("return 1").to_s # => "1"
|
335
|
+
* JS.eval("return null").to_s # => "null"
|
336
|
+
* JS.global.to_s # => "[object global]"
|
337
|
+
*
|
338
|
+
* JS::Object#inspect is an alias for JS::Object#to_s.
|
339
|
+
*/
|
340
|
+
static VALUE _rb_js_obj_to_s(VALUE obj) {
|
341
|
+
struct jsvalue *p = check_jsvalue(obj);
|
342
|
+
rb_js_abi_host_string_t ret0;
|
343
|
+
rb_js_abi_host_js_value_to_string(p->abi, &ret0);
|
344
|
+
return rb_utf8_str_new(ret0.ptr, ret0.len);
|
345
|
+
}
|
346
|
+
|
347
|
+
/*
|
348
|
+
* call-seq:
|
349
|
+
* to_i -> integer
|
350
|
+
*
|
351
|
+
* Converts +self+ to an Integer:
|
352
|
+
* JS.eval("return 1").to_i # => 1
|
353
|
+
* JS.eval("return -1").to_i # => -1
|
354
|
+
* JS.eval("return 5.8").to_i # => 5
|
355
|
+
* JS.eval("return 42n").to_i # => 42
|
356
|
+
* JS.eval("return '3'").to_i # => 3
|
357
|
+
* JS.eval("return ''").to_f # => 0
|
358
|
+
* JS.eval("return 'x'").to_i # => 0
|
359
|
+
* JS.eval("return NaN").to_i # Raises FloatDomainError
|
360
|
+
* JS.eval("return Infinity").to_i # Raises FloatDomainError
|
361
|
+
* JS.eval("return -Infinity").to_i # Raises FloatDomainError
|
362
|
+
*/
|
363
|
+
static VALUE _rb_js_obj_to_i(VALUE obj) {
|
364
|
+
struct jsvalue *p = check_jsvalue(obj);
|
365
|
+
rb_js_abi_host_raw_integer_t ret;
|
366
|
+
rb_js_abi_host_js_value_to_integer(p->abi, &ret);
|
367
|
+
VALUE result;
|
368
|
+
if (ret.tag == RB_JS_ABI_HOST_RAW_INTEGER_F64) {
|
369
|
+
result = rb_dbl2big(ret.val.f64);
|
370
|
+
} else {
|
371
|
+
result = rb_cstr2inum(ret.val.bignum.ptr, 10);
|
372
|
+
}
|
373
|
+
rb_js_abi_host_raw_integer_free(&ret);
|
374
|
+
return result;
|
375
|
+
}
|
376
|
+
|
377
|
+
/*
|
378
|
+
* call-seq:
|
379
|
+
* to_f -> float
|
380
|
+
*
|
381
|
+
* Converts +self+ to a Float:
|
382
|
+
* JS.eval("return 1").to_f # => 1.0
|
383
|
+
* JS.eval("return 1.2").to_f # => 1.2
|
384
|
+
* JS.eval("return -1.2").to_f # => -1.2
|
385
|
+
* JS.eval("return '3.14'").to_f # => 3.14
|
386
|
+
* JS.eval("return ''").to_f # => 0.0
|
387
|
+
* JS.eval("return 'x'").to_f # => 0.0
|
388
|
+
* JS.eval("return NaN").to_f # => Float::NAN
|
389
|
+
* JS.eval("return Infinity").to_f # => Float::INFINITY
|
390
|
+
* JS.eval("return -Infinity").to_f # => -Float::INFINITY
|
391
|
+
*
|
392
|
+
*/
|
393
|
+
static VALUE _rb_js_obj_to_f(VALUE obj) {
|
394
|
+
struct jsvalue *p = check_jsvalue(obj);
|
395
|
+
rb_js_abi_host_raw_integer_t ret;
|
396
|
+
VALUE result;
|
397
|
+
rb_js_abi_host_js_value_to_integer(p->abi, &ret);
|
398
|
+
if (ret.tag == RB_JS_ABI_HOST_RAW_INTEGER_F64) {
|
399
|
+
result = rb_float_new(ret.val.f64);
|
400
|
+
} else {
|
401
|
+
result = DBL2NUM(rb_cstr_to_dbl(ret.val.bignum.ptr, FALSE));
|
402
|
+
}
|
403
|
+
rb_js_abi_host_raw_integer_free(&ret);
|
404
|
+
return result;
|
405
|
+
}
|
406
|
+
|
407
|
+
/*
|
408
|
+
* :nodoc: all
|
409
|
+
* workaround to transfer js value to js by using wit.
|
410
|
+
* wit doesn't allow to communicate a resource to guest and host for now.
|
411
|
+
*/
|
412
|
+
static VALUE _rb_js_export_to_js(VALUE obj) {
|
413
|
+
struct jsvalue *p = check_jsvalue(obj);
|
414
|
+
rb_js_abi_host_export_js_value_to_host(p->abi);
|
415
|
+
return Qnil;
|
416
|
+
}
|
417
|
+
|
418
|
+
static VALUE _rb_js_import_from_js(VALUE obj) {
|
419
|
+
return jsvalue_s_new(rb_js_abi_host_import_js_value_from_host());
|
420
|
+
}
|
421
|
+
|
422
|
+
/*
|
423
|
+
* call-seq:
|
424
|
+
* JS::Object.wrap(obj) -> JS::Object
|
425
|
+
*
|
426
|
+
* Returns +obj+ wrapped by JS class RbValue.
|
427
|
+
*/
|
428
|
+
static VALUE _rb_js_obj_wrap(VALUE obj, VALUE wrapping) {
|
429
|
+
rb_abi_lend_object(wrapping);
|
430
|
+
return jsvalue_s_new(
|
431
|
+
rb_js_abi_host_rb_object_to_js_rb_value((uint32_t)wrapping));
|
432
|
+
}
|
433
|
+
|
434
|
+
/*
|
435
|
+
* call-seq:
|
436
|
+
* to_js -> JS::Object
|
437
|
+
*
|
438
|
+
* Returns +self+ as a JS::Object.
|
439
|
+
*/
|
440
|
+
static VALUE _rb_js_integer_to_js(VALUE obj) {
|
441
|
+
if (FIXNUM_P(obj)) {
|
442
|
+
return jsvalue_s_new(rb_js_abi_host_int_to_js_number(FIX2LONG(obj)));
|
443
|
+
} else {
|
444
|
+
rb_raise(rb_eTypeError, "can't convert Bignum to JS::Object");
|
445
|
+
}
|
446
|
+
}
|
447
|
+
|
448
|
+
/*
|
449
|
+
* call-seq:
|
450
|
+
* to_js -> JS::Object
|
451
|
+
*
|
452
|
+
* Returns +self+ as a JS::Object.
|
453
|
+
*/
|
454
|
+
static VALUE _rb_js_float_to_js(VALUE obj) {
|
455
|
+
return jsvalue_s_new(rb_js_abi_host_float_to_js_number(RFLOAT_VALUE(obj)));
|
456
|
+
}
|
457
|
+
|
458
|
+
/*
|
459
|
+
* call-seq:
|
460
|
+
* to_js -> JS::Object
|
461
|
+
*
|
462
|
+
* Returns +self+ as a JS::Object.
|
463
|
+
*/
|
464
|
+
static VALUE _rb_js_string_to_js(VALUE obj) {
|
465
|
+
rb_js_abi_host_string_t abi_str;
|
466
|
+
rstring_to_abi_string(obj, &abi_str);
|
467
|
+
return jsvalue_s_new(rb_js_abi_host_string_to_js_string(&abi_str));
|
468
|
+
}
|
469
|
+
|
470
|
+
/*
|
471
|
+
* call-seq:
|
472
|
+
* to_js -> JS::Object
|
473
|
+
*
|
474
|
+
* Returns +self+ as a JS::Object.
|
475
|
+
*/
|
476
|
+
static VALUE _rb_js_true_to_js(VALUE obj) {
|
477
|
+
return jsvalue_s_new(rb_js_abi_host_bool_to_js_bool(true));
|
478
|
+
}
|
479
|
+
|
480
|
+
/*
|
481
|
+
* call-seq:
|
482
|
+
* to_js -> JS::Object
|
483
|
+
*
|
484
|
+
* Returns +self+ as a JS::Object.
|
485
|
+
*/
|
486
|
+
static VALUE _rb_js_false_to_js(VALUE obj) {
|
487
|
+
return jsvalue_s_new(rb_js_abi_host_bool_to_js_bool(false));
|
488
|
+
}
|
489
|
+
|
490
|
+
/*
|
491
|
+
* call-seq:
|
492
|
+
* to_js -> JS::Object
|
493
|
+
*
|
494
|
+
* Returns +self+ as a JS::Object.
|
495
|
+
*/
|
496
|
+
static VALUE _rb_js_proc_to_js(VALUE obj) {
|
497
|
+
rb_abi_lend_object(obj);
|
498
|
+
return jsvalue_s_new(rb_js_abi_host_proc_to_js_function((uint32_t)obj));
|
499
|
+
}
|
500
|
+
|
501
|
+
/*
|
502
|
+
* Document-class: JS::Object
|
503
|
+
*
|
504
|
+
* A JS::Object represents a JavaScript object.
|
505
|
+
* Note that JS::Object can represent a JavaScript object that represents a Ruby
|
506
|
+
* object (RbValue).
|
507
|
+
*
|
508
|
+
* == Example
|
509
|
+
*
|
510
|
+
* A simple object access:
|
511
|
+
*
|
512
|
+
* require 'js'
|
513
|
+
* document = JS.global[:document] # => # [object HTMLDocument]
|
514
|
+
* document[:title] # => "Hello, world!"
|
515
|
+
* document[:title] = "Hello, Ruby!"
|
516
|
+
*
|
517
|
+
* document.write("Hello, world!") # is equivalent to the following:
|
518
|
+
* document.call(:write, "Hello, world!")
|
519
|
+
* js_obj = JS.eval(<<-JS)
|
520
|
+
* return {
|
521
|
+
* method1: function(str, num) {
|
522
|
+
* // str is a JavaScript string and num is a JavaScript number.
|
523
|
+
* return str.length + num
|
524
|
+
* },
|
525
|
+
* method2: function(rbObject) {
|
526
|
+
* // Call String#upcase method for the given Ruby object (RbValue).
|
527
|
+
* return rbObject.call("upcase").toString();
|
528
|
+
* }
|
529
|
+
* }
|
530
|
+
* JS
|
531
|
+
* # Non JS::Object args are automatically converted to JS::Object by `to_js`.
|
532
|
+
* js_obj.method1("Hello", 5) # => 10
|
533
|
+
* js_obj.method2(JS::Object.wrap("Hello, Ruby"))
|
534
|
+
* # => "HELLO, RUBY" (JS::Object)
|
535
|
+
*/
|
536
|
+
|
537
|
+
/*
|
538
|
+
* JavaScript interoperations module
|
539
|
+
*/
|
540
|
+
void Init_js() {
|
541
|
+
rb_mJS = rb_define_module("JS");
|
542
|
+
rb_define_module_function(rb_mJS, "is_a?", _rb_js_is_kind_of, 2);
|
543
|
+
rb_define_module_function(rb_mJS, "try_convert", _rb_js_try_convert, 1);
|
544
|
+
rb_define_module_function(rb_mJS, "eval", _rb_js_eval_js, 1);
|
545
|
+
rb_define_module_function(rb_mJS, "global", _rb_js_global_this, 0);
|
546
|
+
|
547
|
+
i_to_js = rb_intern("to_js");
|
548
|
+
rb_cJS_Object = rb_define_class_under(rb_mJS, "Object", rb_cObject);
|
549
|
+
VALUE rb_cJS_singleton = rb_singleton_class(rb_cJS_Object);
|
550
|
+
rb_define_alloc_func(rb_cJS_Object, jsvalue_s_allocate);
|
551
|
+
rb_define_method(rb_cJS_Object, "[]", _rb_js_obj_aref, 1);
|
552
|
+
rb_define_method(rb_cJS_Object, "[]=", _rb_js_obj_aset, 2);
|
553
|
+
rb_define_method(rb_cJS_Object, "strictly_eql?", _rb_js_obj_strictly_eql, 1);
|
554
|
+
rb_define_method(rb_cJS_Object, "eql?", _rb_js_obj_eql, 1);
|
555
|
+
rb_define_method(rb_cJS_Object, "==", _rb_js_obj_eql, 1);
|
556
|
+
rb_define_method(rb_cJS_Object, "hash", _rb_js_obj_hash, 0);
|
557
|
+
rb_define_method(rb_cJS_Object, "call", _rb_js_obj_call, -1);
|
558
|
+
rb_define_method(rb_cJS_Object, "typeof", _rb_js_obj_typeof, 0);
|
559
|
+
rb_define_private_method(rb_cJS_Object, "__export_to_js", _rb_js_export_to_js,
|
560
|
+
0);
|
561
|
+
rb_define_private_method(rb_cJS_singleton, "__import_from_js",
|
562
|
+
_rb_js_import_from_js, 0);
|
563
|
+
rb_define_method(rb_cJS_Object, "to_s", _rb_js_obj_to_s, 0);
|
564
|
+
rb_define_alias(rb_cJS_Object, "inspect", "to_s");
|
565
|
+
rb_define_method(rb_cJS_Object, "to_i", _rb_js_obj_to_i, 0);
|
566
|
+
rb_define_method(rb_cJS_Object, "to_f", _rb_js_obj_to_f, 0);
|
567
|
+
rb_define_singleton_method(rb_cJS_Object, "wrap", _rb_js_obj_wrap, 1);
|
568
|
+
|
569
|
+
rb_define_method(rb_cInteger, "to_js", _rb_js_integer_to_js, 0);
|
570
|
+
rb_define_method(rb_cFloat, "to_js", _rb_js_float_to_js, 0);
|
571
|
+
rb_define_method(rb_cString, "to_js", _rb_js_string_to_js, 0);
|
572
|
+
rb_define_method(rb_cTrueClass, "to_js", _rb_js_true_to_js, 0);
|
573
|
+
rb_define_method(rb_cFalseClass, "to_js", _rb_js_false_to_js, 0);
|
574
|
+
rb_define_method(rb_cProc, "to_js", _rb_js_proc_to_js, 0);
|
575
|
+
|
576
|
+
rb_cJS_Error = rb_define_class_under(rb_mJS, "Error", rb_eStandardError);
|
577
|
+
}
|