RubyGateway
在 Swift 中嵌入 Ruby:加载 Gems、运行 Ruby 脚本、无缝调用 API(双向)。
RubyGateway 是一个基于 Ruby C API 的框架,使在 macOS 或 Linux 上运行的 Swift 程序可以轻松且安全地运行和交互 Ruby 程序。它很容易将 Swift 值传递到 Ruby,并将 Ruby 对象转换回 Swift 类型。
RubyGateway 允许您从 Swift 调用任何 Ruby 方法,包括传递 Swift 闭包作为块。它允许您定义在 Swift 中实现的 Ruby 类和方法。
如果您正在寻找低级别的 Ruby C API 包装器,请参见 CRuby。
示例
服务
Rouge 是一个代码高亮工具。在 Ruby
require 'rouge'
html = Rouge.highlight("let a = 3", "swift", "html")
puts(html)
在 Swift 中
import RubyGateway
try Ruby.require(filename: "rouge")
let html = try Ruby.get("Rouge").call("highlight", args: ["let a = 3", "swift", "html"])
print(html)
调用 Ruby
// Create an object. Use keyword arguments with initializer
let student = RbObject(ofClass: "Academy::Student", kwArgs: ["name": "barney"])!
// Acess an attribute
print("Name is \(student.get("name"))")
// Fix their name by poking an ivar
try! student.setInstanceVar("@name", newValue: "Barney")
// Get a Swift version of `:reading`
let readingSubject = RbSymbol("reading")
// Call a method with mixed Swift data types
try! student.call("add_score", args: [readingSubject, 30])
try! student.call("add_score", args: [readingSubject, 35])
// Get a result as floating point
let avgScoreObj = try! student.call("mean_score_for_subject", args: [readingSubject])
let avgScore = Double(avgScoreObj)!
print("Mean score is \(avgScore)")
// Pass Swift code as a block
let scores = student.all_scores!
scores.call("each") { args in
print("Subject: \(args[0]) Score: \(args[1])")
return .nilObject
}
// Convert to a Swift array
let subjects = Array<String>(student.all_subjects!)
subjectsPopularityDb.submit(subjects: subjects)
调用Swift
绑定类定义
class Cell {
init() {
}
func setup(m: RbMethod) throws {
...
}
func getContent(m: RbMethod) throws -> String {
...
}
}
let cellClass = try Ruby.defineClass("Cell", initializer: Cell.init)
try cellClass.defineMethod("initialize",
argsSpec: RbMethodArgsSpec(mandatoryKeywords: ["width", "height"])
method: Cell.setup)
try cellClass.defineMethod("content",
argsSpec: RbMethodArgsSpec(requiresBlock: true),
method: Cell.getContent)
从Ruby调用
cell = Cell.new(width: 200, height: 100)
cell.content { |c| prettyprint(c) }
全局变量
// epochStore.current: Int
Ruby.defineGlobalVar("$epoch",
get: { epochStore.current },
set: { epochStore.current = newEpoch })
全局函数
let logArgsSpec = RbMethodArgsSpec(leadingMandatoryCount: 1,
optionalKeywordValues: ["priority" : 0])
try Ruby.defineGlobalFunction("log",
argsSpec: logArgsSpec) { _, method in
Logger.log(message: String(method.args.mandatory[0]),
priority: Int(method.args.keyword["priority"]!))
return .nilObject
}
从Ruby调用
log(object_to_log)
log(object2_to_log, priority: 2)
文档
需求
- Swift 5.4或更高版本,从swift.org或Xcode 12.5
- macOS(已在12.6上测试)或Linux(已在Ubuntu Bionic/18.04 x86_64上测试)带有Clang 6。
- Ruby 2.6或更高版本包括开发文件
- 对于macOS,这些与Xcode一同提供。
- 对于Linux,根据Ruby的安装方式,可能需要安装-dev包。
- RubyGateway需要'original' MRI/CRuby Ruby - 不允许使用JRuby/Rubinius等。
由于Ruby 3.2,Ruby 3的Xcode项目存在问题:Xcode中运行测试时显示各种奇怪的错误,看起来像是链接问题,但在SPM中正常运行时不存在。
安装
对于macOS,如果您愿意使用系统Ruby,只需将RubyGateway框架作为一个依赖项包括即可。如果您在Linux上构建或想使用不同的Ruby,还需要配置CRuby。
如果您使用Ruby 3,需要在Swift PM命令行(swift build -Xcc -fdeclspec
)或在Xcode的《其他Swift标志》设置中设置-fdeclspec
Clang标志。
获取框架
Carthage for macOS
github "johnfairh/RubyGateway"
Swift 包管理器,适用于 macOS 或 Linux
.package(url: "https://github.com/johnfairh/RubyGateway", from: "5.4.0")
CocoaPods for macOS
pod 'RubyGateway'
配置 CRuby
CRuby 是 RubyGateway 与您的 Ruby 安装之间的粘合剂。这是一个独立的 GitHub 项目,但 RubyGateway 作为子模块包含它,因此您无需单独安装或要求它。
默认情况下,它指向 macOS 系统版 Ruby。按照 CRuby 使用说明 更改这一点。例如,在 Ubuntu 18 上使用 rbenv
Ruby 3
mkdir MyProject && cd MyProject
swift package init --type executable
vi Package.swift
# add RubyGateway as a package dependency (NOT CRuby)
# add RubyGateway as a target dependency
echo "import RubyGateway; print(Ruby.versionDescription)" > Sources/MyProject/main.swift
swift package update
swift package edit CRuby
Packages/CRuby/cfg-cruby --mode rbenv --name 3.0.0
PKG_CONFIG_PATH=$(pwd)/Packages/CRuby:$PKG_CONFIG_PATH swift run -Xcc -fdeclspec
贡献
欢迎:提交问题 / [email protected] / @johnfairh
许可协议
在 MIT 许可协议下分发。