Gem Version build

Nōdo – call Node.js from Ruby

Nodo provides a Ruby environment to interact with JavaScript running inside a Node process.

ノード means "node" in Japanese.

Why Nodo?

Nodo will dispatch all JS function calls to a single long-running Node process.

JavaScript code is run in a namespaced environment, where you can access your initialized JS objects during sequential function calls without having to re-initialize them.

IPC is done via unix sockets, greatly improving performance over classic process/eval solutions.

Installation

In your Gemfile:

gem 'nodo'

Node.js

Nodo requires a working installation of Node.js.

If the executable is located in your PATH, no configuration is required. Otherwise, the path to to binary can be set using:

Nodo.binary = '/usr/local/bin/node'

Usage

In Nodo, you define JS functions as you would define Ruby methods:

class Foo < Nodo::Core

  function :say_hi, "    (name) => {\n      return `Hello ${name}!`;\n    }\n  JS\n\nend\n\nfoo = Foo.new\nfoo.say_hi('Nodo')\n=> \"Hello Nodo!\"\n"

Using npm modules

Install your modules to node_modules:

$ yarn add uuid

requireing your dependencies will make the library available as a const with the same name:

class Bar < Nodo::Core
  require :uuid

  function :v4, "    () => {\n      return uuid.v4();\n    }\n  JS\nend\n\nbar = Bar.new\nbar.v4 => \"b305f5c4-db9a-4504-b0c3-4e097a5ec8b9\"\n"

Aliasing requires

If the library name cannot be used as name of the constant, the const name can be given using hash syntax:

class FooBar < Nodo::Core
  require commonjs: '@rollup/plugin-commonjs'
end

Setting NODE_PATH

By default, ./node_modules is used as the NODE_PATH.

To set a custom path:

Nodo.modules_root = 'path/to/node_modules'

For Rails applications, it will be set to vendor/node_modules. To use the Rails 6 default of putting node_modules to RAILS_ROOT:

# config/initializers/nodo.rb
Nodo.modules_root = Rails.root.join('node_modules')

Defining JS constants

class BarFoo < Nodo::Core
  const :HELLO, "World"
end

Execute some custom JS during initialization

class BarFoo < Nodo::Core

  script "    // custom JS to be executed during initialization\n    // things defined here can later be used inside functions\n    const bigThing = someLib.init();\n  JS\nend\n"

Inheritance

Subclasses will inherit functions, constants, dependencies and scripts from their superclasses, while only functions can be overwritten.

class Foo < Nodo::Core
  function :foo, "() => 'superclass'"
end

class SubFoo < Foo
  function :bar, "() => { return 'calling' + foo() }"
end

class SubSubFoo < SubFoo
  function :foo, "() => 'subsubclass'"
end

Foo.new.foo => "superclass"
SubFoo.new.bar => "callingsuperclass"
SubSubFoo.new.bar => "callingsubsubclass"

Async functions

Nodo supports calling async functions from Ruby. The Ruby call will happen synchronously, i.e. it will block until the JS function resolves:

class SyncFoo < Nodo::Core
  function :do_something, "    async () => { return await asyncFunc(); }\n  JS\nend\n"