RbObject

Swift
public final class RbObject: RbObjectAccess, Sendable

extension RbObject: CustomStringConvertible,
    CustomDebugStringConvertible,
    CustomPlaygroundDisplayConvertible

extension RbObject: ExpressibleByArrayLiteral

extension RbObject: ExpressibleByBooleanLiteral

extension RbObject: ExpressibleByDictionaryLiteral

extension RbObject: ExpressibleByFloatLiteral

extension RbObject: ExpressibleByIntegerLiteral

extension RbObject: ExpressibleByStringLiteral

extension RbObject: Hashable, Equatable, Comparable

extension RbObject: RbObjectConvertible

extension RbObject: SignedNumeric

A Ruby object.

All Ruby objects whatever their type or class are represented using this Swift type.

Use RbObject.init(ofClass:args:kwArgs:) to create a new Ruby object of some class:

let myObj = RbObject(ofClass: "MyModule::MyClass", args: ["arg1", 25.3])

See RbObjectAccess for ways to call methods, access properties, and find constants from an RbObject:

try myObj.set("name", "fred")  // explicit property set

let results = try myObj.call("process", args: ["arg1", 100])

let answer = try myObj.call("pose", kwArgs: ["questionNumber": 40])

See RbGateway and its global instance Ruby for access to the Ruby ‘top self’ object to get started finding constants or calling global functions.

Converting to and from Swift types

Convert RbObjects to Swift types using failable initializers or the throwing convert methods:

let height = Double(myObj)
let allHeights = Array<Double>(myObj)
let heightDb = Dictionary<String, Double>(myObj)

let width = try myObj.convert(to: Double.self)
model.field = try myObj.convert()

Check RbError.history to see the cause of failed initializations.

In the reverse direction, Swift types convert implicitly to RbObject when passed as arguments via the RbObjectConvertible protocol.

Collection protocols

The conversion example above converts the entire Ruby array to an independent Swift array. An alternative is to use RbObject.collection which provides a dynamic view onto the Ruby array that supports many Swift collection protocols so you can update a Ruby array like:

myArrayObj.collection.sort(4..<8)

Standard library conformances

RbObject conforms to HashableHashable, EquatableEquatable, and ComparableComparable protocols by forwarding to the corresponding Ruby methods. Beware though that it is easy to trigger Ruby errors here that currently cause RubyGateway to crash. For example this is poison:

RbObject(3) < RbObject("barney")

Future releases may add more control over what happens here.

Arithmetic operators

RbObject conforms to the SignedNumericSignedNumeric protocol by forwarding the regular arithmetic operators to the corresponding Ruby methods. This means you can write let a = b + c where all are RbObjects and get a valid value for a provided b and c are any of the Ruby numeric values or any Ruby class that happens to support those operators.

Again you must take ensure that your Ruby objects support these operators or the program will crash.

Defining methods

Use RbObject.defineMethod(...) and RbObject.defineSingletonMethod(...) to add methods implemented in Swift to an object or class. Use RbGateway.defineClass(_:parent:under:) to define entirely new classes.


Topics

init(rubyValue: VALUE)

Wrap up a Ruby object using the its VALUE API handle.

The Ruby object is kept safe from garbage collection until the Swift object is deallocated.

This initializer is public to allow use with other parts of the Ruby API. It is not normally needed.

Declaration
Swift
public init(rubyValue: VALUE)

init(RbObject)

Create another Swift reference to an existing RbObject.

The underlying Ruby object will not be garbage-collected until both RbObjects have been deallocated.

There is still just one Ruby object in the system. To create a separate Ruby object do:

let myClone = myObject.call("clone")
Declaration
Swift
public init(_ value: RbObject)

func withRubyValue<T>(call: (VALUE) -> T) -> T

Safely access the VALUE object handle for use with the Ruby C API.

There is no direct access to the VALUE to prevent accidental use outside the corresponding RbObject’s lifetime.

Declaration
Swift
@discardableResult
public func withRubyValue<T>(call: (VALUE) throws -> T) rethrows -> T
Parameters
call

The closure to pass the object’s VALUE on to.

var rubyType: RbType

The Ruby type of this object. This is a fairly unfriendly enum but might be useful for debugging.

Declaration
Swift
public var rubyType: RbType { get }

var isTruthy: Bool

Is the Ruby object truthy?

Declaration
Swift
public var isTruthy: Bool { get }

var isNil: Bool

Is the Ruby object nil?

If you have Swift nil – that is, you don’t have .some(RbObject) – then Ruby failed – there was probably an exception. Check RbError.history for a list of recent exceptions.

If you’ve got Ruby nil – that is, you’ve got RbObject.isNil – then Ruby worked but the call evaluated to [Ruby] nil.

Declaration
Swift
public var isNil: Bool { get }

static var nilObject: RbObject

An RbObject that means nil to Ruby.

Declaration
Swift
public static let nilObject: RbObject

var collection: RbObjectCollection

A view onto the Ruby object using Swift collection APIs.

Intended for use with Ruby arrays, but any object will work provided it implements [], []=, and length like Array.

This property has a setter to permit syntax like:

myObj.collection[3..<12].sort()

The only thing that can be assigned is the object’s corresponding RbObjectCollection – assigning anything else will trap. Use RbObjectCollection.rubyObject to obtain a collection’s underlying Ruby array.

Declaration
Swift
public var collection: RbObjectCollection { get set }

Retrieving a bound Swift object

func getBoundObject<T>(type: T.Type) -> T

Retrieve the Swift object bound to this Ruby object.

This is for use on Ruby objects created from classes defined with RbGateway.defineClass(_:under:initializer:) to retrieve the bound object.

This function performs an unsafe cast to the type you specify so be sure to get it right.

Declaration
Swift
public func getBoundObject<T>(type: T.Type) throws -> T where T: AnyObject
Parameters
type

The type of the bound object

Throws

RbError.badType(...) if the object doesn’t have a bound Swift class.

Return Value

The bound object

Importing Modules

func include(module: RbObject)

Add methods from a module to a class such that methods from the class override any that match in the module.

Declaration
Swift
public func include(module: RbObject) throws
Parameters
module

Module whose methods are to be added.

Throws

RbError.badType(...) if this object is not a class or if module is not a module. RbError.rubyException(...) if Ruby is unhappy, for example if the operation creates a circular dependency.

func prepend(module: RbObject)

Add methods from a module to a class such that methods from the module override any that match in the class.

See Module#prepend for a better explanation.

Declaration
Swift
public func prepend(module: RbObject) throws
Parameters
module

Module whose methods are to be added.

Throws

RbError.badType(...) if this object is not a class or if module is not a module. RbError.rubyException(...) if Ruby is unhappy, for example if the operation creates a circular dependency.

func extend(module: RbObject)

Add methods from a module to the singleton class of this object.

See Module#extend for a better explanation.

Declaration
Swift
public func extend(module: RbObject) throws
Parameters
module

Module whose methods are to be added.

Throws

RbError.badType(...) if module is not a module. RbError.rubyException(...) if Ruby is unhappy, for example if the operation creates a circular dependency.

RbObjectConvertible

init(any RbObjectConvertible)

Create an RbObject from a Swift type.

RubyGateway conforms most of the Swift standard library types to RbObjectConvertible.

Declaration
Swift
public convenience init(_ value: any RbObjectConvertible)

func convert<T>() -> T

Convert an RbObject to some Swift type.

This is a convenience wrapper around optional conversion for cases where the Swift type can be inferred. See convert(to:) to explicitly specify the desired type.

Declaration
Swift
public func convert<T>() throws -> T where T: RbObjectConvertible
Throws

RbError.badType(...) if the conversion fails. There may be a more detailed exception inside RbError.history.

func convert<T>(to: T.Type) -> T

Convert an RbObject to some Swift type.

This is a convenience wrapper around optional conversion. See convert() for when the desired type can be inferred by the compiler.

Declaration
Swift
public func convert<T>(to type: T.Type) throws -> T where T: RbObjectConvertible
Throws

RbError.badType(...) if the conversion fails. There may be a more detailed exception inside RbError.history.

StringLiteral

init(stringLiteral: String)

Creates an RbObject from a string literal.

Declaration
Swift
public convenience init(stringLiteral value: String)

BooleanLiteral

init(booleanLiteral: Bool)

Creates an RbObject from a boolean literal.

Declaration
Swift
public convenience init(booleanLiteral value: Bool)

IntegerLiteral

init(integerLiteral: Int)

Creates an RbObject from an integer literal.

Declaration
Swift
public convenience init(integerLiteral value: Int)

FloatLiteral

init(floatLiteral: Double)

Creates an RbObject from a floating-point literal.

Declaration
Swift
public convenience init(floatLiteral value: Double)

ArrayLiteral

init(arrayLiteral: RbObject...)

Creates an RbObject from an array literal.

Although the element type here is RbObject you can write things like:

let obj: RbObject = [1, 2, 3]

… because of RbObject’s ExpressibleByIntegerLiteralExpressibleByIntegerLiteral conformance that gets applied recursively.

Declaration
Swift
public convenience init(arrayLiteral value: RbObject...)

DictionaryLiteral

init(dictionaryLiteral: (RbObject, RbObject)...)

Creates an RbObject from a dictionary literal.

Although the key and value types here are RbObject you can write things like:

let obj: RbObject = [1: "fish", 2: "bucket", 3: "wife", 4: "goat"]

… because of RbObject’s ExpressibleByXxxLiteral conformance that gets applied recursively.

Like a regular Dictionary there must be no duplicate keys in the elements.

Declaration
Swift
public convenience init(dictionaryLiteral elements: (RbObject, RbObject)...)

Defining Methods

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

Add or replace a method in all instances of the Ruby class.

The RbObject must be for a Ruby class or module. The method is immediately available to all instances of the class.

You can define the class yourself using RbGateway.defineClass(_:parent:under:) or get hold of an existing class from the global Ruby object, for example:

let clazz = try Ruby.get("Array")
try clazz.defineMethod(name: "sum") { rbSelf, _ in
  rbSelf.collection.reduce(0, +)
}
Declaration
Swift
public func defineMethod(
    _ name: String,
    argsSpec: RbMethodArgsSpec = RbMethodArgsSpec(),
    body: @escaping RbMethodCallback) throws
Parameters
name

The method name.

argsSpec

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

body

The Swift code to run when the method is called.

Throws

RbError.badIdentifier(type:id:) if name is bad. RbError.badType(...) if the object is neither a class nor a module.

func defineMethod<SwiftPeer, Return>(String, argsSpec: RbMethodArgsSpec, method: RbBoundMethodCallback<SwiftPeer, Return>)

Add or replace a method in all instances of the Ruby class.

This version is for methods that have a value to return.

The object must be a Ruby class defined using RbGateway.defineClass(_:under:initializer:) sharing the same type for SwiftPeer. For example:

class InvaderModel {
    init() { ... }
    func fire(rbMethod: RbMethod) throws -> Bool { ... }
}

let invaderClass = try Ruby.defineClass("Invader", initializer: InvaderModel.init)
try invaderClass.defineMethod("fire", method: Invader.fire)

There are unsafe casts involved here so you must be sure to get the types right.

Declaration
Swift
public func defineMethod<
    SwiftPeer: AnyObject & Sendable, Return: RbObjectConvertible & Sendable
>(
    _ name: String,
    argsSpec: RbMethodArgsSpec = RbMethodArgsSpec(),
    method: @escaping RbBoundMethodCallback<SwiftPeer, Return>) throws
Parameters
name

The method name.

argsSpec

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

method

The Swift method to call to fulfill the Ruby method.

Throws

RbError.badIdentifier(type:id:) if name is bad. RbError.badType(...) if the object is not a class.

func defineMethod<SwiftPeer>(String, argsSpec: RbMethodArgsSpec, method: RbBoundMethodVoidCallback<SwiftPeer>)

Add or replace a method in all instances of the Ruby class.

This version is for methods that have no return value. In Ruby all methods return values so RubyBridge substitutes the object itself.

The object must be a Ruby class defined using RbGateway.defineClass(_:under:initializer:) sharing the same type for SwiftPeer. For example:

class InvaderModel {
    init() { ... }
    func initialize(rbMethod: RbMethod) throws -> Void { ... }
}

let invaderClass = try Ruby.defineClass("Invader", initializer: InvaderModel.init)
try invaderClass.defineMethod("initialize",
                              argsSpec: .basic(1),
                              method: InvaderModel.initialize)

There are unsafe casts involved here so you must be sure to get the types right.

Declaration
Swift
public func defineMethod<SwiftPeer: AnyObject & Sendable>(
    _ name: String,
    argsSpec: RbMethodArgsSpec = RbMethodArgsSpec(),
    method: @escaping RbBoundMethodVoidCallback<SwiftPeer>) throws
Parameters
name

The method name.

argsSpec

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

method

The Swift method to call to fulfill the Ruby method.

Throws

RbError.badIdentifier(type:id:) if name is bad. RbError.badType(...) if the object is not a class.

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

Add or replace a method in the Ruby object’s singleton class.

In practice this means: if the RbObject is a class then this adds a class method. Otherwise, if the RbObject is a ‘normal’ instance object then it adds a method valid just for this instance.

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

The method name.

argsSpec

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

body

The Swift code to run when the method is called.

Throws

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

Useful Initializers

init?(ofClass: String, args: [(any RbObjectConvertible)?], kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?>)

Create an instance of a given Ruby class.

Fails (returns nil) if anything goes wrong along the way - check RbError.history to find out what failed.

Declaration
Swift
public convenience init?(
    ofClass className: String,
    args: [(any RbObjectConvertible)?] = [],
    kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?> = [:])
Parameters
ofClass

Name of the class to instantiate. Can contain :: to drill down into module/etc. scope.

args

positional arguments to pass to new call for the object. Default none.

kwArgs

keyword arguments to pass to the new call for the object. Default none.

init?(ofClass: String, args: [(any RbObjectConvertible)?], kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?>, retainBlock: Bool, blockCall: RbBlockCallback)

Create an instance of a given Ruby class passing a Swift closure as a block.

This version is really for cases where Ruby retains the block rather than using it only synchronously during the exection of the new method. For the synchronous case see init(ofClass:args:kwArgs:blockCall:) which does not require an @escapable or SendableSendable block closure.

Fails (returns nil) if anything goes wrong along the way - check RbError.history to find out what failed.

Declaration
Swift
public convenience init?(
    ofClass className: String,
    args: [(any RbObjectConvertible)?] = [],
    kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?> = [:],
    retainBlock: Bool,
    blockCall: @escaping @Sendable RbBlockCallback)
Parameters
ofClass

Name of the class to instantiate. Can contain :: to drill down into module/etc. scope.

args

positional arguments to pass to new call for the object. Default none.

kwArgs

keyword arguments to pass to the new call for the object. Default none.

retainBlock

Should blockCall be retained by the object? Set true if Ruby uses the block after this call. For example creating a Proc object using Proc#new.

blockCall

Swift code to pass as a block to the method.

init?(ofClass: String, args: [(any RbObjectConvertible)?], kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?>, blockCall: RbBlockCallback)

Create an instance of a given Ruby class passing a Swift closure as a block.

The closure is used only synchronously during the new method. For a version appropriate for use with things like Proc#new that retain the block, see init(ofClass:args:kwArgs:retainBlock:blockCall:)

Fails (returns nil) if anything goes wrong along the way - check RbError.history to find out what failed.

Declaration
Swift
public convenience init?(
    ofClass className: String,
    args: [(any RbObjectConvertible)?] = [],
    kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?> = [:],
    blockCall: RbBlockCallback)
Parameters
ofClass

Name of the class to instantiate. Can contain :: to drill down into module/etc. scope.

args

positional arguments to pass to new call for the object. Default none.

kwArgs

keyword arguments to pass to the new call for the object. Default none.

blockCall

Swift code to pass as a block to the method.

init(blockCall: RbBlockCallback)

Create a Ruby Proc object from a Swift closure.

warning

You must not allow this RbObject to be deallocated before Ruby has finished with the block, or the process will crash when Ruby calls it.

Declaration
Swift
public convenience init(blockCall: @escaping @Sendable RbBlockCallback)
Parameters
blockCall

The callback for the proc.

String Convertible

var description: String

A string representation of the Ruby object.

This is the same as String(rbObject) which is approximately Kernel#String.

Declaration
Swift
public var description: String { get }

var debugDescription: String

A developer-appropriate string representation of the Ruby object.

This is the result of inspect with a fallback to description.

Declaration
Swift
public var debugDescription: String { get }

var playgroundDescription: Any

The text from description.

Declaration
Swift
public var playgroundDescription: Any { get }

Standard Library Conformances

func hash(into: inout Hasher)

The hash value for the Ruby object.

Calls the Ruby hash method.

note

Crashes the process (fatalError) if the object does not support hash or if the hash call returns something that can’t be converted to Int.

Declaration
Swift
public func hash(into hasher: inout Hasher)

static func ==(lhs: RbObject, rhs: RbObject) -> Bool

Returns a Boolean value indicating whether two values are equal.

Calls the Ruby == method of the lhs passing rhs as the parameter.

note

Crashes the process (fatalError) if the call to == goes wrong.

Declaration
Swift
public static func == (lhs: RbObject, rhs: RbObject) -> Bool
Return Value

Whether the objects are the same under ==.

static func <(lhs: RbObject, rhs: RbObject) -> Bool

Returns a Boolean value indicating whether the value of the first argument is less than that of the second argument.

Calls the Ruby < method of lhs passing rhs as the parameter.

note

Crashes the process (fatalError) if the call to < goes wrong.

Declaration
Swift
public static func < (lhs: RbObject, rhs: RbObject) -> Bool

SignedNumeric

init<T>(exactly: T)

Create a Ruby object from some type conforming to BinaryIntegerBinaryInteger

Declaration
Swift
public convenience init<T>(exactly value: T) where T: BinaryInteger

static func -(lhs: RbObject, rhs: RbObject) -> RbObject

Subtraction operator for RbObjects.

note

Calls Ruby - method. Crashes the process (fatalError) if the objects do not support subtraction.

Declaration
Swift
public static func - (lhs: RbObject, rhs: RbObject) -> RbObject

static func +(lhs: RbObject, rhs: RbObject) -> RbObject

Addition operator for RbObjects.

note

Calls Ruby + method. Crashes the process (fatalError) if the objects do not support addition.

Declaration
Swift
public static func + (lhs: RbObject, rhs: RbObject) -> RbObject

static func *(lhs: RbObject, rhs: RbObject) -> RbObject

Multiplication operator for RbObjects.

note

Calls Ruby * method. Crashes the process (fatalError) if the objects do not support multiplication.

Declaration
Swift
public static func * (lhs: RbObject, rhs: RbObject) -> RbObject

static func /(lhs: RbObject, rhs: RbObject) -> RbObject

Division operator for RbObjects.

note

Calls Ruby / method. Crashes the process (fatalError) if the objects do not support division.

Declaration
Swift
public static func / (lhs: RbObject, rhs: RbObject) -> RbObject

static func %(lhs: RbObject, rhs: RbObject) -> RbObject

Remainder operator for RbObjects.

note

Calls Ruby % method. Crashes the process (fatalError) if the objects do not support remaindering.

Declaration
Swift
public static func % (lhs: RbObject, rhs: RbObject) -> RbObject

static func +=(lhs: inout RbObject, rhs: RbObject)

Addition-assignment operator for RbObjects.

Declaration
Swift
public static func += (lhs: inout RbObject, rhs: RbObject)

static func -=(lhs: inout RbObject, rhs: RbObject)

Subtraction-assignment operator for RbObjects.

Declaration
Swift
public static func -= (lhs: inout RbObject, rhs: RbObject)

static func *=(lhs: inout RbObject, rhs: RbObject)

Multiplication-assignment operator for RbObjects.

Declaration
Swift
public static func *= (lhs: inout RbObject, rhs: RbObject)

static func /=(lhs: inout RbObject, rhs: RbObject)

Division-assignment operator for RbObjects.

Declaration
Swift
public static func /= (lhs: inout RbObject, rhs: RbObject)

static func %=(lhs: inout RbObject, rhs: RbObject)

Remainder-assignment operator for RbObjects.

Declaration
Swift
public static func %= (lhs: inout RbObject, rhs: RbObject)

var magnitude: RbObject

The magnitude of the value.

note

Calls Ruby magnitude method. Crashes the process (fatalError) if the object does not support magnitude.

Declaration
Swift
public var magnitude: RbObject { get }

static func -(operand: RbObject) -> RbObject

The negated version of the value.

note

Calls Ruby unary - method. Crashes the process (fatalError) if the object does not support this.

Declaration
Swift
public prefix static func - (operand: RbObject) -> RbObject

static func +(operand: RbObject) -> RbObject

Unary plus operator.

note

Calls Ruby unary + method. Crashes the process (fatalError) if the object does not support this.

Declaration
Swift
public prefix static func + (operand: RbObject) -> RbObject

Subscript

subscript(args: any RbObjectConvertible...) -> RbObject

Subscript operator, supports both get + set.

Although you can use RbObjectConvertibles as the subscript arguments, the value assigned in the setter has to be an RbObject. So this doesn’t work:

try myObj[1, "fish", myThirdParamObj] = 4

…instead you have to do:

try myObj[1, "fish", myThirdParamObj] = RbObject(4)
note

Calls Ruby [] and []= methods. Crashes the process (fatalError) if anything goes wrong - Swift can’t throw from subscripts yet.

Declaration
Swift
public subscript(args: any RbObjectConvertible...) -> RbObject { get set }