node-runner-temp-fix-windows 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +23 -0
- data/README.md +102 -0
- data/Rakefile +10 -0
- data/bridgetown.automation.rb +29 -0
- data/lib/node-runner.rb +178 -0
- data/lib/node_runner.js +9 -0
- data/lib/version.rb +4 -0
- data/node-runner-temp-fix-windows.gemspec +19 -0
- metadata +53 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c49ff83ca1cae9983c7228f1cef806c6e6c1e3b533645347bd3db68e24a05dca
|
4
|
+
data.tar.gz: 6b1e4015081845299f93dae7b57c26413c862e77626481150958898eb5adb2aa
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 82e6762b15829446df805a1a06780aa1a5a41bc558bc1fce781a0c5059af3e7d82b2cf86d8ef1e751d8a42e9b241631209acbaca4d2b88630637355788ac061d
|
7
|
+
data.tar.gz: 023ff71fc4ae3b9eeedae777474db761b2b570dfdf4ea8f15788f005f309b9d625324140aa7568e54ab10b05b135911de6cd67d95a0b70ea9acb49d9d108b3b2
|
data/.gitignore
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020-present Jared White and Bridgetown contributors
|
4
|
+
Portions copyright (c) 2015-2016 Sam Stephenson
|
5
|
+
Portions copyright (c) 2015-2016 Josh Peek
|
6
|
+
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
9
|
+
in the Software without restriction, including without limitation the rights
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
12
|
+
furnished to do so, subject to the following conditions:
|
13
|
+
|
14
|
+
The above copyright notice and this permission notice shall be included in
|
15
|
+
all copies or substantial portions of the Software.
|
16
|
+
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# NodeRunner for Ruby
|
2
|
+
|
3
|
+
A simple way to execute Javascript in a Ruby context via Node. (Loosely based on the Node Runtime module from [ExecJS](https://github.com/rails/execjs).)
|
4
|
+
|
5
|
+
[](https://badge.fury.io/rb/node-runner)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Run this command to add this plugin to your project's Gemfile:
|
10
|
+
|
11
|
+
```shell
|
12
|
+
$ bundle add node-runner
|
13
|
+
```
|
14
|
+
|
15
|
+
For [Bridgetown](https://www.bridgetownrb.com) websites (requires v0.15 or later), you can run an automation to install NodeRunner and set up a builder plugin for further customization.
|
16
|
+
|
17
|
+
```shell
|
18
|
+
bundle exec bridgetown apply https://github.com/bridgetownrb/node-runner
|
19
|
+
```
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Simply create a new `NodeRunner` object and pass in the Javascript code you wish to
|
24
|
+
execute:
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
require "node-runner"
|
28
|
+
|
29
|
+
runner = NodeRunner.new(
|
30
|
+
<<~JAVASCRIPT
|
31
|
+
const hello = (response) => {
|
32
|
+
return `Hello? ${response}`
|
33
|
+
}
|
34
|
+
JAVASCRIPT
|
35
|
+
)
|
36
|
+
```
|
37
|
+
|
38
|
+
Then call the function as if it were a genuine Ruby method:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
runner.hello "Goodbye!"
|
42
|
+
|
43
|
+
# output: "Hello? Goodbye!"
|
44
|
+
```
|
45
|
+
|
46
|
+
Under the hood, the data flowing in and out of the Javascript function is translated via JSON, so you'll need to stick to standard JSON-friendly data
|
47
|
+
values (strings, integers, arrays, hashes, etc.)
|
48
|
+
|
49
|
+
You can also use Node require statements in your Javascript:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
runner = NodeRunner.new(
|
53
|
+
<<~JAVASCRIPT
|
54
|
+
const path = require("path")
|
55
|
+
const extname = (filename) => {
|
56
|
+
return path.extname(filename);
|
57
|
+
}
|
58
|
+
JAVASCRIPT
|
59
|
+
)
|
60
|
+
|
61
|
+
extname = runner.extname("README.md")
|
62
|
+
|
63
|
+
extname == ".md"
|
64
|
+
|
65
|
+
# output: true
|
66
|
+
```
|
67
|
+
|
68
|
+
Multiple arguments for a function work, as do multiple function calls (aka
|
69
|
+
if you define `function_one` and `function_two` in your Javascript, you can call
|
70
|
+
`runner.function_one` or `runner.function_two` in Ruby).
|
71
|
+
|
72
|
+
## Node Executor Options
|
73
|
+
|
74
|
+
If you need to customize which `node` binary is executed, or wish to use your
|
75
|
+
own wrapper JS to bootstrap the `node` runtime, you can pass a custom instance
|
76
|
+
of `NodeRunner::Executor` to `NodeRunner`:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
NodeRunner.new "…", executor: NodeRunner::Executor.new(command: "/path/to/custom/node")
|
80
|
+
```
|
81
|
+
|
82
|
+
`command` can be an array as well, if you want to attempt multiple paths until one is found. Inspect the `node-runner.rb` source code for more information on the available options.
|
83
|
+
|
84
|
+
## Caveats
|
85
|
+
|
86
|
+
A single run of a script is quite fast, nearly as fast as running a script directly with the
|
87
|
+
`node` CLI…because that's essentially what is happening here. However, the performance characteristics using
|
88
|
+
this in a high-traffic request/response cycle (say, from a Rails app) is unknown. Likely the best context to use
|
89
|
+
Node Runner would be via a background job, or during a build process like when using a static site generator.
|
90
|
+
(Like our parent project [Bridgetown](https://github.com/bridgetownrb/bridgetown)!)
|
91
|
+
|
92
|
+
## Testing
|
93
|
+
|
94
|
+
* Run `bundle exec rake` to run the test suite.
|
95
|
+
|
96
|
+
## Contributing
|
97
|
+
|
98
|
+
1. Fork it (https://github.com/bridgetownrb/node-runner/fork)
|
99
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
100
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
101
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
102
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
run "bundle add node-runner", abort_on_failure: false
|
2
|
+
|
3
|
+
builder_file = "node_script_builder.rb"
|
4
|
+
create_builder builder_file do
|
5
|
+
<<~RUBY
|
6
|
+
require "node-runner"
|
7
|
+
|
8
|
+
class NodeScriptBuilder < SiteBuilder
|
9
|
+
def build
|
10
|
+
# access output in Liquid with {{ site.data.node_script.hello }}
|
11
|
+
add_data "node_script" do
|
12
|
+
runner = NodeRunner.new(
|
13
|
+
<<~JAVASCRIPT
|
14
|
+
const hello = (response) => {
|
15
|
+
return `Hello? ${response}`
|
16
|
+
}
|
17
|
+
JAVASCRIPT
|
18
|
+
)
|
19
|
+
|
20
|
+
{
|
21
|
+
hello: runner.hello("Goodbye!")
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
RUBY
|
27
|
+
end
|
28
|
+
|
29
|
+
say_status "node-runner", "Installed! Check out plugins/builders/#{builder_file} to customize your Node script"
|
data/lib/node-runner.rb
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
require "tmpdir"
|
2
|
+
require "open3"
|
3
|
+
require "json"
|
4
|
+
|
5
|
+
class NodeRunnerError < StandardError; end
|
6
|
+
|
7
|
+
class NodeRunner
|
8
|
+
def initialize(source = "", options = {})
|
9
|
+
@source = encode(source.strip)
|
10
|
+
@args = options[:args] || {}
|
11
|
+
@executor = options[:executor] || NodeRunner::Executor.new
|
12
|
+
@function_name = options[:function_name] || "main"
|
13
|
+
end
|
14
|
+
|
15
|
+
def output
|
16
|
+
exec
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(m, *args, &block)
|
20
|
+
@function_name = m
|
21
|
+
if block
|
22
|
+
@source = encode(block.call.strip)
|
23
|
+
end
|
24
|
+
@args = *args
|
25
|
+
exec
|
26
|
+
end
|
27
|
+
|
28
|
+
protected
|
29
|
+
|
30
|
+
def encode(string)
|
31
|
+
string.encode('UTF-8')
|
32
|
+
end
|
33
|
+
|
34
|
+
def exec
|
35
|
+
source = @executor.compile_source(@source, @args.to_json, @function_name)
|
36
|
+
tmpfile = write_to_tempfile(source)
|
37
|
+
filepath = tmpfile.path
|
38
|
+
|
39
|
+
begin
|
40
|
+
extract_result(@executor.exec(filepath), filepath)
|
41
|
+
ensure
|
42
|
+
File.unlink(tmpfile)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def create_tempfile(basename)
|
47
|
+
tmpfile = nil
|
48
|
+
Dir::Tmpname.create(basename) do |tmpname|
|
49
|
+
mode = File::WRONLY | File::CREAT | File::EXCL
|
50
|
+
tmpfile = File.open(tmpname, mode, 0600)
|
51
|
+
end
|
52
|
+
tmpfile
|
53
|
+
end
|
54
|
+
|
55
|
+
def write_to_tempfile(contents)
|
56
|
+
tmpfile = create_tempfile(['node_runner', 'js'])
|
57
|
+
tmpfile.write(contents)
|
58
|
+
tmpfile.close
|
59
|
+
tmpfile
|
60
|
+
end
|
61
|
+
|
62
|
+
def extract_result(output, filename)
|
63
|
+
status, value, stack = output.empty? ? [] : ::JSON.parse(output, create_additions: false)
|
64
|
+
if status == "ok"
|
65
|
+
value
|
66
|
+
else
|
67
|
+
stack ||= ""
|
68
|
+
real_filename = File.realpath(filename)
|
69
|
+
stack = stack.split("\n").map do |line|
|
70
|
+
line.sub(" at ", "")
|
71
|
+
.sub(real_filename, "node_runner")
|
72
|
+
.sub(filename, "node_runner")
|
73
|
+
.strip
|
74
|
+
end
|
75
|
+
stack.shift # first line is already part of the message (aka value)
|
76
|
+
error = NodeRunnerError.new(value)
|
77
|
+
error.set_backtrace(stack + caller)
|
78
|
+
raise error
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class NodeRunner::Executor
|
84
|
+
attr_reader :name
|
85
|
+
|
86
|
+
def initialize(options = {})
|
87
|
+
@command = options[:command] || ['node']
|
88
|
+
@modules_path = options[:modules_path] || File.join(Dir.pwd, "node_modules")
|
89
|
+
@runner_path = options[:runner_path] || File.join(File.expand_path(__dir__), '/node_runner.js')
|
90
|
+
@encoding = options[:encoding] || "UTF-8"
|
91
|
+
@binary = nil
|
92
|
+
|
93
|
+
@popen_options = {}
|
94
|
+
@popen_options[:external_encoding] = @encoding if @encoding
|
95
|
+
@popen_options[:internal_encoding] = ::Encoding.default_internal || 'UTF-8'
|
96
|
+
|
97
|
+
if @runner_path
|
98
|
+
instance_eval generate_compile_method(@runner_path)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def exec(filename)
|
103
|
+
ENV["NODE_PATH"] = @modules_path
|
104
|
+
stdout, stderr, status = Open3.capture3("#{binary} #{filename}")
|
105
|
+
if status.success?
|
106
|
+
stdout
|
107
|
+
else
|
108
|
+
raise exec_runtime_error(stderr)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
protected
|
113
|
+
|
114
|
+
def binary
|
115
|
+
@binary ||= which(@command)
|
116
|
+
end
|
117
|
+
|
118
|
+
def locate_executable(command)
|
119
|
+
commands = Array(command)
|
120
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
121
|
+
exts << ''
|
122
|
+
|
123
|
+
commands.find { |cmd|
|
124
|
+
if File.executable? cmd
|
125
|
+
cmd
|
126
|
+
else
|
127
|
+
path = ENV['PATH'].split(File::PATH_SEPARATOR).flat_map { |p|
|
128
|
+
exts.map { |e| File.join(p, "#{cmd}#{e}") }
|
129
|
+
}.find { |p|
|
130
|
+
File.executable?(p) && File.file?(p)
|
131
|
+
}
|
132
|
+
|
133
|
+
path && File.expand_path(path)
|
134
|
+
end
|
135
|
+
}
|
136
|
+
end
|
137
|
+
|
138
|
+
def generate_compile_method(path)
|
139
|
+
<<-RUBY
|
140
|
+
def compile_source(source, args, func)
|
141
|
+
<<-RUNNER
|
142
|
+
#{IO.read(path)}
|
143
|
+
RUNNER
|
144
|
+
end
|
145
|
+
RUBY
|
146
|
+
end
|
147
|
+
|
148
|
+
def encode_source(source)
|
149
|
+
encoded_source = encode_unicode_codepoints(source)
|
150
|
+
::JSON.generate("(function(){ #{encoded_source} })()", quirks_mode: true)
|
151
|
+
end
|
152
|
+
|
153
|
+
def encode_unicode_codepoints(str)
|
154
|
+
str.gsub(/[\u0080-\uffff]/) do |ch|
|
155
|
+
"\\u%04x" % ch.codepoints.to_a
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def exec_runtime_error(output)
|
160
|
+
error = RuntimeError.new(output)
|
161
|
+
lines = output.split("\n")
|
162
|
+
lineno = lines[0][/:(\d+)$/, 1] if lines[0]
|
163
|
+
lineno ||= 1
|
164
|
+
error.set_backtrace(["(node_runner):#{lineno}"] + caller)
|
165
|
+
error
|
166
|
+
end
|
167
|
+
|
168
|
+
def which(command)
|
169
|
+
Array(command).find do |name|
|
170
|
+
name, args = name.split(/\s+/, 2)
|
171
|
+
path = locate_executable(name)
|
172
|
+
|
173
|
+
next unless path
|
174
|
+
|
175
|
+
args ? "#{path} #{args}" : path
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
data/lib/node_runner.js
ADDED
data/lib/version.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "node-runner-temp-fix-windows"
|
7
|
+
spec.version = NodeRunner::VERSION
|
8
|
+
spec.author = "Bridgetown Team"
|
9
|
+
spec.email = "maintainers@bridgetownrb.com"
|
10
|
+
spec.summary = "A simple way to execute Javascript in a Ruby context via Node"
|
11
|
+
spec.homepage = "https://github.com/bridgetownrb/node-runner"
|
12
|
+
spec.license = "MIT"
|
13
|
+
|
14
|
+
spec.required_ruby_version = ">= 2.5"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r!^(test|script|spec|features)/!) }
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
end
|
19
|
+
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: node-runner-temp-fix-windows
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bridgetown Team
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-10-08 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description:
|
14
|
+
email: maintainers@bridgetownrb.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- ".gitignore"
|
20
|
+
- CHANGELOG.md
|
21
|
+
- Gemfile
|
22
|
+
- LICENSE.txt
|
23
|
+
- README.md
|
24
|
+
- Rakefile
|
25
|
+
- bridgetown.automation.rb
|
26
|
+
- lib/node-runner.rb
|
27
|
+
- lib/node_runner.js
|
28
|
+
- lib/version.rb
|
29
|
+
- node-runner-temp-fix-windows.gemspec
|
30
|
+
homepage: https://github.com/bridgetownrb/node-runner
|
31
|
+
licenses:
|
32
|
+
- MIT
|
33
|
+
metadata: {}
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options: []
|
36
|
+
require_paths:
|
37
|
+
- lib
|
38
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '2.5'
|
43
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
requirements: []
|
49
|
+
rubygems_version: 3.0.3
|
50
|
+
signing_key:
|
51
|
+
specification_version: 4
|
52
|
+
summary: A simple way to execute Javascript in a Ruby context via Node
|
53
|
+
test_files: []
|