binary-protocol 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7acca312b640e28dfc66b2bad980b78ee035d76c
4
+ data.tar.gz: c339bdb3911d544e5e47aeea983fed415ed52be7
5
+ SHA512:
6
+ metadata.gz: 1e4fe348d8f69a6d83d7c64e45adf8b7eec9e51f3c29b599a83d1f4dae537c7cddc07feaf68461d7ae60567c2af537a6afd90aaf562be0cd63ab7d70378a13ac
7
+ data.tar.gz: da21c64e0281573263101ee3a77ab253987228cdcbeeab09bf2b89e1bb46afe1c59d2bfb0c215e23df82ab099ee0f803de2114de995df6c8933d50702dc50094
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .rvmrc
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in binary-protocol.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Andrew Bennett
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # Binary::Protocol
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'binary-protocol'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install binary-protocol
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'binary/protocol/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "binary-protocol"
8
+ spec.version = Binary::Protocol::VERSION
9
+ spec.authors = ["Andrew Bennett"]
10
+ spec.email = ["andrew@pagodabox.com"]
11
+ spec.description = %q{Helpful DSL for reading and writing binary protocols}
12
+ spec.summary = %q{Helpful DSL for reading and writing binary protocols}
13
+ spec.homepage = "https://github.com/potatosalad/binary-protocol"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "pry"
23
+ spec.add_development_dependency "rake"
24
+ end
@@ -0,0 +1,397 @@
1
+ require "binary/protocol/version"
2
+ require "binary/protocol/extensions"
3
+
4
+ module Binary
5
+ module Protocol
6
+
7
+ BYTES_8 = 1.freeze
8
+ BYTES_16 = 2.freeze
9
+ BYTES_32 = 4.freeze
10
+ BYTES_64 = 8.freeze
11
+
12
+ INT8_PACK = 'c'.freeze # 8-bit signed (signed char)
13
+ INT16_PACK = 's'.freeze # 16-bit signed, native endian (int16_t)
14
+ INT32_PACK = 'l'.freeze # 32-bit signed, native endian (int32_t)
15
+ INT64_PACK = 'q'.freeze # 64-bit signed, native endian (int64_t)
16
+ INT16BE_PACK = 's>'.freeze # 16-bit signed, big-endian
17
+ INT32BE_PACK = 'l>'.freeze # 32-bit signed, big-endian
18
+ INT64BE_PACK = 'q>'.freeze # 64-bit signed, big-endian
19
+ INT16LE_PACK = 's<'.freeze # 16-bit signed, little-endian
20
+ INT32LE_PACK = 'l<'.freeze # 32-bit signed, little-endian
21
+ INT64LE_PACK = 'q<'.freeze # 64-bit signed, little-endian
22
+
23
+ UINT8_PACK = 'C'.freeze # 8-bit unsigned (unsigned char)
24
+ UINT16_PACK = 'S'.freeze # 16-bit unsigned, native endian (uint16_t)
25
+ UINT32_PACK = 'L'.freeze # 32-bit unsigned, native endian (uint32_t)
26
+ UINT64_PACK = 'Q'.freeze # 64-bit unsigned, native endian (uint64_t)
27
+ UINT16BE_PACK = 'n'.freeze # 16-bit unsigned, network (big-endian) byte order
28
+ UINT32BE_PACK = 'N'.freeze # 32-bit unsigned, network (big-endian) byte order
29
+ UINT64BE_PACK = 'Q>'.freeze # 64-bit unsigned, network (big-endian) byte order
30
+ UINT16LE_PACK = 'v'.freeze # 16-bit unsigned, VAX (little-endian) byte order
31
+ UINT32LE_PACK = 'V'.freeze # 32-bit unsigned, VAX (little-endian) byte order
32
+ UINT64LE_PACK = 'Q<'.freeze # 64-bit unsigned, VAX (little-endian) byte order
33
+
34
+ SINGLE_PACK = 'F'.freeze # 32-bit single-precision, native format
35
+ DOUBLE_PACK = 'D'.freeze # 64-bit double-precision, native format
36
+ SINGLEBE_PACK = 'g'.freeze # 32-bit sinlge-precision, network (big-endian) byte order
37
+ DOUBLEBE_PACK = 'G'.freeze # 64-bit double-precision, network (big-endian) byte order
38
+ SINGLELE_PACK = 'e'.freeze # 32-bit sinlge-precision, little-endian byte order
39
+ DOUBLELE_PACK = 'E'.freeze # 64-bit double-precision, little-endian byte order
40
+
41
+ class << self
42
+
43
+ # Extends the including class with +ClassMethods+.
44
+ #
45
+ # @param [Class] subclass the inheriting class
46
+ def included(base)
47
+ super
48
+
49
+ base.extend ClassMethods
50
+ end
51
+
52
+ private :included
53
+ end
54
+
55
+ # Provides a DSL for defining struct-like fields for building
56
+ # binary messages.
57
+ #
58
+ # @example
59
+ # class Command
60
+ # include Binary::Protocol
61
+ #
62
+ # int32 :length
63
+ # end
64
+ #
65
+ # Command.fields # => [:length]
66
+ # command = Command.new
67
+ # command.length = 12
68
+ # command.serialize_length("") # => "\f\x00\x00\x00"
69
+ module ClassMethods
70
+
71
+ # @return [Array] the methods to run in order for serialiation
72
+ def serialization
73
+ @serialization ||= []
74
+ end
75
+
76
+ # @return [Array] the fields defined for this message
77
+ def fields
78
+ @fields ||= []
79
+ end
80
+
81
+ %w[
82
+ int8
83
+ int16
84
+ int32
85
+ int64
86
+ int16be
87
+ int32be
88
+ int64be
89
+ int16le
90
+ int32le
91
+ int64le
92
+ uint8
93
+ uint16
94
+ uint32
95
+ uint64
96
+ uint16be
97
+ uint32be
98
+ uint64be
99
+ uint16le
100
+ uint32le
101
+ uint64le
102
+ ].each do |name|
103
+ pack_const = "#{name.upcase}_PACK".intern
104
+ size_const = "BYTES_#{name.match(/(\d+)/)[0]}".intern
105
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
106
+ def #{name}(name, options = {}, &block)
107
+ __bytes__(#{pack_const.inspect}, #{size_const.inspect}, name, options, &block)
108
+ end
109
+ RUBY
110
+ end
111
+
112
+ %w[
113
+ single
114
+ singlebe
115
+ singlele
116
+ double
117
+ doublebe
118
+ doublele
119
+ ].each do |name|
120
+ pack_const = "#{name.upcase}_PACK".intern
121
+ size_const = !!(name =~ /single/) ? "BYTES_32".intern : "BYTES_64".intern
122
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
123
+ def #{name}(name, options = {}, &block)
124
+ __bytes__(#{pack_const.inspect}, #{size_const.inspect}, name, options, &block)
125
+ end
126
+ RUBY
127
+ end
128
+
129
+ # Declare a string field.
130
+ #
131
+ # @example
132
+ # class Message
133
+ # include Binary::Protocol
134
+ # string :collection
135
+ # end
136
+ #
137
+ # @param [String] name the name of this field
138
+ def string(name, options = {})
139
+ if options.key?(:always)
140
+ __define_always__(name, options[:always])
141
+ else
142
+ if options.key?(:default)
143
+ __define_default__(name, options[:default])
144
+ else
145
+ attr_accessor name
146
+ end
147
+
148
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
149
+ def deserialize_#{name}(buffer)
150
+ raise NotImplementedError
151
+ end
152
+ RUBY
153
+ end
154
+
155
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
156
+ def serialize_#{name}(buffer)
157
+ buffer << #{name}
158
+ end
159
+ RUBY
160
+
161
+ serialization << :"serialize_#{name}"
162
+ fields << name
163
+ end
164
+
165
+ # Declare a null terminated string field.
166
+ #
167
+ # @example
168
+ # class Message
169
+ # include Binary::Protocol
170
+ # stringz :collection
171
+ # end
172
+ #
173
+ # @param [String] name the name of this field
174
+ def stringz(name, options = {})
175
+ if options.key?(:always)
176
+ __define_always__(name, options[:always])
177
+ else
178
+ if options.key?(:default)
179
+ __define_default__(name, options[:default])
180
+ else
181
+ attr_accessor name
182
+ end
183
+
184
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
185
+ def deserialize_#{name}(buffer)
186
+ raise NotImplementedError
187
+ end
188
+ RUBY
189
+ end
190
+
191
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
192
+ def serialize_#{name}(buffer)
193
+ buffer << #{name}
194
+ buffer << 0
195
+ end
196
+ RUBY
197
+
198
+ serialization << :"serialize_#{name}"
199
+ fields << name
200
+ end
201
+
202
+ # Declares the protocol class as complete, and defines its serialization
203
+ # method from the declared fields.
204
+ def finalize
205
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
206
+ def serialize(buffer = "")
207
+ #{serialization.map { |command| "#{command}(buffer)" }.join("\n")}
208
+ buffer
209
+ end
210
+ alias to_s serialize
211
+ RUBY
212
+ end
213
+
214
+ def deserialize(buffer = nil, &block)
215
+ if block_given?
216
+ re_define_method(:deserialize, &block)
217
+ else
218
+ message = allocate
219
+ message.deserialize(buffer)
220
+ message
221
+ end
222
+ end
223
+
224
+ protected
225
+
226
+ def __bytes__(pack_const, size_const, name, options = {}, &block)
227
+ if block_given?
228
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
229
+ def before_serialize_#{name}(buffer)
230
+ @#{name}_start = buffer.bytesize
231
+ end
232
+ RUBY
233
+
234
+ serialization << :"before_serialize_#{name}"
235
+ end
236
+
237
+ if options.key?(:always)
238
+ __define_always__(name, options[:always])
239
+ else
240
+ if options.key?(:default)
241
+ __define_default__(name, options[:default])
242
+ else
243
+ attr_accessor name
244
+ end
245
+
246
+ if options[:type] == :array
247
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
248
+ def deserialize_#{name}(buffer)
249
+ raise NotImplementedError
250
+ end
251
+ RUBY
252
+ else
253
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
254
+ def deserialize_#{name}(buffer)
255
+ self.#{name}, = buffer.read(#{size_const}).unpack(#{pack_const})
256
+ end
257
+ RUBY
258
+ end
259
+ end
260
+
261
+ if options[:type] == :array
262
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
263
+ def serialize_#{name}(buffer)
264
+ buffer << #{name}.pack(#{pack_const}+"*")
265
+ end
266
+ RUBY
267
+ else
268
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
269
+ def serialize_#{name}(buffer)
270
+ buffer << [#{name}].pack(#{pack_const})
271
+ end
272
+ RUBY
273
+ end
274
+
275
+ serialization << :"serialize_#{name}"
276
+
277
+ if block_given?
278
+ returning = fields << name
279
+ instance_eval(&block)
280
+
281
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
282
+ def after_serialize_#{name}(buffer)
283
+ self.#{name} = buffer.bytesize - @#{name}_start - #{options[:inclusive] ? 0 : size_const}
284
+ buffer[@#{name}_start, #{size_const}] = serialize_#{name} ""
285
+ end
286
+ RUBY
287
+
288
+ serialization << :"after_serialize_#{name}"
289
+
290
+ returning
291
+ else
292
+ fields << name
293
+ end
294
+ end
295
+
296
+ def __define_always__(name, always)
297
+ if always.respond_to?(:call)
298
+ re_define_method(name, &always)
299
+ else
300
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
301
+ def #{name}
302
+ @#{name} ||= #{always.inspect}
303
+ end
304
+ RUBY
305
+ end
306
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
307
+ def deserialize_#{name}(buffer)
308
+ # do nothing
309
+ end
310
+ RUBY
311
+ end
312
+
313
+ def __define_default__(name, default)
314
+ attr_writer name
315
+
316
+ if default.respond_to?(:call)
317
+ dval = :"__#{name}_default_value__"
318
+ ivar = :"@#{name}"
319
+ re_define_method(dval, &default)
320
+ re_define_method(name) do
321
+ if instance_variable_defined?(ivar)
322
+ instance_variable_get(ivar)
323
+ else
324
+ instance_variable_set(ivar, __send__(dval))
325
+ end
326
+ end
327
+ else
328
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
329
+ def #{name}
330
+ @#{name} ||= #{default.inspect}
331
+ end
332
+ RUBY
333
+ end
334
+ end
335
+
336
+ private
337
+
338
+ # This ensures that subclasses of the primary protocol classes have
339
+ # identical fields.
340
+ def inherited(subclass)
341
+ super
342
+
343
+ subclass.serialization.replace serialization
344
+ subclass.fields.replace fields
345
+ end
346
+
347
+ end
348
+
349
+ # Default implementation for a message is to do nothing when receiving
350
+ # replies.
351
+ #
352
+ # @example Receive replies.
353
+ # message.receive_replies(connection)
354
+ #
355
+ # @param [ Connection ] connection The connection.
356
+ #
357
+ # @since 1.0.0
358
+ #
359
+ # @return [ nil ] nil.
360
+ def receive_replies(connection); end
361
+
362
+ def deserialize(buffer)
363
+ self.class.fields.each do |field|
364
+ __send__(:"deserialize_#{field}", buffer)
365
+ end
366
+ self
367
+ end
368
+
369
+ # Serializes the message and all of its fields to a new buffer or to the
370
+ # provided buffer.
371
+ #
372
+ # @param [String] buffer a buffer to serialize to
373
+ # @return [String] the result of serliazing this message
374
+ def serialize(buffer = "")
375
+ raise NotImplementedError, "This method is generated after calling #finalize on a message class"
376
+ end
377
+ alias to_s serialize
378
+
379
+ # @return [String] the nicely formatted version of the message
380
+ def inspect
381
+ fields = self.class.fields.map do |field|
382
+ "@#{field}=" + __send__(field).inspect
383
+ end
384
+ "#<#{self.class.name} " <<
385
+ "#{fields * " "}>"
386
+ end
387
+
388
+ def pretty_inspect
389
+ fields = self.class.fields.map do |field|
390
+ "@#{field}=" + __send__(field).inspect
391
+ end
392
+ "#<#{self.class.name}\n" <<
393
+ " #{fields * "\n "}>"
394
+ end
395
+
396
+ end
397
+ end
@@ -0,0 +1 @@
1
+ require "binary/protocol/extensions/module"
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+ module Binary
3
+ module Protocol
4
+ module Extensions
5
+ module Module
6
+
7
+ # Redefine the method. Will undef the method if it exists or simply
8
+ # just define it.
9
+ #
10
+ # @example Redefine the method.
11
+ # Object.re_define_method("exists?") do
12
+ # self
13
+ # end
14
+ #
15
+ # @param [ String, Symbol ] name The name of the method.
16
+ # @param [ Proc ] block The method body.
17
+ #
18
+ # @return [ Method ] The new method.
19
+ #
20
+ # @since 3.0.0
21
+ def re_define_method(name, &block)
22
+ undef_method(name) if method_defined?(name)
23
+ define_method(name, &block)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ unless ::Module.respond_to?(:re_define_method, true)
31
+ ::Module.__send__(:include, Binary::Protocol::Extensions::Module)
32
+ end
@@ -0,0 +1,5 @@
1
+ module Binary
2
+ module Protocol
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: binary-protocol
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Andrew Bennett
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-03-19 00:00:00.000000000 Z
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: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
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: rake
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: Helpful DSL for reading and writing binary protocols
56
+ email:
57
+ - andrew@pagodabox.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitignore
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - binary-protocol.gemspec
68
+ - lib/binary/protocol.rb
69
+ - lib/binary/protocol/extensions.rb
70
+ - lib/binary/protocol/extensions/module.rb
71
+ - lib/binary/protocol/version.rb
72
+ homepage: https://github.com/potatosalad/binary-protocol
73
+ licenses:
74
+ - MIT
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 2.0.2
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Helpful DSL for reading and writing binary protocols
96
+ test_files: []