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 +4 -4
 - data/README.md +59 -8
 - data/Rakefile +5 -1
 - data/examples/pdf-js.rb +56 -0
 - data/lib/jscall/main.mjs +62 -25
 - data/lib/jscall/synch.mjs +185 -0
 - data/lib/jscall/version.rb +1 -1
 - data/lib/jscall.rb +11 -8
 - metadata +4 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 1df05fa2e6cee8575b7cdf9a95d35c264422d66c1c793f71e620462380a891bc
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 4bae39ef37ec190d8c6b87fb4541c0ec4f074b7c5b09eeecc1d92a4a47dd570c
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 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 
     | 
    
         
            -
             
     | 
| 
      
 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  
     | 
| 
      
 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 
     | 
    
         
            -
             
     | 
| 
      
 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  
     | 
| 
      
 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  
     | 
| 
      
 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  
     | 
| 
      
 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  
     | 
| 
      
 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 
     | 
    
         
            -
            ##  
     | 
| 
      
 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 
     | 
    
         
            -
               
     | 
| 
      
 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
         
     | 
    
        data/examples/pdf-js.rb
    ADDED
    
    | 
         @@ -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 
     | 
    
         
            -
             
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
            const  
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
      
 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,  
     | 
| 
       248 
     | 
    
         
            -
                const  
     | 
| 
      
 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  
     | 
| 
       283 
     | 
    
         
            -
                    const  
     | 
| 
      
 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  
     | 
| 
      
 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  
     | 
| 
       292 
     | 
    
         
            -
                    const  
     | 
| 
       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  
     | 
| 
      
 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 
     | 
    
         
            -
                         
     | 
| 
       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
         
     | 
    
        data/lib/jscall/version.rb
    CHANGED
    
    
    
        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 
     | 
    
         
            -
                         
     | 
| 
      
 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 
     | 
    
         
            -
                                     
     | 
| 
       396 
     | 
    
         
            -
             
     | 
| 
       397 
     | 
    
         
            -
                                         
     | 
| 
       398 
     | 
    
         
            -
             
     | 
| 
       399 
     | 
    
         
            -
                                         
     | 
| 
      
 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 
     | 
    
         
            -
                                         
     | 
| 
      
 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. 
     | 
| 
      
 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- 
     | 
| 
      
 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:
         
     |