lingua_rs 0.2.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c52e545860174c156f8e8276d25762293daa3235766fc88777e5d2b5d53f50f5
4
- data.tar.gz: 90bb85fd278795e300b768e3e5079d465f9c5b85a7c3a62f61c4e45745b5ba96
3
+ metadata.gz: bd0dba860ee235a6acfc46afb3ba851ec08303df9499f403e47624c74b9396e7
4
+ data.tar.gz: b3d9faca1f0f12fb7abee0643b94f1f494ef02e6b4f2c92846fa88e94d503904
5
5
  SHA512:
6
- metadata.gz: 82cc16c4f8b55d0345f3312675cbf6602365ea514b0f085f12cb9d4c8266601fcdf06d3195a06d74ef64a965ada7d9d79215ee44e70f6ac56e70c4f068cefdcd
7
- data.tar.gz: eee0c6da2add0958dd836223f2a5d958e393a83f3b84b240598cf600ff0dbf73c3686e556486ad7b42e44f9781ad4905bcece9a59736e988e9532ec2d4174d4c
6
+ metadata.gz: 2cae21715d81d650c71df5d55b18fb7b09eb86bcfe1356e5ace3b526a48e9ff31be39d852ee43abe342dffed711c7ea08ad3a9342702960b04a864a674df6068
7
+ data.tar.gz: 221eb0c62f4b7158d5c95b4d7c28490a2bcabc3f4cffe64914bea62c413c0d35fc8ceab1a6b6dc81a4750e75f8d7deac522bab1d0aa97b5c02cfd7d49e9eab40
data/README.md CHANGED
@@ -42,19 +42,18 @@ export PATH=/usr/lib/llvm21/bin:$PATH
42
42
  require 'lingua'
43
43
 
44
44
  lang = Lingua.detect('Bonjour le monde')
45
+ lang.french? # => true
45
46
  lang.to_s # => 'French'
46
47
  lang.to_sym # => :french
47
48
  lang.to_iso # => 'fr'
48
- lang.to_iso6391 # => 'fr'
49
49
  lang.to_iso6393 # => 'fra'
50
- lang.inspect # => '#<Lingua::Language French>'
51
50
 
52
51
  Lingua.detect('') # => nil
53
52
  ```
54
53
 
55
54
  ### Restricting languages
56
55
 
57
- Pass a `languages` option to limit detection to a subset of languages. Values can be full names, ISO 639-1 codes, or ISO 639-3 codes, and can be mixed freely.
56
+ Pass a `languages` option to limit detection to a subset of languages. Values can be full names, ISO 639-1 codes, or ISO 639-3 codes, and can be mixed freely. Restricting the candidate set is also faster, since the detector has fewer languages to compare against.
58
57
 
59
58
  ```ruby
60
59
  # By full name
@@ -140,19 +139,37 @@ detector.detect_multiple(text)
140
139
 
141
140
  ### `Lingua::Language` methods
142
141
 
143
- `Lingua::Language` objects support equality (`==`) and can be used as Hash keys.
142
+ `Lingua::Language` objects support equality (`==`) and can be used as Hash keys. You can look up a language by name, ISO 639-1 code, or ISO 639-3 code using `[]`:
143
+
144
+ ```ruby
145
+ Lingua::Language['French'] # => #<Lingua::Language French>
146
+ Lingua::Language[:fr] # => #<Lingua::Language French>
147
+ Lingua::Language['fra'] # => #<Lingua::Language French>
148
+ Lingua::Language['xxx'] # => nil
149
+ ```
144
150
 
145
151
  | Method | Return type | Example |
146
152
  |---|---|---|
147
- | `to_s` | `String` | `'French'` |
153
+ | `name` | `String` | `'French'` |
154
+ | `to_s` | `String` | `'French'` (alias for `name`) |
148
155
  | `to_sym` | `Symbol` | `:french` |
156
+ | `iso_code` | `String` | `'fr'` (alias for `to_iso6391`) |
149
157
  | `to_iso` | `String` | `'fr'` (alias for `to_iso6391`) |
150
158
  | `to_iso6391` | `String` | `'fr'` |
151
159
  | `to_iso6393` | `String` | `'fra'` |
160
+ | `french?` | `Boolean` | `true` (works with name, ISO 639-1 or ISO 639-3: `fr?`, `fra?`) |
152
161
  | `inspect` | `String` | `'#<Lingua::Language French>'` |
153
162
  | `==` | `Boolean` | Compare two languages |
154
163
  | `hash` | `Integer` | Hash value (usable as Hash key) |
155
164
 
165
+ Class methods:
166
+
167
+ | Method | Return type | Description |
168
+ |---|---|---|
169
+ | `Lingua::Language.all` | `Array<Lingua::Language>` | All supported languages |
170
+ | `Lingua::Language.names` | `Array<String>` | All language names (e.g. `'French'`) |
171
+ | `Lingua::Language.iso_codes` | `Array<String>` | All ISO 639-1 codes (e.g. `'fr'`) |
172
+
156
173
  ### `Lingua::ConfidenceResult` methods
157
174
 
158
175
  Returned by `confidence_values`.
@@ -178,6 +195,60 @@ Returned by `detect_multiple`.
178
195
  | `to_s` | `String` | `'French (0-22): Parlez-vous français? '` |
179
196
  | `inspect` | `String` | `'#<Lingua::Segment French (0-22) "Parlez-vous français? ">'` |
180
197
 
198
+ ### Error handling
199
+
200
+ `Lingua::UnknownLanguageError` (subclass of `ArgumentError`) is raised when an unrecognized language name or code is passed:
201
+
202
+ ```ruby
203
+ Lingua.detect('Hello', languages: %w[en zzzz])
204
+ # => Lingua::UnknownLanguageError: unknown language: "zzzz"
205
+
206
+ # Can also be rescued as ArgumentError
207
+ begin
208
+ Lingua.detect('Hello', languages: %w[zzzz])
209
+ rescue ArgumentError => e
210
+ puts e.message
211
+ end
212
+ ```
213
+
214
+ ## Optimization: selecting languages
215
+
216
+ By default, all 75 languages are compiled into the native extension (~278 MB). If you only need a subset, set the `LINGUA_LANGUAGES` environment variable before installing to reduce binary size and improve detection speed:
217
+
218
+ ```bash
219
+ LINGUA_LANGUAGES=core bundle install
220
+ ```
221
+
222
+ This compiles only the selected language models (~29 MB for the `core` bundle). You can use individual language names or predefined bundles, and you can mix both in the same build.
223
+
224
+ This also works with `gem install`, for example:
225
+
226
+ ```bash
227
+ LINGUA_LANGUAGES=french,english,german gem install lingua_rs
228
+ ```
229
+
230
+ Available bundles:
231
+
232
+ | Bundle | Languages |
233
+ | --- | --- |
234
+ | `core` | `english`, `french`, `german`, `spanish`, `italian`, `portuguese` |
235
+ | `europe_common` | `core` + `dutch`, `polish`, `russian`, `turkish` |
236
+ | `americas` | `english`, `spanish`, `portuguese`, `french` |
237
+ | `mena` | `arabic`, `turkish`, `persian`, `hebrew` |
238
+ | `south_asia` | `hindi`, `urdu`, `bengali`, `tamil`, `telugu`, `punjabi`, `marathi`, `gujarati` |
239
+ | `east_asia` | `chinese`, `japanese`, `korean`, `vietnamese`, `thai` |
240
+ | `africa_common` | `arabic`, `english`, `french`, `swahili`, `somali`, `yoruba`, `zulu` |
241
+
242
+ Examples:
243
+
244
+ ```bash
245
+ LINGUA_LANGUAGES=core bundle install
246
+ LINGUA_LANGUAGES=europe_common,polish bundle install
247
+ LINGUA_LANGUAGES=east_asia,english bundle install
248
+ ```
249
+
250
+ Language and bundle names must match the Cargo features defined by this gem (lowercase, e.g. `french`, `english`, `german`, `core`, `europe_common`).
251
+
181
252
  ## Development
182
253
 
183
254
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake compile` to build the native extension and `rake test` to run the tests.
@@ -11,4 +11,187 @@ crate-type = ["cdylib"]
11
11
 
12
12
  [dependencies]
13
13
  magnus = { version = "0.8.2" }
14
- lingua = "1.8.0"
14
+ lingua = { version = "1.8.0", default-features = false }
15
+
16
+ [features]
17
+ default = ["full"]
18
+ full = [
19
+ "europe_common",
20
+ "americas",
21
+ "mena",
22
+ "south_asia",
23
+ "east_asia",
24
+ "africa_common",
25
+ "afrikaans",
26
+ "albanian",
27
+ "armenian",
28
+ "azerbaijani",
29
+ "basque",
30
+ "belarusian",
31
+ "bokmal",
32
+ "bosnian",
33
+ "bulgarian",
34
+ "catalan",
35
+ "croatian",
36
+ "czech",
37
+ "danish",
38
+ "esperanto",
39
+ "estonian",
40
+ "finnish",
41
+ "ganda",
42
+ "georgian",
43
+ "greek",
44
+ "hungarian",
45
+ "icelandic",
46
+ "indonesian",
47
+ "irish",
48
+ "kazakh",
49
+ "latin",
50
+ "latvian",
51
+ "lithuanian",
52
+ "macedonian",
53
+ "malay",
54
+ "maori",
55
+ "mongolian",
56
+ "nynorsk",
57
+ "romanian",
58
+ "serbian",
59
+ "shona",
60
+ "slovak",
61
+ "slovene",
62
+ "sotho",
63
+ "swedish",
64
+ "tagalog",
65
+ "tsonga",
66
+ "tswana",
67
+ "welsh",
68
+ "xhosa",
69
+ ]
70
+ core = [
71
+ "english",
72
+ "french",
73
+ "german",
74
+ "spanish",
75
+ "italian",
76
+ "portuguese",
77
+ ]
78
+ europe_common = [
79
+ "core",
80
+ "dutch",
81
+ "polish",
82
+ "russian",
83
+ "turkish",
84
+ ]
85
+ americas = [
86
+ "english",
87
+ "spanish",
88
+ "portuguese",
89
+ "french",
90
+ ]
91
+ mena = [
92
+ "arabic",
93
+ "turkish",
94
+ "persian",
95
+ "hebrew",
96
+ ]
97
+ south_asia = [
98
+ "hindi",
99
+ "urdu",
100
+ "bengali",
101
+ "tamil",
102
+ "telugu",
103
+ "punjabi",
104
+ "marathi",
105
+ "gujarati",
106
+ ]
107
+ east_asia = [
108
+ "chinese",
109
+ "japanese",
110
+ "korean",
111
+ "vietnamese",
112
+ "thai",
113
+ ]
114
+ africa_common = [
115
+ "arabic",
116
+ "english",
117
+ "french",
118
+ "swahili",
119
+ "somali",
120
+ "yoruba",
121
+ "zulu",
122
+ ]
123
+ afrikaans = ["lingua/afrikaans"]
124
+ albanian = ["lingua/albanian"]
125
+ arabic = ["lingua/arabic"]
126
+ armenian = ["lingua/armenian"]
127
+ azerbaijani = ["lingua/azerbaijani"]
128
+ basque = ["lingua/basque"]
129
+ belarusian = ["lingua/belarusian"]
130
+ bengali = ["lingua/bengali"]
131
+ bokmal = ["lingua/bokmal"]
132
+ bosnian = ["lingua/bosnian"]
133
+ bulgarian = ["lingua/bulgarian"]
134
+ catalan = ["lingua/catalan"]
135
+ chinese = ["lingua/chinese"]
136
+ croatian = ["lingua/croatian"]
137
+ czech = ["lingua/czech"]
138
+ danish = ["lingua/danish"]
139
+ dutch = ["lingua/dutch"]
140
+ english = ["lingua/english"]
141
+ esperanto = ["lingua/esperanto"]
142
+ estonian = ["lingua/estonian"]
143
+ finnish = ["lingua/finnish"]
144
+ french = ["lingua/french"]
145
+ ganda = ["lingua/ganda"]
146
+ georgian = ["lingua/georgian"]
147
+ german = ["lingua/german"]
148
+ greek = ["lingua/greek"]
149
+ gujarati = ["lingua/gujarati"]
150
+ hebrew = ["lingua/hebrew"]
151
+ hindi = ["lingua/hindi"]
152
+ hungarian = ["lingua/hungarian"]
153
+ icelandic = ["lingua/icelandic"]
154
+ indonesian = ["lingua/indonesian"]
155
+ irish = ["lingua/irish"]
156
+ italian = ["lingua/italian"]
157
+ japanese = ["lingua/japanese"]
158
+ kazakh = ["lingua/kazakh"]
159
+ korean = ["lingua/korean"]
160
+ latin = ["lingua/latin"]
161
+ latvian = ["lingua/latvian"]
162
+ lithuanian = ["lingua/lithuanian"]
163
+ macedonian = ["lingua/macedonian"]
164
+ malay = ["lingua/malay"]
165
+ maori = ["lingua/maori"]
166
+ marathi = ["lingua/marathi"]
167
+ mongolian = ["lingua/mongolian"]
168
+ nynorsk = ["lingua/nynorsk"]
169
+ persian = ["lingua/persian"]
170
+ polish = ["lingua/polish"]
171
+ portuguese = ["lingua/portuguese"]
172
+ punjabi = ["lingua/punjabi"]
173
+ romanian = ["lingua/romanian"]
174
+ russian = ["lingua/russian"]
175
+ serbian = ["lingua/serbian"]
176
+ shona = ["lingua/shona"]
177
+ slovak = ["lingua/slovak"]
178
+ slovene = ["lingua/slovene"]
179
+ somali = ["lingua/somali"]
180
+ sotho = ["lingua/sotho"]
181
+ spanish = ["lingua/spanish"]
182
+ swahili = ["lingua/swahili"]
183
+ swedish = ["lingua/swedish"]
184
+ tagalog = ["lingua/tagalog"]
185
+ tamil = ["lingua/tamil"]
186
+ telugu = ["lingua/telugu"]
187
+ thai = ["lingua/thai"]
188
+ tsonga = ["lingua/tsonga"]
189
+ tswana = ["lingua/tswana"]
190
+ turkish = ["lingua/turkish"]
191
+ ukrainian = ["lingua/ukrainian"]
192
+ urdu = ["lingua/urdu"]
193
+ vietnamese = ["lingua/vietnamese"]
194
+ welsh = ["lingua/welsh"]
195
+ xhosa = ["lingua/xhosa"]
196
+ yoruba = ["lingua/yoruba"]
197
+ zulu = ["lingua/zulu"]
@@ -3,4 +3,13 @@
3
3
  require 'mkmf'
4
4
  require 'rb_sys/mkmf'
5
5
 
6
- create_rust_makefile('lingua/lingua')
6
+ # Allow users to select specific languages to reduce binary size.
7
+ # Example: LINGUA_LANGUAGES=french,english,german bundle install
8
+ languages = ENV.fetch('LINGUA_LANGUAGES', '').split(',').map { |lang| lang.strip.downcase }
9
+
10
+ create_rust_makefile('lingua/lingua') do |r|
11
+ unless languages.empty?
12
+ r.extra_cargo_args << '--no-default-features'
13
+ r.features = languages
14
+ end
15
+ end
@@ -1,7 +1,18 @@
1
1
  use lingua::Language;
2
+ use magnus::{Error, RModule, Ruby, method, prelude::*};
2
3
 
3
4
  use crate::language::WrappedLanguage;
4
5
 
6
+ pub fn define(ruby: &Ruby, module: &RModule) -> Result<(), Error> {
7
+ let class = module.define_class("ConfidenceResult", ruby.class_object())?;
8
+ class.undef_default_alloc_func();
9
+ class.define_method("language", method!(ConfidenceResult::language, 0))?;
10
+ class.define_method("confidence", method!(ConfidenceResult::confidence, 0))?;
11
+ class.define_method("to_s", method!(ConfidenceResult::to_s, 0))?;
12
+ class.define_method("inspect", method!(ConfidenceResult::inspect, 0))?;
13
+ Ok(())
14
+ }
15
+
5
16
  #[magnus::wrap(class = "Lingua::ConfidenceResult")]
6
17
  pub struct ConfidenceResult {
7
18
  pub language: Language,
@@ -1,11 +1,21 @@
1
1
  use lingua::{LanguageDetector, LanguageDetectorBuilder};
2
- use magnus::{Error, RArray, RHash, Ruby};
2
+ use magnus::{Error, RArray, RHash, RModule, Ruby, function, method, prelude::*};
3
3
 
4
4
  use crate::confidence_result::ConfidenceResult;
5
5
  use crate::segment::Segment;
6
- use crate::helpers::{fetch_option, parse_language, value_to_string};
6
+ use crate::helpers::{fetch_option, parse_language, unknown_language_error, value_to_string};
7
7
  use crate::language::WrappedLanguage;
8
8
 
9
+ pub fn define(ruby: &Ruby, module: &RModule) -> Result<(), Error> {
10
+ let class = module.define_class("Detector", ruby.class_object())?;
11
+ class.define_singleton_method("new", function!(RubyDetector::new, -1))?;
12
+ class.define_method("detect", method!(RubyDetector::detect, 1))?;
13
+ class.define_method("confidence", method!(RubyDetector::confidence, 2))?;
14
+ class.define_method("confidence_values", method!(RubyDetector::confidence_values, 1))?;
15
+ class.define_method("detect_multiple", method!(RubyDetector::detect_multiple, 1))?;
16
+ Ok(())
17
+ }
18
+
9
19
  pub fn compute_confidence(
10
20
  detector: &LanguageDetector,
11
21
  subject: String,
@@ -15,7 +25,7 @@ pub fn compute_confidence(
15
25
  let language_str = value_to_string(language)?;
16
26
  let lang = parse_language(&language_str).ok_or_else(|| {
17
27
  Error::new(
18
- ruby.exception_arg_error(),
28
+ unknown_language_error(&ruby),
19
29
  format!("unknown language: \"{language_str}\""),
20
30
  )
21
31
  })?;
@@ -106,7 +116,7 @@ pub fn build_detector_from_options(
106
116
  for l in &raw_languages {
107
117
  let lang = parse_language(l).ok_or_else(|| {
108
118
  Error::new(
109
- ruby.exception_arg_error(),
119
+ unknown_language_error(ruby),
110
120
  format!("unknown language: \"{l}\""),
111
121
  )
112
122
  })?;
@@ -1,7 +1,23 @@
1
1
  use std::str::FromStr;
2
+ use std::cell::Cell;
2
3
 
3
4
  use lingua::{IsoCode639_1, IsoCode639_3, Language};
4
- use magnus::{Error, Ruby, Symbol, prelude::*};
5
+ use magnus::{ExceptionClass, Error, RModule, Ruby, Symbol, prelude::*};
6
+
7
+ thread_local! {
8
+ static UNKNOWN_LANGUAGE_ERROR: Cell<Option<ExceptionClass>> = const { Cell::new(None) };
9
+ }
10
+
11
+ pub fn define_errors(module: &RModule) -> Result<(), Error> {
12
+ let ruby = Ruby::get().unwrap();
13
+ let class = module.define_error("UnknownLanguageError", ruby.exception_arg_error())?;
14
+ UNKNOWN_LANGUAGE_ERROR.set(Some(class));
15
+ Ok(())
16
+ }
17
+
18
+ pub fn unknown_language_error(ruby: &Ruby) -> ExceptionClass {
19
+ UNKNOWN_LANGUAGE_ERROR.get().unwrap_or_else(|| ruby.exception_arg_error())
20
+ }
5
21
 
6
22
  pub fn parse_language(input: &str) -> Option<Language> {
7
23
  Language::from_str(input)
@@ -1,11 +1,72 @@
1
1
  use lingua::Language;
2
- use magnus::{Ruby, Symbol};
2
+ use magnus::{Error, RArray, RModule, Ruby, Symbol, function, method, prelude::*};
3
+
4
+ use crate::helpers::value_to_string;
5
+
6
+ pub fn define(ruby: &Ruby, module: &RModule) -> Result<(), Error> {
7
+ let class = module.define_class("Language", ruby.class_object())?;
8
+ class.undef_default_alloc_func();
9
+ class.define_method("name", method!(WrappedLanguage::name, 0))?;
10
+ class.define_method("to_s", method!(WrappedLanguage::name, 0))?;
11
+ class.define_method("to_iso6391", method!(WrappedLanguage::to_iso6391, 0))?;
12
+ class.define_method("to_iso", method!(WrappedLanguage::to_iso6391, 0))?;
13
+ class.define_method("iso_code", method!(WrappedLanguage::to_iso6391, 0))?;
14
+ class.define_method("to_iso6393", method!(WrappedLanguage::to_iso6393, 0))?;
15
+ class.define_method("to_sym", method!(WrappedLanguage::to_sym, 0))?;
16
+ class.define_method("inspect", method!(WrappedLanguage::inspect, 0))?;
17
+ class.define_method("==", method!(WrappedLanguage::eq, 1))?;
18
+ class.define_method("eql?", method!(WrappedLanguage::eq, 1))?;
19
+ class.define_method("hash", method!(WrappedLanguage::hash, 0))?;
20
+ class.define_singleton_method("[]", function!(WrappedLanguage::lookup, 1))?;
21
+ class.define_singleton_method("all", function!(WrappedLanguage::all, 0))?;
22
+ class.define_singleton_method("names", function!(WrappedLanguage::names, 0))?;
23
+ class.define_singleton_method("iso_codes", function!(WrappedLanguage::iso_codes, 0))?;
24
+ Ok(())
25
+ }
3
26
 
4
27
  #[magnus::wrap(class = "Lingua::Language")]
5
28
  pub struct WrappedLanguage(pub Language);
6
29
 
7
30
  impl WrappedLanguage {
8
- pub fn to_s(&self) -> String {
31
+ pub fn lookup(value: magnus::Value) -> Result<Option<WrappedLanguage>, Error> {
32
+ let input = value_to_string(value)?;
33
+ Ok(crate::helpers::parse_language(&input).map(WrappedLanguage))
34
+ }
35
+
36
+ pub fn all() -> Result<RArray, Error> {
37
+ let ruby = Ruby::get().unwrap();
38
+ let mut langs: Vec<Language> = Language::all().into_iter().collect();
39
+ langs.sort_by(|a, b| a.to_string().cmp(&b.to_string()));
40
+ let array = ruby.ary_new_capa(langs.len());
41
+ for lang in langs {
42
+ array.push(WrappedLanguage(lang))?;
43
+ }
44
+ Ok(array)
45
+ }
46
+
47
+ pub fn names() -> Result<RArray, Error> {
48
+ let ruby = Ruby::get().unwrap();
49
+ let mut langs: Vec<Language> = Language::all().into_iter().collect();
50
+ langs.sort_by(|a, b| a.to_string().cmp(&b.to_string()));
51
+ let array = ruby.ary_new_capa(langs.len());
52
+ for lang in langs {
53
+ array.push(lang.to_string())?;
54
+ }
55
+ Ok(array)
56
+ }
57
+
58
+ pub fn iso_codes() -> Result<RArray, Error> {
59
+ let ruby = Ruby::get().unwrap();
60
+ let mut langs: Vec<Language> = Language::all().into_iter().collect();
61
+ langs.sort_by(|a, b| a.to_string().cmp(&b.to_string()));
62
+ let array = ruby.ary_new_capa(langs.len());
63
+ for lang in langs {
64
+ array.push(lang.iso_code_639_1().to_string())?;
65
+ }
66
+ Ok(array)
67
+ }
68
+
69
+ pub fn name(&self) -> String {
9
70
  self.0.to_string()
10
71
  }
11
72
 
@@ -1,14 +1,12 @@
1
1
  mod confidence_result;
2
- mod segment;
3
2
  mod detector;
4
3
  mod helpers;
5
4
  mod language;
5
+ mod segment;
6
6
 
7
- use magnus::{Error, RArray, RHash, Ruby, function, method, prelude::*};
7
+ use magnus::{Error, RArray, RHash, Ruby, function, prelude::*};
8
8
 
9
- use confidence_result::ConfidenceResult;
10
- use segment::Segment;
11
- use detector::{RubyDetector, build_detector_from_options, compute_confidence, compute_confidence_values, compute_detect_multiple};
9
+ use detector::{build_detector_from_options, compute_confidence, compute_confidence_values, compute_detect_multiple};
12
10
  use language::WrappedLanguage;
13
11
 
14
12
  fn detect(ruby: &Ruby, arguments: RArray) -> Result<Option<WrappedLanguage>, Error> {
@@ -47,47 +45,12 @@ fn detect_multiple(ruby: &Ruby, arguments: RArray) -> Result<RArray, Error> {
47
45
  fn init(ruby: &Ruby) -> Result<(), Error> {
48
46
  let module = ruby.define_module("Lingua")?;
49
47
 
50
- // Lingua::Language
51
- let language_class = module.define_class("Language", ruby.class_object())?;
52
- language_class.undef_default_alloc_func();
53
- language_class.define_method("to_s", method!(WrappedLanguage::to_s, 0))?;
54
- language_class.define_method("to_iso6391", method!(WrappedLanguage::to_iso6391, 0))?;
55
- language_class.define_method("to_iso", method!(WrappedLanguage::to_iso6391, 0))?;
56
- language_class.define_method("to_iso6393", method!(WrappedLanguage::to_iso6393, 0))?;
57
- language_class.define_method("to_sym", method!(WrappedLanguage::to_sym, 0))?;
58
- language_class.define_method("inspect", method!(WrappedLanguage::inspect, 0))?;
59
- language_class.define_method("==", method!(WrappedLanguage::eq, 1))?;
60
- language_class.define_method("eql?", method!(WrappedLanguage::eq, 1))?;
61
- language_class.define_method("hash", method!(WrappedLanguage::hash, 0))?;
62
-
63
- // Lingua::ConfidenceResult
64
- let confidence_class = module.define_class("ConfidenceResult", ruby.class_object())?;
65
- confidence_class.undef_default_alloc_func();
66
- confidence_class.define_method("language", method!(ConfidenceResult::language, 0))?;
67
- confidence_class.define_method("confidence", method!(ConfidenceResult::confidence, 0))?;
68
- confidence_class.define_method("to_s", method!(ConfidenceResult::to_s, 0))?;
69
- confidence_class.define_method("inspect", method!(ConfidenceResult::inspect, 0))?;
70
-
71
- // Lingua::Segment
72
- let segment_class = module.define_class("Segment", ruby.class_object())?;
73
- segment_class.undef_default_alloc_func();
74
- segment_class.define_method("language", method!(Segment::language, 0))?;
75
- segment_class.define_method("start_index", method!(Segment::start_index, 0))?;
76
- segment_class.define_method("end_index", method!(Segment::end_index, 0))?;
77
- segment_class.define_method("word_count", method!(Segment::word_count, 0))?;
78
- segment_class.define_method("text", method!(Segment::text, 0))?;
79
- segment_class.define_method("to_s", method!(Segment::to_s, 0))?;
80
- segment_class.define_method("inspect", method!(Segment::inspect, 0))?;
81
-
82
- // Lingua::Detector
83
- let detector_class = module.define_class("Detector", ruby.class_object())?;
84
- detector_class.define_singleton_method("new", function!(RubyDetector::new, -1))?;
85
- detector_class.define_method("detect", method!(RubyDetector::detect, 1))?;
86
- detector_class.define_method("confidence", method!(RubyDetector::confidence, 2))?;
87
- detector_class.define_method("confidence_values", method!(RubyDetector::confidence_values, 1))?;
88
- detector_class.define_method("detect_multiple", method!(RubyDetector::detect_multiple, 1))?;
48
+ helpers::define_errors(&module)?;
49
+ language::define(ruby, &module)?;
50
+ confidence_result::define(ruby, &module)?;
51
+ segment::define(ruby, &module)?;
52
+ detector::define(ruby, &module)?;
89
53
 
90
- // Functional API (module methods)
91
54
  module.define_singleton_method("detect", function!(detect, -2))?;
92
55
  module.define_singleton_method("confidence", function!(confidence, 2))?;
93
56
  module.define_singleton_method("confidence_values", function!(confidence_values, -2))?;
@@ -1,7 +1,21 @@
1
1
  use lingua::Language;
2
+ use magnus::{Error, RModule, Ruby, method, prelude::*};
2
3
 
3
4
  use crate::language::WrappedLanguage;
4
5
 
6
+ pub fn define(ruby: &Ruby, module: &RModule) -> Result<(), Error> {
7
+ let class = module.define_class("Segment", ruby.class_object())?;
8
+ class.undef_default_alloc_func();
9
+ class.define_method("language", method!(Segment::language, 0))?;
10
+ class.define_method("start_index", method!(Segment::start_index, 0))?;
11
+ class.define_method("end_index", method!(Segment::end_index, 0))?;
12
+ class.define_method("word_count", method!(Segment::word_count, 0))?;
13
+ class.define_method("text", method!(Segment::text, 0))?;
14
+ class.define_method("to_s", method!(Segment::to_s, 0))?;
15
+ class.define_method("inspect", method!(Segment::inspect, 0))?;
16
+ Ok(())
17
+ }
18
+
5
19
  #[magnus::wrap(class = "Lingua::Segment")]
6
20
  pub struct Segment {
7
21
  pub language: Language,
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lingua
4
+ # Represents a language returned by Lingua detection and lookup APIs.
5
+ class Language
6
+ private
7
+
8
+ def respond_to_missing?(method_name, include_private = false)
9
+ method_name.end_with?('?') || super
10
+ end
11
+
12
+ def method_missing(method_name, *args)
13
+ if method_name.end_with?('?') && args.empty?
14
+ match = Lingua::Language[method_name.name.delete_suffix('?')]
15
+ !match.nil? && self == match
16
+ else
17
+ super
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lingua
4
- VERSION = '0.2.0'
4
+ VERSION = '0.4.1'
5
5
  end
data/lib/lingua.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative 'lingua/version'
4
4
  require_relative 'lingua/lingua'
5
+ require_relative 'lingua/language'
5
6
 
6
7
  module Lingua
7
8
  class Error < StandardError; end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lingua_rs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sébastien Vrillaud
@@ -43,11 +43,9 @@ email:
43
43
  - kochka@gmail.com
44
44
  executables: []
45
45
  extensions:
46
- - ext/lingua/Cargo.toml
46
+ - ext/lingua/extconf.rb
47
47
  extra_rdoc_files: []
48
48
  files:
49
- - Cargo.lock
50
- - Cargo.toml
51
49
  - LICENSE.txt
52
50
  - README.md
53
51
  - Rakefile
@@ -61,6 +59,7 @@ files:
61
59
  - ext/lingua/src/lib.rs
62
60
  - ext/lingua/src/segment.rs
63
61
  - lib/lingua.rb
62
+ - lib/lingua/language.rb
64
63
  - lib/lingua/version.rb
65
64
  - sig/lingua.rbs
66
65
  homepage: https://github.com/kochka/lingua_rs