Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ jobs:
uses: scientist-labs/rust-gem-release/.github/workflows/build.yml@0.11.0
with:
test-command: bundle exec rake spec
# Match the fat-gem ABI set in release.yml, so PR CI compiles against every
# Ruby we ship a binary for - including 4.0.
ruby-versions: "3.1,3.2,3.3,3.4,4.0"
5 changes: 5 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ jobs:
# "spellkit", so ext-name / gemspec / platform-gem-env all resolve to their
# defaults (spellkit, spellkit.gemspec, RUST_GEM_PLATFORM) and are omitted.
gem-name: spellkit
# 4.0 added in 0.3.0. The shared workflow's default is 3.1-3.4 and deliberately
# excludes 4.0, because Ruby 4.0 changed the C API (rb_sys::RTypedData lost
# typed_flag, rb_fiber_raise's argv became *mut) and magnus 0.7 cannot compile
# against it. spellkit is on magnus 0.8 as of this version, so it can.
ruby-versions: "3.1,3.2,3.3,3.4,4.0"
version-command: ruby -r./lib/spellkit/version -e 'print SpellKit::VERSION'
version: ${{ inputs.version }}
bump-command: |
Expand Down
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -684,9 +684,13 @@ bundle exec rake build
## Platform Support

Pre-built gems available for:
- macOS (x86_64, arm64)
- Linux (glibc, musl)
- Ruby 3.1, 3.2, 3.3
- macOS (arm64)
- Linux (x86_64, aarch64)
- Ruby 3.1, 3.2, 3.3, 3.4, 4.0

A pre-built gem carries one compiled extension per Ruby ABI, so installing under a Ruby
outside that list falls back to building from source and needs a Rust toolchain (>= 1.85).
Ruby 4.0 support arrived in 0.3.0; earlier versions cannot compile against it at all.

## Contributing

Expand Down
2 changes: 1 addition & 1 deletion ext/spellkit/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ name = "spellkit"
crate-type = ["cdylib"]

[dependencies]
magnus = { version = "0.7", features = ["rb-sys"] }
magnus = { version = "0.8", features = ["rb-sys"] }
hashbrown = "0.15"
unicode-normalization = "0.1"
regex = "1.11"
Expand Down
17 changes: 9 additions & 8 deletions ext/spellkit/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
mod symspell;
mod guards;

use magnus::{class, define_module, function, method, prelude::*, Error, RArray, RHash, Ruby, Value, TryConvert};
use magnus::{function, method, prelude::*, Error, RArray, RHash, Ruby, Value, TryConvert};
use std::sync::{Arc, RwLock};
use symspell::SymSpell;
use guards::Guards;
Expand Down Expand Up @@ -264,10 +264,10 @@ impl Checker {

if let Some(ref symspell) = state.symspell {
let suggestions = symspell.suggestions(&word, max_suggestions);
let result = RArray::new();
let result = ruby.ary_new();

for suggestion in suggestions {
let hash = RHash::new();
let hash = ruby.hash_new();
hash.aset("term", suggestion.term)?;
hash.aset("distance", suggestion.distance)?;
hash.aset("freq", suggestion.frequency)?;
Expand Down Expand Up @@ -320,7 +320,7 @@ impl Checker {
return Err(Error::new(ruby.exception_runtime_error(), "Dictionary not loaded. Call load! first"));
}

let result = RArray::new();
let result = ruby.ary_new();

if let Some(ref symspell) = state.symspell {
for token in tokens.into_iter() {
Expand All @@ -336,8 +336,9 @@ impl Checker {
}

fn stats(&self) -> Result<RHash, Error> {
let ruby = Ruby::get().unwrap();
let state = self.state.read().unwrap();
let stats = RHash::new();
let stats = ruby.hash_new();

if !state.loaded {
stats.aset("loaded", false)?;
Expand Down Expand Up @@ -376,9 +377,9 @@ impl Checker {
}

#[magnus::init]
fn init(_ruby: &Ruby) -> Result<(), Error> {
let module = define_module("SpellKit")?;
let checker_class = module.define_class("Checker", class::object())?;
fn init(ruby: &Ruby) -> Result<(), Error> {
let module = ruby.define_module("SpellKit")?;
let checker_class = module.define_class("Checker", ruby.class_object())?;

checker_class.define_singleton_method("new", function!(Checker::new, 0))?;
checker_class.define_method("load!", method!(Checker::load_full, 1))?;
Expand Down
2 changes: 1 addition & 1 deletion lib/spellkit/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# frozen_string_literal: true

module SpellKit
VERSION = "0.2.0"
VERSION = "0.3.0"
end
13 changes: 13 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,17 @@
config.expect_with :rspec do |c|
c.syntax = :expect
end

# `require "webmock/rspec"` in dictionary_loading_spec.rb disables net connect for the
# WHOLE suite, not just that file - so the two examples tagged :integration, whose entire
# purpose is to prove DEFAULT_DICTIONARY_URL really resolves and loads, were blocked by
# WebMock and failed on every Ruby. That is why every build run on this repo has been red.
#
# Let a tagged example reach the network, and restore the block afterwards so no other
# example inherits it.
config.around(:each, :integration) do |example|
WebMock.allow_net_connect! if defined?(WebMock)
example.run
WebMock.disable_net_connect!(allow_localhost: true) if defined?(WebMock)
end
end
3 changes: 3 additions & 0 deletions spellkit.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "webmock"
spec.add_development_dependency "standard", "~> 1.3"
spec.add_development_dependency "irb"
# benchmark left the default gems in Ruby 4.0, so spec/performance_spec.rb's
# `require "benchmark"` fails there unless it is declared.
spec.add_development_dependency "benchmark"
spec.add_development_dependency "benchmark-ips"
spec.add_development_dependency "ffi-aspell"
end
Loading