use std::path::Path;
use magnus::prelude::*;
use magnus::{Error, Ruby, function, method};
use lindera::dictionary::{
Dictionary, DictionaryBuilder, Metadata, UserDictionary,
load_dictionary as lindera_load_dictionary,
load_user_dictionary as lindera_load_user_dictionary,
};
use crate::error::to_magnus_error;
use crate::metadata::RbMetadata;
#[magnus::wrap(class = "Lindera::Dictionary", free_immediately, size)]
#[derive(Clone)]
pub struct RbDictionary {
pub inner: Dictionary,
}
impl RbDictionary {
fn metadata_name(&self) -> String {
self.inner.metadata.name.clone()
}
fn metadata_encoding(&self) -> String {
self.inner.metadata.encoding.clone()
}
fn metadata(&self) -> RbMetadata {
RbMetadata::from(self.inner.metadata.clone())
}
fn to_s(&self) -> String {
"Dictionary".to_string()
}
fn inspect(&self) -> String {
format!(
"#<Lindera::Dictionary: name='{}'>",
self.inner.metadata.name
)
}
}
#[magnus::wrap(class = "Lindera::UserDictionary", free_immediately, size)]
#[derive(Clone)]
pub struct RbUserDictionary {
pub inner: UserDictionary,
}
impl RbUserDictionary {
fn to_s(&self) -> String {
"UserDictionary".to_string()
}
fn inspect(&self) -> String {
"UserDictionary()".to_string()
}
}
fn load_dictionary(uri: String) -> Result<RbDictionary, Error> {
let ruby = Ruby::get().expect("Ruby runtime not initialized");
lindera_load_dictionary(&uri)
.map_err(|e| {
to_magnus_error(
&ruby,
format!("Failed to load dictionary from '{uri}': {e}"),
)
})
.map(|d| RbDictionary { inner: d })
}
fn load_user_dictionary(uri: String, metadata: &RbMetadata) -> Result<RbUserDictionary, Error> {
let ruby = Ruby::get().expect("Ruby runtime not initialized");
let meta: Metadata = metadata.clone().into();
lindera_load_user_dictionary(&uri, &meta)
.map_err(|e| {
to_magnus_error(
&ruby,
format!("Failed to load user dictionary from '{uri}': {e}"),
)
})
.map(|d| RbUserDictionary { inner: d })
}
fn build_dictionary(
input_dir: String,
output_dir: String,
metadata: &RbMetadata,
) -> Result<(), Error> {
let ruby = Ruby::get().expect("Ruby runtime not initialized");
let input_path = Path::new(&input_dir);
let output_path = Path::new(&output_dir);
if !input_path.exists() {
return Err(Error::new(
ruby.exception_arg_error(),
format!("Input directory does not exist: {input_dir}"),
));
}
let builder = DictionaryBuilder::new(metadata.clone().into());
builder
.build_dictionary(input_path, output_path)
.map_err(|e| to_magnus_error(&ruby, format!("Failed to build dictionary: {e}")))?;
Ok(())
}
fn build_user_dictionary(
_kind: String,
input_file: String,
output_dir: String,
metadata: Option<&RbMetadata>,
) -> Result<(), Error> {
let ruby = Ruby::get().expect("Ruby runtime not initialized");
let input_path = Path::new(&input_file);
let output_path = Path::new(&output_dir);
if !input_path.exists() {
return Err(Error::new(
ruby.exception_arg_error(),
format!("Input file does not exist: {input_file}"),
));
}
let meta = match metadata {
Some(m) => m.clone().into(),
None => Metadata::default(),
};
let builder = DictionaryBuilder::new(meta);
builder
.build_user_dictionary(input_path, output_path)
.map_err(|e| to_magnus_error(&ruby, format!("Failed to build user dictionary: {e}")))?;
Ok(())
}
pub fn define(ruby: &Ruby, module: &magnus::RModule) -> Result<(), Error> {
let dict_class = module.define_class("Dictionary", ruby.class_object())?;
dict_class.define_method("metadata_name", method!(RbDictionary::metadata_name, 0))?;
dict_class.define_method(
"metadata_encoding",
method!(RbDictionary::metadata_encoding, 0),
)?;
dict_class.define_method("metadata", method!(RbDictionary::metadata, 0))?;
dict_class.define_method("to_s", method!(RbDictionary::to_s, 0))?;
dict_class.define_method("inspect", method!(RbDictionary::inspect, 0))?;
let user_dict_class = module.define_class("UserDictionary", ruby.class_object())?;
user_dict_class.define_method("to_s", method!(RbUserDictionary::to_s, 0))?;
user_dict_class.define_method("inspect", method!(RbUserDictionary::inspect, 0))?;
module.define_module_function("load_dictionary", function!(load_dictionary, 1))?;
module.define_module_function("load_user_dictionary", function!(load_user_dictionary, 2))?;
module.define_module_function("build_dictionary", function!(build_dictionary, 3))?;
module.define_module_function("build_user_dictionary", function!(build_user_dictionary, 4))?;
Ok(())
}