c0data 0.3.1
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 +143 -0
- data/c0-c/c0.h +3926 -0
- data/ext/c0/c0_ext.c +1061 -0
- data/ext/c0/extconf.rb +7 -0
- data/lib/c0/body.rb +314 -0
- data/lib/c0/builder.rb +64 -0
- data/lib/c0/document.rb +243 -0
- data/lib/c0/pretty.rb +28 -0
- data/lib/c0/stream.rb +76 -0
- data/lib/c0.rb +123 -0
- metadata +53 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 3cf0ff8a402528534f2cd0a46c25d811e0dad7a1875bd0c24993b88c416c0cac
|
|
4
|
+
data.tar.gz: a46da5bc31159944a5ebde356e9e0ba24550b1d92ba8bc4a70ad13a083bd1fec
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 58f26bab23ed8c97f913fe2a0d7fff18d5b2b7ec25dcc9619ce2f946ad459923da2df66c9f5be949f1dea578f3b85f694b3e600c89cc63632e00288a518d645f
|
|
7
|
+
data.tar.gz: 7fa188710231af60512f498dda885f69c804ffac04b2e08c6daff868b8cc4a1eb85523157d01f919595a1f5a61f583fcc0455d8dd4a9a649cb3a3e6a3857fad4
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Thomas Sawyer <transfire@gmail.com>
|
|
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,143 @@
|
|
|
1
|
+
# c0
|
|
2
|
+
|
|
3
|
+
A Ruby implementation of [C0DATA](https://github.com/c0data) 1.0 — structured
|
|
4
|
+
data built on ASCII C0 control codes.
|
|
5
|
+
|
|
6
|
+
This is **not** a reimplementation: it's a thin, fast binding over the
|
|
7
|
+
[c0 C core](https://github.com/c0data/c0-c) (a Ruby C extension, no runtime
|
|
8
|
+
dependencies), so the scan-heavy work runs as native C while the Ruby layer
|
|
9
|
+
provides an idiomatic API. The read path is **zero-copy** — accessors return
|
|
10
|
+
shared byteslices into the input buffer.
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
require "c0"
|
|
16
|
+
|
|
17
|
+
# Write: ␖␁shape␟tabular␝users␁␞name␟amount␞Alice␟1502.30␞Bob␟340.00␄
|
|
18
|
+
buf = C0.build do |b|
|
|
19
|
+
b.syn(shape: "tabular")
|
|
20
|
+
b.group("users", %w[name amount]) do # ␝users then the header row ␁␞name␟amount
|
|
21
|
+
b.record("Alice", "1502.30")
|
|
22
|
+
b.record("Bob", "340.00")
|
|
23
|
+
end
|
|
24
|
+
b.eot
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Read (zero-copy: values are shared byteslices of buf)
|
|
28
|
+
doc = C0::Document.new(buf)
|
|
29
|
+
doc.shape # => "tabular"
|
|
30
|
+
doc["users"].headers # => ["name", "amount"]
|
|
31
|
+
doc["users"].each do |rec|
|
|
32
|
+
name, amount = rec.values # logical values: text decoded, layout trimmed
|
|
33
|
+
rec.value(0) # => "Alice"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Canonical form is hashable for content addressing
|
|
37
|
+
C0.canonical?(doc.body.raw) # => true
|
|
38
|
+
|
|
39
|
+
# Streams, containers, pretty form
|
|
40
|
+
C0::Stream::Reader.new(File.binread("events.c0")) # #torn?, #committed, #blocks, #records
|
|
41
|
+
C0::Container.new(buf) # several documents, EM tail, #blob(name)
|
|
42
|
+
C0::Pretty.format(buf, mode: :aligned) # Unicode Control Pictures
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Values are byte-transparent and written in their one spelling: plain when
|
|
46
|
+
they can be, text (`␂…␃`) when they hold a control byte, a line break or edge
|
|
47
|
+
whitespace. `C0.validate(buf)` checks a buffer against the grammar once
|
|
48
|
+
(raising a `C0::SyntaxError`); the navigators then assume well-formed input.
|
|
49
|
+
|
|
50
|
+
### Keyed records, nesting, references
|
|
51
|
+
|
|
52
|
+
```ruby
|
|
53
|
+
buf = C0.build do |b|
|
|
54
|
+
b.group("server")
|
|
55
|
+
b.map("host" => "0.0.0.0", "port" => "8080") # ␞␁host␟0.0.0.0␁port␟8080
|
|
56
|
+
b.record("Alice")
|
|
57
|
+
b.list(%w[Admin Editor]) # one unit: ␐␞Admin␟Editor␘
|
|
58
|
+
b.level do # ␐ … a whole body … ␘
|
|
59
|
+
b.header(%w[street city])
|
|
60
|
+
b.record("1 Main", "Springfield")
|
|
61
|
+
end
|
|
62
|
+
b.ref("tags") # ␅tags
|
|
63
|
+
b.ref("tags", "001", "label") # ␅␂tags␟001␟label␃
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
g = C0::Document.new(buf)["server"]
|
|
67
|
+
g.record(0).keyed? # => true
|
|
68
|
+
g.record(0)["port"] # => "8080" (last wins)
|
|
69
|
+
g.record(1).list(1) # => ["Admin", "Editor"]
|
|
70
|
+
g.record(1).level(2).record(0) # => the nested record
|
|
71
|
+
g.record(1).ref(4).path # => ["tags", "001", "label"]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
The builder also has `file`, `section`, `header`, `field`, `key` (with a
|
|
75
|
+
block for a nested value), `heading_level`, `note`, `block`, `item`,
|
|
76
|
+
`etb(payload)` and `em(tail)`, matching the Crystal reference; every method
|
|
77
|
+
returns the builder, so calls chain.
|
|
78
|
+
|
|
79
|
+
### Primitives
|
|
80
|
+
|
|
81
|
+
Underneath, the builder has one method per code: `fs`, `gs`, `rs`, `us`,
|
|
82
|
+
`sub` (C0-DIFF only), `soh`, `dle`, `can`, `bel`, `enq`, `syn`, `eot`,
|
|
83
|
+
`etb`, `em`. Each writes its code and, when given, what follows it, so a
|
|
84
|
+
chain reads like the bytes, and anything the grammar allows can be written.
|
|
85
|
+
The argument is optional where the grammar allows the bare code (`gs`, `rs`,
|
|
86
|
+
`us`, `sub`, `soh`, `bel`, `etb`); `enq` takes one name or a path of two or
|
|
87
|
+
three:
|
|
88
|
+
|
|
89
|
+
```ruby
|
|
90
|
+
b.rs("Alice").us("1502.30") # ␞Alice␟1502.30
|
|
91
|
+
b.rs.soh("host").us("localhost").soh("port").us("5432") # ␞␁host␟localhost␁port␟5432
|
|
92
|
+
b.gs("users").soh.rs("name").us("amount") # ␝users␁␞name␟amount: a header row
|
|
93
|
+
b.rs("cfg").us.dle.rs.soh("b").us("2").can # ␞cfg␟␐␞␁b␟2␘: a nested level
|
|
94
|
+
b.bel("checked").rs("x") # ␇checked␞x: a note
|
|
95
|
+
b.bel.gs("old") # ␇␝old: a dead group
|
|
96
|
+
b.gs.gs("sub").rs.enq("users").us.enq("users", "1") # ␝␝sub␞␅users␟␅␂users␟1␃
|
|
97
|
+
b.syn.soh("version").us("1").rs("a").eot # ␖␁version␟1␞a␄
|
|
98
|
+
b.rs("old").sub("new") # ␞old␚new: a C0-DIFF replace-all
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The composed methods above are built on these and cannot write ill-formed
|
|
102
|
+
output; with the primitives, well-formedness is yours. Values keep their one
|
|
103
|
+
spelling either way (there is no STX/ETX primitive), and names are still
|
|
104
|
+
checked. The two layers share the record state and mix freely:
|
|
105
|
+
`b.rs("a").field("b")` writes `␞a␟b`, `b.record.us("c")` writes `␞␟c`.
|
|
106
|
+
|
|
107
|
+
## Install / build
|
|
108
|
+
|
|
109
|
+
```sh
|
|
110
|
+
gem install c0data # the gem is c0data; in code it is `require "c0"`
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
From a checkout, the C core and the shared conformance vectors are git submodules:
|
|
114
|
+
|
|
115
|
+
```sh
|
|
116
|
+
git submodule update --init # pulls in c0-c (the header) and c0-spec
|
|
117
|
+
rake compile # builds the extension
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Requires a C compiler and Ruby development headers (MRI).
|
|
121
|
+
|
|
122
|
+
## Status
|
|
123
|
+
|
|
124
|
+
Binds the c0-c 1.0 core: validator and canonical check, documents and
|
|
125
|
+
containers (SYN heading, EOT, EM tail, warnings), bodies with files, groups,
|
|
126
|
+
header rows, positional and keyed records, nested levels, lists and references
|
|
127
|
+
(all zero-copy), the canonical builder, ETB stream mode (committed region,
|
|
128
|
+
damaged blocks, torn-tail detection) and pretty form (compact, aligned and
|
|
129
|
+
spaced). Passes every shared conformance vector from
|
|
130
|
+
[c0-spec](https://github.com/c0data/c0-spec) (decode, encode, canonical,
|
|
131
|
+
invalid, nested, stream).
|
|
132
|
+
|
|
133
|
+
Converters (CSV / JSON / C0-DIFF) are not yet wrapped.
|
|
134
|
+
|
|
135
|
+
## Test
|
|
136
|
+
|
|
137
|
+
```sh
|
|
138
|
+
rake test
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
MIT
|