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 +7 -0
- data/README.md +87 -0
- data/lib/diff_match_patch_es/diff.rb +1050 -0
- data/lib/diff_match_patch_es/js_string.rb +128 -0
- data/lib/diff_match_patch_es/match.rb +141 -0
- data/lib/diff_match_patch_es/options.rb +58 -0
- data/lib/diff_match_patch_es/patch.rb +551 -0
- data/lib/diff_match_patch_es/version.rb +5 -0
- data/lib/diff_match_patch_es.rb +51 -0
- data/sig/diff_match_patch_es/diff.rbs +113 -0
- data/sig/diff_match_patch_es/js_string.rbs +37 -0
- data/sig/diff_match_patch_es/match.rbs +14 -0
- data/sig/diff_match_patch_es/options.rbs +38 -0
- data/sig/diff_match_patch_es/patch.rbs +60 -0
- data/sig/diff_match_patch_es/version.rbs +3 -0
- data/sig/diff_match_patch_es.rbs +34 -0
- metadata +57 -0
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
|