red-flatbuffers 0.0.2 → 0.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1eb93b3ed4172bc26d7550e590b718554d3b6ef3b47eb1c507003b8d6f8458d1
4
- data.tar.gz: 23995a6216f52ff1d7c47a3ab7ab8f73158feee7d01c2bfc6d2148f5c43d7d70
3
+ metadata.gz: 39624c3160429b2d1492aa6bcf66b0d4e8028cb11c2e5e8538a40014bbfaea58
4
+ data.tar.gz: 296cce04665d4cd2095b60e72e052dc650aede2215e9fba0a9dfd0082f64d242
5
5
  SHA512:
6
- metadata.gz: 7ddbb0daa892ba4b6853e06984d5e3e7c5b81cb454e6023a6b707c72b7eee5ccf8cd3914c6392b9251fbfbbb2d8327c2e933fd61b7874763ee350fdb7e58af6f
7
- data.tar.gz: 11b9ac47ace7e8f91a49ded297e69342bcd723cfc2c3572dbc50a07e02cbe3dcbebfe3e8c87b4247b5aab9201a1cab389d504e88fefab0073530e304109de023
6
+ metadata.gz: bc547bfdc66275abebf0160367c293ff5a3ab328fe6d191fc1ab00952fa6f578330dbe987cce19fba954d145a0881f757012b0e34d80ffeeb69c43cbfa341df1
7
+ data.tar.gz: 7436bbce98bb2fc5400a4392eef2cd7d1438c4585e97ec26f193b0aabd7410f0fda7241fd6be84a34712cbe59941e8b65d98de76b5532dedda9b134de551b2a8
data/doc/text/news.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # News
2
2
 
3
+ ## 0.0.4 - 2026-01-12
4
+
5
+ ### Improvements
6
+
7
+ * Added support for serializing.
8
+
9
+ ## 0.0.3 - 2025-11-28
10
+
11
+ ### Improvements
12
+
13
+ * Added support for outer namespaces in absolute class name.
14
+
15
+ ## 0.0.2 - 2025-11-28
16
+
17
+ ### Improvements
18
+
19
+ * Filled more gem metadata.
20
+
3
21
  ## 0.0.1 - 2025-11-28
4
22
 
5
23
  Initial release!!!
@@ -0,0 +1,42 @@
1
+ # Copyright 2026 Sutou Kouhei <kou@clear-code.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative "append_as_bytes"
16
+
17
+ module FlatBuffers
18
+ using AppendAsBytes if const_defined?(:AppendAsBytes)
19
+
20
+ module Alignable
21
+ LARGEST_ALIGNMENT_SIZE = 8 # IO::Buffer.size_of(:u64)
22
+ LARGEST_PADDING = "\x00" * 7
23
+
24
+ private
25
+ def compute_padding_size(size, alignment_byte)
26
+ (alignment_byte - (size & (alignment_byte - 1))) & (alignment_byte - 1)
27
+ end
28
+
29
+ def padding(padding_size)
30
+ LARGEST_PADDING[0, padding_size]
31
+ end
32
+
33
+ def pad!(data, padding_size)
34
+ return if padding_size.zero?
35
+ data.append_as_bytes(padding(padding_size))
36
+ end
37
+
38
+ def align!(data, alignment_byte)
39
+ pad!(data, compute_padding_size(data.bytesize, alignment_byte))
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,26 @@
1
+ # Copyright 2026 Sutou Kouhei <kou@clear-code.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # This is for Ruby < 3.4
16
+ unless String.method_defined?(:append_as_bytes)
17
+ module FlatBuffers
18
+ module AppendAsBytes
19
+ refine String do
20
+ def append_as_bytes(*objects)
21
+ concat(*objects)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,35 @@
1
+ # Copyright 2026 Sutou Kouhei <kou@clear-code.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module FlatBuffers
16
+ module DataDefinable
17
+ def define_data_class
18
+ if self::FIELDS.empty?
19
+ klass = Class.new
20
+ else
21
+ klass = ::Struct.new(*self::FIELDS.keys) do
22
+ members.each do |member|
23
+ next unless member.end_with?("?")
24
+ alias_method :"#{member.to_s.delete_suffix("?")}=", :"#{member}="
25
+ end
26
+ end
27
+ end
28
+ table_class = self
29
+ klass.singleton_class.define_method(:table_class) do
30
+ table_class
31
+ end
32
+ klass
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,21 @@
1
+ # Copyright 2026 Sutou Kouhei <kou@clear-code.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module FlatBuffers
16
+ class Error < StandardError
17
+ end
18
+
19
+ class VerificationError < Error
20
+ end
21
+ end
@@ -0,0 +1,57 @@
1
+ # Copyright 2025-2026 Sutou Kouhei <kou@clear-code.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative "view"
16
+
17
+ module FlatBuffers
18
+ class Field
19
+ attr_reader :name
20
+ attr_reader :index
21
+ attr_reader :offset
22
+ attr_reader :base_type
23
+ attr_reader :padding
24
+ def initialize(name, index, offset, base_type, padding)
25
+ @name = name
26
+ @index = index
27
+ @offset = offset
28
+ @base_type = base_type
29
+ @padding = padding
30
+ end
31
+
32
+ def alignment_size
33
+ case @base_type
34
+ when :utype
35
+ 4
36
+ when :bool, :byte, :ubyte
37
+ 1
38
+ when :short, :ushort
39
+ 2
40
+ when :int, :uint
41
+ 4
42
+ when :long, :ulong
43
+ 8
44
+ when :float
45
+ 4
46
+ when :double
47
+ 8
48
+ when :string
49
+ 4
50
+ when String
51
+ 4
52
+ when Array
53
+ 4
54
+ end
55
+ end
56
+ end
57
+ end
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Sutou Kouhei <kou@clear-code.com>
1
+ # Copyright 2025-2026 Sutou Kouhei <kou@clear-code.com>
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -70,6 +70,11 @@ module FlatBuffers
70
70
  components.join("::")
71
71
  end
72
72
 
73
+ def to_absolute_class_name(outer_namespaces, namespaces, name)
74
+ namespaces = outer_namespaces + namespaces if outer_namespaces
75
+ "::#{to_namespaced_class_name(namespaces, name)}"
76
+ end
77
+
73
78
  def to_constant_name(name)
74
79
  to_upper_snake_case(name)
75
80
  end
@@ -241,7 +246,9 @@ module FlatBuffers
241
246
  if enum.union?
242
247
  union = @schema.objects[value.union_type.index]
243
248
  *union_namespaces, union_name = denamespace(union.name)
244
- klass = "::#{to_namespaced_class_name(union_namespaces, union_name)}"
249
+ klass = to_absolute_class_name(@outer_namespaces,
250
+ union_namespaces,
251
+ union_name)
245
252
  relative_union_namespaces =
246
253
  resolve_namespaces(union_namespaces, namespaces)
247
254
  path_components = relative_union_namespaces.collect do |ns|
@@ -331,20 +338,113 @@ module FlatBuffers
331
338
  start_modules(writer, namespaces)
332
339
 
333
340
  if object.struct?
341
+ is_root_table = false
334
342
  parent = "::FlatBuffers::Struct"
335
343
  else
336
- parent = "::FlatBuffers::Table"
344
+ is_root_table = (object.name == @schema.root_table&.name)
345
+ if is_root_table
346
+ parent = "::FlatBuffers::RootTable"
347
+ else
348
+ parent = "::FlatBuffers::Table"
349
+ end
337
350
  end
338
351
  generate_documentation(writer, object.documentation)
339
352
  writer << "class #{to_class_name(name)} < #{parent}"
340
353
  writer.indent
341
354
 
342
- n_processed_fields = 0
355
+ if is_root_table
356
+ writer << "class << self"
357
+ writer.indent
358
+
359
+ writer << "def file_identifier"
360
+ writer.indent
361
+ writer << to_ruby_code(@schema.file_ident)
362
+ writer.end
363
+ writer << ""
364
+ writer << "def file_extension"
365
+ writer.indent
366
+ writer << to_ruby_code(@schema.file_ext)
367
+ writer.end
368
+
369
+ writer.end
370
+ writer << ""
371
+ end
372
+
373
+ generate_object_fields(writer, object)
374
+
375
+ writer << "Data = define_data_class"
376
+
377
+ generate_object_methods(writer, object, namespaces)
378
+
379
+ writer.end # class
380
+
381
+ end_modules(writer, namespaces)
382
+ end
383
+
384
+ def generate_object_fields(writer, object)
385
+ writer << "FIELDS = {"
386
+ writer.indent
387
+
388
+ offset_sorted_fields = object.fields&.sort_by(&:offset)
389
+ offset_sorted_fields&.each_with_index do |field, index|
390
+ # Skip writing deprecated fields altogether.
391
+ next if field.deprecated?
392
+
393
+ method_name = to_method_name(field.name)
394
+ type = field.type
395
+ base_type = type.base_type
396
+ if base_type == Reflection::BaseType::BOOL
397
+ method_name = "#{method_name}?".delete_prefix("is_")
398
+ end
399
+ ruby_index = to_ruby_code(index)
400
+ ruby_offset = to_ruby_code(field.offset)
401
+ case base_type
402
+ when Reflection::BaseType::OBJ
403
+ object = @schema.objects[type.index]
404
+ *object_namespaces, object_name = denamespace(object.name)
405
+ klass = to_absolute_class_name(@outer_namespaces,
406
+ object_namespaces,
407
+ object_name)
408
+ ruby_base_type = to_ruby_code(klass)
409
+ when Reflection::BaseType::UNION
410
+ union = @schema.enums[type.index]
411
+ *union_namespaces, union_name = denamespace(union.name)
412
+ klass = to_absolute_class_name(@outer_namespaces,
413
+ union_namespaces,
414
+ union_name)
415
+ ruby_base_type = to_ruby_code(klass)
416
+ when Reflection::BaseType::VECTOR
417
+ element_base_type = type.element
418
+ if element_base_type == Reflection::BaseType::OBJ
419
+ object = @schema.objects[type.index]
420
+ *object_namespaces, object_name = denamespace(object.name)
421
+ klass = to_absolute_class_name(@outer_namespaces,
422
+ object_namespaces,
423
+ object_name)
424
+ ruby_base_type = "[#{to_ruby_code(klass)}]"
425
+ else
426
+ ruby_base_type = "[:#{to_lower_snake_case(element_base_type.name)}]"
427
+ end
428
+ else
429
+ ruby_base_type = ":#{to_lower_snake_case(base_type.name)}"
430
+ end
431
+ ruby_padding = to_ruby_code(field.padding)
432
+ writer << ("#{method_name}: ::FlatBuffers::Field.new(" +
433
+ ":#{method_name}, #{ruby_index}, " +
434
+ "#{ruby_offset}, #{ruby_base_type}, #{ruby_padding}),")
435
+ end
436
+
437
+ writer.unindent
438
+ writer << "}"
439
+ writer << ""
440
+ end
441
+
442
+ def generate_object_methods(writer, object, namespaces)
343
443
  object.fields&.each do |field|
344
444
  # Skip writing deprecated fields altogether.
345
445
  next if field.deprecated?
346
446
 
347
- writer << "" if n_processed_fields > 0
447
+ writer << ""
348
448
 
349
449
  method_name = to_method_name(field.name)
350
450
  type = field.type
@@ -464,13 +564,7 @@ module FlatBuffers
464
564
  writer.end
465
565
  end
466
566
  writer.end
467
-
468
- n_processed_fields += 1
469
567
  end
470
-
471
- writer.end # class
472
-
473
- end_modules(writer, namespaces)
474
568
  end
475
569
 
476
570
  def generate_documentation(writer, documentation)
@@ -578,7 +672,7 @@ module FlatBuffers
578
672
  to_namespaced_class_name(relative_namespaces, name)
579
673
  else
580
674
  # We need to use absolute hierarchy
581
- "::#{to_namespaced_class_name(namespaces, name)}"
675
+ to_absolute_class_name(@outer_namespaces, namespaces, name)
582
676
  end
583
677
  end
584
678
  end
@@ -0,0 +1,57 @@
1
+ # Copyright 2025-2026 Sutou Kouhei <kou@clear-code.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative "serializer"
16
+ require_relative "table"
17
+ require_relative "view"
18
+
19
+ module FlatBuffers
20
+ class RootTable < Table
21
+ class << self
22
+ def save(base_name, data)
23
+ name = "#{base_name}.#{file_extension}"
24
+ File.open(name, "wb") do |output|
25
+ output.print(serialize(data))
26
+ end
27
+ end
28
+
29
+ def serialize(data, table_serializer=nil)
30
+ if table_serializer
31
+ # Referenced table
32
+ super(data, table_serializer)
33
+ else
34
+ # Root table
35
+ serializer = Serializer.new(file_identifier)
36
+ serializer.start_table do |table_serializer|
37
+ super(data, table_serializer)
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def initialize(input)
44
+ if input.is_a?(View)
45
+ # Referenced table
46
+ super
47
+ else
48
+ # Root table
49
+ if input.is_a?(String)
50
+ input = IO::Buffer.for(input)
51
+ end
52
+ offset = input.get_value(:u32, 0)
53
+ super(View.new(input, offset, have_vtable: true))
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,348 @@
1
+ # Copyright 2026 Sutou Kouhei <kou@clear-code.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative "alignable"
16
+
17
+ module FlatBuffers
18
+ using AppendAsBytes if const_defined?(:AppendAsBytes)
19
+
20
+ class Serializer
21
+ module Packable
22
+ private
23
+ def pack_value(base_type, value)
24
+ case base_type
25
+ when :bool
26
+ [value ? 1 : 0].pack("c")
27
+ when :utype
28
+ [value || 0].pack("C")
29
+ when :byte
30
+ [value || 0].pack("c")
31
+ when :ubyte
32
+ [value || 0].pack("C")
33
+ when :short
34
+ [value || 0].pack("s<")
35
+ when :ushort
36
+ [value || 0].pack("S<")
37
+ when :int
38
+ [value || 0].pack("l<")
39
+ when :uint
40
+ [value || 0].pack("L<")
41
+ when :long
42
+ [value || 0].pack("q<")
43
+ when :ulong
44
+ [value || 0].pack("Q<")
45
+ when :float
46
+ [value || 0.0].pack("e")
47
+ when :double
48
+ [value || 0.0].pack("E")
49
+ when :string
50
+ value ||= ""
51
+ packed_value = [value.bytesize].pack("L<")
52
+ packed_value.append_as_bytes(value)
53
+ packed_value.append_as_bytes("\x00")
54
+ packed_value
55
+ when String
56
+ klass = Object.const_get(base_type)
57
+ if klass < Struct
58
+ sub_struct_serializer = StructSerializer.new(+"".b)
59
+ klass.serialize(value, sub_struct_serializer)
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ class StructSerializer
66
+ include Alignable
67
+ include Packable
68
+
69
+ def initialize(buffer)
70
+ @buffer = buffer
71
+ end
72
+
73
+ def start
74
+ yield
75
+ finish
76
+ end
77
+
78
+ def add_field(field, value)
79
+ packed_value = pack_value(field.base_type, value)
80
+ @buffer.append_as_bytes(packed_value)
81
+ unless field.padding.zero?
82
+ pad!(@buffer, field.padding)
83
+ end
84
+ end
85
+
86
+ def finish
87
+ @buffer
88
+ end
89
+ end
90
+
91
+ class TableSerializer
92
+ include Alignable
93
+ include Packable
94
+
95
+ DUMMY_OFFSET = [0].pack("L<")
96
+
97
+ def initialize
98
+ @field_metadata = {}
99
+ # vtable_offset. This is replaced later.
100
+ @table = DUMMY_OFFSET.dup
101
+ @values = +"".b
102
+ end
103
+
104
+ def start
105
+ yield
106
+ finish
107
+ end
108
+
109
+ def add_field(field, value)
110
+ if value.nil?
111
+ @field_metadata[field] = {
112
+ inline: true,
113
+ offset: nil,
114
+ }
115
+ else
116
+ case field.base_type
117
+ when String
118
+ add_field_object(field, value)
119
+ when Array
120
+ add_field_array(field, value)
121
+ when :string
122
+ align!(@table, View::OFFSET_SIZE)
123
+ @field_metadata[field] = {
124
+ inline: false,
125
+ table_offset: @table.bytesize,
126
+ value_offset: @values.bytesize,
127
+ }
128
+ @values.append_as_bytes(pack_value(field.base_type, value))
129
+ @table.append_as_bytes(DUMMY_OFFSET) # Replaced later
130
+ else
131
+ align!(@table, field.alignment_size)
132
+ @field_metadata[field] = {
133
+ inline: true,
134
+ offset: @table.bytesize,
135
+ }
136
+ @table.append_as_bytes(pack_value(field.base_type, value))
137
+ end
138
+ end
139
+ end
140
+
141
+ def finish
142
+ vtable_size = View::VTable.compute_size(@field_metadata.size)
143
+ align!(@table, LARGEST_ALIGNMENT_SIZE)
144
+ table_size = @table.bytesize
145
+
146
+ field_offsets = []
147
+ @field_metadata.each do |field, metadata|
148
+ if metadata[:inline] # Scalar or struct
149
+ offset = metadata[:offset]
150
+ if offset.nil?
151
+ field_offsets[field.index] = 0
152
+ else
153
+ field_offsets[field.index] = offset
154
+ end
155
+ else # Table, string or vector.
156
+ # |vtable|@table|@values|
157
+ #
158
+ # `vtable:` |vtable_size|table_size|field_offsets|
159
+ # `field_offsets` uses relative offset from the start of
160
+ # `vtable`.
161
+ #
162
+ # `@table`: |vtable_offset|fields|
163
+ # `fields` uses relative offset from itself.
164
+
165
+ # The offset in `fields`. This is relative from the start
166
+ # of `@table`.
167
+ table_offset = metadata[:table_offset]
168
+ # The offset in `@values`. This is relative from the start
169
+ # of `@table`.
170
+ value_offset = metadata[:value_offset]
171
+ # `@values` is placed just after `@table`.
172
+ # `offset` is relative from `table_offset`.
173
+ offset = table_size - table_offset + value_offset
174
+ @table[table_offset, View::Table::VTABLE_OFFSET_SIZE] =
175
+ [offset].pack("L<")
176
+ field_offsets[field.index] = table_offset
177
+ end
178
+ end
179
+ field_offsets.each_with_index do |offset, i|
180
+ field_offsets[i] = 0 if offset.nil?
181
+ end
182
+
183
+ data = +"".b
184
+ vtable = View::VTable.serialize(vtable_size,
185
+ table_size,
186
+ field_offsets)
187
+ data.append_as_bytes(vtable)
188
+ # We don't need "-" here because vtable_offset is subtracted
189
+ # (not added).
190
+ vtable_offset = vtable_size
191
+ @table[0, View::Table::VTABLE_OFFSET_SIZE] = [vtable_offset].pack("l<")
192
+ data.append_as_bytes(@table)
193
+ align!(@values, LARGEST_ALIGNMENT_SIZE)
194
+ data.append_as_bytes(@values)
195
+ table_offset = vtable_size
196
+ [data, table_offset]
197
+ end
198
+
199
+ private
200
+ # Struct, union or table
201
+ def add_field_object(field, value)
202
+ align!(@table, View::OFFSET_SIZE)
203
+ klass = Object.const_get(field.base_type)
204
+ if klass < Struct
205
+ @field_metadata[field] = {
206
+ inline: true,
207
+ offset: @table.bytesize,
208
+ }
209
+ sub_struct_serializer = StructSerializer.new(@table)
210
+ klass.serialize(value, sub_struct_serializer)
211
+ elsif klass < Union
212
+ align!(@values, LARGEST_ALIGNMENT_SIZE)
213
+ sub_table_serializer = TableSerializer.new
214
+ sub_table_data, sub_table_offset =
215
+ value.class.table_class.serialize(value, sub_table_serializer)
216
+ @field_metadata[field] = {
217
+ inline: false,
218
+ table_offset: @table.bytesize,
219
+ value_offset: @values.bytesize + sub_table_offset,
220
+ }
221
+ @values.append_as_bytes(sub_table_data)
222
+ @table.append_as_bytes(DUMMY_OFFSET) # Replaced later
223
+ else
224
+ align!(@values, LARGEST_ALIGNMENT_SIZE)
225
+ sub_table_serializer = TableSerializer.new
226
+ sub_table_data, sub_table_offset =
227
+ klass.serialize(value, sub_table_serializer)
228
+ @field_metadata[field] = {
229
+ inline: false,
230
+ table_offset: @table.bytesize,
231
+ value_offset: @values.bytesize + sub_table_offset,
232
+ }
233
+ @values.append_as_bytes(sub_table_data)
234
+ @table.append_as_bytes(DUMMY_OFFSET) # Replaced later
235
+ end
236
+ end
237
+
238
+ def add_field_array(field, value)
239
+ align!(@table, View::OFFSET_SIZE)
240
+ align!(@values, View::OFFSET_SIZE)
241
+ value_offset = @values.bytesize
242
+ # The number of elements.
243
+ @values.append_as_bytes([value.size].pack("L<"))
244
+ element_base_type = field.base_type[0]
245
+ case element_base_type
246
+ when String
247
+ klass = Object.const_get(element_base_type)
248
+ if klass < Struct
249
+ value.each do |v|
250
+ sub_struct_serializer = StructSerializer.new(@values)
251
+ klass.serialize(v, sub_struct_serializer)
252
+ end
253
+ else
254
+ offset_base = @values.bytesize
255
+ # Placeholder for offsets.
256
+ value.size.times do
257
+ @values.append_as_bytes(DUMMY_OFFSET) # Replaced later
258
+ end
259
+ align!(@values, LARGEST_ALIGNMENT_SIZE)
260
+ value.each do |v|
261
+ sub_table_serializer = TableSerializer.new
262
+ sub_table_data, sub_table_offset =
263
+ klass.serialize(v, sub_table_serializer)
264
+
265
+ element_offset = @values.bytesize + sub_table_offset
266
+ # Update offset placeholder.
267
+ relative_element_offset = element_offset - offset_base
268
+ @values[offset_base, View::OFFSET_SIZE] =
269
+ [relative_element_offset].pack("L<")
270
+ offset_base += View::OFFSET_SIZE
271
+
272
+ @values.append_as_bytes(sub_table_data)
273
+ end
274
+ end
275
+ @field_metadata[field] = {
276
+ inline: false,
277
+ table_offset: @table.bytesize,
278
+ value_offset: value_offset,
279
+ }
280
+ when :string
281
+ offset_base = @values.bytesize
282
+ # Placeholder for offsets.
283
+ value.size.times do
284
+ @values.append_as_bytes(DUMMY_OFFSET) # Replaced later
285
+ end
286
+ value.each do |v|
287
+ packed_value = pack_value(element_base_type, v)
288
+
289
+ element_offset = @values.bytesize
290
+ # Update offset placeholder.
291
+ relative_element_offset = element_offset - offset_base
292
+ @values[offset_base, View::OFFSET_SIZE] =
293
+ [relative_element_offset].pack("L<")
294
+ offset_base += View::OFFSET_SIZE
295
+
296
+ @values.append_as_bytes(packed_value)
297
+ end
298
+ @field_metadata[field] = {
299
+ inline: false,
300
+ table_offset: @table.bytesize,
301
+ value_offset: value_offset,
302
+ }
303
+ else
304
+ value.each do |v|
305
+ packed_value = pack_value(element_base_type, v)
306
+ @values.append_as_bytes(packed_value)
307
+ end
308
+ @field_metadata[field] = {
309
+ inline: false,
310
+ table_offset: @table.bytesize,
311
+ value_offset: value_offset,
312
+ }
313
+ end
314
+ @table.append_as_bytes(DUMMY_OFFSET) # Replaced later
315
+ end
316
+ end
317
+
318
+ include Alignable
319
+
320
+ def initialize(identifier)
321
+ identifier = nil if identifier.is_a?(String) and identifier.empty?
322
+ validate_identifier(identifier)
323
+ @identifier = identifier
324
+ end
325
+
326
+ def start_table
327
+ table_serializer = TableSerializer.new
328
+ table, table_offset = yield(table_serializer)
329
+ header_size = View::OFFSET_SIZE
330
+ header_size += View::IDENTIFIER_SIZE if @identifier
331
+ header_size += compute_padding_size(header_size, LARGEST_ALIGNMENT_SIZE)
332
+ root_table_offset = header_size + table_offset
333
+ data = [root_table_offset].pack("L<")
334
+ data.append_as_bytes(@identifier) if @identifier
335
+ align!(data, LARGEST_ALIGNMENT_SIZE)
336
+ data.append_as_bytes(table)
337
+ data
338
+ end
339
+
340
+ private
341
+ def validate_identifier(identifier)
342
+ return if identifier.nil?
343
+ return if identifier.bytesize == View::IDENTIFIER_SIZE
344
+ raise ArgumentError,
345
+ "Identifier must be nil or 4 bytes string: #{identifier.inspect}"
346
+ end
347
+ end
348
+ end
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Sutou Kouhei <kou@clear-code.com>
1
+ # Copyright 2025-2026 Sutou Kouhei <kou@clear-code.com>
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -12,15 +12,34 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ require_relative "data_definable"
15
16
  require_relative "inspectable"
16
- require_relative "view"
17
17
 
18
18
  module FlatBuffers
19
19
  class Struct
20
+ extend DataDefinable
20
21
  include Inspectable
21
22
 
23
+ class << self
24
+ def serialize(data, struct_serializer)
25
+ struct_serializer.start do
26
+ self::FIELDS.each do |name, field|
27
+ value = data&.public_send(name)
28
+ struct_serializer.add_field(field, value)
29
+ end
30
+ end
31
+ end
32
+ end
33
+
22
34
  def initialize(view)
23
35
  @view = view
24
36
  end
37
+
38
+ def ==(other)
39
+ return false unless other.is_a?(self.class)
40
+ self.class::FIELDS.keys.all? do |name|
41
+ public_send(name) == other.public_send(name)
42
+ end
43
+ end
25
44
  end
26
45
  end
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Sutou Kouhei <kou@clear-code.com>
1
+ # Copyright 2025-2026 Sutou Kouhei <kou@clear-code.com>
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -12,22 +12,60 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ require_relative "data_definable"
16
+ require_relative "field"
15
17
  require_relative "inspectable"
16
- require_relative "view"
17
18
 
18
19
  module FlatBuffers
19
20
  class Table
20
21
  include Inspectable
22
+ extend DataDefinable
21
23
 
22
- def initialize(input)
23
- if input.is_a?(View)
24
- @view = input
25
- else
26
- if input.is_a?(String)
27
- input = IO::Buffer.for(input)
24
+ class << self
25
+ def table_class
26
+ self
27
+ end
28
+
29
+ def serialize(data, table_serializer)
30
+ table_serializer.start do
31
+ self::FIELDS.each do |name, field|
32
+ if field.base_type == :utype
33
+ union_field_name = :"#{name.to_s.delete_suffix("_type")}"
34
+ union_field = self::FIELDS[union_field_name]
35
+ union_value = data.public_send(union_field_name)
36
+ if union_value.nil?
37
+ value = nil
38
+ else
39
+ union_class = Object.const_get(union_field.base_type)
40
+ value = union_class.try_convert(union_value.class.table_class)
41
+ end
42
+ else
43
+ value = data.public_send(name)
44
+ end
45
+ table_serializer.add_field(field, value)
46
+ end
28
47
  end
29
- offset = input.get_value(:u32, 0)
30
- @view = View.new(input, offset, have_vtable: true)
48
+ end
49
+ end
50
+
51
+ def initialize(view)
52
+ unless view.is_a?(View)
53
+ # For backward compatibility
54
+ if view.is_a?(IO::Buffer)
55
+ buffer = view
56
+ else
57
+ buffer = IO::Buffer.for(view)
58
+ end
59
+ offset = buffer.get_value(:u32, 0)
60
+ view = View.new(buffer, offset, have_vtable: true)
61
+ end
62
+ @view = view
63
+ end
64
+
65
+ def ==(other)
66
+ return false unless other.is_a?(self.class)
67
+ self.class::FIELDS.keys.all? do |name|
68
+ public_send(name) == other.public_send(name)
31
69
  end
32
70
  end
33
71
  end
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Sutou Kouhei <kou@clear-code.com>
1
+ # Copyright 2025-2026 Sutou Kouhei <kou@clear-code.com>
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -24,7 +24,13 @@ module FlatBuffers
24
24
  when self
25
25
  value
26
26
  else
27
- nil
27
+ if value < Table
28
+ @name_to_union.values.find do |union|
29
+ union.table_class == value
30
+ end
31
+ else
32
+ nil
33
+ end
28
34
  end
29
35
  end
30
36
 
@@ -0,0 +1,54 @@
1
+ # Copyright 2026 Sutou Kouhei <kou@clear-code.com>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require_relative "append_as_bytes"
16
+
17
+ module FlatBuffers
18
+ class Verifier
19
+ def initialize(target)
20
+ @target = target
21
+ end
22
+
23
+ def verify
24
+ view = @target.instance_variable_get(:@view)
25
+ @target.class::FIELDS.each_value do |field|
26
+ offset = view.offset + view.unpack_virtual_offset(field.offset)
27
+ verify_alignment(field, offset)
28
+ case field.base_type
29
+ when String
30
+ sub_target = @target.public_send(field.name)
31
+ next if sub_target.nil?
32
+ next if sub_target.is_a?(Struct)
33
+ Verifier.new(sub_target).verify
34
+ when Array
35
+ next unless field.base_type[0].is_a?(String)
36
+ @target.public_send(field.name)&.each do |value|
37
+ next if value.is_a?(Struct)
38
+ Verifier.new(value).verify
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ private
45
+ def verify_alignment(field, offset)
46
+ unless (offset % field.alignment_size).zero?
47
+ message = "#{@target.class.name}'s #{field.name} " +
48
+ "(#{field.base_type}) value isn't aligned: #{offset}: " +
49
+ "#{field.alignment_size}"
50
+ raise VerificationError.new(message)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -13,5 +13,5 @@
13
13
  # limitations under the License.
14
14
 
15
15
  module FlatBuffers
16
- VERSION = "0.0.2"
16
+ VERSION = "0.0.4"
17
17
  end
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Sutou Kouhei <kou@clear-code.com>
1
+ # Copyright 2025-2026 Sutou Kouhei <kou@clear-code.com>
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -12,11 +12,78 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ require_relative "alignable"
16
+
15
17
  module FlatBuffers
18
+ using AppendAsBytes if const_defined?(:AppendAsBytes)
19
+
16
20
  class View
17
- OFFSET_BYTE_SIZE = 4
18
- VIRTUAL_OFFSET_BYTE_SIZE = 2
21
+ OFFSET_SIZE = 4 # IO::Buffer.size_of(:u32)
22
+ VIRTUAL_OFFSET_SIZE = 2 # IO::Buffer.size_of(:u16)
23
+ IDENTIFIER_SIZE = 4
24
+
25
+ module VTable
26
+ # https://flatbuffers.dev/internals/#tables
27
+ #
28
+ # vtable_size: voffset_t (== uint16_t)
29
+ # table_size: voffset_t (== uint16_t)
30
+ # field_offsets: [voffset_t (== uint16_t)]
31
+
32
+ VTABLE_SIZE_SIZE = VIRTUAL_OFFSET_SIZE
33
+ TABLE_SIZE_SIZE = VIRTUAL_OFFSET_SIZE
34
+
35
+ class << self
36
+ include Alignable
37
+
38
+ def compute_size(n_fields)
39
+ size = VTABLE_SIZE_SIZE +
40
+ TABLE_SIZE_SIZE +
41
+ (VIRTUAL_OFFSET_SIZE * n_fields)
42
+ size += compute_padding_size(size, LARGEST_ALIGNMENT_SIZE)
43
+ size
44
+ end
45
+
46
+ def compute_field_index(offset)
47
+ # offset includes vtable_size and table_size.
48
+ field_offset = (offset - VTABLE_SIZE_SIZE - TABLE_SIZE_SIZE)
49
+ field_offset / VIRTUAL_OFFSET_SIZE
50
+ end
51
+
52
+ def serialize(vtable_size, table_size, field_offsets)
53
+ data = [vtable_size, table_size, *field_offsets].pack("S<*")
54
+ align!(data, LARGEST_ALIGNMENT_SIZE)
55
+ data
56
+ end
57
+ end
58
+ end
59
+
60
+ module Table
61
+ # https://flatbuffers.dev/internals/#tables
62
+ #
63
+ # vtable_offset: soffset_t (== int32_t)
64
+ # fields: []
65
+
66
+ VTABLE_OFFSET_SIZE = OFFSET_SIZE
67
+
68
+ class << self
69
+ include Alignable
19
70
 
71
+ def compute_size(fields_size)
72
+ size = VTABLE_OFFSET_SIZE + fields_size
73
+ size += compute_padding_size(size, LARGEST_ALIGNMENT_SIZE)
74
+ size
75
+ end
76
+
77
+ def serialize(vtable_offset, fields)
78
+ data = [vtable_offset].pack("l<")
79
+ data.append_as_bytes(fields)
80
+ align!(data, LARGEST_ALIGNMENT_SIZE)
81
+ data
82
+ end
83
+ end
84
+ end
85
+
86
+ attr_reader :offset
20
87
  def initialize(data, offset, have_vtable: false)
21
88
  @data = data
22
89
  @offset = offset
@@ -24,15 +91,15 @@ module FlatBuffers
24
91
  vtable_offset = unpack_signed_offset(0)
25
92
  @vtable_start = @offset - vtable_offset
26
93
  # We assume vtable must have length.
27
- @vtable_max_offset = VIRTUAL_OFFSET_BYTE_SIZE
28
- @vtable_length = unpack_virtual_offset(0)
29
- @vtable_max_offset = @vtable_length - VIRTUAL_OFFSET_BYTE_SIZE
30
- @table_length = unpack_virtual_offset(VIRTUAL_OFFSET_BYTE_SIZE)
94
+ @vtable_max_offset = VTable::VTABLE_SIZE_SIZE
95
+ @vtable_size = unpack_virtual_offset(0)
96
+ @vtable_max_offset = @vtable_size
97
+ @table_size = unpack_virtual_offset(VTable::TABLE_SIZE_SIZE)
31
98
  end
32
99
  end
33
100
 
34
101
  def unpack_virtual_offset(vtable_offset)
35
- return 0 if vtable_offset > @vtable_max_offset
102
+ return 0 if (vtable_offset + VIRTUAL_OFFSET_SIZE > @vtable_max_offset)
36
103
  @data.get_value(:u16, @vtable_start + vtable_offset)
37
104
  end
38
105
 
@@ -103,7 +170,7 @@ module FlatBuffers
103
170
  def unpack_string(offset)
104
171
  value_offset = resolve_indirect(offset)
105
172
  length = unpack_offset_raw(value_offset)
106
- @data.get_string(value_offset + OFFSET_BYTE_SIZE,
173
+ @data.get_string(value_offset + OFFSET_SIZE,
107
174
  length)
108
175
  end
109
176
 
@@ -135,42 +202,12 @@ module FlatBuffers
135
202
  length = unpack_offset(relative_vector_offset)
136
203
  return nil if length.zero?
137
204
 
138
- relative_vector_body_offset = relative_vector_offset + OFFSET_BYTE_SIZE
205
+ relative_vector_body_offset = relative_vector_offset + OFFSET_SIZE
139
206
  length.times.collect do |i|
140
207
  relative_element_offset =
141
208
  relative_vector_body_offset + (element_size * i)
142
209
  yield(relative_element_offset)
143
210
  end
144
211
  end
145
-
146
- def unpack_bool_vector(offset, element_size)
147
- unpack_vector(offset, element_size) do |relative_element_offset|
148
- unpack_bool(relative_element_offset)
149
- end
150
- end
151
-
152
- def unpack_ubyte_vector(offset, element_size)
153
- unpack_vector(offset, element_size) do |relative_element_offset|
154
- unpack_ubyte(relative_element_offset)
155
- end
156
- end
157
-
158
- def unpack_string_vector(offset, element_size)
159
- unpack_vector(offset, element_size) do |relative_element_offset|
160
- unpack_string(relative_element_offset)
161
- end
162
- end
163
-
164
- def unpack_table_vector(offset, element_size, klass)
165
- unpack_vector(offset, element_size) do |relative_element_offset|
166
- unpack_table(klass, relative_element_offset)
167
- end
168
- end
169
-
170
- def unpack_struct_vector(offset, element_size, klass)
171
- unpack_vector(offset, element_size) do |relative_element_offset|
172
- unpack_struct(klass, relative_element_offset)
173
- end
174
- end
175
212
  end
176
213
  end
data/lib/flatbuffers.rb CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2025 Sutou Kouhei <kou@clear-code.com>
1
+ # Copyright 2025-2026 Sutou Kouhei <kou@clear-code.com>
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -12,9 +12,12 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
+ require_relative "flatbuffers/serializer"
15
16
  require_relative "flatbuffers/enum"
17
+ require_relative "flatbuffers/error"
16
18
  require_relative "flatbuffers/flags"
17
19
  require_relative "flatbuffers/struct"
18
- require_relative "flatbuffers/table"
20
+ require_relative "flatbuffers/root_table"
19
21
  require_relative "flatbuffers/union"
22
+ require_relative "flatbuffers/verifier"
20
23
  require_relative "flatbuffers/version"
@@ -33,6 +33,7 @@ Gem::Specification.new do |spec|
33
33
  description = clean_white_space.call(entries[2])
34
34
  spec.summary, spec.description, = description.split(/\n\n+/, 3)
35
35
  spec.license = "Apache-2.0"
36
+ spec.required_ruby_version = ">= 3.1.0"
36
37
  spec.files = ["README.md", "#{spec.name}.gemspec"]
37
38
  spec.files += Dir.glob("lib/**/*.rb")
38
39
  spec.files += Dir.glob("doc/text/*")
@@ -40,10 +41,6 @@ Gem::Specification.new do |spec|
40
41
  spec.executables = Dir.glob("*")
41
42
  end
42
43
 
43
- spec.add_development_dependency("bundler")
44
- spec.add_development_dependency("rake")
45
- spec.add_development_dependency("test-unit")
46
-
47
44
  spec.metadata = {
48
45
  "bug_tracker_uri" => "#{spec.homepage}/issues",
49
46
  "changelog_uri" => "#{spec.homepage}/releases/tag/#{spec.version}",
metadata CHANGED
@@ -1,56 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: red-flatbuffers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sutou Kouhei
8
8
  bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
- dependencies:
12
- - !ruby/object:Gem::Dependency
13
- name: bundler
14
- requirement: !ruby/object:Gem::Requirement
15
- requirements:
16
- - - ">="
17
- - !ruby/object:Gem::Version
18
- version: '0'
19
- type: :development
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - ">="
24
- - !ruby/object:Gem::Version
25
- version: '0'
26
- - !ruby/object:Gem::Dependency
27
- name: rake
28
- requirement: !ruby/object:Gem::Requirement
29
- requirements:
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: '0'
33
- type: :development
34
- prerelease: false
35
- version_requirements: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - ">="
38
- - !ruby/object:Gem::Version
39
- version: '0'
40
- - !ruby/object:Gem::Dependency
41
- name: test-unit
42
- requirement: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - ">="
45
- - !ruby/object:Gem::Version
46
- version: '0'
47
- type: :development
48
- prerelease: false
49
- version_requirements: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - ">="
52
- - !ruby/object:Gem::Version
53
- version: '0'
11
+ dependencies: []
54
12
  description: 'Red FlatBuffers can generate Ruby code that reads and writes (not implemented
55
13
  yet) FlatBuffers from `.fbfs` (binary FlatBuffers schema). Red FlatBuffers can''t
56
14
  compile `.fbs` (FlatBuffers schema) to `.fbfs`. You need to use FlatBuffers to compile
@@ -69,8 +27,13 @@ files:
69
27
  - doc/text/apache-2.0.txt
70
28
  - doc/text/news.md
71
29
  - lib/flatbuffers.rb
30
+ - lib/flatbuffers/alignable.rb
31
+ - lib/flatbuffers/append_as_bytes.rb
72
32
  - lib/flatbuffers/command/rbflatc.rb
33
+ - lib/flatbuffers/data_definable.rb
73
34
  - lib/flatbuffers/enum.rb
35
+ - lib/flatbuffers/error.rb
36
+ - lib/flatbuffers/field.rb
74
37
  - lib/flatbuffers/flags.rb
75
38
  - lib/flatbuffers/generator.rb
76
39
  - lib/flatbuffers/inspectable.rb
@@ -86,9 +49,12 @@ files:
86
49
  - lib/flatbuffers/reflection/schema_file.rb
87
50
  - lib/flatbuffers/reflection/service.rb
88
51
  - lib/flatbuffers/reflection/type.rb
52
+ - lib/flatbuffers/root_table.rb
53
+ - lib/flatbuffers/serializer.rb
89
54
  - lib/flatbuffers/struct.rb
90
55
  - lib/flatbuffers/table.rb
91
56
  - lib/flatbuffers/union.rb
57
+ - lib/flatbuffers/verifier.rb
92
58
  - lib/flatbuffers/version.rb
93
59
  - lib/flatbuffers/view.rb
94
60
  - red-flatbuffers.gemspec
@@ -97,7 +63,7 @@ licenses:
97
63
  - Apache-2.0
98
64
  metadata:
99
65
  bug_tracker_uri: https://github.com/red-data-tools/red-flatbuffers/issues
100
- changelog_uri: https://github.com/red-data-tools/red-flatbuffers/releases/tag/0.0.2
66
+ changelog_uri: https://github.com/red-data-tools/red-flatbuffers/releases/tag/0.0.4
101
67
  source_code_uri: https://github.com/red-data-tools/red-flatbuffers
102
68
  rdoc_options: []
103
69
  require_paths:
@@ -106,14 +72,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
106
72
  requirements:
107
73
  - - ">="
108
74
  - !ruby/object:Gem::Version
109
- version: '0'
75
+ version: 3.1.0
110
76
  required_rubygems_version: !ruby/object:Gem::Requirement
111
77
  requirements:
112
78
  - - ">="
113
79
  - !ruby/object:Gem::Version
114
80
  version: '0'
115
81
  requirements: []
116
- rubygems_version: 3.6.9
82
+ rubygems_version: 4.0.3
117
83
  specification_version: 4
118
84
  summary: Red FlatBuffers is a pure Ruby FlatBuffers implementation.
119
85
  test_files: []