toon-parser 0.1.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/.rspec +4 -0
- data/CHANGELOG.md +39 -0
- data/CONTRIBUTING.md +77 -0
- data/LICENSE.txt +22 -0
- data/README.md +437 -0
- data/Rakefile +9 -0
- data/examples/rails_controller_example.rb +89 -0
- data/lib/toon-parser/api.rb +166 -0
- data/lib/toon-parser/controller_helpers.rb +80 -0
- data/lib/toon-parser/parser.rb +375 -0
- data/lib/toon-parser/railtie.rb +34 -0
- data/lib/toon-parser/serializer.rb +137 -0
- data/lib/toon-parser/version.rb +6 -0
- data/lib/toon-parser.rb +66 -0
- data/toon-parser.gemspec +37 -0
- metadata +105 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 146ba580e5b40ed0c57aca735d092c02660125aad2e0ca06643da9336e18d49d
|
|
4
|
+
data.tar.gz: 7e86260004907ad3d34769751964928a88e7712a478e6d0dc628affc9e883ea8
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: e1bacf72b9ba9bcd27934039294b5a1fe16975a75b28e0b70cb7eb7ce8787292fa55247f5a3b2ab9a178d77ca7ab2d7c62cd68f7b148b6567591a38b5a9b5484
|
|
7
|
+
data.tar.gz: ea087bc89093ced0c234f1a76acf962eb1ed934a31a7e7882b053f9dc3eface801692f24a74dc95e8574faba4f0d8c74a73c57346c3d8b1d0c50f19a188b4dcf
|
data/.rspec
ADDED
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2024-01-XX
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Initial release of ToonParser gem
|
|
14
|
+
- Core parsing functionality for TOON format
|
|
15
|
+
- Serialization of Ruby objects to TOON format
|
|
16
|
+
- File operations (`parse_file`, `serialize_to_file`)
|
|
17
|
+
- Rails integration with Railtie
|
|
18
|
+
- Controller helpers for TOON responses
|
|
19
|
+
- Automatic MIME type registration (`application/toon`)
|
|
20
|
+
- Parameter parser for TOON request bodies
|
|
21
|
+
- API client helpers for TOON-formatted HTTP requests
|
|
22
|
+
- Support for nested objects
|
|
23
|
+
- Support for arrays of objects with schemas
|
|
24
|
+
- Support for simple arrays
|
|
25
|
+
- Type inference for numbers, booleans, and null values
|
|
26
|
+
- Comprehensive test suite
|
|
27
|
+
- Documentation and examples
|
|
28
|
+
|
|
29
|
+
### Features
|
|
30
|
+
- Parse TOON strings to Ruby objects (Hash/Array)
|
|
31
|
+
- Serialize Ruby objects to TOON format
|
|
32
|
+
- Rails controller integration with `render toon: data`
|
|
33
|
+
- Automatic request body parsing for TOON format
|
|
34
|
+
- HTTP client for TOON APIs
|
|
35
|
+
- Round-trip conversion support
|
|
36
|
+
|
|
37
|
+
[Unreleased]: https://github.com/afshmini/toon-parser/compare/v0.1.0...HEAD
|
|
38
|
+
[0.1.0]: https://github.com/afshmini/toon-parser/releases/tag/v0.1.0
|
|
39
|
+
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# Contributing to ToonParser
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing to ToonParser! This document provides guidelines and instructions for contributing.
|
|
4
|
+
|
|
5
|
+
## How to Contribute
|
|
6
|
+
|
|
7
|
+
### Reporting Bugs
|
|
8
|
+
|
|
9
|
+
If you find a bug, please open an issue on GitHub with:
|
|
10
|
+
|
|
11
|
+
- A clear, descriptive title
|
|
12
|
+
- Steps to reproduce the issue
|
|
13
|
+
- Expected behavior
|
|
14
|
+
- Actual behavior
|
|
15
|
+
- Ruby version and gem version
|
|
16
|
+
- Any relevant code examples
|
|
17
|
+
|
|
18
|
+
### Suggesting Features
|
|
19
|
+
|
|
20
|
+
Feature suggestions are welcome! Please open an issue with:
|
|
21
|
+
|
|
22
|
+
- A clear description of the feature
|
|
23
|
+
- Use cases and examples
|
|
24
|
+
- Any potential implementation ideas
|
|
25
|
+
|
|
26
|
+
### Pull Requests
|
|
27
|
+
|
|
28
|
+
1. **Fork the repository** and create your branch from `main`
|
|
29
|
+
2. **Make your changes** following the coding standards
|
|
30
|
+
3. **Add tests** for new functionality
|
|
31
|
+
4. **Ensure all tests pass** (`bundle exec rspec`)
|
|
32
|
+
5. **Update documentation** if needed
|
|
33
|
+
6. **Submit a pull request** with a clear description
|
|
34
|
+
|
|
35
|
+
## Development Setup
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Clone your fork
|
|
39
|
+
git clone https://github.com/YOUR_USERNAME/toon-parser.git
|
|
40
|
+
cd toon-parser
|
|
41
|
+
|
|
42
|
+
# Install dependencies
|
|
43
|
+
bundle install
|
|
44
|
+
|
|
45
|
+
# Run tests
|
|
46
|
+
bundle exec rspec
|
|
47
|
+
|
|
48
|
+
# Run linter
|
|
49
|
+
bundle exec rubocop
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Coding Standards
|
|
53
|
+
|
|
54
|
+
- Follow Ruby style guidelines
|
|
55
|
+
- Write tests for new features
|
|
56
|
+
- Keep code simple and readable
|
|
57
|
+
- Add documentation for public methods
|
|
58
|
+
- Use meaningful variable and method names
|
|
59
|
+
|
|
60
|
+
## Testing
|
|
61
|
+
|
|
62
|
+
- Write tests for all new features
|
|
63
|
+
- Ensure existing tests still pass
|
|
64
|
+
- Aim for good test coverage
|
|
65
|
+
- Test edge cases
|
|
66
|
+
|
|
67
|
+
## Documentation
|
|
68
|
+
|
|
69
|
+
- Update README.md for user-facing changes
|
|
70
|
+
- Add code comments for complex logic
|
|
71
|
+
- Update examples if API changes
|
|
72
|
+
- Keep CHANGELOG.md updated
|
|
73
|
+
|
|
74
|
+
## Questions?
|
|
75
|
+
|
|
76
|
+
Feel free to open an issue for any questions about contributing!
|
|
77
|
+
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 afshmini
|
|
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.
|
|
22
|
+
|
data/README.md
ADDED
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
# ToonParser
|
|
2
|
+
|
|
3
|
+
[](https://www.ruby-lang.org/)
|
|
4
|
+
[](LICENSE.txt)
|
|
5
|
+
[](https://github.com/afshmini/toon-parser)
|
|
6
|
+
|
|
7
|
+
A Ruby gem for parsing and serializing **TOON** (Token-Oriented Object Notation) format. TOON is a compact, human-readable data format designed to reduce token usage in LLM applications by **30-60%** compared to JSON.
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [Features](#features)
|
|
12
|
+
- [Installation](#installation)
|
|
13
|
+
- [Quick Start](#quick-start)
|
|
14
|
+
- [Usage](#usage)
|
|
15
|
+
- [Basic Parsing](#basic-parsing)
|
|
16
|
+
- [Basic Serialization](#basic-serialization)
|
|
17
|
+
- [File Operations](#file-operations)
|
|
18
|
+
- [Rails Controller Integration](#rails-controller-integration)
|
|
19
|
+
- [API Integration](#api-integration)
|
|
20
|
+
- [Advanced Usage](#advanced-usage)
|
|
21
|
+
- [TOON Format Overview](#toon-format-overview)
|
|
22
|
+
- [Examples](#examples)
|
|
23
|
+
- [Development](#development)
|
|
24
|
+
- [Contributing](#contributing)
|
|
25
|
+
- [License](#license)
|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
✨ **Key Features:**
|
|
30
|
+
|
|
31
|
+
- 🚀 **Fast parsing and serialization** of TOON format
|
|
32
|
+
- 🎯 **Rails integration** - Use TOON in controllers instead of JSON
|
|
33
|
+
- 📦 **File operations** - Read and write TOON files
|
|
34
|
+
- 🌐 **API helpers** - Built-in HTTP client for TOON APIs
|
|
35
|
+
- 🔄 **Round-trip conversion** - Parse and serialize without data loss
|
|
36
|
+
- 🎨 **Type inference** - Automatic detection of numbers, booleans, and null
|
|
37
|
+
- 📝 **Human-readable** - Compact yet readable format
|
|
38
|
+
- 🔌 **Optional Rails dependency** - Works standalone or with Rails
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
Add this line to your application's Gemfile:
|
|
43
|
+
|
|
44
|
+
```ruby
|
|
45
|
+
gem 'toon-parser'
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
And then execute:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
$ bundle install
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Or install it yourself as:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
$ gem install toon-parser
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Quick Start
|
|
61
|
+
|
|
62
|
+
```ruby
|
|
63
|
+
require 'toon-parser'
|
|
64
|
+
|
|
65
|
+
# Parse TOON string
|
|
66
|
+
toon = "users[2]{id,name}:\n 1,Alice\n 2,Bob"
|
|
67
|
+
data = ToonParser.parse(toon)
|
|
68
|
+
# => {"users" => [{"id" => 1, "name" => "Alice"}, {"id" => 2, "name" => "Bob"}]}
|
|
69
|
+
|
|
70
|
+
# Serialize to TOON
|
|
71
|
+
data = { "users" => [{ "id" => 1, "name" => "Alice" }] }
|
|
72
|
+
toon = ToonParser.serialize(data)
|
|
73
|
+
# => "users[1]{id,name}:\n 1,Alice"
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Usage
|
|
77
|
+
|
|
78
|
+
### Basic Parsing
|
|
79
|
+
|
|
80
|
+
Parse a TOON string into Ruby objects:
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
require 'toon-parser'
|
|
84
|
+
|
|
85
|
+
toon = <<~TOON
|
|
86
|
+
users[2]{id,name}:
|
|
87
|
+
1,Alice
|
|
88
|
+
2,Bob
|
|
89
|
+
TOON
|
|
90
|
+
|
|
91
|
+
data = ToonParser.parse(toon)
|
|
92
|
+
# => {"users" => [{"id" => 1, "name" => "Alice"}, {"id" => 2, "name" => "Bob"}]}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Basic Serialization
|
|
96
|
+
|
|
97
|
+
Convert Ruby objects to TOON format:
|
|
98
|
+
|
|
99
|
+
```ruby
|
|
100
|
+
data = {
|
|
101
|
+
"users" => [
|
|
102
|
+
{ "id" => 1, "name" => "Alice" },
|
|
103
|
+
{ "id" => 2, "name" => "Bob" }
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
toon = ToonParser.serialize(data)
|
|
108
|
+
# => "users[2]{id,name}:\n 1,Alice\n 2,Bob"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### File Operations
|
|
112
|
+
|
|
113
|
+
Parse a TOON file:
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
data = ToonParser.parse_file("data.toon")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Serialize to a TOON file:
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
ToonParser.serialize_to_file(data, "output.toon")
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Rails Controller Integration
|
|
126
|
+
|
|
127
|
+
Use TOON format in your Rails controllers instead of JSON. The gem automatically integrates with Rails when available.
|
|
128
|
+
|
|
129
|
+
#### Basic Controller Usage
|
|
130
|
+
|
|
131
|
+
```ruby
|
|
132
|
+
# app/controllers/api/users_controller.rb
|
|
133
|
+
class Api::UsersController < ApplicationController
|
|
134
|
+
before_action :set_toon_format
|
|
135
|
+
|
|
136
|
+
def index
|
|
137
|
+
@users = User.all
|
|
138
|
+
render toon: {
|
|
139
|
+
users: @users.map { |u| { id: u.id, name: u.name, email: u.email } }
|
|
140
|
+
}
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def show
|
|
144
|
+
@user = User.find(params[:id])
|
|
145
|
+
render toon: {
|
|
146
|
+
user: { id: @user.id, name: @user.name, email: @user.email }
|
|
147
|
+
}
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def create
|
|
151
|
+
# TOON request body is automatically parsed if Content-Type is application/toon
|
|
152
|
+
user_data = parse_toon_request
|
|
153
|
+
@user = User.create(user_data)
|
|
154
|
+
|
|
155
|
+
if @user.persisted?
|
|
156
|
+
render toon: { user: @user }, status: :created
|
|
157
|
+
else
|
|
158
|
+
render toon: { errors: @user.errors.full_messages }, status: :unprocessable_entity
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
private
|
|
163
|
+
|
|
164
|
+
def set_toon_format
|
|
165
|
+
request.format = :toon if request.format == :html
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
#### Setting Default Format
|
|
171
|
+
|
|
172
|
+
Set TOON as the default format for API controllers:
|
|
173
|
+
|
|
174
|
+
```ruby
|
|
175
|
+
# app/controllers/api/base_controller.rb
|
|
176
|
+
class Api::BaseController < ApplicationController
|
|
177
|
+
before_action :set_toon_format
|
|
178
|
+
|
|
179
|
+
private
|
|
180
|
+
|
|
181
|
+
def set_toon_format
|
|
182
|
+
request.format = :toon if request.format == :html
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
#### Responding to Multiple Formats
|
|
188
|
+
|
|
189
|
+
Support both TOON and JSON:
|
|
190
|
+
|
|
191
|
+
```ruby
|
|
192
|
+
class Api::UsersController < ApplicationController
|
|
193
|
+
def index
|
|
194
|
+
@users = User.all
|
|
195
|
+
data = { users: @users.map { |u| { id: u.id, name: u.name } } }
|
|
196
|
+
|
|
197
|
+
respond_to do |format|
|
|
198
|
+
format.toon { render toon: data }
|
|
199
|
+
format.json { render json: data }
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
#### Parsing TOON Request Bodies
|
|
206
|
+
|
|
207
|
+
The gem automatically registers a parameter parser for TOON request bodies. When a request has `Content-Type: application/toon`, Rails will automatically parse the body. You can also manually parse:
|
|
208
|
+
|
|
209
|
+
```ruby
|
|
210
|
+
class Api::UsersController < ApplicationController
|
|
211
|
+
def create
|
|
212
|
+
# Option 1: Automatic parsing (if Content-Type is application/toon)
|
|
213
|
+
# The body is automatically parsed into params
|
|
214
|
+
|
|
215
|
+
# Option 2: Manual parsing
|
|
216
|
+
user_data = parse_toon_request
|
|
217
|
+
@user = User.create(user_data)
|
|
218
|
+
render toon: { user: @user }
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Note:** The automatic parameter parser only works if the request has `Content-Type: application/toon` header. For manual parsing, use the `parse_toon_request` helper method.
|
|
224
|
+
|
|
225
|
+
#### Routes Configuration
|
|
226
|
+
|
|
227
|
+
Configure routes to accept TOON format:
|
|
228
|
+
|
|
229
|
+
```ruby
|
|
230
|
+
# config/routes.rb
|
|
231
|
+
Rails.application.routes.draw do
|
|
232
|
+
namespace :api do
|
|
233
|
+
resources :users, defaults: { format: :toon }
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
#### Available Controller Helpers
|
|
239
|
+
|
|
240
|
+
- `render_toon(data, options = {})` - Render TOON response
|
|
241
|
+
- `parse_toon_request` - Parse TOON request body
|
|
242
|
+
- `set_toon_format` - Set TOON as default format
|
|
243
|
+
- `respond_to_toon(data, options = {})` - Support multiple formats
|
|
244
|
+
|
|
245
|
+
### API Integration
|
|
246
|
+
|
|
247
|
+
Use the API helper for TOON-formatted API requests and responses:
|
|
248
|
+
|
|
249
|
+
```ruby
|
|
250
|
+
# Create an API client
|
|
251
|
+
api = ToonParser.api("https://api.example.com", headers: { "Authorization" => "Bearer token" })
|
|
252
|
+
|
|
253
|
+
# GET request
|
|
254
|
+
users = api.get("/users")
|
|
255
|
+
|
|
256
|
+
# POST request with TOON body
|
|
257
|
+
new_user = api.post("/users", data: { "name" => "Alice", "email" => "alice@example.com" })
|
|
258
|
+
|
|
259
|
+
# PUT request
|
|
260
|
+
updated = api.put("/users/1", data: { "name" => "Alice Updated" })
|
|
261
|
+
|
|
262
|
+
# PATCH request
|
|
263
|
+
patched = api.patch("/users/1", data: { "name" => "Alice Patched" })
|
|
264
|
+
|
|
265
|
+
# DELETE request
|
|
266
|
+
api.delete("/users/1")
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Advanced Usage
|
|
270
|
+
|
|
271
|
+
#### Nested Objects
|
|
272
|
+
|
|
273
|
+
```ruby
|
|
274
|
+
toon = <<~TOON
|
|
275
|
+
user:
|
|
276
|
+
id: 1
|
|
277
|
+
name: Alice
|
|
278
|
+
profile:
|
|
279
|
+
age: 30
|
|
280
|
+
city: New York
|
|
281
|
+
TOON
|
|
282
|
+
|
|
283
|
+
data = ToonParser.parse(toon)
|
|
284
|
+
# => {"user" => {"id" => 1, "name" => "Alice", "profile" => {"age" => 30, "city" => "New York"}}}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
#### Arrays of Primitives
|
|
288
|
+
|
|
289
|
+
```ruby
|
|
290
|
+
toon = <<~TOON
|
|
291
|
+
numbers[3]:
|
|
292
|
+
1
|
|
293
|
+
2
|
|
294
|
+
3
|
|
295
|
+
TOON
|
|
296
|
+
|
|
297
|
+
data = ToonParser.parse(toon)
|
|
298
|
+
# => {"numbers" => [1, 2, 3]}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
#### Boolean and Null Values
|
|
302
|
+
|
|
303
|
+
```ruby
|
|
304
|
+
toon = <<~TOON
|
|
305
|
+
data:
|
|
306
|
+
active: true
|
|
307
|
+
deleted: false
|
|
308
|
+
value: null
|
|
309
|
+
TOON
|
|
310
|
+
|
|
311
|
+
data = ToonParser.parse(toon)
|
|
312
|
+
# => {"data" => {"active" => true, "deleted" => false, "value" => nil}}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
#### Floating Point Numbers
|
|
316
|
+
|
|
317
|
+
```ruby
|
|
318
|
+
toon = <<~TOON
|
|
319
|
+
prices[2]:
|
|
320
|
+
19.99
|
|
321
|
+
29.50
|
|
322
|
+
TOON
|
|
323
|
+
|
|
324
|
+
data = ToonParser.parse(toon)
|
|
325
|
+
# => {"prices" => [19.99, 29.50]}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
## TOON Format Overview
|
|
329
|
+
|
|
330
|
+
TOON uses a compact syntax that eliminates unnecessary brackets, quotes, and whitespace:
|
|
331
|
+
|
|
332
|
+
**JSON:**
|
|
333
|
+
```json
|
|
334
|
+
{
|
|
335
|
+
"users": [
|
|
336
|
+
{ "id": 1, "name": "Alice" },
|
|
337
|
+
{ "id": 2, "name": "Bob" }
|
|
338
|
+
]
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
**TOON:**
|
|
343
|
+
```
|
|
344
|
+
users[2]{id,name}:
|
|
345
|
+
1,Alice
|
|
346
|
+
2,Bob
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### Key Features
|
|
350
|
+
|
|
351
|
+
- **Array notation**: `[size]` indicates array length
|
|
352
|
+
- **Object schema**: `{field1,field2}` defines object structure
|
|
353
|
+
- **Tabular data**: Rows are comma-separated values
|
|
354
|
+
- **Type inference**: Numbers, booleans, and null are automatically detected
|
|
355
|
+
- **Indentation**: Used for nesting and structure
|
|
356
|
+
- **Compact**: 30-60% smaller than JSON for typical data structures
|
|
357
|
+
|
|
358
|
+
## Examples
|
|
359
|
+
|
|
360
|
+
See the [examples directory](examples/) for more usage examples:
|
|
361
|
+
|
|
362
|
+
- [Rails Controller Example](examples/rails_controller_example.rb) - Complete Rails controller implementation
|
|
363
|
+
|
|
364
|
+
## Development
|
|
365
|
+
|
|
366
|
+
After checking out the repo, run:
|
|
367
|
+
|
|
368
|
+
```bash
|
|
369
|
+
$ bundle install
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
To run the test suite:
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
$ bundle exec rspec
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
Or run tests directly:
|
|
379
|
+
|
|
380
|
+
```bash
|
|
381
|
+
$ rspec spec/
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
To install this gem onto your local machine, run:
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
$ bundle exec rake install
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
To release a new version:
|
|
391
|
+
|
|
392
|
+
1. Update the version number in `lib/toon-parser/version.rb`
|
|
393
|
+
2. Run `bundle exec rake release`
|
|
394
|
+
|
|
395
|
+
This will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
396
|
+
|
|
397
|
+
## Contributing
|
|
398
|
+
|
|
399
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
400
|
+
|
|
401
|
+
1. Fork the repository
|
|
402
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
403
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
404
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
405
|
+
5. Open a Pull Request
|
|
406
|
+
|
|
407
|
+
### Development Setup
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
# Clone the repository
|
|
411
|
+
git clone https://github.com/afshmini/toon-parser.git
|
|
412
|
+
cd toon-parser
|
|
413
|
+
|
|
414
|
+
# Install dependencies
|
|
415
|
+
bundle install
|
|
416
|
+
|
|
417
|
+
# Run tests
|
|
418
|
+
bundle exec rspec
|
|
419
|
+
|
|
420
|
+
# Run linter
|
|
421
|
+
bundle exec rubocop
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
## License
|
|
425
|
+
|
|
426
|
+
The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
|
|
427
|
+
|
|
428
|
+
## Links
|
|
429
|
+
|
|
430
|
+
- [GitHub Repository](https://github.com/afshmini/toon-parser)
|
|
431
|
+
- [Issue Tracker](https://github.com/afshmini/toon-parser/issues)
|
|
432
|
+
- [RubyGems](https://rubygems.org/gems/toon-parser) (when published)
|
|
433
|
+
|
|
434
|
+
## Acknowledgments
|
|
435
|
+
|
|
436
|
+
- Inspired by the [TOON format specification](https://github.com/toon-format/spec)
|
|
437
|
+
- Designed to reduce token usage in LLM applications
|
data/Rakefile
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Example Rails Controller using TOON format
|
|
2
|
+
# Place this in app/controllers/api/users_controller.rb
|
|
3
|
+
|
|
4
|
+
class Api::UsersController < ApplicationController
|
|
5
|
+
# Set TOON as default format for this controller
|
|
6
|
+
before_action :set_toon_format
|
|
7
|
+
|
|
8
|
+
def index
|
|
9
|
+
@users = User.all
|
|
10
|
+
# Render as TOON format
|
|
11
|
+
render toon: {
|
|
12
|
+
users: @users.map do |user|
|
|
13
|
+
{
|
|
14
|
+
id: user.id,
|
|
15
|
+
name: user.name,
|
|
16
|
+
email: user.email,
|
|
17
|
+
created_at: user.created_at
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def show
|
|
24
|
+
@user = User.find(params[:id])
|
|
25
|
+
render toon: {
|
|
26
|
+
user: {
|
|
27
|
+
id: @user.id,
|
|
28
|
+
name: @user.name,
|
|
29
|
+
email: @user.email,
|
|
30
|
+
profile: {
|
|
31
|
+
bio: @user.bio,
|
|
32
|
+
avatar: @user.avatar_url
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def create
|
|
39
|
+
# Parse TOON request body
|
|
40
|
+
user_data = parse_toon_request
|
|
41
|
+
|
|
42
|
+
@user = User.new(user_data)
|
|
43
|
+
if @user.save
|
|
44
|
+
render toon: { user: @user }, status: :created
|
|
45
|
+
else
|
|
46
|
+
render toon: { errors: @user.errors.full_messages }, status: :unprocessable_entity
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def update
|
|
51
|
+
@user = User.find(params[:id])
|
|
52
|
+
user_data = parse_toon_request
|
|
53
|
+
|
|
54
|
+
if @user.update(user_data)
|
|
55
|
+
render toon: { user: @user }
|
|
56
|
+
else
|
|
57
|
+
render toon: { errors: @user.errors.full_messages }, status: :unprocessable_entity
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def destroy
|
|
62
|
+
@user = User.find(params[:id])
|
|
63
|
+
@user.destroy
|
|
64
|
+
render toon: { message: "User deleted successfully" }, status: :ok
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
private
|
|
68
|
+
|
|
69
|
+
def set_toon_format
|
|
70
|
+
# Set TOON as default format if not specified
|
|
71
|
+
request.format = :toon if request.format == :html
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Example: Support both TOON and JSON
|
|
76
|
+
class Api::ProductsController < ApplicationController
|
|
77
|
+
def index
|
|
78
|
+
@products = Product.all
|
|
79
|
+
data = {
|
|
80
|
+
products: @products.map { |p| { id: p.id, name: p.name, price: p.price } }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
respond_to do |format|
|
|
84
|
+
format.toon { render toon: data }
|
|
85
|
+
format.json { render json: data }
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|