RbObjectAccess

Swift
public class RbObjectAccess

Provides services to manipulate a Ruby object:

  • Call methods;
  • Access properties and instance variables;
  • Access class variables;
  • Access global variables;
  • Find constants, classes, and modules.

The class is abstract. You use it via RbObject and the global Ruby instance of RbGateway.

By default all methods throw RbErrors if anything goes wrong including when Ruby raises an exception. Use the RbObjectAccess.failable adapter to access an alternative API that returns nil on errors instead. You can still see any Ruby exceptions via RbError.history.

Calling methods

Ruby has a few different ways to call methods that are reflected in the various Swift methods here and their types. The degrees of freedom are:

  1. Call method by name or by symbol;
  2. Pass positional and/or keyword arguments;
  3. Optionally pass a block that can be expressed as a Swift function or a Ruby Proc.
  4. Method can either raise an exception or return a value.

From the simple:

try! obj.call("myMethod")

…to more baroque:

do {
    let result =
         try obj.call(symbol: myMethodSymbol,
                      args: [1, "3.5", myHash],
                      kwArgs: [("mode", RbSymbol("debug")]) { blockArgs in
                          blockArgs.forEach {
                              process($0)
                          }
                          return .nilObject
                      }
} catch RbError.rubyException(let exn) {
    handleErrors(error)
} catch {
    ...
}

When passing a Swift function as a block there are two methods to choose from. If the block is used only within the method execution you can provide a non-escaping, non-sendable function; if the block is persisted and used later then you must provide a retention rule and an escaping, sendable function.


Topics

Instance Variables

func getInstanceVar(String) -> RbObject

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

For a version that does not throw, see failable.

Declaration
Swift
public 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 Ruby instance variable. Creates a new one if it doesn’t exist yet.

For a version that does not throw, see failable.

Declaration
Swift
@discardableResult
public 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.

Failable Access

var failable: RbFailableAccess

Get a version of this API that returns nil instead of throwing errors. See RbFailableAccess.

Declaration
Swift
public var failable: RbFailableAccess { get }

Constants

func getConstant(String) -> RbObject

Get an RbObject that represents a Ruby constant.

In Ruby constants include things that users think of as constants like Math::PI, classes, and modules. You can use this routine with any kind of constant, but see getClass(...) for a little more sugar.

let rubyPi = Ruby.getConstant("Math::PI")
let crumbs = rubyPi - Double.pi

This is a dynamic call into Ruby that can cause calls to const_missing and autoloading.

For a version that does not throw, see failable.

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

The name of the constant to look up. Can contain ‘::’ sequences to drill down through nested classes and modules.

If you call this method on an RbObject then name is resolved like Ruby does, looking up the inheritance chain if there is no local match.

Throws

RbError.rubyException(_:) if the constant cannot be found.

Return Value

An RbObject for the constant.

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

Bind an object to a constant name.

Use this to add value-constants to the class/module name hierarchy. For example:

let defaultInvader = RbObject(ofClass: "Invader", kwArgs: ["name" : "Zaltor"])
try Ruby.setConstant("Game::Invaders::DEFAULT", defaultInvader)

To define new classes and modules, use RbGateway.defineClass(...) and RbGateway.defineModule(...) instead of this method.

For a version that does not throw, see failable.

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

The name of the constant to create or replace. Can contain ‘::’ sequences to drill down through nested classes and modules.

newValue

The value for the constant.

Throws

RbError.badIdentifier(type:id:) if name looks wrong. rubyException(_:) if there is a Ruby exception. RbError.badType(_:) if the current object is not a class or module.

Return Value

The value set for the constant.

func getClass(String) -> RbObject

Get an RbObject that represents a Ruby class.

This is a dynamic call into Ruby that can cause calls to const_missing and autoloading.

One way of creating an instance of a class:

let myClass = try Ruby.getClass("MyModule::MyClass")
let myObj = try myClass.call("new")

Although it is easier to write:

let myObj = try RbObject(ofClass: "MyModule::MyClass")

For a version that does not throw, see failable.

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

The name of the class to look up. Can contain ‘::’ sequences to drill down through nested classes and modules.

If you call this method on an RbObject then name is resolved like Ruby does, looking up the inheritance chain if there is no match.

Throws

RbError.rubyException(_:) if the constant cannot be found. RbError.badType(_:) if the constant is found but is not a class.

Return Value

An RbObject for the class.

Method Call

func call(String, args: [(any RbObjectConvertible)?], kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?>) -> RbObject

Call a Ruby object method.

For a version that does not throw, see failable.

Declaration
Swift
@discardableResult
public func call(
    _ methodName: String,
    args: [(any RbObjectConvertible)?] = [],
    kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?> = [:]
) throws -> RbObject
Parameters
methodName

The name of the method to call.

args

The positional arguments to the method. None by default.

kwArgs

The keyword arguments to the method. None by default.

Throws

RbError.rubyException(_:) if there is a Ruby exception. RbError.duplicateKwArg(_:) if there are duplicate keywords in kwArgs.

Return Value

The result of calling the method.

func call(String, args: [(any RbObjectConvertible)?], kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?>, blockCall: RbBlockCallback) -> RbObject

Call a Ruby object method passing Swift code as a block used immediately.

This version is for something like Enumerable#each where the block is used only in the context of this method and never again. The Swift closure does not have to be escaping or sendable.

If the method you’re calling retains the block in some way, associating it with the called or returned object for future use, then the Swift closure must be both escaping and sendable and you must call the method with call(_:args:kwArgs:blockRetention:blockCall:).

For a version that does not throw, see failable.

Declaration
Swift
@discardableResult
public func call(
    _ methodName: String,
    args: [(any RbObjectConvertible)?] = [],
    kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?> = [:],
    blockCall: RbBlockCallback
) throws -> RbObject
Parameters
methodName

The name of the method to call.

args

The positional arguments to the method. None by default.

kwArgs

The keyword arguments to the method. None by default.

blockCall

Swift code to pass as a block to the method.

Throws

RbError.rubyException(_:) if there is a Ruby exception. RbError.duplicateKwArg(_:) if there are duplicate keywords in kwArgs.

Return Value

The result of calling the method.

func call(String, args: [(any RbObjectConvertible)?], kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?>, blockRetention: RbBlockRetention, blockCall: RbBlockCallback) -> RbObject

Call a Ruby object method passing Swift code as a block.

For a version that does not throw, see failable.

Declaration
Swift
@discardableResult
public func call(
    _ methodName: String,
    args: [(any RbObjectConvertible)?] = [],
    kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?> = [:],
    blockRetention: RbBlockRetention,
    blockCall: @escaping @Sendable RbBlockCallback
) throws -> RbObject
Parameters
methodName

The name of the method to call.

args

The positional arguments to the method. None by default.

kwArgs

The keyword arguments to the method. None by default.

blockRetention

Should the blockCall closure be retained for longer than this call? See RbBlockRetention.

blockCall

Swift code to pass as a block to the method.

Throws

RbError.rubyException(_:) if there is a Ruby exception. RbError.duplicateKwArg(_:) if there are duplicate keywords in kwArgs.

Return Value

The result of calling the method.

func call(String, args: [(any RbObjectConvertible)?], kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?>, block: any RbObjectConvertible) -> RbObject

Call a Ruby object method passing a Ruby Proc as a block.

For a version that does not throw, see failable.

Declaration
Swift
@discardableResult
public func call(
    _ methodName: String,
    args: [(any RbObjectConvertible)?] = [],
    kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?> = [:],
    block: any RbObjectConvertible
) throws -> RbObject
Parameters
methodName

The name of the method to call.

args

The positional arguments to the method. None by default.

kwArgs

The keyword arguments to the method. None by default.

block

A Ruby proc to pass as a block to the method.

Throws

RbError.rubyException(_:) if there is a Ruby exception. RbError.duplicateKwArg(_:) if there are duplicate keywords in kwArgs. RbError.badType(_:) if block does not convert to a Proc.

Return Value

The result of calling the method.

func call(symbol: any RbObjectConvertible, args: [(any RbObjectConvertible)?], kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?>) -> RbObject

Call a Ruby object method using a symbol.

For a version that does not throw, see failable.

Declaration
Swift
@discardableResult
public func call(
    symbol: any RbObjectConvertible,
    args: [(any RbObjectConvertible)?] = [],
    kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?> = [:]
) throws -> RbObject
Parameters
symbol

The symbol for the name of the method to call.

args

The positional arguments to the method. None by default.

kwArgs

The keyword arguments to the method. None by default.

Throws

RbError.rubyException(_:) if there is a Ruby exception. RbError.badType(_:) if symbol is not a symbol. RbError.duplicateKwArg(_:) if there are duplicate keywords in kwArgs.

Return Value

The result of calling the method.

func call(symbol: any RbObjectConvertible, args: [(any RbObjectConvertible)?], kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?>, blockCall: RbBlockCallback) -> RbObject

Call a Ruby object method using a symbol passing Swift code as a block used immediately.

This version is for something like Enumerable#each where the block is used only in the context of this method and never again. The Swift closure does not have to be escaping or sendable.

If the method you’re calling retains the block in some way, associating it with the called or returned object for future use, then the Swift closure must be both escaping and sendable and you must call the method with call(symbol:args:kwArgs:blockRetention:blockCall:).

For a version that does not throw, see failable.

Declaration
Swift
@discardableResult
public func call(
    symbol: any RbObjectConvertible,
    args: [(any RbObjectConvertible)?] = [],
    kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?> = [:],
    blockCall: RbBlockCallback
) throws -> RbObject
Parameters
symbol

The symbol for the name of the method to call.

args

The positional arguments to the method. None by default.

kwArgs

The keyword arguments to the method. None by default.

blockCall

Swift code to pass as a block to the method.

Throws

RbError.rubyException(_:) if there is a Ruby exception. RbError.badType(_:) if symbol is not a symbol. RbError.duplicateKwArg(_:) if there are duplicate keywords in kwArgs.

Return Value

The result of calling the method.

func call(symbol: any RbObjectConvertible, args: [(any RbObjectConvertible)?], kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?>, blockRetention: RbBlockRetention, blockCall: RbBlockCallback) -> RbObject

Call a Ruby object method using a symbol passing Swift code as a block.

For a version that does not throw, see failable.

Declaration
Swift
@discardableResult
public func call(
    symbol: any RbObjectConvertible,
    args: [(any RbObjectConvertible)?] = [],
    kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?> = [:],
    blockRetention: RbBlockRetention,
    blockCall: @escaping @Sendable RbBlockCallback
) throws -> RbObject
Parameters
symbol

The symbol for the name of the method to call.

args

The positional arguments to the method. None by default.

kwArgs

The keyword arguments to the method. None by default.

blockRetention

Should the blockCall closure be retained for longer than this call? See RbBlockRetention.

blockCall

Swift code to pass as a block to the method.

Throws

RbError.rubyException(_:) if there is a Ruby exception. RbError.badType(_:) if symbol is not a symbol. RbError.duplicateKwArg(_:) if there are duplicate keywords in kwArgs.

Return Value

The result of calling the method.

func call(symbol: any RbObjectConvertible, args: [(any RbObjectConvertible)?], kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?>, block: any RbObjectConvertible) -> RbObject

Call a Ruby object method using a symbol passing a Ruby Proc as a block.

For a version that does not throw, see failable.

Declaration
Swift
@discardableResult
public func call(
    symbol: any RbObjectConvertible,
    args: [(any RbObjectConvertible)?] = [],
    kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?> = [:],
    block: any RbObjectConvertible
) throws -> RbObject
Parameters
symbol

The symbol for the name of the method to call.

args

The positional arguments to the method. None by default.

kwArgs

The keyword arguments to the method. None by default.

block

A Ruby proc to pass as a block to the method.

Throws

RbError.rubyException(_:) if there is a Ruby exception. RbError.badType(_:) if symbol is not a symbol. RbError.duplicateKwArg(_:) if there are duplicate keywords in kwArgs. RbError.badType(_:) if block does not convert to a Proc.

Return Value

The result of calling the method.

Attributes

func getAttribute(String) -> RbObject

Get an attribute of a Ruby object.

Attributes are declared with :attr_accessor and so on – this routine is a simple wrapper around call(...) for symmetry with setAttribute(...).

For a version that does not throw, see failable.

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

The name of the attribute to get.

Throws

RbError.badIdentifier(type:id:) if name looks wrong. RbError.rubyException(_:) if Ruby has a problem, probably means attribute doesn’t exist.

Return Value

The value of the attribute.

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

Set an attribute of a Ruby object.

Attributes are declared with :attr_accessor and so on – this routine is a wrapper around a call to the attrname= method.

For a version that does not throw, see failable.

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

The name of the attribute to set.

value

The new value of the attribute.

Throws

RbError.badIdentifier(type:id:) if name looks wrong. RbError.rubyException(_:) if Ruby has a problem, probably means attribute doesn’t exist.

Return Value

Whatever the attribute setter returns, typically the new value.

Class Variables

func getClassVar(String) -> RbObject

Get the value of a Ruby class variable that has already been written.

Must be called on an RbObject for a class, or RbGateway. Note this is different from Ruby as-written where you write @@fred in an object context to get a CVar on the object’s class.

The behavior of accessing a non-existent CVar is not consistent with IVars or GVars. This is how Ruby works; one more reason to avoid CVars.

For a version that does not throw, see failable.

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

Name of CVar to get. Must begin with ‘@@’.

Throws

RbError.badIdentifier(type:id:) if name looks wrong. RbError.badType(_:) if the object is not a class. RbError.rubyException(_:) if Ruby has a problem – in particular, if the CVar does not exist.

Return Value

The value of the CVar.

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

Set a Ruby class variable. Creates a new one if it doesn’t exist yet.

Must be called on an RbObject for a class, or RbGateway. Note this is different from Ruby as-written where you write @@fred = thing in an object context to set a CVar on the object’s class.

For a version that does not throw, see failable.

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

Name of the CVar to set. Must begin with ‘@@’.

newValue

The new value to set.

Throws

RbError.badIdentifier(type:id:) if name looks wrong. RbError.badType(_:) if the object is not a class. RbError.rubyException(_:) if Ruby has a problem.

Return Value

The value that was set.

Global Variables

func getGlobalVar(String) -> RbObject

Get the value of a Ruby global variable.

For a version that does not throw, see failable.

(This method is present in this class meaning you can call it on any RbObject as well as RbGateway without any difference in effect. This is purely convenience to put all these getter/setter pairs in the same place and make construction of RbFailableAccess a bit easier. Best practice probably to avoid calling the RbObject version.)

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

Name of global variable to get. Must begin with ‘$’.

Throws

RbError if name looks wrong.

Return Value

Value of the variable, or Ruby nil if not set before.

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

Set a Ruby global variable. Creates a new one if it doesn’t exist yet.

For a version that does not throw, see failable.

(This method is present in this class meaning you can call it on any RbObject as well as RbGateway without any difference in effect. This is purely convenience to put all these getter/setter pairs in the same place and make construction of RbFailableAccess a bit easier. Best practice probably to avoid calling the RbObject version.)

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

Name of global variable to set. Must begin with ‘$’.

newValue

New value to set.

Throws

RbError if name looks wrong.

Return Value

The value that was set.

Polymorphic Getter

func get(String) -> RbObject

Get some kind of Ruby object based on the name parameter:

  • If name starts with a capital letter then access a constant under this object;
  • If name starts with ‘@’ or ‘@@’ then access an IVar/CVar for a class object;
  • If name starts with ‘$’ then access a global variable;
  • Otherwise call a zero-args method.

This is a convenience helper to let you access Ruby structures without worrying about precisely what they are.

For a version that does not throw, see failable.

Declaration
Swift
@discardableResult
public func get(_ name: String) throws -> RbObject
Parameters
name

Name of thing to access.

Throws

RbError.rubyException(_:) if Ruby has a problem. RbError of some other kind if name looks wrong in some way.

Return Value

The accessed thing .