jscall 1.1.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5fb1072aa12a5e884d9c92537f6ae7a5c632d4940715008865ec9760940f1c2
4
- data.tar.gz: 597c3199f5ee21f98d80a42b05bf9822b729a22311d7c9f43e2cf45d54594983
3
+ metadata.gz: 1df05fa2e6cee8575b7cdf9a95d35c264422d66c1c793f71e620462380a891bc
4
+ data.tar.gz: 4bae39ef37ec190d8c6b87fb4541c0ec4f074b7c5b09eeecc1d92a4a47dd570c
5
5
  SHA512:
6
- metadata.gz: 54c16c0015f2296309523ecf5d966bbf2071303136afef04e0bbdf139aa204c4b3db332a73ea65c0194fce7cea795503db17577805b4110a56edda796fca0a0b
7
- data.tar.gz: ada3a68d6c19093c22087982e520ed18a0f3f3709584fc2c30978aed7909c1b6b8568eb48e24fde6c57cc759dc235b1a824524b1c0d43053d4d80512767339a8
6
+ metadata.gz: 16c12783ff80fefb85e4453ca09b54faf4b614895157f4e57108379a51ef0ebbacc2fb38ddff7d87faef50a5c3880a6690cfeb03dc5e5d67be447e36236475af
7
+ data.tar.gz: a5b57ae8e5d7d891648d457ed32f481ea1b0d528d973e693e164f5053e39f6bfce235148fc22990a53e52e5d7ceaa5eb91dc3297b4b89b8a7af90aa47b88ff54
data/README.md CHANGED
@@ -18,7 +18,7 @@ Jscall.exec '1 + 1'
18
18
  ```
19
19
 
20
20
  This returns `2`. The argument passed to `Jscall.exec` can be
21
- multipe lines. It is executed as source code written in JavaScript.
21
+ multiple lines. It is executed as source code written in JavaScript.
22
22
 
23
23
  `Jscall.exec` returns a resulting value. Numbers, character strings (and symbols), boolean values, and `nil` (and `null`)
24
24
  are copied when passing between Ruby and JavaScript. An array is shallow-copied.
@@ -64,7 +64,7 @@ when this ruby object is passed to JavaScript as an argument,
64
64
  a normal object `{ a: 2, b: 3 }` is created as its copy in JavaScript
65
65
  and passed to a JavaScript method.
66
66
 
67
- To call a JavaScript function from Ruby, call a mehtod on `Jscall`.
67
+ To call a JavaScript function from Ruby, call a method on `Jscall`.
68
68
  For example,
69
69
 
70
70
  ```
@@ -90,7 +90,7 @@ Jscall.console.log('Hello')
90
90
  ```
91
91
 
92
92
  This prints `Hello` on a JavaScript console. `Jscall.console` returns a remote
93
- refererence to the value of `console` in JavaScript. Then, `.log('Hello')`
93
+ reference to the value of `console` in JavaScript. Then, `.log('Hello')`
94
94
  calls the `log` method on `console` in JavaScript.
95
95
 
96
96
  When a Ruby object is passed to a JavaScript function/method,
@@ -110,7 +110,7 @@ created in Ruby.
110
110
  Note that you must `await` every call to Ruby object since it is
111
111
  asynchronous call.
112
112
 
113
- In JavaScript, `Ruby.exec` is availale to run a program in Ruby.
113
+ In JavaScript, `Ruby.exec` is available to run a program in Ruby.
114
114
  For example,
115
115
 
116
116
  ```
@@ -261,7 +261,7 @@ fs_module = await load('fs')
261
261
  ## Promise
262
262
 
263
263
  If a program attempts to pass a `Promise` object from JavaScript to Ruby,
264
- it waits until the promise is fullfilled. Then Jscall passes
264
+ it waits until the promise is fulfilled. Then Jscall passes
265
265
  the value of that promise from JavaScript to Ruby instead of that
266
266
  promise itself (or a remote reference to that promise). When that promise
267
267
  is rejected, an error object is passed to Ruby
@@ -270,7 +270,7 @@ This design reflects the fact that an `async` function in JavaScript
270
270
  also returns a `Promise` object but this object must not be returned
271
271
  to Ruby as is when that `async` function is called from Ruby.
272
272
  Jscall cannot determine whether a promise should be passed as is to Ruby
273
- or its value must be passed to Ruby after the promise is fullfilled.
273
+ or its value must be passed to Ruby after the promise is fulfilled.
274
274
 
275
275
  When enforcing Jscall to pass a `Promise` object from JavaScript to Ruby,
276
276
  `.async` must be inserted between a receiver and a method name.
@@ -288,6 +288,27 @@ prom = obj.async.a # promise
288
288
  prom.then(->(r) { puts r }) # 7
289
289
  ```
290
290
 
291
+ ## Synchronous calls
292
+
293
+ You might want to avoid writing `await` when you call a method on a Ruby
294
+ object or you execute Ruby code by `Ruby.exec` from JavaScript.
295
+ For example, that call is included in library code and you might not
296
+ be able to modify the library code so that `await` will be inserted.
297
+
298
+ Jscall supports synchronous calls from JavaScript to Ruby only when
299
+ the underlying JavaScript engine is node.js on Linux.
300
+ In the mode of synchronous calls, you do not have to `await` a method call
301
+ on a Ruby object or a call to `Ruby.exec`.
302
+ It blocks until the return value comes back from Ruby.
303
+ While it blocks, all calls from Ruby to JavaScript are
304
+ synchronously processed.
305
+
306
+ To change to the mode of synchronous calls,
307
+ call `Jscall.config`:
308
+
309
+ ```
310
+ Jscall.config(sync: true)
311
+ ```
291
312
 
292
313
  ## Configuration
293
314
 
@@ -348,15 +369,45 @@ Passing `true` for `browser:` switches the execution engine to a web browser.
348
369
  The default engine is node.js.
349
370
  To switch the engine back to node.js, pass `false` for `browser:`.
350
371
  Call `Jscall.close` to detach the current execution engine.
351
- A new enigine with a new configuration will be created.
372
+ A new engine with a new configuration will be created.
352
373
 
353
374
  `port:` specifies the port number of an http server. It is optional.
354
375
  The example above specifies that Ruby receives http requests
355
376
  sent to http://localhost:10082 from JavaScript on a web browser.
356
377
 
357
378
 
379
+ ### Misc.
380
+
381
+ To change to the mode of synchronous calls,
382
+
383
+ ```
384
+ Jscall.config(sync: true)
385
+ ```
386
+
387
+ To set all the configurations to the default ones,
388
+
389
+ ```
390
+ Jscall.config()
391
+ ```
392
+
358
393
  ### Other configurations
359
394
 
395
+ To obtain more detailed error messages,
396
+ set a debugging level to 10.
397
+ In Ruby,
398
+
399
+ ```
400
+ Jscall.debug = 10
401
+ ```
402
+
403
+ In JavaScript,
404
+
405
+ ```
406
+ Ruby.setDebugLevel(10)
407
+ ```
408
+
409
+ The default debugging level is 0.
410
+
360
411
  To change the name of the node command,
361
412
 
362
413
  ```
@@ -415,7 +466,7 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/csg-to
415
466
 
416
467
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
417
468
 
418
- ## Acknowledgement
469
+ ## Acknowledgment
419
470
 
420
471
  The icon image for jscall was created by partly using the Ruby logo, which was obtained
421
472
  from https://www.ruby-lang.org/en/about/logo/ under CC BY-SA 2.5.
data/Rakefile CHANGED
@@ -6,7 +6,11 @@ require "rake/testtask"
6
6
  Rake::TestTask.new(:test) do |t|
7
7
  t.libs << "test"
8
8
  t.libs << "lib"
9
- t.test_files = FileList["test/**/test_*.rb"]
9
+ files = FileList["test/**/test_*.rb"]
10
+ unless /linux/ =~ RbConfig::CONFIG['host_os']
11
+ files.exclude "test/test_sync_io.rb"
12
+ end
13
+ t.test_files = files
10
14
  end
11
15
 
12
16
  task default: :test
@@ -0,0 +1,56 @@
1
+ # Display a pdf file by using pdf.js
2
+
3
+ require 'jscall'
4
+
5
+ # Run a JavaScript program on a browser
6
+ Jscall.config browser: true
7
+
8
+ # Write HTML code on a blank web page.
9
+ Jscall.dom.append_to_body(<<CODE)
10
+ <h1>PDF.js 'Hello, world!' example</h1>
11
+ <canvas id="the-canvas"></canvas>
12
+ CODE
13
+
14
+ # import pdf.js
15
+ pdfjs = Jscall.dyn_import('https://mozilla.github.io/pdf.js/build/pdf.js')
16
+
17
+ # A pdf file
18
+ url = "https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/examples/learning/helloworld.pdf"
19
+
20
+ pdf = Jscall.exec 'window["pdfjs-dist/build/pdf"]'
21
+
22
+ pdf.GlobalWorkerOptions.workerSrc = "https://mozilla.github.io/pdf.js/build/pdf.worker.js"
23
+
24
+ loadingTask = pdf.getDocument(url)
25
+ loadingTask.async.promise.then(-> (pdf) {
26
+ puts "PDF loaded"
27
+
28
+ # Fetch the first page
29
+ pageNumber = 1;
30
+ pdf.async.getPage(pageNumber).then(-> (page) {
31
+ puts "Page loaded"
32
+
33
+ scale = 1.5;
34
+ viewport = page.getViewport({ scale: scale })
35
+
36
+ canvas = Jscall.document.getElementById("the-canvas")
37
+ context = canvas.getContext("2d")
38
+ canvas.height = viewport.height
39
+ canvas.width = viewport.width
40
+
41
+ # Render the pdf page
42
+ renderContext = {
43
+ canvasContext: context,
44
+ viewport: viewport,
45
+ }
46
+ renderTask = page.render(renderContext)
47
+ renderTask.async.promise.then(-> (r) {
48
+ # Print a message when the rendering succeeds.
49
+ puts "Page rendered #{r}"
50
+ })
51
+ })
52
+ },
53
+ -> (reason) {
54
+ # an error occurs.
55
+ puts reason
56
+ })
data/lib/jscall/main.mjs CHANGED
@@ -1,12 +1,19 @@
1
1
  // Copyright (C) 2022- Shigeru Chiba. All rights reserved.
2
2
 
3
- const cmd_eval = 1
4
- const cmd_call = 2
5
- const cmd_reply = 3
6
- const cmd_async_call = 4
7
- const cmd_async_eval = 5
8
- const cmd_retry = 6
9
- const cmd_reject = 7
3
+ let debug_level = 0
4
+
5
+ // debug level is 0 (default) or 10.
6
+ export const setDebugLevel = d => {
7
+ debug_level = d
8
+ }
9
+
10
+ export const cmd_eval = 1
11
+ export const cmd_call = 2
12
+ export const cmd_reply = 3
13
+ export const cmd_async_call = 4
14
+ export const cmd_async_eval = 5
15
+ export const cmd_retry = 6
16
+ export const cmd_reject = 7
10
17
 
11
18
  const param_array = 0
12
19
  const param_object = 1
@@ -185,12 +192,23 @@ const decode_obj = obj => {
185
192
  throw `decode_obj: unsupported value, ${obj}`
186
193
  }
187
194
 
195
+ export const decode_obj_or_error = obj => {
196
+ const result = decode_obj(obj)
197
+ if (result instanceof RubyError)
198
+ return result.get()
199
+ else
200
+ return result
201
+ }
202
+
188
203
  const js_eval = eval
189
204
 
190
- const funcall_from_ruby = cmd => {
205
+ export const funcall_from_ruby = cmd => {
191
206
  const receiver = decode_obj(cmd[2])
192
207
  const name = cmd[3]
193
208
  const args = cmd[4].map(e => decode_obj(e))
209
+ if (debug_level >= 10)
210
+ console.error(`RubyToJS> ${name} ${cmd[1]}`)
211
+
194
212
  if (name.endsWith('=')) {
195
213
  const name2 = name.substring(0, name.length - 1)
196
214
  if (receiver === null)
@@ -211,8 +229,8 @@ const funcall_from_ruby = cmd => {
211
229
  }
212
230
  else {
213
231
  const f = Reflect.get(receiver, name)
214
- if (f)
215
- if (typeof f === 'function')
232
+ if (f !== undefined)
233
+ if (typeof f === 'function' && !(f instanceof RemoteRef))
216
234
  return Reflect.apply(f, receiver, args)
217
235
  else if (args.length === 0)
218
236
  return f // obtain a propety
@@ -221,7 +239,7 @@ const funcall_from_ruby = cmd => {
221
239
  throw `unknown JS function/method was called: ${name} on <${receiver}>`
222
240
  }
223
241
 
224
- let stdout_puts = console.log
242
+ export let stdout_puts = console.log
225
243
  let num_generated_ids = 0
226
244
 
227
245
  const fresh_id = () => {
@@ -229,7 +247,7 @@ const fresh_id = () => {
229
247
  return num_generated_ids
230
248
  }
231
249
 
232
- const reply = (message_id, value, sync_mode) => {
250
+ export const reply = (message_id, value, sync_mode) => {
233
251
  if (sync_mode && value instanceof Promise)
234
252
  value.then(result => { reply(message_id, result, true) })
235
253
  .catch(err => reply_error(message_id, err))
@@ -244,8 +262,10 @@ const reply = (message_id, value, sync_mode) => {
244
262
  }
245
263
  }
246
264
 
247
- const reply_error = (message_id, e) => {
248
- const cmd = reply_with_piggyback([cmd_reply, message_id, encode_error(e)])
265
+ export const reply_error = (message_id, error) => {
266
+ const msg = typeof error === 'string' ? error : error.toString() +
267
+ '\n ---\n' + error.stack
268
+ const cmd = reply_with_piggyback([cmd_reply, message_id, encode_error(msg)])
249
269
  stdout_puts(JSON.stringify(cmd))
250
270
  }
251
271
 
@@ -279,24 +299,39 @@ let reply_counter = 0
279
299
 
280
300
  export const exec = src => {
281
301
  return new Promise((resolve, reject) => {
282
- const message_id = fresh_id()
283
- const cmd = reply_with_piggyback([cmd_eval, message_id, src])
302
+ const cmd = make_cmd_eval(src)
303
+ const message_id = cmd[1]
284
304
  callback_stack.push([message_id, resolve, reject])
285
305
  stdout_puts(JSON.stringify(cmd))
286
306
  })
287
307
  }
288
308
 
289
- const funcall_to_ruby = (receiver_id, name, args) => {
309
+ export const make_cmd_eval = src => {
310
+ const message_id = fresh_id()
311
+ return reply_with_piggyback([cmd_eval, message_id, src])
312
+ }
313
+
314
+ let funcall_to_ruby = (receiver_id, name, args) => {
290
315
  return new Promise((resolve, reject) => {
291
- const message_id = fresh_id()
292
- const receiver = [param_local_object, receiver_id]
293
- const encoded_args = args.map(e => encode_obj(e))
294
- const cmd = reply_with_piggyback([cmd_call, message_id, receiver, name, encoded_args])
316
+ const cmd = make_cmd_call(receiver_id, name, args)
317
+ const message_id = cmd[1]
295
318
  callback_stack.push([message_id, resolve, reject])
319
+ if (debug_level >= 10)
320
+ console.error(`JStoRuby< ${name} ${message_id}`)
321
+
296
322
  stdout_puts(JSON.stringify(cmd))
297
323
  })
298
324
  }
299
325
 
326
+ export const set_funcall_to_ruby = f => { funcall_to_ruby = f }
327
+
328
+ export const make_cmd_call = (receiver_id, name, args) => {
329
+ const message_id = fresh_id()
330
+ const receiver = [param_local_object, receiver_id]
331
+ const encoded_args = args.map(e => encode_obj(e))
332
+ return reply_with_piggyback([cmd_call, message_id, receiver, name, encoded_args])
333
+ }
334
+
300
335
  const returned_from_callback = cmd => {
301
336
  const message_id = cmd[1]
302
337
  const result = decode_obj(cmd[2])
@@ -412,6 +447,10 @@ export class MessageReader {
412
447
  }
413
448
  }
414
449
 
450
+ let make_message_reader = (stdin) => new MessageReader(stdin)
451
+
452
+ export const set_make_message_reader = (f) => { make_message_reader = f }
453
+
415
454
  export const start = async (stdin, use_stdout) => {
416
455
  if (use_stdout)
417
456
  console.log = console.error // on node.js
@@ -419,7 +458,7 @@ export const start = async (stdin, use_stdout) => {
419
458
  stdout_puts = (m) => stdin.puts(m) // on browser
420
459
 
421
460
  stdin.setEncoding('utf8')
422
- for await (const json_data of new MessageReader(stdin)) {
461
+ for await (const json_data of make_message_reader(stdin)) {
423
462
  let cmd
424
463
  try {
425
464
  cmd = JSON.parse(json_data)
@@ -451,9 +490,7 @@ export const start = async (stdin, use_stdout) => {
451
490
  else // cmd_retry and other unknown commands
452
491
  reply_error(cmd[1], `invalid command ${cmd[0]}`)
453
492
  } catch (error) {
454
- const msg = typeof error === 'string' ? error : error.toString() +
455
- '\n ---\n' + error.stack
456
- reply_error(cmd[1], msg)
493
+ reply_error(cmd[1], error)
457
494
  }
458
495
  }
459
496
  }
@@ -0,0 +1,185 @@
1
+ // Copyright (C) 2022- Shigeru Chiba. All rights reserved.
2
+ // This works only with node.js on Linux
3
+
4
+ import * as main from './main.mjs'
5
+ import { readSync, openSync } from 'fs'
6
+
7
+ class SynchronousStdin {
8
+ constructor() {
9
+ this.buf_size = 4096
10
+ this.buffer = Buffer.alloc(this.buf_size);
11
+ this.stdin = openSync('/dev/stdin', 'rs')
12
+ }
13
+
14
+ *[Symbol.iterator]() {
15
+ let str
16
+ while ((str = this.readOne()) !== null)
17
+ yield str
18
+ }
19
+
20
+ readOne() {
21
+ while (true) {
22
+ try {
23
+ const nbytes = readSync(this.stdin, this.buffer, 0, this.buf_size)
24
+ if (nbytes > 0)
25
+ return this.buffer.toString('utf-8', 0, nbytes)
26
+ else
27
+ return null // maybe EOF on macOS
28
+ }
29
+ catch (e) {
30
+ if (e.code === 'EOF')
31
+ return null
32
+ else if (e.code !== 'EAGAIN')
33
+ throw e
34
+ }
35
+ }
36
+ }
37
+ }
38
+
39
+ class SyncMessageReader extends main.MessageReader {
40
+ constructor(stream) {
41
+ super(stream)
42
+ this.stdin = new SynchronousStdin()
43
+ this.generator = null
44
+ }
45
+
46
+ gets_function() {
47
+ const iterator = this[Symbol.iterator]()
48
+ return () => {
49
+ const v = iterator.next()
50
+ if (v.done)
51
+ return null
52
+ else
53
+ return v.value
54
+ }
55
+ }
56
+
57
+ async *[Symbol.asyncIterator]() {
58
+ if (this.generator !== null) {
59
+ while (true) {
60
+ const v = this.generator.next()
61
+ if (v.done)
62
+ break
63
+ else
64
+ yield v.value
65
+ }
66
+ }
67
+ for await (const data of this.stream) {
68
+ this.acc += data
69
+ this.generator = this.generatorBody()
70
+ while (true) {
71
+ const v = this.generator.next()
72
+ if (v.done)
73
+ break
74
+ else
75
+ yield v.value
76
+ }
77
+ }
78
+ this.checkEOS()
79
+ }
80
+
81
+ *[Symbol.iterator]() {
82
+ if (this.generator !== null) {
83
+ while (true) {
84
+ const v = this.generator.next()
85
+ if (v.done)
86
+ break
87
+ else
88
+ yield v.value
89
+ }
90
+ }
91
+ for (const data of this.stdin) {
92
+ this.acc += data
93
+ this.generator = this.generatorBody()
94
+ while (true) {
95
+ const v = this.generator.next()
96
+ if (v.done)
97
+ break
98
+ else
99
+ yield v.value
100
+ }
101
+ }
102
+ this.checkEOS()
103
+ }
104
+
105
+ *generatorBody() {
106
+ let pos = 0
107
+ while (true) {
108
+ const result = this.iteratorBody(pos)
109
+ if (result[0] === false)
110
+ break
111
+ else if (result[0] !== true)
112
+ yield result[0] // result[0] is a string
113
+
114
+ pos = result[1]
115
+ if (this.checkEmptiness(pos))
116
+ break
117
+ }
118
+ }
119
+ }
120
+
121
+ export const start = main.start
122
+
123
+ let stdin_gets = null
124
+
125
+ main.set_make_message_reader((stdin) => {
126
+ const reader = new SyncMessageReader(stdin)
127
+ stdin_gets = reader.gets_function()
128
+ return reader
129
+ })
130
+
131
+ const js_eval = eval
132
+ const exported = main.get_exported_imported()[0]
133
+
134
+ const event_loop = () => {
135
+ let json_data
136
+ while ((json_data = stdin_gets()) !== null) {
137
+ let cmd
138
+ try {
139
+ cmd = JSON.parse(json_data)
140
+
141
+ // scavenge remote references
142
+ if (cmd.length > 5)
143
+ cmd[5].forEach(i => exported.remove(i))
144
+
145
+ if (cmd[0] == main.cmd_eval || cmd[0] == main.cmd_async_eval) {
146
+ const result = js_eval(cmd[2])
147
+ main.reply(cmd[1], result, false)
148
+ }
149
+ else if (cmd[0] == main.cmd_call || cmd[0] == main.cmd_async_call) {
150
+ const result = main.funcall_from_ruby(cmd)
151
+ main.reply(cmd[1], result, false)
152
+ }
153
+ else if (cmd[0] == main.cmd_reply)
154
+ return main.decode_obj_or_error(cmd[2])
155
+ else { // cmd_retry, cmd_reject, and other unknown commands
156
+ console.error(`*** node.js; bad message received: ${json_data}`)
157
+ break
158
+ }
159
+ } catch (error) {
160
+ const msg = typeof error === 'string' ? error : error.toString() +
161
+ '\n ---\n' + error.stack
162
+ main.reply_error(cmd[1], msg)
163
+ }
164
+ }
165
+ return undefined
166
+ }
167
+
168
+ export const exec = src => {
169
+ const cmd = main.make_cmd_eval(src)
170
+ main.stdout_puts(JSON.stringify(cmd))
171
+ return event_loop()
172
+ }
173
+
174
+ main.set_funcall_to_ruby((receiver_id, name, args) => {
175
+ const cmd = main.make_cmd_call(receiver_id, name, args)
176
+ main.stdout_puts(JSON.stringify(cmd))
177
+ return event_loop()
178
+ })
179
+
180
+ export const scavenge_references = main.scavenge_references
181
+
182
+ // for testing and debugging
183
+ export const get_exported_imported = main.get_exported_imported
184
+
185
+ export const dyn_import = main.dyn_import
@@ -3,5 +3,5 @@
3
3
  # Copyright (C) 2022- Shigeru Chiba. All rights reserved.
4
4
 
5
5
  module Jscall
6
- VERSION = "1.1.0"
6
+ VERSION = "1.3.0"
7
7
  end
data/lib/jscall.rb CHANGED
@@ -231,7 +231,8 @@ module Jscall
231
231
  script2 += "import * as m#{i + 2} from \"#{module_names[i][1]}#{module_names[i][2]}\"; globalThis.#{module_names[i][0]} = m#{i + 2}; "
232
232
  end
233
233
  script2 += "import { createRequire } from \"node:module\"; globalThis.require = createRequire(\"file://#{Dir.pwd}/\");"
234
- script = "'import * as m1 from \"#{__dir__}/jscall/main.mjs\"; globalThis.Ruby = m1; #{script2}; Ruby.start(process.stdin, true)'"
234
+ main_js_file = if config[:sync] then "synch.mjs" else "main.mjs" end
235
+ script = "'import * as m1 from \"#{__dir__}/jscall/#{main_js_file}\"; globalThis.Ruby = m1; #{script2}; Ruby.start(process.stdin, true)'"
235
236
  @pipe = IO.popen("#{@@node_cmd} #{options} --input-type 'module' -e #{script}", "r+t")
236
237
  @pipe.autoclose = true
237
238
  end
@@ -392,13 +393,15 @@ module Jscall
392
393
  if reply[1] != message_id
393
394
  send_reply(reply[1], nil, false, CMD_REJECT)
394
395
  else
395
- result = @pending_replies.delete(message_id)
396
- if result.nil?
397
- raise RuntimeError.new("bad CMD_RETRY: #{reply}")
398
- elsif result.is_a?(JavaScriptError)
399
- raise result
396
+ if @pending_replies.key?(message_id)
397
+ result = @pending_replies.delete(message_id)
398
+ if result.is_a?(JavaScriptError)
399
+ raise result
400
+ else
401
+ return result
402
+ end
400
403
  else
401
- return result
404
+ raise RuntimeError.new("bad CMD_RETRY: #{reply}")
402
405
  end
403
406
  end
404
407
  else
@@ -432,7 +435,7 @@ module Jscall
432
435
  @configurations = {}
433
436
  @pipeToJsClass = PipeToJs
434
437
 
435
- #def self.config(module_names: [], options: '', browser: false)
438
+ #def self.config(module_names: [], options: '', browser: false, sync: false)
436
439
  def self.config(**kw)
437
440
  if kw.nil? || kw == {}
438
441
  @configurations = {}
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jscall
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shigeru Chiba
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-08-11 00:00:00.000000000 Z
11
+ date: 2022-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: webrick
@@ -35,6 +35,7 @@ files:
35
35
  - LICENSE
36
36
  - README.md
37
37
  - Rakefile
38
+ - examples/pdf-js.rb
38
39
  - jscall.gemspec
39
40
  - lib/jscall.rb
40
41
  - lib/jscall/apple-touch-icon.png
@@ -43,6 +44,7 @@ files:
43
44
  - lib/jscall/favicon.ico
44
45
  - lib/jscall/jscall.html
45
46
  - lib/jscall/main.mjs
47
+ - lib/jscall/synch.mjs
46
48
  - lib/jscall/version.rb
47
49
  homepage: https://github.com/csg-tokyo/jscall
48
50
  licenses: