iostruct 0.4.0 → 0.6.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 +4 -4
- data/.rubocop.yml +68 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +44 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +49 -9
- data/README.md +247 -6
- data/Rakefile +3 -1
- data/iostruct.gemspec +8 -9
- data/lib/iostruct/hash_fmt.rb +92 -0
- data/lib/iostruct/pack_fmt.rb +68 -0
- data/lib/iostruct/version.rb +1 -1
- data/lib/iostruct.rb +122 -98
- data/spec/.rubocop.yml +27 -0
- data/spec/hash_fmt_spec.rb +215 -0
- data/spec/iostruct_spec.rb +271 -16
- metadata +12 -51
data/spec/iostruct_spec.rb
CHANGED
|
@@ -2,24 +2,206 @@ require 'spec_helper'
|
|
|
2
2
|
require 'stringio'
|
|
3
3
|
|
|
4
4
|
describe IOStruct do
|
|
5
|
+
describe "#pack" do
|
|
6
|
+
it "serializes struct back to binary" do
|
|
7
|
+
struct = described_class.new('L S C', :a, :b, :c)
|
|
8
|
+
obj = struct.new(a: 0x12345678, b: 0xABCD, c: 0xEF)
|
|
9
|
+
expect(obj.pack).to eq [0x12345678, 0xABCD, 0xEF].pack('L S C')
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "round-trips correctly" do
|
|
13
|
+
struct = described_class.new('L S C', :a, :b, :c)
|
|
14
|
+
data = [123, 456, 78].pack('L S C')
|
|
15
|
+
obj = struct.read(data)
|
|
16
|
+
expect(obj.pack).to eq data
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "#empty?" do
|
|
21
|
+
let(:struct) { described_class.new('L S', :a, :b) }
|
|
22
|
+
|
|
23
|
+
it "returns true when all fields are zero" do
|
|
24
|
+
expect(struct.new(a: 0, b: 0)).to be_empty
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "returns true when all fields are nil" do
|
|
28
|
+
expect(struct.new).to be_empty
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "returns false when any field is non-zero" do
|
|
32
|
+
expect(struct.new(a: 1, b: 0)).not_to be_empty
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
it "returns true for null-filled strings" do
|
|
36
|
+
str_struct = described_class.new('a4', :name)
|
|
37
|
+
expect(str_struct.new(name: "\x00\x00\x00\x00")).to be_empty
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "returns false for non-empty strings" do
|
|
41
|
+
str_struct = described_class.new('a4', :name)
|
|
42
|
+
expect(str_struct.new(name: "test")).not_to be_empty
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe "hash-style initialization" do
|
|
47
|
+
let(:struct) { described_class.new('L S C', :a, :b, :c) }
|
|
48
|
+
|
|
49
|
+
it "initializes fields by name" do
|
|
50
|
+
obj = struct.new(a: 100, c: 50)
|
|
51
|
+
expect(obj.a).to eq 100
|
|
52
|
+
expect(obj.b).to be_nil
|
|
53
|
+
expect(obj.c).to eq 50
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe "auto-generated field names" do
|
|
58
|
+
it "generates names based on offset" do
|
|
59
|
+
struct = described_class.new('C S L')
|
|
60
|
+
expect(struct.members).to eq [:f0, :f1, :f3]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe "field renaming" do
|
|
65
|
+
it "renames auto-generated fields via kwargs" do
|
|
66
|
+
struct = described_class.new('C S L', f0: :byte_field, f3: :long_field)
|
|
67
|
+
expect(struct.members).to eq [:byte_field, :f1, :long_field]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "renames named fields via kwargs" do
|
|
71
|
+
struct = described_class.new('C S L', :a, :b, :c, a: :first, c: :last)
|
|
72
|
+
expect(struct.members).to eq [:first, :b, :last]
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
describe "float types" do
|
|
77
|
+
it "unpacks single-precision float (f/F)" do
|
|
78
|
+
data = [3.14159].pack('f')
|
|
79
|
+
struct = described_class.new('f', :val)
|
|
80
|
+
expect(struct.read(data).val).to be_within(0.0001).of(3.14159)
|
|
81
|
+
expect(struct::SIZE).to eq 4
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it "unpacks double-precision float (d/D)" do
|
|
85
|
+
data = [3.141592653589793].pack('d')
|
|
86
|
+
struct = described_class.new('d', :val)
|
|
87
|
+
expect(struct.read(data).val).to be_within(0.0000001).of(3.141592653589793)
|
|
88
|
+
expect(struct::SIZE).to eq 8
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "unpacks little-endian floats (e/E)" do
|
|
92
|
+
data = [2.5].pack('e')
|
|
93
|
+
struct = described_class.new('e', :val)
|
|
94
|
+
expect(struct.read(data).val).to be_within(0.0001).of(2.5)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "unpacks big-endian floats (g/G)" do
|
|
98
|
+
data = [2.5].pack('G')
|
|
99
|
+
struct = described_class.new('G', :val)
|
|
100
|
+
expect(struct.read(data).val).to be_within(0.0001).of(2.5)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "formats floats in to_table" do
|
|
104
|
+
struct = described_class.new('f', :val)
|
|
105
|
+
obj = struct.new(val: 3.14159)
|
|
106
|
+
expect(obj.to_table).to match(/val=\s*3\.142/)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
describe "signed integer types" do
|
|
111
|
+
it "reads signed 8-bit (c)" do
|
|
112
|
+
struct = described_class.new('c', :val)
|
|
113
|
+
expect(struct.read("\x80").val).to eq(-128)
|
|
114
|
+
expect(struct.read("\x7f").val).to eq(127)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "reads signed 16-bit (s)" do
|
|
118
|
+
struct = described_class.new('s', :val)
|
|
119
|
+
expect(struct.read("\x00\x80").val).to eq(-32768)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "reads signed 32-bit (i)" do
|
|
123
|
+
struct = described_class.new('i', :val)
|
|
124
|
+
expect(struct.read("\x00\x00\x00\x80").val).to eq(-2147483648)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it "reads signed 64-bit (q)" do
|
|
128
|
+
struct = described_class.new('q', :val)
|
|
129
|
+
expect(struct.read("\x00\x00\x00\x00\x00\x00\x00\x80").val).to eq(-9223372036854775808)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
describe "string types" do
|
|
134
|
+
it "unpacks space-padded string (A)" do
|
|
135
|
+
struct = described_class.new('A8', :name)
|
|
136
|
+
obj = struct.read("hello ")
|
|
137
|
+
expect(obj.name).to eq "hello"
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
it "unpacks null-terminated string (Z)" do
|
|
141
|
+
struct = described_class.new('Z8', :name)
|
|
142
|
+
obj = struct.read("hello\x00\x00\x00")
|
|
143
|
+
expect(obj.name).to eq "hello"
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it "unpacks raw string (a)" do
|
|
147
|
+
struct = described_class.new('a8', :name)
|
|
148
|
+
obj = struct.read("hello\x00\x00\x00")
|
|
149
|
+
expect(obj.name).to eq "hello\x00\x00\x00"
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
describe "error handling" do
|
|
154
|
+
it "raises when no fmt and no :fields" do
|
|
155
|
+
expect { described_class.new }.to raise_error(/no fmt and no :fields/)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
it "raises when reading from unsupported source" do
|
|
159
|
+
struct = described_class.new('L', :val)
|
|
160
|
+
expect { struct.read(12345) }.to raise_error(/don't know how to read/)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
describe "inspect_name_override (deprecated)" do
|
|
165
|
+
it "works as alias for struct_name" do
|
|
166
|
+
struct = described_class.new('L', :val, inspect_name_override: 'MyStruct')
|
|
167
|
+
expect(struct.new.inspect).to match(/<MyStruct/)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
describe ":name" do
|
|
172
|
+
context "when set" do
|
|
173
|
+
it "uses the custom name" do
|
|
174
|
+
x = described_class.new('LL', :x, :y, struct_name: 'Point')
|
|
175
|
+
expect(x.new.inspect).to match(/<Point x=nil y=nil>/)
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
context "when not set" do
|
|
180
|
+
it "has default name" do
|
|
181
|
+
x = described_class.new('LL', :x, :y)
|
|
182
|
+
expect(x.new.inspect).to match(/<struct x=nil y=nil>/)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
5
187
|
describe "#read" do
|
|
6
188
|
let(:a) { [12345, 56789] }
|
|
7
189
|
let(:data) { a.pack('L2') }
|
|
8
190
|
|
|
9
191
|
it "reads from IO" do
|
|
10
|
-
x =
|
|
192
|
+
x = described_class.new('LL', :x, :y).read(StringIO.new(data))
|
|
11
193
|
expect(x.x).to eq a[0]
|
|
12
194
|
expect(x.y).to eq a[1]
|
|
13
195
|
end
|
|
14
196
|
|
|
15
197
|
it "reads from String" do
|
|
16
|
-
x =
|
|
198
|
+
x = described_class.new('LL', :x, :y).read(data)
|
|
17
199
|
expect(x.x).to eq a[0]
|
|
18
200
|
expect(x.y).to eq a[1]
|
|
19
201
|
end
|
|
20
202
|
|
|
21
203
|
it "creates a new instance of a subclass" do
|
|
22
|
-
klass = Class.new(
|
|
204
|
+
klass = Class.new( described_class.new('LL', :x, :y) )
|
|
23
205
|
x = klass.read(data)
|
|
24
206
|
expect(x).to be_a klass
|
|
25
207
|
end
|
|
@@ -27,7 +209,7 @@ describe IOStruct do
|
|
|
27
209
|
|
|
28
210
|
context "zero-length strings" do
|
|
29
211
|
let(:data) { [1, 2].pack('CC') }
|
|
30
|
-
let(:struct) {
|
|
212
|
+
let(:struct) { described_class.new('C a0 C', :a, :b, :c) }
|
|
31
213
|
|
|
32
214
|
it "deserializes" do
|
|
33
215
|
x = struct.read(data)
|
|
@@ -45,8 +227,8 @@ describe IOStruct do
|
|
|
45
227
|
end
|
|
46
228
|
|
|
47
229
|
it "reads correct number of bytes from IO" do
|
|
48
|
-
io = StringIO.new(data*2)
|
|
49
|
-
|
|
230
|
+
io = StringIO.new(data * 2)
|
|
231
|
+
struct.read(io)
|
|
50
232
|
expect(io.pos).to eq 2
|
|
51
233
|
end
|
|
52
234
|
|
|
@@ -59,29 +241,30 @@ describe IOStruct do
|
|
|
59
241
|
it "skips on 'x'" do
|
|
60
242
|
a = [12345, 56789]
|
|
61
243
|
data = a.pack('L2')
|
|
62
|
-
x =
|
|
244
|
+
x = described_class.new('x4L', :y).read(data)
|
|
63
245
|
expect(x.y).to eq a[1]
|
|
64
246
|
end
|
|
65
247
|
|
|
66
248
|
it "unpacks hex-string (H)" do
|
|
67
249
|
data = "1234"
|
|
68
|
-
struct =
|
|
250
|
+
struct = described_class.new('H8', :x).read(data)
|
|
69
251
|
expect(struct.x).to eq "31323334"
|
|
70
252
|
expect(struct.pack).to eq data
|
|
71
253
|
end
|
|
72
254
|
|
|
73
255
|
it "unpacks reverse-nibbled hex-string (h)" do
|
|
74
256
|
data = "1234"
|
|
75
|
-
struct =
|
|
257
|
+
struct = described_class.new('h8', :x).read(data)
|
|
76
258
|
expect(struct.x).to eq "13233343"
|
|
77
259
|
expect(struct.pack).to eq data
|
|
78
260
|
end
|
|
79
261
|
|
|
262
|
+
# rubocop:disable RSpec/RepeatedExample
|
|
80
263
|
['n', 'N', 'S>', 'L>', 'I>'].each do |fmt|
|
|
81
264
|
it "unpacks unsigned big-endian '#{fmt}'" do
|
|
82
265
|
a = [12345]
|
|
83
266
|
data = a.pack(fmt)
|
|
84
|
-
x =
|
|
267
|
+
x = described_class.new(fmt, :x).read(data)
|
|
85
268
|
expect(x.x).to eq a[0]
|
|
86
269
|
expect(x.pack).to eq data
|
|
87
270
|
end
|
|
@@ -91,27 +274,26 @@ describe IOStruct do
|
|
|
91
274
|
it "unpacks unsigned little-endian '#{fmt}'" do
|
|
92
275
|
a = [12345]
|
|
93
276
|
data = a.pack(fmt)
|
|
94
|
-
x =
|
|
277
|
+
x = described_class.new(fmt, :x).read(data)
|
|
95
278
|
expect(x.x).to eq a[0]
|
|
96
279
|
expect(x.pack).to eq data
|
|
97
280
|
end
|
|
98
281
|
end
|
|
282
|
+
# rubocop:enable RSpec/RepeatedExample
|
|
99
283
|
|
|
100
284
|
it "throws exception on unknown format" do
|
|
101
|
-
expect {
|
|
285
|
+
expect { described_class.new('K', :x) }.to raise_error('Unknown field type "K"')
|
|
102
286
|
end
|
|
103
287
|
|
|
104
288
|
context '__offset field' do
|
|
105
289
|
let(:data) { 0x100.times.to_a.pack('L*') }
|
|
106
290
|
let(:io) { StringIO.new(data) }
|
|
107
|
-
let(:struct) {
|
|
291
|
+
let(:struct) { described_class.new('LLLL', :a, :b, :c, :d) }
|
|
108
292
|
|
|
109
293
|
context 'when src is an IO' do
|
|
110
294
|
it 'is set to the current IO position' do
|
|
111
295
|
a = []
|
|
112
|
-
|
|
113
|
-
a << struct.read(io)
|
|
114
|
-
end
|
|
296
|
+
a << struct.read(io) until io.eof?
|
|
115
297
|
expect(a.map(&:__offset)).to eq (0...0x400).step(0x10).to_a
|
|
116
298
|
end
|
|
117
299
|
end
|
|
@@ -123,4 +305,77 @@ describe IOStruct do
|
|
|
123
305
|
end
|
|
124
306
|
end
|
|
125
307
|
end
|
|
308
|
+
|
|
309
|
+
describe "to_table" do
|
|
310
|
+
context "when inspect is :hex" do
|
|
311
|
+
it "formats signed struct as table" do
|
|
312
|
+
signed_struct = described_class.new('c s i q', inspect: :hex)
|
|
313
|
+
expect(signed_struct.new.to_table).to eq(
|
|
314
|
+
"<struct f0= 0 f1= 0 f3= 0 f7= 0>"
|
|
315
|
+
)
|
|
316
|
+
expect(signed_struct.read("\xff" * 16).to_table).to eq(
|
|
317
|
+
"<struct f0=ff f1=ffff f3=ffffffff f7=ffffffffffffffff>"
|
|
318
|
+
)
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
it "formats unsigned struct as table" do
|
|
322
|
+
unsigned_struct = described_class.new('C S I Q', inspect: :hex)
|
|
323
|
+
expect(unsigned_struct.new.to_table).to eq(
|
|
324
|
+
"<struct f0= 0 f1= 0 f3= 0 f7= 0>"
|
|
325
|
+
)
|
|
326
|
+
expect(unsigned_struct.read("\xff" * 16).to_table).to eq(
|
|
327
|
+
"<struct f0=ff f1=ffff f3=ffffffff f7=ffffffffffffffff>"
|
|
328
|
+
)
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
it "works with unknown types" do
|
|
332
|
+
struct = described_class.new('C', :a, :name, inspect: :hex)
|
|
333
|
+
s = struct.new
|
|
334
|
+
expect(s.to_table).to eq(
|
|
335
|
+
"<struct a= 0 name=nil>"
|
|
336
|
+
)
|
|
337
|
+
s.name = "test"
|
|
338
|
+
expect(s.to_table).to eq(
|
|
339
|
+
'<struct a= 0 name="test">'
|
|
340
|
+
)
|
|
341
|
+
end
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
context "when inspect is not :hex" do
|
|
345
|
+
it "formats signed struct as table" do
|
|
346
|
+
signed_struct = described_class.new('c s i q', inspect: :dec)
|
|
347
|
+
expect(signed_struct.new.to_table).to eq(
|
|
348
|
+
"<struct f0= 0 f1= 0 f3= 0 f7= 0>"
|
|
349
|
+
)
|
|
350
|
+
expect(signed_struct.read("\xff" * 16).to_table).to eq(
|
|
351
|
+
"<struct f0= -1 f1= -1 f3= -1 f7= -1>"
|
|
352
|
+
)
|
|
353
|
+
expect(signed_struct.read("\x80\x00\x80\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x80").to_table).to eq(
|
|
354
|
+
"<struct f0=-128 f1=-32768 f3=-2147483648 f7=-9223372036854775808>"
|
|
355
|
+
)
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
it "formats unsigned struct as table" do
|
|
359
|
+
unsigned_struct = described_class.new('C S I Q', inspect: :dec)
|
|
360
|
+
expect(unsigned_struct.new.to_table).to eq(
|
|
361
|
+
"<struct f0= 0 f1= 0 f3= 0 f7= 0>"
|
|
362
|
+
)
|
|
363
|
+
expect(unsigned_struct.read("\xff" * 16).to_table).to eq(
|
|
364
|
+
"<struct f0= 255 f1= 65535 f3= 4294967295 f7=18446744073709551615>"
|
|
365
|
+
)
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
it "works with unknown types" do
|
|
369
|
+
struct = described_class.new('C', :a, :name, inspect: :dec)
|
|
370
|
+
s = struct.new
|
|
371
|
+
expect(s.to_table).to eq(
|
|
372
|
+
"<struct a= 0 name=nil>"
|
|
373
|
+
)
|
|
374
|
+
s.name = "test"
|
|
375
|
+
expect(s.to_table).to eq(
|
|
376
|
+
'<struct a= 0 name="test">'
|
|
377
|
+
)
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
end
|
|
126
381
|
end
|
metadata
CHANGED
|
@@ -1,58 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: iostruct
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Andrey "Zed" Zaikin
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
12
|
-
dependencies:
|
|
13
|
-
- !ruby/object:Gem::Dependency
|
|
14
|
-
name: bundler
|
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
|
16
|
-
requirements:
|
|
17
|
-
- - ">="
|
|
18
|
-
- !ruby/object:Gem::Version
|
|
19
|
-
version: '0'
|
|
20
|
-
type: :development
|
|
21
|
-
prerelease: false
|
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
-
requirements:
|
|
24
|
-
- - ">="
|
|
25
|
-
- !ruby/object:Gem::Version
|
|
26
|
-
version: '0'
|
|
27
|
-
- !ruby/object:Gem::Dependency
|
|
28
|
-
name: rake
|
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
|
30
|
-
requirements:
|
|
31
|
-
- - ">="
|
|
32
|
-
- !ruby/object:Gem::Version
|
|
33
|
-
version: '0'
|
|
34
|
-
type: :development
|
|
35
|
-
prerelease: false
|
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
-
requirements:
|
|
38
|
-
- - ">="
|
|
39
|
-
- !ruby/object:Gem::Version
|
|
40
|
-
version: '0'
|
|
41
|
-
- !ruby/object:Gem::Dependency
|
|
42
|
-
name: rspec
|
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
|
44
|
-
requirements:
|
|
45
|
-
- - ">="
|
|
46
|
-
- !ruby/object:Gem::Version
|
|
47
|
-
version: '0'
|
|
48
|
-
type: :development
|
|
49
|
-
prerelease: false
|
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
-
requirements:
|
|
52
|
-
- - ">="
|
|
53
|
-
- !ruby/object:Gem::Version
|
|
54
|
-
version: '0'
|
|
55
|
-
description:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
56
12
|
email: zed.0xff@gmail.com
|
|
57
13
|
executables: []
|
|
58
14
|
extensions: []
|
|
@@ -60,6 +16,8 @@ extra_rdoc_files: []
|
|
|
60
16
|
files:
|
|
61
17
|
- ".gitignore"
|
|
62
18
|
- ".rspec"
|
|
19
|
+
- ".rubocop.yml"
|
|
20
|
+
- ".ruby-version"
|
|
63
21
|
- CHANGELOG.md
|
|
64
22
|
- Gemfile
|
|
65
23
|
- Gemfile.lock
|
|
@@ -68,14 +26,18 @@ files:
|
|
|
68
26
|
- Rakefile
|
|
69
27
|
- iostruct.gemspec
|
|
70
28
|
- lib/iostruct.rb
|
|
29
|
+
- lib/iostruct/hash_fmt.rb
|
|
30
|
+
- lib/iostruct/pack_fmt.rb
|
|
71
31
|
- lib/iostruct/version.rb
|
|
32
|
+
- spec/.rubocop.yml
|
|
33
|
+
- spec/hash_fmt_spec.rb
|
|
72
34
|
- spec/iostruct_spec.rb
|
|
73
35
|
- spec/spec_helper.rb
|
|
74
36
|
homepage: http://github.com/zed-0xff/iostruct
|
|
75
37
|
licenses:
|
|
76
38
|
- MIT
|
|
77
|
-
metadata:
|
|
78
|
-
|
|
39
|
+
metadata:
|
|
40
|
+
rubygems_mfa_required: 'true'
|
|
79
41
|
rdoc_options: []
|
|
80
42
|
require_paths:
|
|
81
43
|
- lib
|
|
@@ -90,8 +52,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
90
52
|
- !ruby/object:Gem::Version
|
|
91
53
|
version: '0'
|
|
92
54
|
requirements: []
|
|
93
|
-
rubygems_version: 3.
|
|
94
|
-
signing_key:
|
|
55
|
+
rubygems_version: 3.6.9
|
|
95
56
|
specification_version: 4
|
|
96
57
|
summary: A Struct that can read/write itself from/to IO-like objects
|
|
97
58
|
test_files: []
|