diff_match_patch_es 2.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 49966ab58af40ac9cb914af9464c7ef51f9d99e3c5e7d031b00d0d16a8e72646
4
+ data.tar.gz: de0d632f1833ff01e32793458f65545e57e892b08f87d13879028331c6063909
5
+ SHA512:
6
+ metadata.gz: '064728afac4b40eb29a51516f7a341832e6f6ac45e79d7faf4676ac62515b5c17b99b9da96d86b748f4a41b2b5009aac7b57c3f7819d97f2bc4b2b51655dfce6'
7
+ data.tar.gz: 0c835902b2f68d6c502b7c6eaaa251fdc699e965da8ddbf34fa7f33831c576cc71b83f72b59984a815e6cd29f1043942c84684574f0fa5634b564934e7d7a641
data/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # diff_match_patch_es (Ruby)
2
+
3
+ A thread-safe Ruby port of [diff-match-patch-es](https://github.com/antfu/diff-match-patch-es) (the TypeScript/ESM rewrite of Google's [diff-match-patch](https://github.com/google/diff-match-patch)), producing results identical to the JavaScript implementation.
4
+
5
+ ## Usage
6
+
7
+ ```ruby
8
+ require 'diff_match_patch_es'
9
+
10
+ diffs = DiffMatchPatchES.diff_main('Apples are a fruit.', 'Bananas are also fruit.')
11
+ # => [[-1, "Apple"], [1, "Banana"], [0, "s are a"], [1, "lso"], [0, " fruit."]]
12
+
13
+ patches = DiffMatchPatchES.patch_make('The quick brown fox.', 'The slow green fox.')
14
+ text = DiffMatchPatchES.patch_to_text(patches)
15
+ DiffMatchPatchES.patch_apply(DiffMatchPatchES.patch_from_text(text), 'The quick brown fox.')
16
+ # => ["The slow green fox.", [true]]
17
+
18
+ DiffMatchPatchES.match_main('abcdefghijk', 'fgh', 5) # => 5
19
+ ```
20
+
21
+ Every exported function of the JS package has a snake_case equivalent (`diffMain` -> `diff_main`, `patchApply` -> `patch_apply`, …), plus the short aliases `diff`, `match`, and `patch`.
22
+ Diffs are `[op, text]` arrays with the ops `DIFF_DELETE` (-1), `DIFF_EQUAL` (0), and `DIFF_INSERT` (1); patches are `DiffMatchPatchES::Patch` objects whose `#to_s` emits the GNU-diff-style format.
23
+
24
+ Options are passed as a trailing hash (or a resolved `DiffMatchPatchES::Options`), mirroring the JS option names:
25
+
26
+ ```ruby
27
+ DiffMatchPatchES.diff_main(a, b, { diff_timeout: 0, diff_edit_cost: 4 })
28
+ DiffMatchPatchES.match_main(text, pattern, loc, { match_threshold: 0.4, match_distance: 100 })
29
+ ```
30
+
31
+ ## Type signatures
32
+
33
+ Full RBS signatures for the public API (and internal helpers) ship with the gem under `sig/`, so Steep/TypeProf/`rbs` pick them up automatically.
34
+ Diffs are typed as `[op, String]` tuples where `op` is the literal union `-1 | 0 | 1`, and every `patch_make` call format is covered by an overload.
35
+
36
+ ## Thread/Ractor safety
37
+
38
+ The entire API is stateless module functions: no globals are mutated, all constants (including `DEFAULT_OPTIONS`) are frozen, and every call operates only on its arguments and locals.
39
+ Calling any function from multiple threads (or Ractors) concurrently is safe!
40
+ The only caveat is the obvious one: don't mutate a single `Options` instance or a shared diffs array from two threads at the same time.
41
+
42
+ ## Parity with the JavaScript implementation
43
+
44
+ The port is verified two ways:
45
+
46
+ - The upstream vitest suite is ported 1:1 to minitest (`test/`).
47
+ - A cross-language parity suite (`parity/`) runs a static corpus of 404 cases (`parity/cases.json` — committed, human-readable) through both the published npm package (pinned by `parity/yarn.lock`) and this port, and asserts byte-identical output for every public function (diffs, cleanups, deltas, patch text, patch apply, match):
48
+
49
+ ```sh
50
+ bundle exec rake parity
51
+ ```
52
+
53
+ Requires Node with corepack enabled (the JS side is installed with Yarn via
54
+ the `packageManager` pin). CI runs this on every push. The corpus was
55
+ generated once with `node parity/gen_cases.mjs` (seeded PRNG plus
56
+ hand-picked edge cases); rerun that script to regenerate or expand it.
57
+
58
+ JS-specific semantics are reproduced deliberately, including `substring`
59
+ clamping, `encodeURI`/`decodeURI` behavior (reserved `%XX` escapes are left
60
+ intact; malformed UTF-8 raises), `parseInt` prefix parsing, 32-bit bitwise
61
+ arithmetic in the Bitap matcher, and the sparse-array behavior of the
62
+ semantic cleanup's equalities stack.
63
+
64
+ **Known divergence:** JavaScript strings are UTF-16 code units, so on
65
+ supplementary-plane input (emoji, some CJK extensions) the JS implementation
66
+ may split surrogate pairs and emit lone surrogates, e.g.
67
+ `diffMain('🍏x', '🍎x')` → `[[0,'\ud83c'],[-1,'\udf4f'],[1,'\udf4e'],[0,'x']]`.
68
+ Lone surrogates cannot exist in UTF-8, so the Ruby port operates on whole
69
+ characters and returns `[[-1,'🍏'],[1,'🍎'],[0,'x']]` — same edit, valid
70
+ strings. For all text within the Basic Multilingual Plane the outputs are
71
+ identical.
72
+
73
+ `diff_timeout` (default 1 second) cuts the search off at a wall-clock
74
+ deadline, so under timeout pressure any two runs — in either language — can
75
+ legitimately differ; pass `diff_timeout: 0` for deterministic (slower)
76
+ results.
77
+
78
+ ## Tests
79
+
80
+ ```sh
81
+ rake test
82
+ ```
83
+
84
+ ## Credits
85
+
86
+ - Neil Fraser for the implementation that started it all
87
+ - Anthony Fu for the TypeScript/ESM rewrite that allowed this to be a significantly easier process