RbGateway

Swift
public final class RbGateway: RbObjectAccess, Sendable

Provides top-level Ruby services: information about the Ruby VM, evaluate expressions, access various kinds of Ruby objects, and define new Ruby classes, modules, and functions.

You cannot instantiate this type. Instead RubyGateway exports a public instance Ruby. Among other things this permits a dynamic member lookup programming style.

The Ruby VM is initialized when the object is first accessed and is automatically stopped when the process ends. The VM can be manually shut down before process exit by calling RbGateway.cleanup() but once this has been done the VM cannot be restarted and subsequent calls to RubyGateway services will fail.

The loadpath (where require looks) is set to the lib/ruby directories adjacent to the libruby the program is linked against and $RUBYLIB. RubyGems are enabled.

Accessing Ruby objects

The class inherits from RbObjectAccess which lets you look up constants or call functions as you would at the top level of a Ruby script, for example:

import RubyGateway

print("Ruby version is \(Ruby.version)")

do {
   try Ruby.require(filename: "rouge")
   let html = try Ruby.get("Rouge").call("highlight", args: ["let a = 1", "swift", "html"])
} catch {
}

If you just want to create a Ruby object of some class, see RbObject.init(ofClass:args:kwArgs:).

Running Ruby code

Use RbGateway.eval(ruby:) to evaulate a Ruby expression in the current VM. For example:

let result = try Ruby.eval(ruby: "Rouge.highlight('let a = 1', 'swift', 'html')")

Defining new Ruby classes

Use RbGateway.defineClass(_:parent:under:) and RbGateway.defineModule(_:under:) to define new classes and modules. Then add methods using RbObject.defineMethod(...) and RbObject.defineSingletonMethod(...).


Topics

func cleanup() -> Int32

Explicitly shut down Ruby and release resources. This includes calling END{} code and procs registered by Kernel.#at_exit.

You generally don’t need to call this: it happens automatically as part of process exit.

Once called you cannot continue to use Ruby in this process: the VM cannot be re-setup.

Declaration
Swift
public func cleanup() -> Int32
Return Value

0 if the cleanup went fine, otherwise some error code from Ruby.

func getID(for: String) -> RbObject.VALUE

Get an ID ready to call a method, for example.

This is public to permit interop with CRuby. It is not needed for regular RubyGateway use.

Declaration
Swift
public func getID(for name: String) throws -> RbObject.VALUE
Parameters
name

Name to look up, typically constant or method name.

Throws

RbError.rubyException(_:) if Ruby raises an exception. This probably means the ID space is full, which is fairly unlikely.

Return Value

The corresponding ID.

func softSetup() -> Bool

Attempt to initialize Ruby but swallow any error.

This is for use from places that could be the first use of Ruby but it is not practical to throw an exception for API or aesthetic reasons.

The idea is that callers can get by long enough for the user to call require() or send() which will properly report the VM setup error.

This is public to let you implement RbObjectConvertible.rubyObject for custom types. It is not required for regular RubyGateway use.

Declaration
Swift
public func softSetup() -> Bool

Top Self Instance Variables

func getInstanceVar(String) -> RbObject

Get the value of a top-level instance variable. Creates a new one with a nil value if it doesn’t exist yet.

This is like doing @f at the top level of a Ruby script.

For a version that does not throw, see RbObjectAccess.failable.

Declaration
Swift
public override func getInstanceVar(_ name: String) throws -> RbObject
Parameters
name

Name of IVar to get. Must begin with a single ‘@’.

Throws

RbError.badIdentifier(type:id:) if name looks wrong. RbError.rubyException(_:) if Ruby has a problem.

Return Value

Value of the IVar or Ruby nil if it has not been assigned yet.

func setInstanceVar(String, newValue: (any RbObjectConvertible)?) -> RbObject

Set a top-level instance variable. Creates a new one if it doesn’t exist yet.

This is like doing @f = 3 at the top level of a Ruby script.

For a version that does not throw, see RbObjectAccess.failable.

Declaration
Swift
@discardableResult
public override func setInstanceVar(
    _ name: String, newValue: (any RbObjectConvertible)?
) throws -> RbObject
Parameters
name

Name of IVar to set. Must begin with a single ‘@’.

newValue

New value to set.

Throws

RbError.badIdentifier(type:id:) if name looks wrong. RbError.rubyException(_:) if Ruby has a problem.

Return Value

The value that was set.

Defining New Classes and Modules

func defineClass(String, parent: RbObject?, under: RbObject?) -> RbObject

Define a new, empty, Ruby class.

Declaration
Swift
@discardableResult
public func defineClass(
    _ name: String, parent: RbObject? = nil, under: RbObject? = nil
) throws -> RbObject
Parameters
name

Name of the class.

parent

Parent class for the new class to inherit from. The default is nil which means the new class inherits from Object.

under

The class or module under which to nest this new class. The default is nil which means the class is at the top level.

Throws

RbError.badIdentifier(type:id:) if name is bad. RbError.badType(...) if parent is provided but is not a class, or if under is neither class nor module. RbError.rubyException(...) if Ruby is unhappy with the definition, for example when the class already exists with a different parent.

Return Value

The class object for the new class.

func defineClass<SwiftPeer>(String, under: RbObject?, initializer: () -> SwiftPeer) -> RbObject

Define a new, empty, Ruby class associated with a Swift class.

The Ruby class inherits from the Ruby DataData class.

When any new instance of the Ruby class is created, the initializer closure is called to get hold of an instance of the bound Swift class. Typically this closure is an initializer for the Swift class. A strong reference is held to the Swift object while the Ruby object is live; this reference is released only when the Ruby object is garbage-collected.

If you want to implement the Ruby initialize entrypoint to support passing arguments to new then you need to do that separately with one of the RbObject.defineMethod(_:argsSpec:method:) methods.

Ruby methods defined with RbObject.defineMethod(_:argsSpec:method:) can be bound directly to methods of the SwiftPeer class.

Declaration
Swift
@discardableResult
public func defineClass<SwiftPeer: AnyObject & Sendable>(
    _ name: String,
    under: RbObject? = nil,
    initializer: @escaping () -> SwiftPeer
) throws -> RbObject
Parameters
name

Name of the class.

under

The class or module under which to nest this new class. The default is nil which means the class is at the top level.

initializer

Closure to return an instance of SwiftPeer, typically a new instance.

Throws

RbError.badIdentifier(type:id:) if name is bad. RbError.badType(...) if parent is provided but is not a class, or if under is neither class nor module. RbError.rubyException(...) if Ruby is unhappy with the definition, for example when the class already exists with a different parent.

Return Value

The class object for the new class.

func defineModule(String, under: RbObject?) -> RbObject

Define a new, empty, Ruby module.

For example to create a module Math::Advanced:

let mathModule = try Ruby.get("Math")
let advancedMathModule = try Ruby.defineModule(name: "Advanced", under: mathModule)
Declaration
Swift
@discardableResult
public func defineModule(_ name: String, under: RbObject? = nil) throws
    -> RbObject
Parameters
name

Name of the module.

under

The class or module under which to nest this new module.

Throws

RbError.badIdentifier(type:id:) if name is bad. RbError.badType(...) if under is neither class nor module. RbError.rubyException(...) if Ruby is unhappy with the definition, for example when a non-module constant already exists with this name.

Return Value

The module object for the new module.

VM Properties

var debug: Bool

Debug mode for Ruby code, sets $DEBUG / $-d.

Declaration
Swift
public var debug: Bool { get set }

enum Verbosity

Verbosity setting for Ruby scripts - affects Kernel#warn etc.

Declaration
Swift
public enum Verbosity

var verbose: Verbosity

Verbose mode for Ruby code, sets $VERBOSE / $-v.

Declaration
Swift
public var verbose: Verbosity { get set }

var scriptName: String

Value of Ruby $PROGRAM_NAME / $0.

Declaration
Swift
public var scriptName: String { get set }

var apiVersion: (Int32, Int32, Int32)

The component major/minor/teeny version numbers of Ruby being used.

Declaration
Swift
public var apiVersion: (Int32, Int32, Int32) { get }

var version: String

The version number triple of Ruby being used, for example 2.5.0.

Declaration
Swift
public var version: String { get }

var versionDescription: String

The full version string for the Ruby being used.

For example ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin17].

Declaration
Swift
public var versionDescription: String { get }

func setArguments([String])

Set the program arguments for the Ruby VM.

Updates the ARGV constant.

Declaration
Swift
public func setArguments(_ newArgv: [String]) throws
Parameters
newArgv

The strings to make up the new version of ARGV.

Throws

Various RbErrors if the arguments can’t be set.

Ruby Code Execution

func eval(ruby: String) -> RbObject

Evaluate some Ruby and return the result.

note

This is a lower level than Kernel#eval and less flexible - if you need that function then access it via RbGateway.call("eval"). Don’t be tempted by rb_eval_string_wrap(), it is broken. #10466.

Declaration
Swift
@discardableResult
public func eval(ruby: String) throws -> RbObject
Parameters
ruby

Ruby code to execute at the top level.

Throws

RbError if something goes wrong.

Return Value

The result of executing the code.

func require(filename: String) -> Bool

Load a Ruby file once-only. See Kernel#require, but note this method is dispatched dynamically so it will invoke any replacements of require.

Declaration
Swift
@discardableResult
public func require(filename: String) throws -> Bool
Parameters
filename

The name of the file to load.

Throws

RbError if something goes wrong. This usually means that Ruby couldn’t find the file.

Return Value

true if the file was loaded OK, false if it is already loaded.

func load(filename: String, wrap: Bool)

See Ruby Kernel#load. Load a file, reloads if already loaded.

Declaration
Swift
public func load(filename: String, wrap: Bool = false) throws
Parameters
filename

The name of the file to load

wrap

If true, load the file into a fresh anonymous namespace instead of the current program. See Kernel#load.

Throws

RbError if something goes wrong.

Swift Global Variables

func defineGlobalVar<T>(String, get: () -> T)

Create a readonly Ruby global variable implemented by Swift code.

If your global variable is not a simple Swift value type then use RbObject as the closure return type.

Declaration
Swift
public func defineGlobalVar<T: RbObjectConvertible>(
    _ name: String,
    get: @escaping @Sendable () -> T) throws
Parameters
name

The name of the global variable. Must begin with $. Any existing global variable with this name is overwritten.

get

Function called whenever Ruby code reads the global variable.

Throws

RbError.badIdentifier(type:id:) if name is bad; some other kind of error if Ruby is not working.

func defineGlobalVar<T>(String, get: () -> T, set: (T) -> Void)

Create a read-write Ruby global variable implemented by Swift code.

Errors thrown from the setter closure propagate into Ruby as exceptions. Ruby does not permit getters to raise exceptions.

If your global variable is not a simple Swift value type then use RbObject as the closure return/argument type; you can manually throw an RbException from the setter if the provided Ruby value is the wrong shape.

Declaration
Swift
public func defineGlobalVar<T: RbObjectConvertible>(
    _ name: String,
    get: @escaping @Sendable () -> T,
    set: @escaping @Sendable (T) throws -> Void) throws
Parameters
name

The name of the global variable. Must begin with $. Any existing global variable with this name is overwritten.

get

Function called whenever Ruby code reads the global variable.

set

Function called whenever Ruby code writes the global variable.

Throws

RbError.badIdentifier(type:id:) if name is bad; some other kind of error if Ruby is not working.

Swift Global Functions

func defineGlobalFunction(String, argsSpec: RbMethodArgsSpec, body: RbMethodCallback)

Define a global function that can use positional, keyword, and optional arguments as well as splatting. The function can also be passed a block.

Use the RbMethod passed into body to access the function arguments; RubyBridge validates the arguments according to argsSpec before invoking this callback.

The first parameter to the body callback is best ignored: it is the Ruby internal object that is used to implement so-called “global functions”.

Declaration
Swift
public func defineGlobalFunction(
    _ name: String,
    argsSpec: RbMethodArgsSpec = RbMethodArgsSpec(),
    body: @escaping RbMethodCallback) throws
Parameters
name

The function name.

argsSpec

A description of the arguments required by the function. The default for this parameter specifies a function that does not take any arguments.

body

The Swift code to run when the function is called.

Throws

RbError.badIdentifier(type:id:) if name is bad.

Some other kind of RbError if Ruby is not working.