packed_struct 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.
- data/LICENSE +19 -0
- data/README.md +33 -0
- data/lib/packed_struct.rb +25 -0
- data/lib/packed_struct/directive.rb +355 -0
- data/lib/packed_struct/package.rb +127 -0
- data/lib/packed_struct/version.rb +5 -0
- metadata +54 -0
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2013 Jeremy Rodi
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# PackedStruct
|
2
|
+
|
3
|
+
`PackedStruct` is a way to define packing strings (see [`Array#pack`](http://ruby-doc.org/core-2.0/Array.html#method-i-pack)).
|
4
|
+
It was created after @charliesome suggested [a format](https://gist.github.com/redjazz96/6dda0554f62e4f77253a) for defining these strings, but never finished it.
|
5
|
+
|
6
|
+
The basic way of defining a packed struct is such:
|
7
|
+
|
8
|
+
```Ruby
|
9
|
+
class RconPacket
|
10
|
+
include PackedStruct
|
11
|
+
struct_layout :packet do
|
12
|
+
little_endian signed size[32] # defaults to a number of size 32.
|
13
|
+
little_endian signed id[32]
|
14
|
+
little_endian signed type[32]
|
15
|
+
string body[size]
|
16
|
+
null
|
17
|
+
end
|
18
|
+
end
|
19
|
+
```
|
20
|
+
|
21
|
+
This can be accessed as:
|
22
|
+
|
23
|
+
```Ruby
|
24
|
+
RconPacket.structs[:packet].pack(size: 11, id: 1, type: 0, body: "hello world")
|
25
|
+
# => "\v\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00hello world\x00"
|
26
|
+
```
|
27
|
+
|
28
|
+
You can also unpack strings.
|
29
|
+
|
30
|
+
```Ruby
|
31
|
+
RconPacket.structs[:packet].unpack("\v\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00hello world\x00")
|
32
|
+
# => {:size => 11, :id => 1, :type => 0, :body => "hello world"}
|
33
|
+
```
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'packed_struct/package'
|
2
|
+
require 'packed_struct/directive'
|
3
|
+
|
4
|
+
module PackedStruct
|
5
|
+
|
6
|
+
def structs
|
7
|
+
@structs ||= {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def struct_layout(name = nil, &block)
|
11
|
+
structs[name] = Package.new
|
12
|
+
structs[name].instance_exec &block
|
13
|
+
|
14
|
+
if name == nil
|
15
|
+
@structs = structs[name]
|
16
|
+
end
|
17
|
+
|
18
|
+
structs
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.included(reciever)
|
22
|
+
reciever.extend self
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,355 @@
|
|
1
|
+
module PackedStruct
|
2
|
+
|
3
|
+
# Contains information about a directive. A directive can be a name
|
4
|
+
# of the type, the endian(ness) of the type, the type of the type
|
5
|
+
# (short, int, long, etc.), and the signed(ness) of the type.
|
6
|
+
class Directive
|
7
|
+
|
8
|
+
# The name of the directive. This is passed as the first value of
|
9
|
+
# the directive; from {Package}, it is the name of the method call.
|
10
|
+
#
|
11
|
+
# @return [Symbol]
|
12
|
+
attr_reader :name
|
13
|
+
|
14
|
+
# The arguments passed to the directive.
|
15
|
+
#
|
16
|
+
# @return [Array<Object>]
|
17
|
+
attr_reader :options
|
18
|
+
|
19
|
+
# The tags the directive has, such as type, signed(ness),
|
20
|
+
# endian(ness), and size. Not filled until {#to_s} is called.
|
21
|
+
#
|
22
|
+
# @return [Hash]
|
23
|
+
attr_accessor :tags
|
24
|
+
|
25
|
+
# The children of this directive. If this directive has a parent,
|
26
|
+
# this is nil.
|
27
|
+
#
|
28
|
+
# @return [nil, Array<Directive>]
|
29
|
+
attr_reader :subs
|
30
|
+
|
31
|
+
# The parent of this directive. The relationship is such that
|
32
|
+
# +parent.subs.include?(self)+ is true. If this has a parent, it
|
33
|
+
# is nil.
|
34
|
+
#
|
35
|
+
# @return [nil, Directive]
|
36
|
+
attr_accessor :parent
|
37
|
+
|
38
|
+
# The value this directive holds. Only for use when packing.
|
39
|
+
#
|
40
|
+
# @return [nil, Object]
|
41
|
+
attr_writer :value
|
42
|
+
|
43
|
+
# @!parse
|
44
|
+
# attr_reader :value
|
45
|
+
def value
|
46
|
+
@value || (@tags[:original].value if @tags[:original])
|
47
|
+
end
|
48
|
+
|
49
|
+
# Initialize the directive.
|
50
|
+
#
|
51
|
+
# @param name [Symbol] the name of the directive.
|
52
|
+
def initialize(name, *arguments)
|
53
|
+
@name = name
|
54
|
+
|
55
|
+
@options = arguments
|
56
|
+
@tags = {}
|
57
|
+
@subs = []
|
58
|
+
@parent = nil
|
59
|
+
@value = nil
|
60
|
+
|
61
|
+
if arguments.first.is_a? Directive
|
62
|
+
arguments.first.add_child(self)
|
63
|
+
@subs = nil
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Add a child to this (or its parent's) directive. If this is a
|
68
|
+
# child itself, it adds it to the parent of this. Invalidates the
|
69
|
+
# caches for {#sub_names} and {#to_s}
|
70
|
+
#
|
71
|
+
# @param child [Directive] the child to add.
|
72
|
+
# @return [Directive] the child.
|
73
|
+
def add_child(child)
|
74
|
+
if @parent
|
75
|
+
@parent.add_child(child)
|
76
|
+
else
|
77
|
+
@_str = nil
|
78
|
+
@_sub_types = nil
|
79
|
+
@subs << child
|
80
|
+
child.parent = self
|
81
|
+
child
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Set the size of this directive.
|
86
|
+
#
|
87
|
+
# @return [self]
|
88
|
+
def [](size)
|
89
|
+
@tags[:size] = size
|
90
|
+
self
|
91
|
+
end
|
92
|
+
|
93
|
+
# Turn the directive into a string. Analyzes the subs before
|
94
|
+
# determining information, then outputs that. Caches the value
|
95
|
+
# until {#add_child} is next called.
|
96
|
+
#
|
97
|
+
# @return [String]
|
98
|
+
def to_s
|
99
|
+
return "" unless @subs
|
100
|
+
@subs.compact!
|
101
|
+
@tags[:signed] = determine_signed
|
102
|
+
@tags[:type] = determine_type
|
103
|
+
@tags[:endian] = determine_endian
|
104
|
+
"#{make_directive}#{make_length}"
|
105
|
+
end
|
106
|
+
|
107
|
+
# Inspects the directive.
|
108
|
+
#
|
109
|
+
# @return [String]
|
110
|
+
def inspect
|
111
|
+
"#<#{self.class.name}:#{name}>"
|
112
|
+
end
|
113
|
+
|
114
|
+
# To show the size of something else, relative to this directive.
|
115
|
+
#
|
116
|
+
# @return [Directive]
|
117
|
+
def -(other)
|
118
|
+
dir = dup
|
119
|
+
dir.tags = tags.dup
|
120
|
+
dir.tags[:original ] = self
|
121
|
+
dir.tags[:size_modify] = -other
|
122
|
+
dir
|
123
|
+
end
|
124
|
+
|
125
|
+
# To show the size of something else, relative to this directive.
|
126
|
+
#
|
127
|
+
# @return [Directive]
|
128
|
+
def +(other)
|
129
|
+
dir = dup
|
130
|
+
dir.tags = tags.dup
|
131
|
+
dir.tags[:original ] = self
|
132
|
+
dir.tags[:size_modify] = +other
|
133
|
+
dir
|
134
|
+
end
|
135
|
+
|
136
|
+
private
|
137
|
+
|
138
|
+
# Returns all of the names of the subs, and caches it.
|
139
|
+
#
|
140
|
+
# @param force [Boolean] force reloading the names of the subs.
|
141
|
+
# @return [Array<Symbol>]
|
142
|
+
def sub_names(force = false)
|
143
|
+
if @_sub_types && !force
|
144
|
+
@_sub_types
|
145
|
+
else
|
146
|
+
@subs.map(&:name) + [@name]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Determines the size of the directive by checking if it's in the
|
151
|
+
# tags, or by searching the subs.
|
152
|
+
#
|
153
|
+
# @return [Numeric]
|
154
|
+
def size
|
155
|
+
case @tags[:size]
|
156
|
+
when Directive
|
157
|
+
(@tags[:size].value || 0) + (@tags[:size].tags[:size_modify] || 0)
|
158
|
+
when Numeric
|
159
|
+
@tags[:size]
|
160
|
+
when nil
|
161
|
+
@subs.select { |s| s && s.tags[:size] }.map { |s| s.tags[:size] }.last
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Determine the type of this directive. Uses {#sub_names} to
|
166
|
+
# search for matching types. Defaults to +nil+.
|
167
|
+
#
|
168
|
+
# @return [nil, Symbol] the return value can be any of +:short+,
|
169
|
+
# +:int+, +:long+, +:string+, +:float+, or +nil+.
|
170
|
+
def determine_type
|
171
|
+
case true
|
172
|
+
when sub_names.include?(:short)
|
173
|
+
:short
|
174
|
+
when sub_names.include?(:int)
|
175
|
+
:int
|
176
|
+
when sub_names.include?(:long)
|
177
|
+
:long
|
178
|
+
when sub_names.include?(:char), sub_names.include?(:string)
|
179
|
+
:string
|
180
|
+
when sub_names.include?(:float)
|
181
|
+
:float
|
182
|
+
when sub_names.include?(:null)
|
183
|
+
:null
|
184
|
+
else
|
185
|
+
nil
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Determines the endianness of this directive. Uses {#sub_names}
|
190
|
+
# to search for matching names. Defaults to +:native+.
|
191
|
+
#
|
192
|
+
# @return [Symbol] the return value can be any of +:little+,
|
193
|
+
# +:big+, or +:native+.
|
194
|
+
def determine_endian
|
195
|
+
case true
|
196
|
+
when sub_names.include?(:little), sub_names.include?(:little_endian),
|
197
|
+
sub_names.include?(:lsb), sub_names.include?(:low)
|
198
|
+
:little
|
199
|
+
when sub_names.include?(:big), sub_names.include?(:big_endian),
|
200
|
+
sub_names.include?(:msb), sub_names.include?(:high),
|
201
|
+
sub_names.include?(:network)
|
202
|
+
:big
|
203
|
+
else
|
204
|
+
:native
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Determines the signedness of this directive. Uses {#sub_names}
|
209
|
+
# to search for matching names. Defaults to +:signed+.
|
210
|
+
#
|
211
|
+
# @return [Symbol] the return value can be any of +:unsigned+ or
|
212
|
+
# +:signed+.
|
213
|
+
def determine_signed
|
214
|
+
if sub_names.include?(:unsigned) && !sub_names.include?(:null)
|
215
|
+
:unsigned
|
216
|
+
else
|
217
|
+
:signed
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
# Determines the directive to be used in the pack string, using
|
222
|
+
# the type from {#determine_type} to manage it.
|
223
|
+
#
|
224
|
+
# @return [String] the directive for the pack string.
|
225
|
+
def make_directive
|
226
|
+
case @tags[:type]
|
227
|
+
when nil
|
228
|
+
handle_nil_type
|
229
|
+
when :short
|
230
|
+
modify_if_needed "S"
|
231
|
+
when :int
|
232
|
+
modify_if_needed "I"
|
233
|
+
when :long
|
234
|
+
modify_if_needed "L"
|
235
|
+
when :string
|
236
|
+
handle_string_type
|
237
|
+
when :float
|
238
|
+
handle_float_type
|
239
|
+
when :null
|
240
|
+
"x" * (size || 1)
|
241
|
+
else
|
242
|
+
nil
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# Determines the length to be added to the pack string.
|
247
|
+
#
|
248
|
+
# @return [String]
|
249
|
+
def make_length
|
250
|
+
if size && ![:null, nil].include?(@tags[:type])
|
251
|
+
size.to_s
|
252
|
+
else
|
253
|
+
""
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
# Handles the nil type. Uses the size to match the type with
|
258
|
+
# the directive.
|
259
|
+
#
|
260
|
+
# @return [String]
|
261
|
+
def handle_nil_type
|
262
|
+
maps = {
|
263
|
+
8 => "C",
|
264
|
+
16 => "S",
|
265
|
+
32 => "L",
|
266
|
+
64 => "Q"
|
267
|
+
}
|
268
|
+
|
269
|
+
raise StandardError,
|
270
|
+
"Cannot make number of #{size} length" unless
|
271
|
+
maps.keys.include?(size)
|
272
|
+
|
273
|
+
modify_if_needed maps[size]
|
274
|
+
end
|
275
|
+
|
276
|
+
# Handles a string type. If the name of the directive is
|
277
|
+
# +:null+, returns a string containing a number of +x+s (nulls)
|
278
|
+
# exactly equal to the size (or 1, if it doesn't exist).
|
279
|
+
# Otherwise, determines the type of string from the sub names;
|
280
|
+
# types of strings can include +:hex+, +:base64+, +:bit+, or
|
281
|
+
# +:binary+ (defaults to binary).
|
282
|
+
#
|
283
|
+
# @return [String]
|
284
|
+
def handle_string_type
|
285
|
+
|
286
|
+
case true
|
287
|
+
when sub_names.include?(:hex)
|
288
|
+
modify_if_needed "H"
|
289
|
+
when sub_names.include?(:base64)
|
290
|
+
"m"
|
291
|
+
when sub_names.include?(:bit)
|
292
|
+
modify_if_needed "B", false
|
293
|
+
else
|
294
|
+
modify_if_needed "A", false
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
# Handles float types. Can handle double- or single- precision
|
299
|
+
# floats, and manage their byte order.
|
300
|
+
#
|
301
|
+
# @return [String]
|
302
|
+
def handle_float_type
|
303
|
+
double = sub_names.include?(:double)
|
304
|
+
|
305
|
+
case @tags[:endian]
|
306
|
+
when :native
|
307
|
+
if double
|
308
|
+
"D"
|
309
|
+
else
|
310
|
+
"F"
|
311
|
+
end
|
312
|
+
when :little
|
313
|
+
if double
|
314
|
+
"E"
|
315
|
+
else
|
316
|
+
"e"
|
317
|
+
end
|
318
|
+
when :big
|
319
|
+
if double
|
320
|
+
"G"
|
321
|
+
else
|
322
|
+
"g"
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
# Modifies the given string as needed; it assumes that a lowercase
|
328
|
+
# letter stands for a signed type and the given string stands for
|
329
|
+
# an unsigned type. It also assumes that "<" added means little
|
330
|
+
# endian, and that ">" added means big endian (and that nothing
|
331
|
+
# added stands for native).
|
332
|
+
#
|
333
|
+
# @param str [String]
|
334
|
+
# @return [String]
|
335
|
+
def modify_if_needed(str, include_endian = true)
|
336
|
+
base = if @tags[:signed] == :signed
|
337
|
+
str.downcase
|
338
|
+
else
|
339
|
+
str
|
340
|
+
end
|
341
|
+
|
342
|
+
base += case @tags[:endian]
|
343
|
+
when :little
|
344
|
+
"<"
|
345
|
+
when :big
|
346
|
+
">"
|
347
|
+
else
|
348
|
+
""
|
349
|
+
end if include_endian
|
350
|
+
|
351
|
+
base
|
352
|
+
end
|
353
|
+
|
354
|
+
end
|
355
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module PackedStruct
|
2
|
+
|
3
|
+
# Manages the struct overall, and keeps track of the directives.
|
4
|
+
# Directives are packed in the order that they are joined, such
|
5
|
+
# that the first one defined is the first one on the string.
|
6
|
+
class Package
|
7
|
+
|
8
|
+
# The list of directives that the package has.
|
9
|
+
#
|
10
|
+
# @return [Array<Directive>]
|
11
|
+
def directives
|
12
|
+
@directives.select! { |x| x.parent.nil? }
|
13
|
+
@directives
|
14
|
+
end
|
15
|
+
|
16
|
+
# Initialize the package.
|
17
|
+
def initialize
|
18
|
+
@directives = []
|
19
|
+
end
|
20
|
+
|
21
|
+
# Turn the package into a string. Uses the directives (calls
|
22
|
+
# {Directive#to_s} on them), and joins the result.
|
23
|
+
#
|
24
|
+
# @return [String] the string ready for #pack.
|
25
|
+
def to_s
|
26
|
+
@_str ||= directives.map(&:to_s).join(' ')
|
27
|
+
end
|
28
|
+
|
29
|
+
alias_method :to_str, :to_s
|
30
|
+
|
31
|
+
# Packs the given data into a string. The keys of the data
|
32
|
+
# correspond to the names of the directives.
|
33
|
+
#
|
34
|
+
# @param [Hash<Symbol, Object>] the data.
|
35
|
+
# @return [String] the packed data.
|
36
|
+
def pack(data)
|
37
|
+
values = []
|
38
|
+
data.each do |k, v|
|
39
|
+
values.push([k, v])
|
40
|
+
end
|
41
|
+
|
42
|
+
mapped_directives = @directives.map(&:name)
|
43
|
+
|
44
|
+
values.sort do |a, b|
|
45
|
+
directives.index(a) <=> directives.index(b)
|
46
|
+
end
|
47
|
+
|
48
|
+
pack_with_array(values.map(&:last))
|
49
|
+
end
|
50
|
+
|
51
|
+
# Packs the directives into a string. Uses an array.
|
52
|
+
# The parameters can either be an array, or a set of values.
|
53
|
+
#
|
54
|
+
# @return [String]
|
55
|
+
def pack_with_array(*array)
|
56
|
+
array.flatten!
|
57
|
+
|
58
|
+
directives.each_with_index { |e, i| e.value = array[i] }
|
59
|
+
out = array.pack(self.to_s)
|
60
|
+
directives.each { |x| x.value = nil }
|
61
|
+
out
|
62
|
+
end
|
63
|
+
|
64
|
+
# Unpacks the given string with the directives. Returns a hash
|
65
|
+
# containing the values, with the keys being the names of the
|
66
|
+
# directives.
|
67
|
+
#
|
68
|
+
# @param string [String] the packed string.
|
69
|
+
# @return [Hash<Symbol, Object>] the unpacked data.
|
70
|
+
def unpack(string)
|
71
|
+
total = ""
|
72
|
+
parts = {}
|
73
|
+
directives.each_with_index do |directive, i|
|
74
|
+
total << directive.to_s
|
75
|
+
value = string.unpack(total)[i]
|
76
|
+
directive.value = value
|
77
|
+
parts[directive.name] = value
|
78
|
+
end
|
79
|
+
|
80
|
+
directives.each { |x| x.value = nil }
|
81
|
+
|
82
|
+
parts.delete(:null) {}
|
83
|
+
parts
|
84
|
+
end
|
85
|
+
|
86
|
+
# This unpacks the entire string at once. It assumes that none of
|
87
|
+
# the directives will need the values of other directives. If
|
88
|
+
# you're not sure what this means, don't use it.
|
89
|
+
#
|
90
|
+
# @param string [String] the packed string.
|
91
|
+
# @return [Hash<Symbol, Object>] the unpacked data.
|
92
|
+
def fast_unpack(string)
|
93
|
+
out = string.unpack(to_s)
|
94
|
+
parts = {}
|
95
|
+
|
96
|
+
directives.each_with_index do |directive, i|
|
97
|
+
parts[directive.name] = out[i]
|
98
|
+
end
|
99
|
+
|
100
|
+
parts.delete(:null) {}
|
101
|
+
parts
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
# Inspects the package.
|
106
|
+
#
|
107
|
+
# @return [String]
|
108
|
+
def inspect
|
109
|
+
"#<#{self.class.name}:#{"0x%014x" % directives.map(&:object_id).inject(&:+)}>"
|
110
|
+
end
|
111
|
+
|
112
|
+
# Creates a new directive with the given method and arguments.
|
113
|
+
#
|
114
|
+
# @return [Directive] the new directive.
|
115
|
+
def method_missing(method, *arguments, &block)
|
116
|
+
if @directives.map(&:name).include?(method) && arguments.length == 0
|
117
|
+
@directives.select { |x| x.name == method }.first
|
118
|
+
else
|
119
|
+
@_str = nil
|
120
|
+
directive = Directive.new(method, *arguments)
|
121
|
+
@directives << directive
|
122
|
+
directive
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
end
|
metadata
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: packed_struct
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jeremy Rodi
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-06-26 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: ! ' Cleans up the string mess when packing items (in Array#pack) and
|
15
|
+
unpacking items (in String#unpack).
|
16
|
+
|
17
|
+
'
|
18
|
+
email: redjazz96@gmail.com
|
19
|
+
executables: []
|
20
|
+
extensions: []
|
21
|
+
extra_rdoc_files: []
|
22
|
+
files:
|
23
|
+
- README.md
|
24
|
+
- LICENSE
|
25
|
+
- lib/packed_struct/version.rb
|
26
|
+
- lib/packed_struct/package.rb
|
27
|
+
- lib/packed_struct/directive.rb
|
28
|
+
- lib/packed_struct.rb
|
29
|
+
homepage: http://github.com/redjazz96/packed_struct
|
30
|
+
licenses: []
|
31
|
+
post_install_message:
|
32
|
+
rdoc_options: []
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
none: false
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubyforge_project:
|
49
|
+
rubygems_version: 1.8.25
|
50
|
+
signing_key:
|
51
|
+
specification_version: 3
|
52
|
+
summary: Cleans up the string mess when packing items.
|
53
|
+
test_files: []
|
54
|
+
has_rdoc: false
|