polytypo 1.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/LICENSE +21 -0
- data/README.md +109 -0
- data/lib/polytypo/data/README.md +20 -0
- data/lib/polytypo/data/UNICODE +1 -0
- data/lib/polytypo/data/VERSION +1 -0
- data/lib/polytypo/data/fixtures/de-CH.json +501 -0
- data/lib/polytypo/data/fixtures/de-DE.json +547 -0
- data/lib/polytypo/data/fixtures/el.json +239 -0
- data/lib/polytypo/data/fixtures/en-GB.json +1274 -0
- data/lib/polytypo/data/fixtures/en-US.json +1807 -0
- data/lib/polytypo/data/fixtures/fi.json +1306 -0
- data/lib/polytypo/data/fixtures/fr-CA.json +268 -0
- data/lib/polytypo/data/fixtures/fr.json +603 -0
- data/lib/polytypo/data/fixtures/locale-resolution.json +209 -0
- data/lib/polytypo/data/fixtures/ru.json +688 -0
- data/lib/polytypo/data/fixtures/sv.json +1290 -0
- data/lib/polytypo/data/locales/de-CH.json +77 -0
- data/lib/polytypo/data/locales/de-DE.json +76 -0
- data/lib/polytypo/data/locales/el.json +90 -0
- data/lib/polytypo/data/locales/en-GB.json +115 -0
- data/lib/polytypo/data/locales/en-US.json +133 -0
- data/lib/polytypo/data/locales/fi.json +136 -0
- data/lib/polytypo/data/locales/fr-CA.json +78 -0
- data/lib/polytypo/data/locales/fr.json +84 -0
- data/lib/polytypo/data/locales/registry.json +9 -0
- data/lib/polytypo/data/locales/ru.json +112 -0
- data/lib/polytypo/data/locales/sv.json +124 -0
- data/lib/polytypo/data/rules/dashes.md +1238 -0
- data/lib/polytypo/data/rules/order.json +78 -0
- data/lib/polytypo/data/schema/fixtures.schema.json +79 -0
- data/lib/polytypo/data/schema/locale.schema.json +235 -0
- data/lib/polytypo/data/schema/registry.schema.json +29 -0
- data/lib/polytypo/data/schema/resolution.schema.json +50 -0
- data/lib/polytypo/engine/codepoints.rb +24 -0
- data/lib/polytypo/engine/edits.rb +64 -0
- data/lib/polytypo/engine/locale.rb +138 -0
- data/lib/polytypo/engine/pipeline.rb +61 -0
- data/lib/polytypo/engine/registry.rb +47 -0
- data/lib/polytypo/engine/rules/apostrophe.rb +127 -0
- data/lib/polytypo/engine/rules/dash_shared.rb +342 -0
- data/lib/polytypo/engine/rules/dashes.rb +125 -0
- data/lib/polytypo/engine/rules/ellipsis.rb +100 -0
- data/lib/polytypo/engine/rules/hyphen.rb +207 -0
- data/lib/polytypo/engine/rules/nbsp.rb +616 -0
- data/lib/polytypo/engine/rules/quote_ambiguity.rb +241 -0
- data/lib/polytypo/engine/rules/quotes.rb +420 -0
- data/lib/polytypo/engine/rules/ranges.rb +124 -0
- data/lib/polytypo/engine/rules/spaces.rb +232 -0
- data/lib/polytypo/engine/rules/symbols.rb +291 -0
- data/lib/polytypo/engine/rules.rb +19 -0
- data/lib/polytypo/engine/sentinels.rb +23 -0
- data/lib/polytypo/engine/unicode_util.rb +390 -0
- data/lib/polytypo/errors.rb +24 -0
- data/lib/polytypo/modes/html.rb +233 -0
- data/lib/polytypo/modes/markdown.rb +187 -0
- data/lib/polytypo/modes/parse_error.rb +19 -0
- data/lib/polytypo/modes/runner.rb +57 -0
- data/lib/polytypo/modes/spans.rb +132 -0
- data/lib/polytypo/version.rb +5 -0
- data/lib/polytypo.rb +91 -0
- data/polytypo.gemspec +37 -0
- metadata +122 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 05bb3c57adf30c19b96896ce40858128d7fee5102bee1c3b533c84fcc55d852e
|
|
4
|
+
data.tar.gz: '0088837892eb60339829d77c2f2204adc23f44fdd6587bdf9294e17885a44271'
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 14d6279d9fdae3d660709dc7c0a4f5c75711befd10c74bcd8f66a4b0026cc7ddec5d83ffb67e7c6609b496322021c29c1097bf6ee24c804e233685e3a9be27c8
|
|
7
|
+
data.tar.gz: ceaf4caf52d16a2e3189916caa72272d24513e71ea2f8262bb254a1d975247be66d5eac8e46dde0f46b5a62383ee6aeaf043a1a61acc5ceab4168136c466d4d3
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Iurii Rogulia
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/polytypo/polytypo/main/brand/logo/polytypo-lockup-stacked.svg" alt="polytypo" width="260">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">polytypo</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://rubygems.org/gems/polytypo"><img src="https://img.shields.io/gem/v/polytypo.svg" alt="Gem version"></a>
|
|
9
|
+
<a href="https://github.com/polytypo/polytypo-ruby/actions/workflows/ci.yml"><img src="https://github.com/polytypo/polytypo-ruby/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
10
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License: MIT"></a>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
<p align="center">
|
|
14
|
+
Locale-correct quotes, dashes, ellipses, apostrophes, symbols and no-break spaces —<br>
|
|
15
|
+
one portable spec, designed for byte-identical output across runtimes.
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<strong>Try it live, no install: <a href="https://polytypo.dev/">polytypo.dev</a></strong>
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
This is the Ruby implementation. The full spec — all locales, all rules, worked examples in
|
|
23
|
+
each — lives in [polytypo/polytypo](https://github.com/polytypo/polytypo). This runtime supports
|
|
24
|
+
the `text` and `html` modes fully, and `markdown` for the `commonmark` dialect only — `mdx`
|
|
25
|
+
returns `POLYTYPO_INVALID_DIALECT` (no MDX/JSX parser is available for Ruby; see
|
|
26
|
+
[Supported dialects](#supported-dialects)).
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
```sh
|
|
31
|
+
gem install polytypo
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or in a Gemfile:
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
gem "polytypo"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Usage
|
|
41
|
+
|
|
42
|
+
```ruby
|
|
43
|
+
require "polytypo"
|
|
44
|
+
|
|
45
|
+
Polytypo.transform(%q{She said, "it's fine" -- but I wasn't sure...}, locale: "en-US")
|
|
46
|
+
# => "She said, “it’s fine”—but I wasn’t sure…"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Same input, one locale changed — quotes, dash spacing and all follow the target locale, not a
|
|
50
|
+
single hardcoded style:
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
Polytypo.transform(%q{Sie sagte: "Alles gut" -- aber ich war mir nicht sicher...}, locale: "de-DE")
|
|
54
|
+
# => "Sie sagte: „Alles gut“ – aber ich war mir nicht sicher…"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
HTML and Markdown are first-class modes, not an afterthought — tags, attributes and fenced code
|
|
58
|
+
are left alone; only text content is touched:
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
Polytypo.transform(%q{<a title="test... wait">Wait... she said "go on."</a>}, locale: "en-US", mode: "html")
|
|
62
|
+
# => "<a title=\"test... wait\">Wait… she said “go on.”</a>"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`locale:` has no default anywhere and must always be passed explicitly — there is no silent
|
|
66
|
+
fallback to English. `mode:` defaults to `"text"` if omitted.
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
Polytypo.transform(input, locale: "fr", mode: "markdown", dialect: "commonmark")
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
`require "polytypo"` never loads the native `commonmarker` extension unless you actually call
|
|
73
|
+
`Polytypo.transform` with `mode: "markdown"` — the require happens lazily, inside the markdown
|
|
74
|
+
pipeline only. A single `Polytypo.transform` module method (not separate
|
|
75
|
+
`polytypo/text`/`html`/`markdown` gems) is the idiomatic Ruby shape for this — Ruby's dynamic
|
|
76
|
+
`require` already gets you the same dependency isolation JS/Python's subpath split exists for,
|
|
77
|
+
without a separate namespace per mode.
|
|
78
|
+
|
|
79
|
+
### Errors
|
|
80
|
+
|
|
81
|
+
Every error `Polytypo.transform` raises is a `Polytypo::Error` carrying one of seven stable
|
|
82
|
+
codes — check `#code`, not the message text, which is English and informative but not part of
|
|
83
|
+
the contract:
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
begin
|
|
87
|
+
Polytypo.transform("x", locale: "xx-ZZ")
|
|
88
|
+
rescue Polytypo::Error => e
|
|
89
|
+
e.code # => "POLYTYPO_UNKNOWN_LOCALE"
|
|
90
|
+
end
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Supported dialects
|
|
94
|
+
|
|
95
|
+
`markdown` mode requires a `dialect:`, exactly as the spec requires (no default, detection is
|
|
96
|
+
forbidden). This runtime supports `dialect: "commonmark"` (CommonMark plus GFM — tables,
|
|
97
|
+
strikethrough, task lists, autolink literals). `dialect: "mdx"` is a real dialect the spec names,
|
|
98
|
+
but this runtime has no MDX/JSX parser for it and raises `Polytypo::Error` with
|
|
99
|
+
`POLYTYPO_INVALID_DIALECT` immediately rather than silently mishandling it — a narrower, honest
|
|
100
|
+
conformance claim, not a port defect.
|
|
101
|
+
|
|
102
|
+
## Thread safety
|
|
103
|
+
|
|
104
|
+
`Polytypo.transform` is a pure module method with no class-level mutable state: safe to call
|
|
105
|
+
concurrently from any number of `Thread`s with no external synchronization.
|
|
106
|
+
|
|
107
|
+
## Licence
|
|
108
|
+
|
|
109
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Vendored spec subset
|
|
2
|
+
|
|
3
|
+
This directory is a manually-synced copy of the subset of `polytypo/polytypo`'s canonical `spec/`
|
|
4
|
+
that this gem needs at runtime: `locales/`, `fixtures/`, `rules/order.json`, `rules/dashes.md`,
|
|
5
|
+
`schema/`, `VERSION`, `UNICODE`. It is **not** the canonical spec — the rest of the normative
|
|
6
|
+
prose (`spec/rules/*.md` beyond `dashes.md`) and `validate-spec.mjs` live only in
|
|
7
|
+
`polytypo/polytypo`.
|
|
8
|
+
|
|
9
|
+
Named `lib/polytypo/data/`, not `vendor/polytypo-spec/` like the JS/Python ports: a Ruby
|
|
10
|
+
gemspec's `files` list can include any path directly, so there is no need for a separate
|
|
11
|
+
`vendor/` staging copy plus a second, separately-generated package-data copy the way Python
|
|
12
|
+
needed (its build backend does not include arbitrary files without explicit config). This is the
|
|
13
|
+
one copy, shipped as part of the gem's own `lib/` payload and loaded via `File.read` relative to
|
|
14
|
+
`__dir__` at runtime — never a network or external-filesystem read.
|
|
15
|
+
|
|
16
|
+
Editing a file here does not change the spec; it only drifts this copy from canonical. When
|
|
17
|
+
canonical's `spec/` changes, re-copy the affected files here. How this vendoring will work
|
|
18
|
+
long-term (submodule, per-ecosystem spec package, or something else) is an open decision tracked
|
|
19
|
+
in `polytypo/polytypo`'s roadmap; this is the interim, manually-synced form — the same status
|
|
20
|
+
every other port's vendored copy has.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
17.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.0.0
|