iostruct 0.5.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 +35 -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 -103
- data/spec/.rubocop.yml +27 -0
- data/spec/hash_fmt_spec.rb +215 -0
- data/spec/iostruct_spec.rb +260 -21
- metadata +12 -51
data/spec/iostruct_spec.rb
CHANGED
|
@@ -2,18 +2,184 @@ require 'spec_helper'
|
|
|
2
2
|
require 'stringio'
|
|
3
3
|
|
|
4
4
|
describe IOStruct do
|
|
5
|
-
describe "
|
|
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
|
|
6
172
|
context "when set" do
|
|
7
173
|
it "uses the custom name" do
|
|
8
|
-
x =
|
|
9
|
-
expect(x.new.inspect).to match
|
|
174
|
+
x = described_class.new('LL', :x, :y, struct_name: 'Point')
|
|
175
|
+
expect(x.new.inspect).to match(/<Point x=nil y=nil>/)
|
|
10
176
|
end
|
|
11
177
|
end
|
|
12
178
|
|
|
13
179
|
context "when not set" do
|
|
14
180
|
it "has default name" do
|
|
15
|
-
x =
|
|
16
|
-
expect(x.new.inspect).to match
|
|
181
|
+
x = described_class.new('LL', :x, :y)
|
|
182
|
+
expect(x.new.inspect).to match(/<struct x=nil y=nil>/)
|
|
17
183
|
end
|
|
18
184
|
end
|
|
19
185
|
end
|
|
@@ -23,19 +189,19 @@ describe IOStruct do
|
|
|
23
189
|
let(:data) { a.pack('L2') }
|
|
24
190
|
|
|
25
191
|
it "reads from IO" do
|
|
26
|
-
x =
|
|
192
|
+
x = described_class.new('LL', :x, :y).read(StringIO.new(data))
|
|
27
193
|
expect(x.x).to eq a[0]
|
|
28
194
|
expect(x.y).to eq a[1]
|
|
29
195
|
end
|
|
30
196
|
|
|
31
197
|
it "reads from String" do
|
|
32
|
-
x =
|
|
198
|
+
x = described_class.new('LL', :x, :y).read(data)
|
|
33
199
|
expect(x.x).to eq a[0]
|
|
34
200
|
expect(x.y).to eq a[1]
|
|
35
201
|
end
|
|
36
202
|
|
|
37
203
|
it "creates a new instance of a subclass" do
|
|
38
|
-
klass = Class.new(
|
|
204
|
+
klass = Class.new( described_class.new('LL', :x, :y) )
|
|
39
205
|
x = klass.read(data)
|
|
40
206
|
expect(x).to be_a klass
|
|
41
207
|
end
|
|
@@ -43,7 +209,7 @@ describe IOStruct do
|
|
|
43
209
|
|
|
44
210
|
context "zero-length strings" do
|
|
45
211
|
let(:data) { [1, 2].pack('CC') }
|
|
46
|
-
let(:struct) {
|
|
212
|
+
let(:struct) { described_class.new('C a0 C', :a, :b, :c) }
|
|
47
213
|
|
|
48
214
|
it "deserializes" do
|
|
49
215
|
x = struct.read(data)
|
|
@@ -61,8 +227,8 @@ describe IOStruct do
|
|
|
61
227
|
end
|
|
62
228
|
|
|
63
229
|
it "reads correct number of bytes from IO" do
|
|
64
|
-
io = StringIO.new(data*2)
|
|
65
|
-
|
|
230
|
+
io = StringIO.new(data * 2)
|
|
231
|
+
struct.read(io)
|
|
66
232
|
expect(io.pos).to eq 2
|
|
67
233
|
end
|
|
68
234
|
|
|
@@ -75,29 +241,30 @@ describe IOStruct do
|
|
|
75
241
|
it "skips on 'x'" do
|
|
76
242
|
a = [12345, 56789]
|
|
77
243
|
data = a.pack('L2')
|
|
78
|
-
x =
|
|
244
|
+
x = described_class.new('x4L', :y).read(data)
|
|
79
245
|
expect(x.y).to eq a[1]
|
|
80
246
|
end
|
|
81
247
|
|
|
82
248
|
it "unpacks hex-string (H)" do
|
|
83
249
|
data = "1234"
|
|
84
|
-
struct =
|
|
250
|
+
struct = described_class.new('H8', :x).read(data)
|
|
85
251
|
expect(struct.x).to eq "31323334"
|
|
86
252
|
expect(struct.pack).to eq data
|
|
87
253
|
end
|
|
88
254
|
|
|
89
255
|
it "unpacks reverse-nibbled hex-string (h)" do
|
|
90
256
|
data = "1234"
|
|
91
|
-
struct =
|
|
257
|
+
struct = described_class.new('h8', :x).read(data)
|
|
92
258
|
expect(struct.x).to eq "13233343"
|
|
93
259
|
expect(struct.pack).to eq data
|
|
94
260
|
end
|
|
95
261
|
|
|
262
|
+
# rubocop:disable RSpec/RepeatedExample
|
|
96
263
|
['n', 'N', 'S>', 'L>', 'I>'].each do |fmt|
|
|
97
264
|
it "unpacks unsigned big-endian '#{fmt}'" do
|
|
98
265
|
a = [12345]
|
|
99
266
|
data = a.pack(fmt)
|
|
100
|
-
x =
|
|
267
|
+
x = described_class.new(fmt, :x).read(data)
|
|
101
268
|
expect(x.x).to eq a[0]
|
|
102
269
|
expect(x.pack).to eq data
|
|
103
270
|
end
|
|
@@ -107,27 +274,26 @@ describe IOStruct do
|
|
|
107
274
|
it "unpacks unsigned little-endian '#{fmt}'" do
|
|
108
275
|
a = [12345]
|
|
109
276
|
data = a.pack(fmt)
|
|
110
|
-
x =
|
|
277
|
+
x = described_class.new(fmt, :x).read(data)
|
|
111
278
|
expect(x.x).to eq a[0]
|
|
112
279
|
expect(x.pack).to eq data
|
|
113
280
|
end
|
|
114
281
|
end
|
|
282
|
+
# rubocop:enable RSpec/RepeatedExample
|
|
115
283
|
|
|
116
284
|
it "throws exception on unknown format" do
|
|
117
|
-
expect {
|
|
285
|
+
expect { described_class.new('K', :x) }.to raise_error('Unknown field type "K"')
|
|
118
286
|
end
|
|
119
287
|
|
|
120
288
|
context '__offset field' do
|
|
121
289
|
let(:data) { 0x100.times.to_a.pack('L*') }
|
|
122
290
|
let(:io) { StringIO.new(data) }
|
|
123
|
-
let(:struct) {
|
|
291
|
+
let(:struct) { described_class.new('LLLL', :a, :b, :c, :d) }
|
|
124
292
|
|
|
125
293
|
context 'when src is an IO' do
|
|
126
294
|
it 'is set to the current IO position' do
|
|
127
295
|
a = []
|
|
128
|
-
|
|
129
|
-
a << struct.read(io)
|
|
130
|
-
end
|
|
296
|
+
a << struct.read(io) until io.eof?
|
|
131
297
|
expect(a.map(&:__offset)).to eq (0...0x400).step(0x10).to_a
|
|
132
298
|
end
|
|
133
299
|
end
|
|
@@ -139,4 +305,77 @@ describe IOStruct do
|
|
|
139
305
|
end
|
|
140
306
|
end
|
|
141
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
|
|
142
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: []
|