ruby-await-nodejs 0.0.4

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b011818d77969f2e0efdfdf27dee659cfa4d7d896f34181178c260135053ac81
4
+ data.tar.gz: 32aa42178b25ef2d007d36bc1521bbfa9c3ae889fbb35391df9c7e4ca09fde35
5
+ SHA512:
6
+ metadata.gz: 3f5ae612ab8609130e3733c2bcfe66926f36daaaa1f023578f487d84b11a078f45681190e5b9431299b133e8a9ae2cd04f07cc54f34f42945c95e9a81c11f8c6
7
+ data.tar.gz: 2af21e88750990aaaa2aad0b4c85325e3aadb4253dbf54a41da3d97eae94517f2dc5c7175eb0d848e2dce0905abb4031b044ac69537cd97890b7221e019f50d2
@@ -0,0 +1,17 @@
1
+ version: 2
2
+ template:
3
+ docker: &docker
4
+ - image: cimg/ruby:2.6.5-node
5
+ jobs:
6
+ test:
7
+ docker: *docker
8
+ steps:
9
+ - checkout
10
+ - run: gem install bundler:1.16.1
11
+ - run: bundle
12
+ - run: bundle exec rspec spec/
13
+ workflows:
14
+ version: 2
15
+ test:
16
+ jobs:
17
+ - test
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ tags
2
+ .byebug_history
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+
4
+ ruby ">= 2.6.5"
5
+
6
+ # Specify your gem's dependencies in mavenlink-js.gemspec
7
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,37 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ruby-await-nodejs (0.0.4)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ byebug (11.1.3)
10
+ diff-lcs (1.3)
11
+ rspec (3.8.0)
12
+ rspec-core (~> 3.8.0)
13
+ rspec-expectations (~> 3.8.0)
14
+ rspec-mocks (~> 3.8.0)
15
+ rspec-core (3.8.2)
16
+ rspec-support (~> 3.8.0)
17
+ rspec-expectations (3.8.4)
18
+ diff-lcs (>= 1.2.0, < 2.0)
19
+ rspec-support (~> 3.8.0)
20
+ rspec-mocks (3.8.1)
21
+ diff-lcs (>= 1.2.0, < 2.0)
22
+ rspec-support (~> 3.8.0)
23
+ rspec-support (3.8.2)
24
+
25
+ PLATFORMS
26
+ ruby
27
+
28
+ DEPENDENCIES
29
+ byebug (~> 11.1.3)
30
+ rspec
31
+ ruby-await-nodejs!
32
+
33
+ RUBY VERSION
34
+ ruby 3.1.2p20
35
+
36
+ BUNDLED WITH
37
+ 1.16.1
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Mavenlink, Inc.
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # Introduction
2
+
3
+ This was inspired by https://github.com/mavenlink/alaska
4
+ Unfortunately, alaska was designed to run every new script in a new
5
+ sandbox, thus things like require won't work. So we don't have access to
6
+ all the power offered by nodejs
7
+
8
+ Out of our need to call javascript in a rapid fashion from javascript
9
+ with minimal setup, we decided to rewrite alaska into ruby-await-node
10
+ with the goal of efficiently execute sophisticated javascript code from
11
+ ruby.
12
+
13
+ The key to the performance is to launch a nodejs webserver, then use
14
+ such webserver to dangerously eval any given javascript part.
15
+
16
+ It's risky, we know. But with great power come great responsibility. You
17
+ should be using this if you want to leverage the expertise of javascript
18
+ where ruby fall short
19
+
20
+ # TODO For ruby-await-node
21
+
22
+ - [x] Execute any javascript from ruby
23
+ - [x] Pass all test
24
+ - [x] Execute await/async method
25
+
26
+ # Getting Started
27
+
28
+ ```ruby
29
+ gem 'ruby-await-node'
30
+ ```
31
+
32
+ Or if you want to run the latest version
33
+
34
+ ```ruby
35
+ gem 'ruby-await-node', :git => 'git@github.com:remitano/ruby-await-node.git'
36
+ ```
37
+
38
+ Then to invoke some javascript
39
+
40
+ ```ruby
41
+ runtime = RubyAwaitNode::Runtime.new(debug: true)
42
+ context = RubyAwaitNode::Context.new(runtime)
43
+ entry_path = File.expand_path("entry.js", __dir__)
44
+ context.eval("global.actor = require(#{entry_path.to_json})")
45
+ result = context.eval("actor.method()")
46
+ ```
47
+
48
+ Your entry.js may look like this:
49
+ ```javascript
50
+ const moment = require("moment")
51
+ module.exports = {
52
+ method: function() {
53
+ return something;
54
+ },
55
+
56
+ asyncMethod: async function() {
57
+ await operation;
58
+ return something;
59
+ }
60
+ }
61
+ ```
62
+
63
+ Under the hood ruby-await-node will automatically wait for async method
64
+ to complete
65
+
66
+ ## Examples
67
+
68
+ ### Load a javascript file
69
+ ```
70
+ context.load(File.expand_path("entry.js", __dir__))
71
+ ```
72
+
73
+ *Warning*: always pass the absolute path
74
+ ### Simple execution
75
+ ```
76
+ context.eval("1.0 + 2.0")
77
+ context.eval("global.a = 1.0")
78
+ ```
79
+
80
+ ### Calling function with arguments
81
+ ```
82
+ context.call("(function(b) { return global.a * b })", 5)
83
+ ```
84
+
85
+ This will be equivalent to execute this in nodejs
86
+ ```
87
+ (function(b) { return a * b }).apply(this, [5])
88
+ ```
89
+
90
+ ### Other examples
91
+ Look into spec/ for other potential examples
@@ -0,0 +1,83 @@
1
+ require 'net/http'
2
+ require 'socket'
3
+ require 'tempfile'
4
+ require 'json'
5
+ require_relative "exception"
6
+
7
+ module RubyAwaitNodejs
8
+ class Context
9
+ # runtime is an instance of RubyAwaitNodejs
10
+ # src is the js code to be eval()'d in the nodejs context
11
+ def initialize(runtime, src = "", options = {})
12
+ @runtime = runtime
13
+ @execution_timeout = options[:execution_timeout] || 60 # seconds
14
+
15
+ # compile context source, in most cases
16
+ # this is something like the CoffeeScript compiler
17
+ # or the SASS compiler
18
+ eval(src)
19
+ end
20
+
21
+ def eval(src)
22
+ if /\S/ =~ src #IMPORTANT! /\S/ =~ "()" => 0
23
+ exec(src)
24
+ end
25
+ end
26
+
27
+ def load(path)
28
+ exec("require(#{path.to_json})")
29
+ end
30
+
31
+ def exec(src)
32
+ return "" unless src.length > 0
33
+
34
+ src = src.encode('UTF-8', :undef => :replace, :replace => '')
35
+ src = compile_source(src)
36
+
37
+ # src is either an empty object
38
+ # OR a valid JSON string in the form
39
+ # ['ok', 'result-of-coffeescript-or-sass-compiler']
40
+ # OR if an error occured
41
+ # ['err', 'some sort of error to be presented to the developer as a sprockets error']
42
+ #
43
+ status, value = src.empty? ? [] : ::JSON.parse(src, create_additions: false)
44
+ if status == "ok"
45
+ value
46
+ elsif value =~ /SyntaxError:/
47
+ raise RuntimeError, value
48
+ else
49
+ raise ProgramError, value
50
+ end
51
+ end
52
+
53
+ def call(identifier, *args)
54
+ eval "#{identifier}.apply(this, #{::JSON.generate(args)})"
55
+ end
56
+
57
+ private
58
+
59
+ def compile_source(contents)
60
+ sock = Net::BufferedIO.new(
61
+ @runtime.provision_socket,
62
+ read_timeout: @execution_timeout,
63
+ write_timeout: @execution_timeout,
64
+ continue_timeout: @execution_timeout
65
+ )
66
+ request = Net::HTTP::Post.new("/")
67
+ request['Connection'] = 'close'
68
+ request['Content-Type'] = 'application/x-www-form-urlencoded'
69
+ # This Host header to make sure NodeJS does not throw ClientError, since change from version 23.x with new HTTP parser
70
+ request['Host'] = 'localhost'
71
+ request.body = contents
72
+ request.exec(sock, "1.1", "/")
73
+
74
+ begin
75
+ response = Net::HTTPResponse.read_new(sock)
76
+ end while response.kind_of?(Net::HTTPContinue)
77
+
78
+ response.reading_body(sock, request.response_body_permitted?) { }
79
+ sock.close
80
+ response.body
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,4 @@
1
+ module RubyAwaitNodejs
2
+ class RuntimeError < StandardError; end
3
+ class ProgramError < StandardError; end
4
+ end
@@ -0,0 +1,105 @@
1
+ require 'tempfile'
2
+
3
+ require_relative 'context'
4
+
5
+ module RubyAwaitNodejs
6
+ class Runtime
7
+ attr_accessor :debug, :nodejs_cmd, :port, :pid, :semaphore
8
+
9
+ def initialize(opts = {})
10
+ srand
11
+
12
+ @debug = opts[:debug]
13
+ @nodejs_cmd = "node"
14
+ @pid = nil
15
+ @semaphore = Mutex.new
16
+ end
17
+
18
+ def name
19
+ "RubyAwaitNodejs"
20
+ end
21
+
22
+ def available?
23
+ ENV["PATH"].split(":").detect do |path|
24
+ %w{
25
+ nodejs
26
+ node
27
+ }.detect do |node|
28
+ File.exist?(File.join(path, node)) || File.symlink?(File.join(path, node))
29
+ end
30
+ end
31
+ end
32
+
33
+ def deprecated?
34
+ false
35
+ end
36
+
37
+ def context_class
38
+ RubyAwaitNodejs::Context
39
+ end
40
+
41
+ #NOTE: this should be thread-safe
42
+ def provision_socket
43
+ ensure_startup unless @pid
44
+
45
+ wait_socket = nil
46
+ checks = 0
47
+ max_retries = 12
48
+
49
+ while checks < max_retries
50
+ begin
51
+ checks += 1
52
+ wait_socket = UNIXSocket.new(@port)
53
+ break
54
+ rescue Errno::ENOENT, Errno::ECONNREFUSED, Errno::ENOTDIR
55
+ wait_socket = nil
56
+ sleep 0.5
57
+ end
58
+ end
59
+
60
+ if checks >= max_retries
61
+ ensure_shutdown
62
+ raise RuntimeError, "unable to connect to ruby-await-nodejs.js server"
63
+ end
64
+
65
+ wait_socket
66
+ end
67
+
68
+ private
69
+
70
+ def ensure_startup
71
+ @semaphore.synchronize {
72
+ return if @pid
73
+
74
+ @port = begin
75
+ tmpfile = Tempfile.new("ruby-await-nodejs")
76
+ path = tmpfile.path
77
+ tmpfile.close
78
+ tmpfile.unlink
79
+ path
80
+ end
81
+
82
+ ruby_await_nodejs_js_path = File.join(File.dirname(File.expand_path(__FILE__)), '../../ruby-await-nodejs.js')
83
+ command_options = [ruby_await_nodejs_js_path, "--debug #{!!@debug}"] # --other --command-line --options --go --here
84
+
85
+ @initialize_pid = Process.pid
86
+ @pid = Process.spawn({"PORT" => @port.to_s}, @nodejs_cmd, *command_options, {:err => :out})
87
+
88
+ at_exit do
89
+ ensure_shutdown
90
+ end
91
+ }
92
+ end
93
+
94
+ def ensure_shutdown
95
+ return unless @pid
96
+ return unless Process.pid == @initialize_pid
97
+
98
+ Process.kill("TERM", @pid) rescue Errno::ECHILD
99
+ Process.wait(@pid) rescue Errno::ECHILD
100
+
101
+ @port = nil
102
+ @pid = nil
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,3 @@
1
+ module RubyAwaitNodejs
2
+ VERSION = "0.0.4"
3
+ end
@@ -0,0 +1,2 @@
1
+ require 'ruby-await-nodejs/version'
2
+ require 'ruby-await-nodejs/runtime'
@@ -0,0 +1,18 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'ruby-await-nodejs/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'ruby-await-nodejs'
7
+ s.version = RubyAwaitNodejs::VERSION
8
+ s.summary = "Efficiently execute js from ruby by keeping a long run nodejs process"
9
+ s.description = "Efficiently execute js from ruby by keeping a long run nodejs process"
10
+ s.authors = ["Phuong Nguyen", "Jon Bardin", "Stephen Grider", "Ville Lautanala", "Giovanni Bonetti"]
11
+ s.email = 'phuongnd08@gmail.com'
12
+ s.files = `git ls-files -z`.split("\x0")
13
+ s.homepage = "https://github.com/remitano/ruby-await-nodejs"
14
+ s.license = 'MIT'
15
+
16
+ s.add_development_dependency 'rspec'
17
+ s.add_development_dependency 'byebug', '~> 11.1.3'
18
+ end
@@ -0,0 +1,69 @@
1
+ const http = require("http");
2
+
3
+ const debugOpt = "--debug true";
4
+ let debug = false;
5
+
6
+ process.argv.forEach((val, index, array) => {
7
+ if (debugOpt === val) {
8
+ debug = true;
9
+ }
10
+ });
11
+
12
+ const webPrint = (res, respBody) => {
13
+ res.writeHead(200, { Connection: "keep-alive" });
14
+ res.write(respBody);
15
+ res.end();
16
+ };
17
+
18
+ const webPrintResult = (res, result) => {
19
+ webPrint(res, JSON.stringify(["ok", result]));
20
+ };
21
+
22
+ const webPrintError = (res, error) => {
23
+ webPrint(res, JSON.stringify(["err", error.toString()]));
24
+ };
25
+
26
+ function isPromise(value) {
27
+ return Boolean(value && typeof value.then === "function");
28
+ }
29
+
30
+ const server = http.createServer((req, res) => {
31
+ let contents = "";
32
+
33
+ req.on("data", (dataIn) => {
34
+ contents += dataIn;
35
+ });
36
+
37
+ req.on("end", () => {
38
+ try {
39
+ const result = eval(contents);
40
+ if (typeof result == "undefined" && result !== null) {
41
+ webPrintResult(res, null);
42
+ } else if (isPromise(result)) {
43
+ result
44
+ .then((value) => {
45
+ webPrintResult(res, value);
46
+ })
47
+ .catch((err) => {
48
+ webPrintError(res, err);
49
+ });
50
+ } else {
51
+ try {
52
+ webPrintResult(res, result);
53
+ } catch (err) {
54
+ webPrintError(res, err);
55
+ }
56
+ }
57
+ } catch (err) {
58
+ webPrintError(res, err);
59
+ }
60
+ });
61
+ });
62
+
63
+ const port = process.env.PORT || 3001;
64
+ server.listen(port);
65
+
66
+ if (debug) {
67
+ console.log("Listening on port:", port);
68
+ console.error("RubyAwaitNode.js started. Piping coffee to warmer climates.");
69
+ }
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'byebug'
4
+ require 'ruby-await-nodejs'
5
+
6
+ ruby_await_node_runtime = RubyAwaitNodejs::Runtime.new(:debug => false)
7
+ context = RubyAwaitNodejs::Context.new(ruby_await_node_runtime)
8
+ context.eval("global.a = 2.0")
9
+
10
+ fork_count = 4
11
+
12
+ pids = (0...fork_count).map do |i|
13
+ fork do
14
+ sleep i * 0.1 # simulate different process exit at different time to expose premature shutdown of shared nodejs process
15
+ result = context.call("(function(b) { return (global.a * b); })", i)
16
+ exit result #use the exit code to communicate the calculation result
17
+ end
18
+ end
19
+
20
+ exit_statuses = pids.map { |pid| Process.wait2(pid) }
21
+
22
+ results = []
23
+
24
+ exit_statuses.each do |pid, status|
25
+ results << status.exitstatus
26
+ end
27
+
28
+ # http://www.wolframalpha.com/input/?i=3rd+trianglur+number
29
+ sum = results.compact.inject(0) { |result, element| result + element }
30
+
31
+ if (sum) == 12
32
+ exit 0
33
+ else
34
+ exit 1
35
+ end
@@ -0,0 +1,162 @@
1
+ require 'spec_helper'
2
+
3
+ describe RubyAwaitNodejs do
4
+ def return_42
5
+ "(function() { var f = 42; return 42;})()"
6
+ end
7
+
8
+ def await_return_42
9
+ "(async function() { var f = 42; await new Promise(resolve => setTimeout(resolve, 1000)); return 42;})()"
10
+ end
11
+
12
+ def create_ruby_await_node_runtime
13
+ RubyAwaitNodejs::Runtime.new(:debug => false)
14
+ end
15
+
16
+ def create_ruby_await_node_context(timeout: nil)
17
+ RubyAwaitNodejs::Context.new(create_ruby_await_node_runtime, "", { execution_timeout: timeout })
18
+ end
19
+
20
+ context "simple javascript" do
21
+ it "returns desired value" do
22
+ js_result = create_ruby_await_node_context.eval(return_42)
23
+ expect(js_result).to eq 42
24
+ end
25
+ end
26
+
27
+ context "await javascript" do
28
+ it "return desired value" do
29
+ js_result = create_ruby_await_node_context.eval(await_return_42)
30
+ expect(js_result).to eq 42
31
+ end
32
+
33
+ it "will raise error if the execution_timeout is less than actual execution time" do
34
+ expect do
35
+ create_ruby_await_node_context(timeout: 0.05).eval(await_return_42)
36
+ end.to raise_error(Net::ReadTimeout)
37
+ end
38
+ end
39
+
40
+ describe "load an entry file" do
41
+ it "loads correctly" do
42
+ path = File.expand_path("sample_entry.js", __dir__)
43
+ context = create_ruby_await_node_context
44
+ context.load(path)
45
+ js_result = context.eval("global.entryName")
46
+ expect(js_result).to eq "sample"
47
+ end
48
+ end
49
+
50
+ it "raises an RubyAwaitNodejs::ProgramError on error" do
51
+ expect {
52
+ create_ruby_await_node_context.eval("(function() { throw new Error('foo\\nbar', 0, 'test.js'); })()")
53
+ }.to raise_error(RubyAwaitNodejs::ProgramError)
54
+ end
55
+
56
+ it "requires js to be in a self-executing function" do
57
+ js_result = -1
58
+
59
+ expect {
60
+ js_result = create_ruby_await_node_context.eval("return true;")
61
+ }.to raise_error(RubyAwaitNodejs::RuntimeError)
62
+
63
+ expect(js_result).to eq(-1)
64
+ end
65
+
66
+ it "safely allows subsequent #eval calls after runtime error" do
67
+ js_result = create_ruby_await_node_context.eval(return_42)
68
+ expect(js_result).to eq 42
69
+
70
+ expect {
71
+ js_result = create_ruby_await_node_context.eval("return true;")
72
+ }.to raise_error(RubyAwaitNodejs::RuntimeError)
73
+
74
+ js_result = create_ruby_await_node_context.eval(return_42)
75
+ expect(js_result).to eq 42
76
+ end
77
+
78
+ it "should be thread safe when sharing context between threads" do
79
+ thread_count = 128
80
+ threads = []
81
+ semaphore = Mutex.new
82
+ results = []
83
+
84
+ context = create_ruby_await_node_context
85
+ context.eval("global.a = 1.0;")
86
+
87
+ thread_count.times { |index|
88
+ threads << Thread.new {
89
+ result = context.call("(function(b) { return (global.a * b); })", index)
90
+ semaphore.synchronize {
91
+ results << result
92
+ }
93
+ }
94
+ }
95
+
96
+ threads.each { |t| t.join }
97
+
98
+ sum = results.inject(0) { |result, element| result + element }
99
+
100
+ expect(sum).to eq(8128) # http://www.wolframalpha.com/input/?i=127th+trianglur+number
101
+ end
102
+
103
+ it "should be thread safe when creating new contexts in threads" do
104
+ thread_count = 128
105
+ threads = []
106
+ semaphore = Mutex.new
107
+ results = []
108
+
109
+ thread_count.times { |index|
110
+ threads << Thread.new {
111
+ context = create_ruby_await_node_context
112
+ context.eval("global.a = 2.0;") # this asserts that the context is shared
113
+ result = context.call("(function(b) { return (a * b); })", index)
114
+ semaphore.synchronize {
115
+ results << result
116
+ }
117
+ }
118
+ }
119
+
120
+ threads.each { |t| t.join }
121
+
122
+ sum = results.inject(0) { |result, element| result + element }
123
+
124
+ expect(sum).to eq(8128 * 2) # http://www.wolframalpha.com/input/?i=127th+trianglur+number
125
+ end
126
+
127
+ it "should not break if exception occurs in thread" do
128
+ context_a = create_ruby_await_node_context
129
+
130
+ g_err_a = nil
131
+ g_err_b = nil
132
+
133
+ make_program_error_thread = Thread.new {
134
+ begin
135
+ _b = context_a.call("(function() { asd() })")
136
+ rescue => err_a
137
+ g_err_a = err_a
138
+ end
139
+ }
140
+
141
+ context_b = create_ruby_await_node_context
142
+
143
+ begin
144
+ _c = context_b.call("(function() { asd) })")
145
+ rescue => err_b
146
+ g_err_b = err_b
147
+ end
148
+
149
+ make_program_error_thread.join
150
+
151
+ expect(g_err_a).to be_kind_of(RubyAwaitNodejs::ProgramError)
152
+ expect(g_err_b).to be_kind_of(RubyAwaitNodejs::RuntimeError)
153
+ end
154
+
155
+ it "should work when the context is shared between forked processes" do
156
+ fork_test_harness_pid = Process.spawn("bundle exec ruby spec/fork_test_harness.rb")
157
+ exit_pid, exit_status = Process.wait2(fork_test_harness_pid)
158
+
159
+ expect(exit_pid).to eq(fork_test_harness_pid)
160
+ expect(exit_status).to eq(0)
161
+ end
162
+ end
@@ -0,0 +1 @@
1
+ global.entryName = "sample"
@@ -0,0 +1,2 @@
1
+ require 'byebug'
2
+ require 'ruby-await-nodejs'
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-await-nodejs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Phuong Nguyen
8
+ - Jon Bardin
9
+ - Stephen Grider
10
+ - Ville Lautanala
11
+ - Giovanni Bonetti
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+ date: 2025-07-02 00:00:00.000000000 Z
16
+ dependencies:
17
+ - !ruby/object:Gem::Dependency
18
+ name: rspec
19
+ requirement: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: '0'
24
+ type: :development
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
31
+ - !ruby/object:Gem::Dependency
32
+ name: byebug
33
+ requirement: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - "~>"
36
+ - !ruby/object:Gem::Version
37
+ version: 11.1.3
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - "~>"
43
+ - !ruby/object:Gem::Version
44
+ version: 11.1.3
45
+ description: Efficiently execute js from ruby by keeping a long run nodejs process
46
+ email: phuongnd08@gmail.com
47
+ executables: []
48
+ extensions: []
49
+ extra_rdoc_files: []
50
+ files:
51
+ - ".circleci/config.yml"
52
+ - ".gitignore"
53
+ - Gemfile
54
+ - Gemfile.lock
55
+ - LICENSE
56
+ - README.md
57
+ - lib/ruby-await-nodejs.rb
58
+ - lib/ruby-await-nodejs/context.rb
59
+ - lib/ruby-await-nodejs/exception.rb
60
+ - lib/ruby-await-nodejs/runtime.rb
61
+ - lib/ruby-await-nodejs/version.rb
62
+ - ruby-await-nodejs.gemspec
63
+ - ruby-await-nodejs.js
64
+ - spec/fork_test_harness.rb
65
+ - spec/ruby_await_node_spec.rb
66
+ - spec/sample_entry.js
67
+ - spec/spec_helper.rb
68
+ homepage: https://github.com/remitano/ruby-await-nodejs
69
+ licenses:
70
+ - MIT
71
+ metadata: {}
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubygems_version: 3.3.7
88
+ signing_key:
89
+ specification_version: 4
90
+ summary: Efficiently execute js from ruby by keeping a long run nodejs process
91
+ test_files: []