icu4x 0.6.2 → 0.8.0

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: a9647737d3f7715bf56e3bc7c7c06be56aff4ac715e984bd245fa1d4410d4542
4
- data.tar.gz: 5841b15fb21057937fcbdf98fedb4b78ff77acbb831a265ac7929106cd7ff39f
3
+ metadata.gz: 7871f9d79af05cf7edf90ca57fc7351b6cf8d027b5017606369748825265d359
4
+ data.tar.gz: e47cf84063cf0d7b8841d22c8776937cabb2fab7324a0dcb3e9129e5cec2df61
5
5
  SHA512:
6
- metadata.gz: a86b5b21224069d5309cfd87f468313cc53636c8e724fd6d22644c15a6057d109f5e447d43466cb9b2ed36d82c1fad1dc9fffaa4ae6405ff127a10ee882b4751
7
- data.tar.gz: bab512907b93d835df787cf89f3b4f98d0e8e31009d4e851f202904a2f57ec13e7d6e04e24e52b8157ce3b0f2cab570a34df7b7728e5d794b7c6cd668c708c8c
6
+ metadata.gz: 9b7d7683237505c31d148451262825f40458ab916717949f7a6e1c6f76397eb94f898eda81a00d5131efee1ef904623d2b128b38a366ef39f8804c90fda48daa
7
+ data.tar.gz: 1ec09d4d5f4a4529aa4ac6a2747d1c16f3c5b66fbc60e3b28fcb8bafd5e0c4ba43b41a4fde5cdc5cd5e14f7bc2edb8cd0793ca86fe2b4052787929baa5e469be
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.8.0] - 2026-01-10
4
+
5
+ ### Added
6
+
7
+ - `ICU4X::Locale#maximize!` and `#maximize` methods to expand locale using Likely Subtags algorithm (UTS #35)
8
+ - `ICU4X::Locale#minimize!` and `#minimize` methods to remove redundant subtags
9
+
10
+ ## [0.7.0] - 2026-01-09
11
+
12
+ ### Added
13
+
14
+ - `DateTimeFormat#format` now accepts any object responding to `#to_time` (e.g., `Date`, `DateTime`)
15
+
3
16
  ## [0.6.2] - 2026-01-02
4
17
 
5
18
  ### Fixed
@@ -46,7 +46,18 @@ pub struct Collator {
46
46
  case_first: Option<CaseFirstOption>,
47
47
  }
48
48
 
49
- // SAFETY: Ruby's GVL protects access to this type.
49
+ // SAFETY: This type is marked as Send to allow Ruby to move it between threads.
50
+ //
51
+ // Thread safety is guaranteed by Ruby's Global VM Lock (GVL):
52
+ // - All Ruby method calls are serialized by the GVL
53
+ // - Only one thread can execute Ruby code at a time
54
+ // - The underlying ICU4X types are only accessed through Ruby method calls
55
+ //
56
+ // WARNING: This safety guarantee does NOT hold if:
57
+ // - The GVL is released via `rb_thread_call_without_gvl`
58
+ // - Using threading libraries that bypass the GVL
59
+ //
60
+ // In such cases, concurrent access to this type would be unsafe.
50
61
  unsafe impl Send for Collator {}
51
62
 
52
63
  impl Collator {
@@ -25,8 +25,18 @@ pub struct DataProvider {
25
25
  pub(crate) inner: LocaleFallbackProvider<BlobDataProvider>,
26
26
  }
27
27
 
28
- // SAFETY: Ruby's GVL protects access to this type. The provider is only
29
- // accessed through Ruby method calls, which are serialized by the GVL.
28
+ // SAFETY: This type is marked as Send to allow Ruby to move it between threads.
29
+ //
30
+ // Thread safety is guaranteed by Ruby's Global VM Lock (GVL):
31
+ // - All Ruby method calls are serialized by the GVL
32
+ // - Only one thread can execute Ruby code at a time
33
+ // - The underlying ICU4X types are only accessed through Ruby method calls
34
+ //
35
+ // WARNING: This safety guarantee does NOT hold if:
36
+ // - The GVL is released via `rb_thread_call_without_gvl`
37
+ // - Using threading libraries that bypass the GVL
38
+ //
39
+ // In such cases, concurrent access to this type would be unsafe.
30
40
  unsafe impl Send for DataProvider {}
31
41
 
32
42
  impl DataProvider {
@@ -106,7 +106,18 @@ pub struct DateTimeFormat {
106
106
  calendar: Calendar,
107
107
  }
108
108
 
109
- // SAFETY: Ruby's GVL protects access to this type.
109
+ // SAFETY: This type is marked as Send to allow Ruby to move it between threads.
110
+ //
111
+ // Thread safety is guaranteed by Ruby's Global VM Lock (GVL):
112
+ // - All Ruby method calls are serialized by the GVL
113
+ // - Only one thread can execute Ruby code at a time
114
+ // - The underlying ICU4X types are only accessed through Ruby method calls
115
+ //
116
+ // WARNING: This safety guarantee does NOT hold if:
117
+ // - The GVL is released via `rb_thread_call_without_gvl`
118
+ // - Using threading libraries that bypass the GVL
119
+ //
120
+ // In such cases, concurrent access to this type would be unsafe.
110
121
  unsafe impl Send for DateTimeFormat {}
111
122
 
112
123
  impl DateTimeFormat {
@@ -264,27 +275,34 @@ impl DateTimeFormat {
264
275
  }
265
276
  }
266
277
 
267
- /// Format a Ruby Time object
278
+ /// Format a Ruby Time object or any object responding to #to_time
268
279
  ///
269
280
  /// # Arguments
270
- /// * `time` - A Ruby Time object
281
+ /// * `time` - A Ruby Time object or an object responding to #to_time (e.g., Date, DateTime)
271
282
  ///
272
283
  /// # Returns
273
284
  /// A formatted string
274
285
  fn format(&self, time: Value) -> Result<String, Error> {
275
286
  let ruby = Ruby::get().expect("Ruby runtime should be available");
276
287
 
277
- // Validate that time is a Time object
288
+ // Convert to Time if the object responds to #to_time
289
+ let time_value = if time.respond_to("to_time", false)? {
290
+ time.funcall::<_, _, Value>("to_time", ())?
291
+ } else {
292
+ time
293
+ };
294
+
295
+ // Validate that the result is a Time object
278
296
  let time_class: Value = ruby.eval("Time")?;
279
- if !time.is_kind_of(magnus::RClass::try_convert(time_class)?) {
297
+ if !time_value.is_kind_of(magnus::RClass::try_convert(time_class)?) {
280
298
  return Err(Error::new(
281
299
  ruby.exception_type_error(),
282
- "argument must be a Time object",
300
+ "argument must be a Time object or respond to #to_time",
283
301
  ));
284
302
  }
285
303
 
286
304
  // Convert Ruby Time to ICU4X DateTime, applying timezone if specified
287
- let datetime = self.convert_time_to_datetime(&ruby, time)?;
305
+ let datetime = self.convert_time_to_datetime(&ruby, time_value)?;
288
306
 
289
307
  // Format the datetime
290
308
  let formatted = self.inner.format(&datetime);
@@ -72,7 +72,18 @@ pub struct DisplayNames {
72
72
  fallback: DisplayNamesFallback,
73
73
  }
74
74
 
75
- // SAFETY: Ruby's GVL protects access to this type.
75
+ // SAFETY: This type is marked as Send to allow Ruby to move it between threads.
76
+ //
77
+ // Thread safety is guaranteed by Ruby's Global VM Lock (GVL):
78
+ // - All Ruby method calls are serialized by the GVL
79
+ // - Only one thread can execute Ruby code at a time
80
+ // - The underlying ICU4X types are only accessed through Ruby method calls
81
+ //
82
+ // WARNING: This safety guarantee does NOT hold if:
83
+ // - The GVL is released via `rb_thread_call_without_gvl`
84
+ // - Using threading libraries that bypass the GVL
85
+ //
86
+ // In such cases, concurrent access to this type would be unsafe.
76
87
  unsafe impl Send for DisplayNames {}
77
88
 
78
89
  impl DisplayNames {
@@ -43,7 +43,18 @@ pub struct ListFormat {
43
43
  list_style: ListStyle,
44
44
  }
45
45
 
46
- // SAFETY: Ruby's GVL protects access to this type.
46
+ // SAFETY: This type is marked as Send to allow Ruby to move it between threads.
47
+ //
48
+ // Thread safety is guaranteed by Ruby's Global VM Lock (GVL):
49
+ // - All Ruby method calls are serialized by the GVL
50
+ // - Only one thread can execute Ruby code at a time
51
+ // - The underlying ICU4X types are only accessed through Ruby method calls
52
+ //
53
+ // WARNING: This safety guarantee does NOT hold if:
54
+ // - The GVL is released via `rb_thread_call_without_gvl`
55
+ // - Using threading libraries that bypass the GVL
56
+ //
57
+ // In such cases, concurrent access to this type would be unsafe.
47
58
  unsafe impl Send for ListFormat {}
48
59
 
49
60
  impl ListFormat {
@@ -1,6 +1,6 @@
1
1
  use crate::helpers;
2
- use icu_locale::Locale as IcuLocale;
3
- use magnus::{Error, RHash, RModule, Ruby, function, method, prelude::*};
2
+ use icu_locale::{Locale as IcuLocale, LocaleExpander, TransformResult};
3
+ use magnus::{Error, RHash, RModule, Ruby, function, method, prelude::*, typed_data::Obj};
4
4
  use std::cell::RefCell;
5
5
 
6
6
  /// Ruby wrapper for ICU4X Locale
@@ -162,6 +162,48 @@ impl Locale {
162
162
  fn eq(&self, other: &Locale) -> bool {
163
163
  *self.inner.borrow() == *other.inner.borrow()
164
164
  }
165
+
166
+ /// Maximize the locale in place (Add Likely Subtags algorithm, UTS #35)
167
+ /// Returns self if modified, nil if unchanged
168
+ fn maximize_bang(rb_self: Obj<Self>) -> Option<Obj<Self>> {
169
+ let expander = LocaleExpander::new_common();
170
+ let mut locale = rb_self.inner.borrow_mut();
171
+ match expander.maximize(&mut locale.id) {
172
+ TransformResult::Modified => Some(rb_self),
173
+ TransformResult::Unmodified => None,
174
+ }
175
+ }
176
+
177
+ /// Maximize the locale, returning a new Locale object
178
+ fn maximize(&self) -> Self {
179
+ let expander = LocaleExpander::new_common();
180
+ let mut new_id = self.inner.borrow().id.clone();
181
+ expander.maximize(&mut new_id);
182
+ Self {
183
+ inner: RefCell::new(IcuLocale::from(new_id)),
184
+ }
185
+ }
186
+
187
+ /// Minimize the locale in place (Remove Likely Subtags algorithm, UTS #35)
188
+ /// Returns self if modified, nil if unchanged
189
+ fn minimize_bang(rb_self: Obj<Self>) -> Option<Obj<Self>> {
190
+ let expander = LocaleExpander::new_common();
191
+ let mut locale = rb_self.inner.borrow_mut();
192
+ match expander.minimize(&mut locale.id) {
193
+ TransformResult::Modified => Some(rb_self),
194
+ TransformResult::Unmodified => None,
195
+ }
196
+ }
197
+
198
+ /// Minimize the locale, returning a new Locale object
199
+ fn minimize(&self) -> Self {
200
+ let expander = LocaleExpander::new_common();
201
+ let mut new_id = self.inner.borrow().id.clone();
202
+ expander.minimize(&mut new_id);
203
+ Self {
204
+ inner: RefCell::new(IcuLocale::from(new_id)),
205
+ }
206
+ }
165
207
  }
166
208
 
167
209
  pub fn init(ruby: &Ruby, module: &RModule) -> Result<(), Error> {
@@ -174,5 +216,9 @@ pub fn init(ruby: &Ruby, module: &RModule) -> Result<(), Error> {
174
216
  class.define_method("extensions", method!(Locale::extensions, 0))?;
175
217
  class.define_method("to_s", method!(Locale::to_s, 0))?;
176
218
  class.define_method("==", method!(Locale::eq, 1))?;
219
+ class.define_method("maximize!", method!(Locale::maximize_bang, 0))?;
220
+ class.define_method("maximize", method!(Locale::maximize, 0))?;
221
+ class.define_method("minimize!", method!(Locale::minimize_bang, 0))?;
222
+ class.define_method("minimize", method!(Locale::minimize, 0))?;
177
223
  Ok(())
178
224
  }
@@ -83,7 +83,18 @@ pub struct NumberFormat {
83
83
  rounding_mode: RoundingMode,
84
84
  }
85
85
 
86
- // SAFETY: Ruby's GVL protects access to this type.
86
+ // SAFETY: This type is marked as Send to allow Ruby to move it between threads.
87
+ //
88
+ // Thread safety is guaranteed by Ruby's Global VM Lock (GVL):
89
+ // - All Ruby method calls are serialized by the GVL
90
+ // - Only one thread can execute Ruby code at a time
91
+ // - The underlying ICU4X types are only accessed through Ruby method calls
92
+ //
93
+ // WARNING: This safety guarantee does NOT hold if:
94
+ // - The GVL is released via `rb_thread_call_without_gvl`
95
+ // - Using threading libraries that bypass the GVL
96
+ //
97
+ // In such cases, concurrent access to this type would be unsafe.
87
98
  unsafe impl Send for NumberFormat {}
88
99
 
89
100
  impl NumberFormat {
@@ -17,7 +17,18 @@ pub struct PluralRules {
17
17
  rule_type: PluralRuleType,
18
18
  }
19
19
 
20
- // SAFETY: Ruby's GVL protects access to this type.
20
+ // SAFETY: This type is marked as Send to allow Ruby to move it between threads.
21
+ //
22
+ // Thread safety is guaranteed by Ruby's Global VM Lock (GVL):
23
+ // - All Ruby method calls are serialized by the GVL
24
+ // - Only one thread can execute Ruby code at a time
25
+ // - The underlying ICU4X types are only accessed through Ruby method calls
26
+ //
27
+ // WARNING: This safety guarantee does NOT hold if:
28
+ // - The GVL is released via `rb_thread_call_without_gvl`
29
+ // - Using threading libraries that bypass the GVL
30
+ //
31
+ // In such cases, concurrent access to this type would be unsafe.
21
32
  unsafe impl Send for PluralRules {}
22
33
 
23
34
  impl PluralRules {
@@ -75,7 +75,18 @@ pub struct RelativeTimeFormat {
75
75
  numeric: NumericMode,
76
76
  }
77
77
 
78
- // SAFETY: Ruby's GVL protects access to this type.
78
+ // SAFETY: This type is marked as Send to allow Ruby to move it between threads.
79
+ //
80
+ // Thread safety is guaranteed by Ruby's Global VM Lock (GVL):
81
+ // - All Ruby method calls are serialized by the GVL
82
+ // - Only one thread can execute Ruby code at a time
83
+ // - The underlying ICU4X types are only accessed through Ruby method calls
84
+ //
85
+ // WARNING: This safety guarantee does NOT hold if:
86
+ // - The GVL is released via `rb_thread_call_without_gvl`
87
+ // - Using threading libraries that bypass the GVL
88
+ //
89
+ // In such cases, concurrent access to this type would be unsafe.
79
90
  unsafe impl Send for RelativeTimeFormat {}
80
91
 
81
92
  impl RelativeTimeFormat {
@@ -38,7 +38,18 @@ pub struct Segmenter {
38
38
  granularity: Granularity,
39
39
  }
40
40
 
41
- // SAFETY: Ruby's GVL protects access to this type.
41
+ // SAFETY: This type is marked as Send to allow Ruby to move it between threads.
42
+ //
43
+ // Thread safety is guaranteed by Ruby's Global VM Lock (GVL):
44
+ // - All Ruby method calls are serialized by the GVL
45
+ // - Only one thread can execute Ruby code at a time
46
+ // - The underlying ICU4X types are only accessed through Ruby method calls
47
+ //
48
+ // WARNING: This safety guarantee does NOT hold if:
49
+ // - The GVL is released via `rb_thread_call_without_gvl`
50
+ // - Using threading libraries that bypass the GVL
51
+ //
52
+ // In such cases, concurrent access to this type would be unsafe.
42
53
  unsafe impl Send for Segmenter {}
43
54
 
44
55
  impl Segmenter {
data/lib/icu4x/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ICU4X
4
- VERSION = "0.6.2"
4
+ VERSION = "0.8.0"
5
5
  public_constant :VERSION
6
6
  end
@@ -274,6 +274,74 @@
274
274
  # # @return [Integer] hash code
275
275
  # #
276
276
  # def hash; end
277
+ #
278
+ # # Maximizes the locale in place using the Add Likely Subtags algorithm (UTS #35).
279
+ # #
280
+ # # Adds likely script and region subtags based on the language.
281
+ # # This is useful for language negotiation.
282
+ # #
283
+ # # @return [self, nil] self if the locale was modified, nil if already maximized
284
+ # #
285
+ # # @example
286
+ # # locale = ICU4X::Locale.parse("en")
287
+ # # locale.maximize! #=> locale
288
+ # # locale.to_s #=> "en-Latn-US"
289
+ # #
290
+ # # @example Already maximized
291
+ # # locale = ICU4X::Locale.parse("en-Latn-US")
292
+ # # locale.maximize! #=> nil
293
+ # #
294
+ # # @see https://unicode.org/reports/tr35/#Likely_Subtags
295
+ # #
296
+ # def maximize!; end
297
+ #
298
+ # # Returns a new locale with likely subtags added.
299
+ # #
300
+ # # Non-destructive version of {#maximize!}. The original locale is unchanged.
301
+ # #
302
+ # # @return [Locale] a new locale with likely subtags added
303
+ # #
304
+ # # @example
305
+ # # locale = ICU4X::Locale.parse("zh")
306
+ # # expanded = locale.maximize
307
+ # # locale.to_s #=> "zh" (unchanged)
308
+ # # expanded.to_s #=> "zh-Hans-CN"
309
+ # #
310
+ # def maximize; end
311
+ #
312
+ # # Minimizes the locale in place using the Remove Likely Subtags algorithm (UTS #35).
313
+ # #
314
+ # # Removes redundant script and region subtags that can be inferred.
315
+ # # This is useful for language negotiation.
316
+ # #
317
+ # # @return [self, nil] self if the locale was modified, nil if already minimal
318
+ # #
319
+ # # @example
320
+ # # locale = ICU4X::Locale.parse("ja-Jpan-JP")
321
+ # # locale.minimize! #=> locale
322
+ # # locale.to_s #=> "ja"
323
+ # #
324
+ # # @example Already minimal
325
+ # # locale = ICU4X::Locale.parse("en")
326
+ # # locale.minimize! #=> nil
327
+ # #
328
+ # # @see https://unicode.org/reports/tr35/#Likely_Subtags
329
+ # #
330
+ # def minimize!; end
331
+ #
332
+ # # Returns a new locale with redundant subtags removed.
333
+ # #
334
+ # # Non-destructive version of {#minimize!}. The original locale is unchanged.
335
+ # #
336
+ # # @return [Locale] a new locale with redundant subtags removed
337
+ # #
338
+ # # @example
339
+ # # locale = ICU4X::Locale.parse("zh-Hans-CN")
340
+ # # minimal = locale.minimize
341
+ # # locale.to_s #=> "zh-Hans-CN" (unchanged)
342
+ # # minimal.to_s #=> "zh"
343
+ # #
344
+ # def minimize; end
277
345
  # end
278
346
  #
279
347
  # # Provides locale-aware plural rules for cardinal and ordinal numbers.
@@ -441,7 +509,7 @@
441
509
  #
442
510
  # # Formats a time value according to the configured options.
443
511
  # #
444
- # # @param time [Time] the time to format
512
+ # # @param time [Time, #to_time] the time to format (or any object responding to #to_time)
445
513
  # # @return [String] the formatted date/time string
446
514
  # #
447
515
  # def format(time); end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: icu4x
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - OZAWA Sakuro
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-01-02 00:00:00.000000000 Z
11
+ date: 2026-01-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-configurable
@@ -38,7 +38,10 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0.9'
41
- description: icu4x
41
+ description: |-
42
+ ICU4X provides Ruby bindings for the ICU4X library, offering Unicode
43
+ internationalization support including locale handling, number formatting,
44
+ date/time formatting, collation, segmentation, and more.
42
45
  email:
43
46
  - 10973+sakuro@users.noreply.github.com
44
47
  executables: []
@@ -100,5 +103,5 @@ requirements: []
100
103
  rubygems_version: 3.4.19
101
104
  signing_key:
102
105
  specification_version: 4
103
- summary: icu4x
106
+ summary: Ruby bindings for ICU4X Unicode internationalization library
104
107
  test_files: []