Schmooze lets Ruby and Node.js work together intimately. It has a DSL that allows you to define what methods you need, and it executes code by spawning a Node.js process and sending messages back and forth.
Schmooze requires that you have nodejs installed and in the $PATH.
Add this line to your application's Gemfile:
gem 'schmooze'And then execute:
$ bundle
If you need the latest bug fixes (including the finalizer freeze fix), you can use the speee/schmooze fork:
gem 'schmooze', github: 'speee/schmooze', tag: 'v26.1.1'To use Schmooze, you first need to create a sublcass of Schmooze::Base. Your subclass needs to list all of the package dependencies, and methods that you want to have available. For example, here is a Schmooze class that interfaces with Babel:
require 'schmooze'
class BabelSchmoozer < Schmooze::Base
dependencies babel: 'babel-core'
method :transform, 'babel.transform'
method :version, 'function() { return [process.version, babel.version]; }'
endNote that the babel-core package is available under the name babel, because that's how we requested it.
To define a method, you simply give it a name and pass in a JavaScript string that should resolve to a function. Let's put this class to use!
First we need to make sure we install any needed packages.
$ npm install babel-core babel-preset-es2015
All we need to do next is to instantiate the class with a path to where the node modules are installed, and then we can call the methods! (Note that we need to pass in ast: false because of a caveat).
$ pry
Ruby 2.2.2
pry> load './babel_schmoozer.rb'
pry> babel = BabelSchmoozer.new(__dir__)
pry> babel.version
=> ["v5.5.0", "6.5.2"]
pry> puts babel.transform('a = () => 1', ast: false, presets: ['es2015'])['code']
"use strict";
a = function a() {
return 1;
};This could easily be turned into a Sprockets plugin.
Errors happen, and Schmooze tries to make them as painless as possible to handle. If there is a dependency missing, Schmooze will throw a helpful Error when you try to initialize the class. Here is an example from the tests:
class ErrorSchmoozer < Schmooze::Base
dependencies nonexistant: 'this-package-is-not-here'
end
ErrorSchmoozer.new(__dir__)This will raise
Schmooze::DependencyError: Cannot find module 'this-package-is-not-here'.
You need to add it to '/Users/bouke/code/schmooze/test/fixtures/uninstalled_package/package.json' and run 'npm install'
Any JavaScript errors that happen get converted to Ruby errors under the Schmooze::Javascript namespace. For example (once again, from the tests):
class CoffeeSchmoozer < Schmooze::Base
dependencies coffee: 'coffee-script'
method :compile, 'coffee.compile'
end
CoffeeSchmoozer.new(__dir__).compile('<=> 1')This will raise
Schmooze::JavaScript::SyntaxError: [stdin]:1:1: error: unexpected <=
<=> 1
^^
- Because we serialize the return values from JavaScript to JSON, you can't return circular data structures (like the Babel AST).
The speee/schmooze fork includes the following improvements:
- Fix close() method hanging - Fixed an issue where the
close()method would hang indefinitely when used with long-running Node.js processes (e.g., processes usingsetTimeoutor event listeners). The fix ensures the process is terminated before waiting for it to exit. - Ruby 3.4 and 4.0 support - Added support for Ruby 3.4 and Ruby 4.0 with minitest 6.x compatibility.
- Docker test setup - Added Docker configuration for testing across multiple Ruby versions (2.6 - 4.0).
- CI improvements - Updated GitHub Actions workflow with Ruby 3.4/4.0 support and dependency updates.
Bug reports and pull requests are welcome on GitHub at https://github.com/Shopify/schmooze.
For the speee fork, please submit issues and pull requests at https://github.com/speee/schmooze.
Run the setup script
$ ./script/setup
Run the tests
$ ./script/test