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 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