execjs-fastnode 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 13794e0f836dc1cc7c7eb16a23391df25a556e99
4
+ data.tar.gz: 66e77b96d13a3bd2be1fd42e249f89e9c832aafb
5
+ SHA512:
6
+ metadata.gz: 017acad49287c35d0cf4c573939ddbdad3af1e55413d041ec024a71d76b7444286fa9794515fa18b395934e7f75e033100b393b52d3ade132b2e9ec1c85f8b0e
7
+ data.tar.gz: af736abba04aeb15cae84a798f2556d9ebb052ae12c76329de34e2c3f65073c26bec5f4e9616a0420b8cb3cd109ffe6e73c0b8e2560f01bcdc15a26084d13f8f
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1,3 @@
1
+ [submodule "execjs"]
2
+ path = execjs
3
+ url = https://github.com/rails/execjs
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ cache: bundler
3
+ sudo: false
4
+ before_script:
5
+ - node --version
6
+ matrix:
7
+ include:
8
+ - rvm: 2.0.0
9
+ - rvm: 2.1
10
+ - rvm: 2.2
11
+ - rvm: 2.3.1
12
+ - rvm: jruby-19mode
13
+ - os: osx
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+
4
+ gem 'therubyracer'
5
+
6
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 John Hawthorn
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,98 @@
1
+ # ExecJS FastNode
2
+
3
+ ## What's this?
4
+
5
+ An alternative implementation of ExecJS's Node.js integration. This aims to speed up sprockets compilation without needing to embed a javascript interpreter inside of ruby like [therubyracer](cowboyd/therubyracer).
6
+
7
+ ## How much faster is it?
8
+
9
+ Much.
10
+
11
+ ```
12
+ $ rake bench
13
+ ...
14
+ user system total real
15
+ Node.js (V8) fast 0.000000 0.000000 0.000000 ( 0.069723)
16
+ therubyracer (V8) 0.020000 0.000000 0.020000 ( 0.018010)
17
+ Node.js (V8) 0.000000 0.010000 1.470000 ( 1.487579)
18
+ ```
19
+
20
+ Okay, so it's not as fast as `therubyracer`, but it's 20x faster than the standard ExecJS Node.js implementation.
21
+
22
+ The benchmark measures the time to compile the javascript CoffeeScript compiler and then eval a small snippet 10 times.
23
+
24
+ ## How?
25
+
26
+ The existing ExecJS runtime has to run a new Node.js process each time any JS is to be run. This means that if you are loading up the CoffeeScript compiler in order to compile some sprockets assets, it needs to reload the node executable and the entire coffeescript compiler for each file it is compiling.
27
+
28
+ This implementation avoids this by starting an always running Node.js process connected by pipes to STDIN and STDOUT. The JS to execute is piped into the process and the results are recieved from its output. Isolation between different ExecJS contexts is achieved through Node's [vm.Script](https://nodejs.org/api/vm.html).
29
+
30
+ | Old | New |
31
+ | --- | --- |
32
+ | ![](docs/example_old.png) | ![](docs/example_new.png) |
33
+
34
+ ## Is this production ready?
35
+
36
+ Maybe? It needs more testing to be labeled as such. If you encounter any troubles please [file an issue](https://github.com/jhawthorn/execjs-fastnode/issues/new).
37
+
38
+ Currently minimal effort is made to handle catastrophic errors: Node.js crashing, running out of memory, being killed. All of which result in `Errno::EPIPE: Broken pipe` for future ExecJS calls.
39
+
40
+ It's probably fine for development.
41
+
42
+ ## Installation
43
+
44
+ Add this line to your application's Gemfile:
45
+
46
+ ```ruby
47
+ gem 'execjs-fastnode'
48
+ ```
49
+
50
+ And then `bundle install`. You know the drill.
51
+
52
+ You can verify that this runtime is being autodetected and used by checking `ExecJS.runtime` in a console.
53
+
54
+ You can force a certain runtime to be used using `EXECJS_RUNTIME=FastNode`
55
+
56
+ ```
57
+ $ EXECJS_RUNTIME=FastNode bin/console
58
+ > ExecJS.runtime
59
+ => #<ExecJS::FastNode::ExternalPipedRuntime:0x005599c0d38740 @name="Node.js (V8) fast"...
60
+
61
+ $ EXECJS_RUNTIME=Node bin/console
62
+ > ExecJS.runtime
63
+ => #<ExecJS::ExternalRuntime:0x00559c440347c0 @name="Node.js (V8)" ...
64
+ ```
65
+
66
+ ## Why not upstream this to execjs?
67
+
68
+ I'd like to, but it will take time. The goal of this endeavour is to give users a fast ExecJS runtime without needing any additional dependencies, just a Node.js installation. However most users don't (and shouldn't have to) think about ExecJS and need it to Just Work. This is a pretty significant change and it probably won't "Just Work" right now, and more time is needed to tell if it can.
69
+
70
+ I have sent a pull request upstream to [use vm.runInContext](https://github.com/rails/execjs/pull/55), which would be the first step to merging this upstream.
71
+
72
+ ## Why not just use therubyracer?
73
+
74
+ Maybe you should, if you need the speed.
75
+
76
+ Heroku [recommends againts it](https://devcenter.heroku.com/articles/rails-asset-pipeline#therubyracer) as do various stack overflow answers with vague mentions of high memory usage.
77
+ I haven't seen any benchmarks or bug reports that demonstrate this, so I consider these claims somewhat suspect.
78
+
79
+ [mini_racer](https://github.com/discourse/mini_racer) is another option.
80
+
81
+ The ExecJS Node runtime has its benefits as well. It should works on jRuby and other non-MRI runtimes.
82
+ If this were merged upstream it would give developers fast javascript execution without needing an extra gem or configuration, just a working `node` somewhere in `$PATH`.
83
+
84
+ ## Development
85
+
86
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
87
+
88
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
89
+
90
+ ## Contributing
91
+
92
+ Bug reports and pull requests are welcome on GitHub at https://github.com/jhawthorn/execjs-fastnode.
93
+
94
+
95
+ ## License
96
+
97
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
98
+
@@ -0,0 +1,17 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ task :bench do
5
+ sh 'ruby -Ilib -r./test/shim test/bench_execjs.rb'
6
+ end
7
+
8
+ task :test do
9
+ ENV["EXECJS_RUNTIME"] = 'FastNode'
10
+ end
11
+ Rake::TestTask.new(:test) do |t|
12
+ t.libs << "test"
13
+ t.libs << "lib"
14
+ t.test_files = FileList['test/shim.rb', 'test/**/*_test.rb', 'test/test_execjs.rb']
15
+ end
16
+
17
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "execjs/fastnode"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,21 @@
1
+ msc {
2
+ hscale = "1";
3
+
4
+ ruby,node;
5
+
6
+ node=>node [ label = "start" ] ;
7
+ ruby=>ruby [ label = "c = ExecJS.compile(...)" ];
8
+ ruby->node [ label = "CoffeeScript source code" ] ;
9
+ node=>node [ label = "Evaluate CoffeeScript source" ] ;
10
+ ||| ;
11
+ ruby=>ruby [ label = "c.call('CoffeeScript', 'compile', ...)" ];
12
+ ruby->node [ label = "CoffeeScript.compile('(x) -> x * x')" ] ;
13
+ node=>node [ label = "CoffeeScript.compile(...)" ] ;
14
+ node->ruby [ label = "\"(function(x){ return x * x })\"" ] ;
15
+ ||| ;
16
+ ruby=>ruby [ label = "c.call('CoffeeScript', 'compile', ...)" ];
17
+ ruby->node [ label = "CoffeeScript.compile('(x) -> x * 2')" ] ;
18
+ node=>node [ label = "CoffeeScript.compile(...)" ] ;
19
+ node->ruby [ label = "\"(function(x){ return x * 2 })\"" ] ;
20
+ }
21
+
Binary file
@@ -0,0 +1,25 @@
1
+ msc {
2
+ hscale = "1";
3
+
4
+ ruby,node;
5
+
6
+ ruby=>ruby [ label = "c = ExecJS.compile(...)" ];
7
+ ruby=>ruby [ label = "c.call('CoffeeScript', 'compile', ...)" ];
8
+ node=>node [ label = "start" ] ;
9
+ ruby->node [ label = "CoffeeScript source code" ] ;
10
+ ruby->node [ label = "CoffeeScript.compile('(x) -> x * x')" ] ;
11
+ node=>node [ label = "Evaluate CoffeeScript source" ] ;
12
+ node=>node [ label = "CoffeeScript.compile(...)" ] ;
13
+ node->ruby [ label = "\"(function(x){ return x * x })\"" ] ;
14
+ node=>node [ label = "exit" ] ;
15
+ ||| ;
16
+ ruby=>ruby [ label = "c.call('CoffeeScript', 'compile', ...)" ];
17
+ node=>node [ label = "start" ] ;
18
+ ruby->node [ label = "CoffeeScript source code" ] ;
19
+ ruby->node [ label = "CoffeeScript.compile('(x) -> x * 2')" ] ;
20
+ node=>node [ label = "Evaluate CoffeeScript source" ] ;
21
+ node=>node [ label = "CoffeeScript.compile(...)" ] ;
22
+ node->ruby [ label = "\"(function(x){ return x * 2 })\"" ] ;
23
+ node=>node [ label = "exit" ] ;
24
+ }
25
+
Binary file
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'execjs/fastnode/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "execjs-fastnode"
8
+ spec.version = ExecJS::FastNode::VERSION
9
+ spec.authors = ["John Hawthorn"]
10
+ spec.email = ["john.hawthorn@gmail.com"]
11
+
12
+ spec.summary = %q{A faster implementation of ExecJS's node runtime}
13
+ spec.description = %q{An ExecJS node runtime which uses pipes to avoid repeated startup costs}
14
+ spec.homepage = "https://github.com/jhawthorn/execjs-fastnode"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_dependency "execjs", "~> 2.0"
25
+ spec.add_development_dependency "bundler", "~> 1.7"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency "minitest", "~> 5.0"
28
+ end
@@ -0,0 +1,8 @@
1
+ require "execjs/fastnode/version"
2
+
3
+ # Insert our new runtime into the list
4
+ require "execjs/fastnode/runtimes"
5
+
6
+ # Re-detect runtime
7
+ require 'execjs'
8
+ ExecJS.runtime = ExecJS::Runtimes.autodetect
@@ -0,0 +1,47 @@
1
+ module ExecJS
2
+ module FastNode
3
+ class Command
4
+ def initialize(command)
5
+ @command = command
6
+ end
7
+
8
+ def to_cmd
9
+ which
10
+ end
11
+
12
+ private
13
+
14
+ def locate_executable(command)
15
+ commands = Array(command)
16
+ if ExecJS.windows? && File.extname(command) == ""
17
+ ENV['PATHEXT'].split(File::PATH_SEPARATOR).each { |p|
18
+ commands << (command + p)
19
+ }
20
+ end
21
+
22
+ commands.find { |cmd|
23
+ if File.executable? cmd
24
+ cmd
25
+ else
26
+ path = ENV['PATH'].split(File::PATH_SEPARATOR).find { |p|
27
+ full_path = File.join(p, cmd)
28
+ File.executable?(full_path) && File.file?(full_path)
29
+ }
30
+ path && File.expand_path(cmd, path)
31
+ end
32
+ }
33
+ end
34
+
35
+ def which
36
+ Array(@command).find do |name|
37
+ name, args = name.split(/\s+/, 2)
38
+ path = locate_executable(name)
39
+
40
+ next unless path
41
+
42
+ args ? "#{path} #{args}" : path
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,155 @@
1
+ require "tmpdir"
2
+ require 'json'
3
+ require "open3"
4
+ require "thread"
5
+ require "execjs/runtime"
6
+ require "execjs/fastnode/command"
7
+
8
+ module ExecJS
9
+ module FastNode
10
+ class ExternalPipedRuntime < ExecJS::Runtime
11
+ class VM
12
+ attr_reader :stdin, :stdout
13
+
14
+ def initialize(options)
15
+ @mutex = Mutex.new
16
+ @stdin = @stdout = @wait_thr = nil
17
+ @options = options
18
+ end
19
+
20
+ def started?
21
+ !!@stdin
22
+ end
23
+
24
+ def self.finalize(stdin)
25
+ proc { stdin.puts('{"cmd": "exit", "arguments": [0]}') }
26
+ end
27
+
28
+ def exec(context, source)
29
+ command("exec", {context: context, source: source})
30
+ end
31
+
32
+ def delete_context(context)
33
+ command("deleteContext", context)
34
+ end
35
+
36
+ def start
37
+ return if started?
38
+ @mutex.synchronize do
39
+ # will double check started? with the lock held
40
+ start_without_synchronization
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def start_without_synchronization
47
+ return if started?
48
+ @stdin, @stdout, @wait_thr = Open3.popen2(@options[:binary], @options[:runner_path])
49
+ ObjectSpace.define_finalizer(self, self.class.finalize(@stdin))
50
+ end
51
+
52
+ def command(cmd, *arguments)
53
+ start
54
+ @mutex.synchronize do
55
+ @stdin.puts(::JSON.generate({cmd: cmd, args: arguments}))
56
+ result = ::JSON.parse(@stdout.gets, create_additions: false)
57
+ end
58
+ end
59
+ end
60
+
61
+ class Context < Runtime::Context
62
+ def initialize(runtime, source = "", options = {})
63
+ @runtime = runtime
64
+ @uuid = SecureRandom.uuid
65
+
66
+ ObjectSpace.define_finalizer(self, self.class.finalize(@runtime, @uuid))
67
+
68
+ source = encode(source)
69
+
70
+ raw_exec(source)
71
+ end
72
+
73
+ def self.finalize(runtime, uuid)
74
+ proc { runtime.vm.delete_context(uuid) }
75
+ end
76
+
77
+ def eval(source, options = {})
78
+ if /\S/ =~ source
79
+ raw_exec("(#{source})")
80
+ end
81
+ end
82
+
83
+ def exec(source, options = {})
84
+ raw_exec("(function(){#{source}})()")
85
+ end
86
+
87
+ def raw_exec(source, options = {})
88
+ source = encode(source)
89
+
90
+ result = @runtime.vm.exec(@uuid, source)
91
+ extract_result(result)
92
+ end
93
+
94
+ def call(identifier, *args)
95
+ eval "#{identifier}.apply(this, #{::JSON.generate(args)})"
96
+ end
97
+
98
+ protected
99
+
100
+ def extract_result(output)
101
+ status, value, stack = output
102
+ if status == "ok"
103
+ value
104
+ else
105
+ stack ||= ""
106
+ stack = stack.split("\n").map do |line|
107
+ line.sub(" at ", "").strip
108
+ end
109
+ stack.reject! { |line| ["eval code", "eval@[native code]"].include?(line) }
110
+ stack.shift unless stack[0].to_s.include?("(execjs)")
111
+ error_class = value =~ /SyntaxError:/ ? RuntimeError : ProgramError
112
+ error = error_class.new(value)
113
+ error.set_backtrace(stack + caller)
114
+ raise error
115
+ end
116
+ end
117
+ end
118
+
119
+ attr_reader :name, :vm
120
+
121
+ def initialize(options)
122
+ @name = options[:name]
123
+ @command = Command.new(options[:command])
124
+ @runner_path = options[:runner_path]
125
+ @encoding = options[:encoding]
126
+ @deprecated = !!options[:deprecated]
127
+ @binary = nil
128
+
129
+ @popen_options = {}
130
+ @popen_options[:external_encoding] = @encoding if @encoding
131
+ @popen_options[:internal_encoding] = ::Encoding.default_internal || 'UTF-8'
132
+ end
133
+
134
+ def vm
135
+ @vm ||= VM.new(
136
+ binary: @binary,
137
+ runner_path: @runner_path
138
+ )
139
+ end
140
+
141
+ def available?
142
+ binary ? true : false
143
+ end
144
+
145
+ def deprecated?
146
+ @deprecated
147
+ end
148
+
149
+ private
150
+ def binary
151
+ @binary ||= @command.to_cmd
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,72 @@
1
+ (function(){
2
+ var stdin = process.stdin
3
+ var stdout = process.stdout
4
+ var buf = ""
5
+
6
+ stdin.setEncoding('utf8')
7
+
8
+ var vm = require('vm');
9
+ var contexts = {};
10
+
11
+ function getContext(uuid) {
12
+ return contexts[uuid] || (contexts[uuid] = vm.createContext())
13
+ }
14
+
15
+ var commands = {
16
+ deleteContext: function(uuid) {
17
+ delete contexts[uuid];
18
+ return 1;
19
+ },
20
+ exit: function(code) {
21
+ process.exit(code)
22
+ },
23
+ exec: function execJS(input) {
24
+ var context = getContext(input.context);
25
+ var source = input.source;
26
+ try {
27
+ var program = function(){
28
+ return vm.runInContext(source, context, "(execjs)");
29
+ }
30
+ result = program();
31
+ if (typeof result == 'undefined' && result !== null) {
32
+ return ['ok'];
33
+ } else {
34
+ try {
35
+ return ['ok', result];
36
+ } catch (err) {
37
+ return ['err', '' + err, err.stack];
38
+ }
39
+ }
40
+ } catch (err) {
41
+ return ['err', '' + err, err.stack];
42
+ }
43
+ }
44
+ }
45
+
46
+ function processLine(line){
47
+ var input = JSON.parse(line)
48
+ var result = commands[input.cmd].apply(null, input.args)
49
+
50
+ var outputJSON = JSON.stringify(result)
51
+ stdout.write(outputJSON)
52
+ stdout.write('\n')
53
+ }
54
+
55
+ function processBuffer(){
56
+ if(buf.indexOf('\n') >= 0){
57
+ var lines = buf.split('\n')
58
+ for(var i = 0; i < lines.length - 1; i++) {
59
+ processLine(lines[i]);
60
+ }
61
+ buf = lines[lines.length - 1]
62
+ }
63
+ }
64
+
65
+ process.stdin.on('readable', function(){
66
+ var chunk = process.stdin.read();
67
+ if (chunk !== null) {
68
+ buf += chunk
69
+ processBuffer()
70
+ }
71
+ });
72
+ })();
@@ -0,0 +1,18 @@
1
+ require "execjs/fastnode/version"
2
+ require "execjs/fastnode/external_piped_runtime"
3
+ require "execjs/runtimes"
4
+
5
+ module ExecJS
6
+ module Runtimes
7
+ # re-opening the runtimes class
8
+ FastNode = FastNode::ExternalPipedRuntime.new(
9
+ name: "Node.js (V8) fast",
10
+ command: ["nodejs", "node"],
11
+ runner_path: File.expand_path('../../fastnode/node_piped_runner.js', __FILE__),
12
+ encoding: 'UTF-8'
13
+ )
14
+
15
+ # Place FastNode runtime first
16
+ runtimes.unshift(FastNode)
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ module ExecJS
2
+ module FastNode
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: execjs-fastnode
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - John Hawthorn
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-10-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: execjs
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.7'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ description: An ExecJS node runtime which uses pipes to avoid repeated startup costs
70
+ email:
71
+ - john.hawthorn@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".gitmodules"
78
+ - ".travis.yml"
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - bin/console
84
+ - bin/setup
85
+ - docs/example_new.mscgen
86
+ - docs/example_new.png
87
+ - docs/example_old.mscgen
88
+ - docs/example_old.png
89
+ - execjs-fastnode.gemspec
90
+ - lib/execjs/fastnode.rb
91
+ - lib/execjs/fastnode/command.rb
92
+ - lib/execjs/fastnode/external_piped_runtime.rb
93
+ - lib/execjs/fastnode/node_piped_runner.js
94
+ - lib/execjs/fastnode/runtimes.rb
95
+ - lib/execjs/fastnode/version.rb
96
+ homepage: https://github.com/jhawthorn/execjs-fastnode
97
+ licenses:
98
+ - MIT
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 2.5.1
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: A faster implementation of ExecJS's node runtime
120
+ test_files: []