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
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ToonParser
|
|
4
|
+
# Serializer for converting Ruby objects to TOON format
|
|
5
|
+
class Serializer
|
|
6
|
+
def initialize(indent: 2)
|
|
7
|
+
@indent_size = indent
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Serialize Ruby objects into TOON format
|
|
11
|
+
#
|
|
12
|
+
# @param data [Hash, Array] Ruby object to serialize
|
|
13
|
+
# @return [String] TOON formatted string
|
|
14
|
+
def serialize(data)
|
|
15
|
+
serialize_value(data, 0)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def serialize_value(value, level)
|
|
21
|
+
case value
|
|
22
|
+
when Hash
|
|
23
|
+
serialize_hash(value, level)
|
|
24
|
+
when Array
|
|
25
|
+
serialize_array(value, level)
|
|
26
|
+
else
|
|
27
|
+
serialize_primitive(value)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def serialize_hash(hash, level)
|
|
32
|
+
result = []
|
|
33
|
+
indent = " " * (level * @indent_size)
|
|
34
|
+
|
|
35
|
+
hash.each do |key, value|
|
|
36
|
+
key_str = key.to_s
|
|
37
|
+
|
|
38
|
+
case value
|
|
39
|
+
when Array
|
|
40
|
+
if array_of_objects?(value)
|
|
41
|
+
# Array of objects with schema
|
|
42
|
+
schema = detect_schema(value)
|
|
43
|
+
result << "#{indent}#{key_str}[#{value.size}]{#{schema.join(',')}}:"
|
|
44
|
+
value.each do |item|
|
|
45
|
+
row = serialize_object_row(item, schema)
|
|
46
|
+
result << "#{indent} #{row}"
|
|
47
|
+
end
|
|
48
|
+
else
|
|
49
|
+
# Simple array
|
|
50
|
+
result << "#{indent}#{key_str}[#{value.size}]:"
|
|
51
|
+
value.each do |item|
|
|
52
|
+
item_str = serialize_primitive(item)
|
|
53
|
+
result << "#{indent} #{item_str}"
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
when Hash
|
|
57
|
+
result << "#{indent}#{key_str}:"
|
|
58
|
+
result << serialize_hash(value, level + 1)
|
|
59
|
+
else
|
|
60
|
+
value_str = serialize_primitive(value)
|
|
61
|
+
result << "#{indent}#{key_str}: #{value_str}"
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
result.join("\n")
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def serialize_array(array, level)
|
|
69
|
+
result = []
|
|
70
|
+
indent = " " * (level * @indent_size)
|
|
71
|
+
|
|
72
|
+
if array_of_objects?(array)
|
|
73
|
+
# Array of objects with schema
|
|
74
|
+
schema = detect_schema(array)
|
|
75
|
+
result << "#{indent}[#{array.size}]{#{schema.join(',')}}:"
|
|
76
|
+
array.each do |item|
|
|
77
|
+
row = serialize_object_row(item, schema)
|
|
78
|
+
result << "#{indent} #{row}"
|
|
79
|
+
end
|
|
80
|
+
else
|
|
81
|
+
# Simple array
|
|
82
|
+
result << "#{indent}[#{array.size}]:"
|
|
83
|
+
array.each do |item|
|
|
84
|
+
item_str = serialize_primitive(item)
|
|
85
|
+
result << "#{indent} #{item_str}"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
result.join("\n")
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def array_of_objects?(array)
|
|
93
|
+
return false unless array.is_a?(Array) && !array.empty?
|
|
94
|
+
|
|
95
|
+
array.all? { |item| item.is_a?(Hash) }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def detect_schema(array)
|
|
99
|
+
return [] if array.empty?
|
|
100
|
+
|
|
101
|
+
# Get all unique keys from all objects
|
|
102
|
+
all_keys = array.flat_map(&:keys).uniq.map(&:to_s)
|
|
103
|
+
all_keys.sort
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def serialize_object_row(obj, schema)
|
|
107
|
+
values = schema.map do |key|
|
|
108
|
+
value = obj[key.to_sym] || obj[key]
|
|
109
|
+
serialize_primitive(value)
|
|
110
|
+
end
|
|
111
|
+
values.join(",")
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def serialize_primitive(value)
|
|
115
|
+
case value
|
|
116
|
+
when nil
|
|
117
|
+
"null"
|
|
118
|
+
when true
|
|
119
|
+
"true"
|
|
120
|
+
when false
|
|
121
|
+
"false"
|
|
122
|
+
when Integer, Float
|
|
123
|
+
value.to_s
|
|
124
|
+
when String
|
|
125
|
+
# Quote if contains special characters or spaces
|
|
126
|
+
if value.match?(/[,\s:\[\]{}]/) || value.empty?
|
|
127
|
+
"\"#{value.gsub('"', '\\"')}\""
|
|
128
|
+
else
|
|
129
|
+
value
|
|
130
|
+
end
|
|
131
|
+
else
|
|
132
|
+
value.to_s
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
data/lib/toon-parser.rb
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "toon-parser/version"
|
|
4
|
+
|
|
5
|
+
module ToonParser
|
|
6
|
+
class Error < StandardError; end
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
require_relative "toon-parser/parser"
|
|
10
|
+
require_relative "toon-parser/serializer"
|
|
11
|
+
require_relative "toon-parser/api"
|
|
12
|
+
|
|
13
|
+
# Load Rails integration if Rails is available
|
|
14
|
+
begin
|
|
15
|
+
require "rails"
|
|
16
|
+
require_relative "toon-parser/railtie"
|
|
17
|
+
require_relative "toon-parser/controller_helpers"
|
|
18
|
+
rescue LoadError
|
|
19
|
+
# Rails is not available, skip Rails integration
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
module ToonParser
|
|
23
|
+
|
|
24
|
+
# Parse a TOON string into Ruby objects
|
|
25
|
+
#
|
|
26
|
+
# @param toon_string [String] The TOON formatted string
|
|
27
|
+
# @return [Hash, Array] Parsed Ruby object
|
|
28
|
+
#
|
|
29
|
+
# @example
|
|
30
|
+
# ToonParser.parse("users[2]{id,name}:\n 1,Alice\n 2,Bob")
|
|
31
|
+
# # => {"users" => [{"id" => 1, "name" => "Alice"}, {"id" => 2, "name" => "Bob"}]}
|
|
32
|
+
def self.parse(toon_string)
|
|
33
|
+
Parser.new.parse(toon_string)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Serialize Ruby objects into TOON format
|
|
37
|
+
#
|
|
38
|
+
# @param data [Hash, Array] Ruby object to serialize
|
|
39
|
+
# @return [String] TOON formatted string
|
|
40
|
+
#
|
|
41
|
+
# @example
|
|
42
|
+
# ToonParser.serialize({"users" => [{"id" => 1, "name" => "Alice"}]})
|
|
43
|
+
# # => "users[1]{id,name}:\n 1,Alice"
|
|
44
|
+
def self.serialize(data)
|
|
45
|
+
Serializer.new.serialize(data)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Parse a TOON file
|
|
49
|
+
#
|
|
50
|
+
# @param file_path [String] Path to the TOON file
|
|
51
|
+
# @return [Hash, Array] Parsed Ruby object
|
|
52
|
+
def self.parse_file(file_path)
|
|
53
|
+
content = File.read(file_path)
|
|
54
|
+
parse(content)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Serialize Ruby objects to a TOON file
|
|
58
|
+
#
|
|
59
|
+
# @param data [Hash, Array] Ruby object to serialize
|
|
60
|
+
# @param file_path [String] Path where to save the TOON file
|
|
61
|
+
def self.serialize_to_file(data, file_path)
|
|
62
|
+
content = serialize(data)
|
|
63
|
+
File.write(file_path, content)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
data/toon-parser.gemspec
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/toon-parser/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "toon-parser"
|
|
7
|
+
spec.version = ToonParser::VERSION
|
|
8
|
+
spec.authors = ["afshmini"]
|
|
9
|
+
spec.email = [""]
|
|
10
|
+
|
|
11
|
+
spec.summary = "A Ruby gem for parsing and serializing TOON (Token-Oriented Object Notation) format"
|
|
12
|
+
spec.description = "Parse TOON files and handle TOON-formatted API requests/responses. TOON is a compact, human-readable data format designed to reduce token usage in LLM applications."
|
|
13
|
+
spec.homepage = "https://github.com/afshmini/toon-parser"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
spec.required_ruby_version = ">= 2.7.0"
|
|
16
|
+
|
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
18
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
|
19
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
20
|
+
|
|
21
|
+
# Specify which files should be added to the gem when it is released.
|
|
22
|
+
spec.files = Dir.chdir(__dir__) do
|
|
23
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
24
|
+
(File.expand_path(f) == __FILE__) ||
|
|
25
|
+
f.start_with?(*%w[bin/ test/ spec/ features/ .git .github appveyor Gemfile])
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
spec.bindir = "exe"
|
|
29
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
|
30
|
+
spec.require_paths = ["lib"]
|
|
31
|
+
|
|
32
|
+
# Dependencies
|
|
33
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
|
34
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
|
35
|
+
spec.add_development_dependency "rubocop", "~> 1.21"
|
|
36
|
+
end
|
|
37
|
+
|
metadata
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: toon-parser
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- afshmini
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: exe
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2025-11-20 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: rake
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '13.0'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '13.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rspec
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '3.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '3.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: rubocop
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '1.21'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '1.21'
|
|
55
|
+
description: Parse TOON files and handle TOON-formatted API requests/responses. TOON
|
|
56
|
+
is a compact, human-readable data format designed to reduce token usage in LLM applications.
|
|
57
|
+
email:
|
|
58
|
+
- ''
|
|
59
|
+
executables: []
|
|
60
|
+
extensions: []
|
|
61
|
+
extra_rdoc_files: []
|
|
62
|
+
files:
|
|
63
|
+
- ".rspec"
|
|
64
|
+
- CHANGELOG.md
|
|
65
|
+
- CONTRIBUTING.md
|
|
66
|
+
- LICENSE.txt
|
|
67
|
+
- README.md
|
|
68
|
+
- Rakefile
|
|
69
|
+
- examples/rails_controller_example.rb
|
|
70
|
+
- lib/toon-parser.rb
|
|
71
|
+
- lib/toon-parser/api.rb
|
|
72
|
+
- lib/toon-parser/controller_helpers.rb
|
|
73
|
+
- lib/toon-parser/parser.rb
|
|
74
|
+
- lib/toon-parser/railtie.rb
|
|
75
|
+
- lib/toon-parser/serializer.rb
|
|
76
|
+
- lib/toon-parser/version.rb
|
|
77
|
+
- toon-parser.gemspec
|
|
78
|
+
homepage: https://github.com/afshmini/toon-parser
|
|
79
|
+
licenses:
|
|
80
|
+
- MIT
|
|
81
|
+
metadata:
|
|
82
|
+
homepage_uri: https://github.com/afshmini/toon-parser
|
|
83
|
+
source_code_uri: https://github.com/afshmini/toon-parser
|
|
84
|
+
changelog_uri: https://github.com/afshmini/toon-parser/blob/main/CHANGELOG.md
|
|
85
|
+
post_install_message:
|
|
86
|
+
rdoc_options: []
|
|
87
|
+
require_paths:
|
|
88
|
+
- lib
|
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
90
|
+
requirements:
|
|
91
|
+
- - ">="
|
|
92
|
+
- !ruby/object:Gem::Version
|
|
93
|
+
version: 2.7.0
|
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
|
+
requirements:
|
|
96
|
+
- - ">="
|
|
97
|
+
- !ruby/object:Gem::Version
|
|
98
|
+
version: '0'
|
|
99
|
+
requirements: []
|
|
100
|
+
rubygems_version: 3.5.20
|
|
101
|
+
signing_key:
|
|
102
|
+
specification_version: 4
|
|
103
|
+
summary: A Ruby gem for parsing and serializing TOON (Token-Oriented Object Notation)
|
|
104
|
+
format
|
|
105
|
+
test_files: []
|