RbObject
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 RbObject
s 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 Hashable
Hashable
, Equatable
Equatable
, and Comparable
Comparable
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 SignedNumeric
SignedNumeric
protocol by forwarding the regular
arithmetic operators to the corresponding Ruby methods. This means you can
write let a = b + c
where all are RbObject
s 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)
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
public init(rubyValue: VALUE)
init(RbObject)
init(RbObject)
Create another Swift reference to an existing RbObject
.
The underlying Ruby object will not be garbage-collected until
both RbObject
s 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
public init(_ value: RbObject)
func withRubyValue<T>(call: (VALUE) -> T) -> T
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
@discardableResult
public func withRubyValue<T>(call: (VALUE) throws -> T) rethrows -> T
Parameters
call |
The closure to pass the object’s |
var rubyType: RbType
var rubyType: RbType
The Ruby type of this object. This is a fairly unfriendly enum but might be useful for debugging.
Declaration
public var rubyType: RbType { get }
var isTruthy: Bool
var isTruthy: Bool
var isNil: Bool
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
public var isNil: Bool { get }
static var nilObject: RbObject
static var nilObject: RbObject
var collection: RbObjectCollection
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
public var collection: RbObjectCollection { get set }
Retrieving a bound Swift object
func getBoundObject<T>(type: T.Type) -> T
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
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)
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
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)
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
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)
func extend(module: RbObject)
Add methods from a module to the singleton class of this object.
See Module#extend
for a better explanation.
Declaration
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)
init(any RbObjectConvertible)
Create an RbObject
from a Swift type.
RubyGateway conforms most of the Swift standard library types
to RbObjectConvertible
.
Declaration
public convenience init(_ value: any RbObjectConvertible)
func convert<T>() -> T
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
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
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
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)
init(stringLiteral: String)
BooleanLiteral
init(booleanLiteral: Bool)
init(booleanLiteral: Bool)
IntegerLiteral
init(integerLiteral: Int)
init(integerLiteral: Int)
FloatLiteral
init(floatLiteral: Double)
init(floatLiteral: Double)
ArrayLiteral
init(arrayLiteral: RbObject...)
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 ExpressibleByIntegerLiteral
ExpressibleByIntegerLiteral
conformance
that gets applied recursively.
Declaration
public convenience init(arrayLiteral value: RbObject...)
DictionaryLiteral
init(dictionaryLiteral: (RbObject, RbObject)...)
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
Defining Methods
func defineMethod(String, argsSpec: RbMethodArgsSpec, body: RbMethodCallback)
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
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>)
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
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>)
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
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)
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
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)?>)
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
public convenience init?(
ofClass className: String,
args: [(any RbObjectConvertible)?] = [],
kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?> = [:])
Parameters
ofClass |
Name of the class to instantiate. Can contain |
args |
positional arguments to pass to |
kwArgs |
keyword arguments to pass to the |
init?(ofClass: String, args: [(any RbObjectConvertible)?], kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?>, retainBlock: Bool, blockCall: RbBlockCallback)
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 Sendable
Sendable
block closure.
Fails (returns nil
) if anything goes wrong along the way - check RbError.history
to
find out what failed.
Declaration
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 |
args |
positional arguments to pass to |
kwArgs |
keyword arguments to pass to the |
retainBlock |
Should |
blockCall |
Swift code to pass as a block to the method. |
init?(ofClass: String, args: [(any RbObjectConvertible)?], kwArgs: KeyValuePairs<String, (any RbObjectConvertible)?>, blockCall: RbBlockCallback)
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
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 |
args |
positional arguments to pass to |
kwArgs |
keyword arguments to pass to the |
blockCall |
Swift code to pass as a block to the method. |
init(blockCall: RbBlockCallback)
init(blockCall: RbBlockCallback)
Create a Ruby Proc object from a Swift closure.
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
public convenience init(blockCall: @escaping @Sendable RbBlockCallback)
Parameters
blockCall |
The callback for the proc. |
String Convertible
var description: String
var description: String
A string representation of the Ruby object.
This is the same as String(rbObject)
which is approximately Kernel#String
.
Declaration
public var description: String { get }
var debugDescription: String
var debugDescription: String
A developer-appropriate string representation of the Ruby object.
This is the result of inspect
with a fallback to description
.
Declaration
public var debugDescription: String { get }
var playgroundDescription: Any
var playgroundDescription: Any
Standard Library Conformances
func hash(into: inout Hasher)
func hash(into: inout Hasher)
static func ==(lhs: RbObject, rhs: RbObject) -> Bool
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.
Crashes the process (fatalError
) if the call to ==
goes wrong.
Declaration
Return Value
Whether the objects are the same under ==
.
static func <(lhs: RbObject, rhs: RbObject) -> Bool
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.
Crashes the process (fatalError
) if the call to <
goes wrong.
Declaration
SignedNumeric
init<T>(exactly: T)
init<T>(exactly: T)
Create a Ruby object from some type conforming to BinaryInteger
BinaryInteger
Declaration
public convenience init<T>(exactly value: T) where T: BinaryInteger
static func -(lhs: RbObject, rhs: RbObject) -> RbObject
static func -(lhs: RbObject, rhs: RbObject) -> RbObject
static func +(lhs: RbObject, rhs: RbObject) -> RbObject
static func +(lhs: RbObject, rhs: RbObject) -> RbObject
static func *(lhs: RbObject, rhs: RbObject) -> RbObject
static func *(lhs: RbObject, rhs: RbObject) -> RbObject
static func /(lhs: RbObject, rhs: RbObject) -> RbObject
static func /(lhs: RbObject, rhs: RbObject) -> RbObject
static func %(lhs: RbObject, rhs: RbObject) -> RbObject
static func %(lhs: RbObject, rhs: RbObject) -> RbObject
static func +=(lhs: inout RbObject, rhs: RbObject)
static func +=(lhs: inout RbObject, rhs: RbObject)
static func -=(lhs: inout RbObject, rhs: RbObject)
static func -=(lhs: inout RbObject, rhs: RbObject)
static func *=(lhs: inout RbObject, rhs: RbObject)
static func *=(lhs: inout RbObject, rhs: RbObject)
static func /=(lhs: inout RbObject, rhs: RbObject)
static func /=(lhs: inout RbObject, rhs: RbObject)
static func %=(lhs: inout RbObject, rhs: RbObject)
static func %=(lhs: inout RbObject, rhs: RbObject)
var magnitude: RbObject
var magnitude: RbObject
The magnitude of the value.
Calls Ruby magnitude
method. Crashes the process (fatalError
)
if the object does not support magnitude.
Declaration
public var magnitude: RbObject { get }
static func -(operand: RbObject) -> RbObject
static func -(operand: RbObject) -> RbObject
static func +(operand: RbObject) -> RbObject
static func +(operand: RbObject) -> RbObject
Subscript
subscript(args: any RbObjectConvertible...) -> RbObject
subscript(args: any RbObjectConvertible...) -> RbObject
Subscript operator, supports both get + set.
Although you can use RbObjectConvertible
s 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)
Calls Ruby []
and []=
methods. Crashes the process (fatalError
)
if anything goes wrong - Swift can’t throw from subscripts yet.
Declaration
public subscript(args: any RbObjectConvertible...) -> RbObject { get set }