js 0.0.1 → 2.5.0
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.
- 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 +39 -22
- 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
|
+
}
|