disarm 0.16.0-aarch64-linux → 0.17.2-aarch64-linux

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: 8ecc331ffb977947b213f31133c21afa3aede8d64f44a43a5e624eeb122013df
4
- data.tar.gz: e09891674097fa1eb7f61318e3df6c7e23740a132e313f309012ff68a2951bfe
3
+ metadata.gz: e6b272d5f6d1d04facd6e0799badd0e45611437f933ea0c1c5c3ab15f57a6b9c
4
+ data.tar.gz: c55d1928a81a21870b7152cafcbf364ffbf9f80872a100b26cb3dfc3f3a11d45
5
5
  SHA512:
6
- metadata.gz: 1784010e8ff92e9493d600eabb0bd856d56405310dd3d12b53fdc1badeddbb7c668efcf608812360f2332772c51735cb7d44dff5bf4d1287dc5ec74497ac1bd3
7
- data.tar.gz: 0dfc2d60de872b386ac671594a8bea2bc0c4cf87b731c15343dc488d494c4d9e8a7bc4728b7249a44877b2d82ec953ea3c3135299f8ef973f458a1302f40b7ba
6
+ metadata.gz: b785345089c2bcbfb9b83ced9b02108b04dc7911b65e535bb51e73facc133bb252fc69ba602e7cc9356bf5c38e41c07730644e77c4d0d637781ba25a2bc1f08e
7
+ data.tar.gz: 67c55f33eff752f93ce65161e77d87a4cf40b3a6df82d3e64ff28e390d6b2b32d3a5816f0454ce54f892231ce980e0a7e13becb3f31f66300e9da1f2a5a15367
data/README.md CHANGED
@@ -19,10 +19,10 @@ gem "disarm"
19
19
  gem install disarm
20
20
  ```
21
21
 
22
- Requires Ruby >= 3.1. Precompiled platform gems ship for Ruby 3.1 through 4.0
22
+ Requires Ruby >= 3.3. Precompiled platform gems ship for Ruby 3.3 through 4.0
23
23
  (Linux x86_64/aarch64, macOS x86_64/arm64, Windows). On a supported Ruby with no
24
24
  matching platform gem, the source gem installs and compiles locally, which needs a
25
- Rust toolchain. Below 3.1 the gem does not install at all.
25
+ Rust toolchain. Below 3.3 the gem does not install at all.
26
26
 
27
27
  ## Usage
28
28
 
Binary file
Binary file
Binary file
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Disarm
4
4
  # Kept in lockstep with the Rust crate / Python package version.
5
- VERSION = "0.16.0"
5
+ VERSION = "0.17.2"
6
6
  end
data/lib/disarm.rb CHANGED
@@ -24,6 +24,13 @@ end
24
24
  # keyword arguments with the core's defaults, symbol tokens (:latin, :default, …),
25
25
  # a single transliterate(text, scheme:) entrypoint, and a Disarm::Error hierarchy.
26
26
  # Each method is still a thin wrapper over the pure-Rust `disarm` core.
27
+ #
28
+ # Text arguments are read by the encoding the String declares. UTF-8 and US-ASCII are
29
+ # read as they are, and ASCII-8BIT (BINARY) is read as UTF-8, the way the C ABI reads
30
+ # its bytes; any other encoding (ISO-8859-1, Windows-1251, UTF-16LE, ...) is transcoded
31
+ # to UTF-8 first. A malformed or unmappable sequence becomes one U+FFFD, and so does a
32
+ # lone surrogate, the contract every binding shares (#469). An encoding Ruby cannot
33
+ # convert from at all raises Disarm::InvalidArgument.
27
34
  module Disarm
28
35
  # Base class for every error disarm raises, so consumers can `rescue
29
36
  # Disarm::Error`. The native shim raises Ruby's built-in ArgumentError /
@@ -38,7 +45,8 @@ module Disarm
38
45
  # Transliterate Unicode text to ASCII. `scheme:` selects the standard:
39
46
  # :default (the general-purpose scheme), :strict_iso9, or :gost7034. `lang:`
40
47
  # applies a language profile on top of the scheme (e.g. "uk" → Київ → "Kyiv",
41
- # "de" → ü → "ue"); nil means no profile. Both accept a String or Symbol.
48
+ # "de" → ü → "ue"); nil means no profile. Both accept a String or Symbol. Raises
49
+ # Disarm::InvalidArgument on an unknown lang, as every binding does.
42
50
  def transliterate(text, scheme: :default, lang: nil)
43
51
  scheme = scheme.to_s
44
52
  lang = lang&.to_s
@@ -53,7 +61,8 @@ module Disarm
53
61
  end
54
62
  end
55
63
 
56
- # Fold cross-script confusables toward `target:` (:latin or :cyrillic).
64
+ # Fold cross-script confusables toward `target:` (:latin, :cyrillic, :arabic or
65
+ # :hebrew).
57
66
  #
58
67
  # `digit_policy:` selects how non-Latin DIGITS fold (#561).
59
68
  #
@@ -61,9 +70,9 @@ module Disarm
61
70
  # right for prose, where a Devanagari zero really is a zero.
62
71
  #
63
72
  # `:tr39` uses upstream's targets, which send most of them to a Latin letter
64
- # (`०` → `o`; three of the 45 rows fold to `.` or to the two characters `rn`
73
+ # (`०` → `o`; three of the 47 rows fold to `.` or to the two characters `rn`
65
74
  # instead). That is what an identifier *skeleton* wants, since its only job is to
66
- # make two confusable identifiers collide. The two differ on 45 rows and agree
75
+ # make two confusable identifiers collide. The two differ on 47 rows and agree
67
76
  # everywhere else. Scoped to `target: :latin` — the override rows are generated from
68
77
  # the Latin table and carry TR39's Latin-script targets, so with `target: :cyrillic`
69
78
  # it is a no-op.
@@ -75,15 +84,16 @@ module Disarm
75
84
  translate_errors { _normalize_confusables(text, target.to_s, digit_policy.to_s) }
76
85
  end
77
86
 
78
- # Whether `text` contains a character confusable with `target:` (:latin or
79
- # :cyrillic).
87
+ # Whether `text` contains a character confusable with `target:` (:latin,
88
+ # :cyrillic, :arabic or :hebrew).
80
89
  def confusable?(text, target: :latin)
81
90
  translate_errors { _confusable?(text, target.to_s) }
82
91
  end
83
92
 
84
93
  # Generate a URL-safe slug. Mirrors the core's `SlugConfig` defaults; every
85
94
  # option past `text` is keyword-only. (`regex_pattern`/`replacements` are not
86
- # surfaced yet — see ext/disarm/src/lib.rs.)
95
+ # surfaced yet — see ext/disarm/src/lib.rs.) Raises Disarm::InvalidArgument on an
96
+ # unknown `lang:`.
87
97
  def slugify(
88
98
  text,
89
99
  separator: "-",
@@ -111,7 +121,9 @@ module Disarm
111
121
  end
112
122
 
113
123
  # Replace emoji with their plain names (e.g. "👍" → "thumbs up").
114
- # `strip_modifiers:` drops skin-tone / variation modifiers before naming.
124
+ # `strip_modifiers:` drops skin-tone / variation modifiers before naming. An emoji
125
+ # CLDR cannot name (a regional indicator or a Plane 14 tag character standing
126
+ # alone) becomes "[?]", the sentinel #transliterate writes, as in every binding.
115
127
  def demojize(text, strip_modifiers: false)
116
128
  translate_errors { _demojize(text, strip_modifiers) }
117
129
  end
@@ -122,7 +134,8 @@ module Disarm
122
134
  # +demojize+ asks what CLDR calls a character, so its domain is the name table, which
123
135
  # is wider than the emoji: <tt>demojize("x\u2122y")</tt> is "x trade mark y". This
124
136
  # asks whether the UCD calls it an emoji — Emoji_Presentation=Yes, an Emoji=Yes base
125
- # carrying U+FE0F, and the ZWJ, modifier, keycap and flag sequences on those. Nothing
137
+ # carrying U+FE0F (not an Extended_Pictographic one, so a black star with a selector
138
+ # stays), and the ZWJ, modifier, keycap and flag sequences on those. Nothing
126
139
  # else moves.
127
140
  #
128
141
  # +replacement+ is inserted exactly as given: "" closes an intra-word split and " "
@@ -146,7 +159,7 @@ module Disarm
146
159
  # keeps the VS15/VS16 presentation selectors after a base, which the naive chain
147
160
  # deletes, and it collapses TAB/LF to a space, which the primitives leave alone.
148
161
  def strip_format(text)
149
- _strip_format(text)
162
+ translate_errors { _strip_format(text) }
150
163
  end
151
164
 
152
165
  # Remove obfuscation (zero-width, bidi, combining-mark abuse) while keeping
@@ -219,7 +232,12 @@ module Disarm
219
232
  # `max_distance:` (#894). Reports; it does not decide. An exact match is reported with
220
233
  # distance 0, and ties go to the first candidate at the lowest distance.
221
234
  def nearest_match(value, candidates, max_distance: 1)
222
- hit = translate_errors { _nearest_match(value, candidates.map(&:to_s), max_distance) }
235
+ hit = translate_errors do
236
+ # A non-collection is a wrong-typed argument, not a NoMethodError (N2).
237
+ raise ::TypeError, "candidates must be an Array or Enumerable" unless candidates.respond_to?(:map)
238
+
239
+ _nearest_match(value, candidates.map(&:to_s), max_distance)
240
+ end
223
241
  hit && { value: hit[0], distance: hit[1] }
224
242
  end
225
243
 
@@ -378,15 +396,18 @@ module Disarm
378
396
  translate_errors { _strip_pua(text) }
379
397
  end
380
398
 
381
- # Strip "zalgo" combining-mark stacking, keeping at most `max_marks:` (2)
382
- # combining marks per base character.
383
- def strip_zalgo(text, max_marks: 2)
399
+ # Strip "zalgo" combining-mark stacking, keeping at most `max_marks:` marks of each
400
+ # combining class on one base character. The default is the core's,
401
+ # DEFAULT_ZALGO_MAX_MARKS (3), equal to #zalgo?'s threshold (#788), so this never
402
+ # strips from text #zalgo? declines to flag.
403
+ def strip_zalgo(text, max_marks: DEFAULT_ZALGO_MAX_MARKS)
384
404
  translate_errors { _strip_zalgo(text, max_marks) }
385
405
  end
386
406
 
387
407
  # Whether `text` looks like zalgo: any base character carries more than
388
- # `threshold:` (3) combining marks.
389
- def zalgo?(text, threshold: 3)
408
+ # `threshold:` marks of one combining class. The default is the core's,
409
+ # DEFAULT_ZALGO_THRESHOLD (3).
410
+ def zalgo?(text, threshold: DEFAULT_ZALGO_THRESHOLD)
390
411
  translate_errors { _zalgo?(text, threshold) }
391
412
  end
392
413
 
@@ -422,13 +443,16 @@ module Disarm
422
443
  # Turn arbitrary text into a safe filename. `platform:` is :universal
423
444
  # (default), :windows, or :posix; `preserve_extension:` keeps the final
424
445
  # extension when truncating to `max_length:`. Raises Disarm::InvalidArgument
425
- # on an unknown platform.
446
+ # on an unknown platform, or on a `separator:` that is not printable, non-space
447
+ # ASCII, contains a character illegal on the platform, or contains a path
448
+ # separator ("/" or "\\"). An empty separator is allowed, and so is " " on its
449
+ # own.
426
450
  #
427
451
  # A safe *filename*, not a safe URL path segment. "%" is legal in a filename, so one
428
452
  # the caller typed is kept — sanitize_filename("..%2Fetc") returns "%2Fetc" — and a
429
453
  # consumer that percent-decodes the result must validate AFTER decoding. What this
430
- # will not do is manufacture one: "%" never appears in the output unless it appeared
431
- # in the input (#721).
454
+ # will not do is manufacture one: every "%" in the output is one the input
455
+ # contained, or part of the separator (#721).
432
456
  def sanitize_filename(text, separator: "_", max_length: 255, platform: :universal,
433
457
  lang: nil, preserve_extension: true)
434
458
  translate_errors do
@@ -475,8 +499,9 @@ module Disarm
475
499
  end
476
500
  end
477
501
 
478
- # ML/NLP normalization: NFKC → emoji→text → transliterate → strip accents →
479
- # [case fold] → strip control → strip zero-width → collapse whitespace.
502
+ # ML/NLP normalization: resolve deletions → NFKC → emoji→text → transliterate →
503
+ # strip accents → emoji→text → [case fold] → strip control → strip zero-width →
504
+ # collapse whitespace → NFC.
480
505
  #
481
506
  # `fold_case:` defaults to true. Pass false in front of a CASED model — folding is
482
507
  # destructive, cannot be undone downstream, and an uncased evaluation harness cannot
@@ -513,7 +538,7 @@ module Disarm
513
538
  # anomaly detector's `bidi` kind reports nine of the twelve, holding back LRM, RLM
514
539
  # and ALM because a lone directional mark is ordinary in right-to-left text.
515
540
  def bidi_control?(text)
516
- _has_bidi_control?(text)
541
+ translate_errors { _has_bidi_control?(text) }
517
542
  end
518
543
 
519
544
  # Explain how `lang: "auto"` detection resolves `text`: a hash with
@@ -674,13 +699,14 @@ module Disarm
674
699
  # whole surface. The original backtrace is preserved (passed as the third
675
700
  # `raise` argument) so the failing native call site stays visible. A bad
676
701
  # argument from the native layer can arrive as ArgumentError (an invalid
677
- # scheme/target), TypeError (a non-String argument), or RangeError (e.g. a
678
- # negative max_length) — all map to Disarm::InvalidArgument.
702
+ # scheme/target), TypeError (a non-String argument), RangeError (e.g. a
703
+ # negative max_length) or EncodingError (a String in an encoding Ruby cannot
704
+ # transcode to UTF-8) — all map to Disarm::InvalidArgument.
679
705
  def translate_errors
680
706
  yield
681
707
  rescue Error
682
708
  raise # already in our hierarchy — don't re-wrap
683
- rescue ::ArgumentError, ::TypeError, ::RangeError => e
709
+ rescue ::ArgumentError, ::TypeError, ::RangeError, ::EncodingError => e
684
710
  raise InvalidArgument, e.message, e.backtrace
685
711
  rescue ::RuntimeError => e
686
712
  raise Error, e.message, e.backtrace
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: disarm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.16.0
4
+ version: 0.17.2
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - Richard Quinn
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-09-06 00:00:00.000000000 Z
11
+ date: 2026-09-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -95,8 +95,6 @@ files:
95
95
  - LICENSE
96
96
  - README.md
97
97
  - lib/disarm.rb
98
- - lib/disarm/3.1/disarm.so
99
- - lib/disarm/3.2/disarm.so
100
98
  - lib/disarm/3.3/disarm.so
101
99
  - lib/disarm/3.4/disarm.so
102
100
  - lib/disarm/4.0/disarm.so
@@ -117,7 +115,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
117
115
  requirements:
118
116
  - - ">="
119
117
  - !ruby/object:Gem::Version
120
- version: '3.1'
118
+ version: '3.3'
121
119
  - - "<"
122
120
  - !ruby/object:Gem::Version
123
121
  version: 4.1.dev
Binary file
Binary file