jscall 1.1.0 → 1.3.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 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: