bunny 0.7.13 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.gitignore +2 -2
  2. data/.travis.yml +7 -16
  3. data/CHANGELOG +3 -21
  4. data/Gemfile +2 -4
  5. data/README.textile +31 -9
  6. data/Rakefile +3 -3
  7. data/bunny.gemspec +6 -3
  8. data/examples/{simple_08.rb → simple.rb} +1 -1
  9. data/examples/{simple_ack_08.rb → simple_ack.rb} +1 -1
  10. data/examples/{simple_consumer_08.rb → simple_consumer.rb} +4 -4
  11. data/examples/{simple_fanout_08.rb → simple_fanout.rb} +1 -1
  12. data/examples/{simple_headers_08.rb → simple_headers.rb} +2 -2
  13. data/examples/{simple_publisher_09.rb → simple_publisher.rb} +1 -1
  14. data/examples/{simple_topic_09.rb → simple_topic.rb} +2 -2
  15. data/ext/amqp-0.9.1.json +1 -0
  16. data/ext/config.yml +3 -3
  17. data/ext/qparser.rb +9 -52
  18. data/lib/bunny/{client09.rb → client.rb} +34 -46
  19. data/lib/bunny/{exchange09.rb → exchange.rb} +16 -15
  20. data/lib/bunny/{queue09.rb → queue.rb} +26 -23
  21. data/lib/bunny/{subscription09.rb → subscription.rb} +11 -6
  22. data/lib/bunny/version.rb +1 -1
  23. data/lib/bunny.rb +15 -33
  24. data/lib/qrack/client.rb +31 -22
  25. data/lib/qrack/protocol/{protocol08.rb → protocol.rb} +2 -1
  26. data/lib/qrack/protocol/{spec09.rb → spec.rb} +8 -7
  27. data/lib/qrack/{qrack08.rb → qrack.rb} +4 -4
  28. data/lib/qrack/subscription.rb +58 -9
  29. data/lib/qrack/transport/{buffer08.rb → buffer.rb} +9 -1
  30. data/lib/qrack/transport/{frame08.rb → frame.rb} +7 -22
  31. data/spec/spec_09/amqp_url_spec.rb +1 -1
  32. data/spec/spec_09/bunny_spec.rb +11 -9
  33. data/spec/spec_09/connection_spec.rb +9 -4
  34. data/spec/spec_09/exchange_spec.rb +23 -25
  35. data/spec/spec_09/queue_spec.rb +33 -19
  36. metadata +71 -81
  37. checksums.yaml +0 -7
  38. data/examples/simple_09.rb +0 -32
  39. data/examples/simple_ack_09.rb +0 -35
  40. data/examples/simple_consumer_09.rb +0 -55
  41. data/examples/simple_fanout_09.rb +0 -41
  42. data/examples/simple_headers_09.rb +0 -42
  43. data/examples/simple_publisher_08.rb +0 -29
  44. data/examples/simple_topic_08.rb +0 -61
  45. data/ext/amqp-0.8.json +0 -616
  46. data/lib/bunny/channel09.rb +0 -39
  47. data/lib/bunny/client08.rb +0 -480
  48. data/lib/bunny/exchange08.rb +0 -177
  49. data/lib/bunny/queue08.rb +0 -403
  50. data/lib/bunny/subscription08.rb +0 -87
  51. data/lib/qrack/protocol/protocol09.rb +0 -135
  52. data/lib/qrack/protocol/spec08.rb +0 -828
  53. data/lib/qrack/qrack09.rb +0 -20
  54. data/lib/qrack/transport/buffer09.rb +0 -305
  55. data/lib/qrack/transport/frame09.rb +0 -97
  56. data/spec/spec_08/bunny_spec.rb +0 -75
  57. data/spec/spec_08/connection_spec.rb +0 -24
  58. data/spec/spec_08/exchange_spec.rb +0 -175
  59. data/spec/spec_08/queue_spec.rb +0 -239
  60. data/spec/spec_helper.rb +0 -8
  61. /data/lib/bunny/{channel08.rb → channel.rb} +0 -0
data/lib/bunny/queue08.rb DELETED
@@ -1,403 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Bunny
4
-
5
- =begin rdoc
6
-
7
- === DESCRIPTION:
8
-
9
- Queues store and forward messages. Queues can be configured in the server or created at runtime.
10
- Queues must be attached to at least one exchange in order to receive messages from publishers.
11
-
12
- =end
13
-
14
- class Queue < Qrack::Queue
15
-
16
- def initialize(client, name, opts = {})
17
- # check connection to server
18
- raise Bunny::ConnectionError, 'Not connected to server' if client.status == :not_connected
19
-
20
- @client = client
21
- @opts = opts
22
- @delivery_tag = nil
23
- @subscription = nil
24
-
25
- # Queues without a given name are named by the server and are generally
26
- # bound to the process that created them.
27
- if !name
28
- opts = {
29
- :passive => false,
30
- :durable => false,
31
- :exclusive => true,
32
- :auto_delete => true
33
- }.merge(opts)
34
- end
35
-
36
- # ignore the :nowait option if passed, otherwise program will hang waiting for a
37
- # response that will not be sent by the server
38
- opts.delete(:nowait)
39
-
40
- opts = { :queue => name || '', :nowait => false }.merge(opts)
41
-
42
- client.send_frame(Qrack::Protocol::Queue::Declare.new(opts))
43
-
44
- method = client.next_method
45
-
46
- client.check_response(method, Qrack::Protocol::Queue::DeclareOk, "Error declaring queue #{name}")
47
-
48
- @name = method.queue
49
- client.queues[@name] = self
50
- end
51
-
52
- # @return [Bunny::Consumer] Default consumer associated with this queue (if any), or nil
53
- # @note Default consumer is the one registered with the convenience {Bunny::Queue#subscribe} method. It has no special properties of any kind.
54
- # @see Queue#subscribe
55
- # @see Bunny::Consumer
56
- # @api public
57
- def default_consumer
58
- @default_consumer
59
- end
60
-
61
-
62
- # @return [Class]
63
- # @private
64
- def self.consumer_class
65
- # Bunny::Consumer
66
- Bunny::Subscription
67
- end # self.consumer_class
68
-
69
- =begin rdoc
70
-
71
- === DESCRIPTION:
72
-
73
- Acknowledges one or more messages delivered via the _Deliver_ or _Get_-_Ok_ methods. The client can
74
- ask to confirm a single message or a set of messages up to and including a specific message.
75
-
76
- ==== OPTIONS:
77
-
78
- * <tt>:delivery_tag</tt>
79
- * <tt>:multiple => true or false (_default_)</tt> - If set to _true_, the delivery tag is treated
80
- as "up to and including", so that the client can acknowledge multiple messages with a single
81
- method. If set to _false_, the delivery tag refers to a single message. If the multiple field
82
- is _true_, and the delivery tag is zero, tells the server to acknowledge all outstanding messages.
83
-
84
- =end
85
-
86
- def ack(opts={})
87
- # Set delivery tag
88
- if delivery_tag.nil? and opts[:delivery_tag].nil?
89
- raise Bunny::AcknowledgementError, "No delivery tag received"
90
- else
91
- self.delivery_tag = opts[:delivery_tag] if delivery_tag.nil?
92
- end
93
-
94
- opts = {:delivery_tag => delivery_tag, :multiple => false}.merge(opts)
95
-
96
- client.send_frame(Qrack::Protocol::Basic::Ack.new(opts))
97
-
98
- # reset delivery tag
99
- self.delivery_tag = nil
100
- end
101
-
102
- =begin rdoc
103
-
104
- === DESCRIPTION:
105
-
106
- Binds a queue to an exchange. Until a queue is bound it will not receive any messages. Queues are
107
- bound to the direct exchange '' by default. If error occurs, a _Bunny_::_ProtocolError_ is raised.
108
-
109
- * <tt>:key => 'routing key'* <tt>:key => 'routing_key'</tt> - Specifies the routing key for
110
- the binding. The routing key is used for routing messages depending on the exchange configuration.
111
- * <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
112
-
113
- ==== RETURNS:
114
-
115
- <tt>:bind_ok</tt> if successful.
116
-
117
- =end
118
-
119
- def bind(exchange, opts = {})
120
- exchange = exchange.respond_to?(:name) ? exchange.name : exchange
121
-
122
- # ignore the :nowait option if passed, otherwise program will hang waiting for a
123
- # response that will not be sent by the server
124
- opts.delete(:nowait)
125
-
126
- opts = {
127
- :queue => name,
128
- :exchange => exchange,
129
- :routing_key => opts.delete(:key),
130
- :nowait => false
131
- }.merge(opts)
132
-
133
- client.send_frame(Qrack::Protocol::Queue::Bind.new(opts))
134
-
135
- method = client.next_method
136
-
137
- client.check_response(method, Qrack::Protocol::Queue::BindOk, "Error binding queue: #{name} to exchange: #{exchange}")
138
-
139
- # return message
140
- :bind_ok
141
- end
142
-
143
- =begin rdoc
144
-
145
- === DESCRIPTION:
146
-
147
- Requests that a queue is deleted from broker/server. When a queue is deleted any pending messages
148
- are sent to a dead-letter queue if this is defined in the server configuration. Removes reference
149
- from queues if successful. If an error occurs raises _Bunny_::_ProtocolError_.
150
-
151
- ==== Options:
152
-
153
- * <tt>:if_unused => true or false (_default_)</tt> - If set to _true_, the server will only
154
- delete the queue if it has no consumers. If the queue has consumers the server does not
155
- delete it but raises a channel exception instead.
156
- * <tt>:if_empty => true or false (_default_)</tt> - If set to _true_, the server will only
157
- delete the queue if it has no messages. If the queue is not empty the server raises a channel
158
- exception.
159
- * <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
160
-
161
- ==== Returns:
162
-
163
- <tt>:delete_ok</tt> if successful
164
- =end
165
-
166
- def delete(opts = {})
167
- # ignore the :nowait option if passed, otherwise program will hang waiting for a
168
- # response that will not be sent by the server
169
- opts.delete(:nowait)
170
-
171
- opts = { :queue => name, :nowait => false }.merge(opts)
172
-
173
- client.send_frame(Qrack::Protocol::Queue::Delete.new(opts))
174
-
175
- method = client.next_method
176
-
177
- client.check_response(method, Qrack::Protocol::Queue::DeleteOk, "Error deleting queue #{name}")
178
-
179
- client.queues.delete(name)
180
-
181
- # return confirmation
182
- :delete_ok
183
- end
184
-
185
- =begin rdoc
186
-
187
- === DESCRIPTION:
188
-
189
- Gets a message from a queue in a synchronous way. If error occurs, raises _Bunny_::_ProtocolError_.
190
-
191
- ==== OPTIONS:
192
-
193
- * <tt>:ack => false (_default_) or true</tt> - If set to _false_, the server does not expect an
194
- acknowledgement message from the client. If set to _true_, the server expects an acknowledgement
195
- message from the client and will re-queue the message if it does not receive one within a time specified
196
- by the server.
197
-
198
- ==== RETURNS:
199
-
200
- Hash <tt>{:header, :payload, :delivery_details}</tt>. <tt>:delivery_details</tt> is
201
- a hash <tt>{:consumer_tag, :delivery_tag, :redelivered, :exchange, :routing_key}</tt>.
202
-
203
- If the queue is empty the returned hash will contain the values -
204
-
205
- :header => nil
206
- :payload => :queue_empty
207
- :delivery_details => nil
208
-
209
- N.B. If a block is provided then the hash will be passed into the block and the return value
210
- will be nil.
211
-
212
- =end
213
-
214
- def pop(opts = {}, &blk)
215
-
216
- # do we want to have to provide an acknowledgement?
217
- ack = opts.delete(:ack)
218
-
219
- opts = {
220
- :queue => name,
221
- :consumer_tag => name,
222
- :no_ack => !ack,
223
- :nowait => true
224
- }.merge(opts)
225
-
226
- client.send_frame(Qrack::Protocol::Basic::Get.new(opts))
227
-
228
- method = client.next_method
229
-
230
- if method.is_a?(Qrack::Protocol::Basic::GetEmpty) then
231
- queue_empty = true
232
- elsif !method.is_a?(Qrack::Protocol::Basic::GetOk)
233
- raise Bunny::ProtocolError, "Error getting message from queue #{name}"
234
- end
235
-
236
- if !queue_empty
237
- # get delivery tag to use for acknowledge
238
- self.delivery_tag = method.delivery_tag if ack
239
-
240
- header = client.next_payload
241
-
242
- # If maximum frame size is smaller than message payload body then message
243
- # will have a message header and several message bodies
244
- msg = ''
245
- while msg.length < header.size
246
- msg << client.next_payload
247
- end
248
-
249
- msg_hash = {:header => header, :payload => msg, :delivery_details => method.arguments}
250
-
251
- else
252
- msg_hash = {:header => nil, :payload => :queue_empty, :delivery_details => nil}
253
- end
254
-
255
- # Pass message hash to block or return message hash
256
- blk ? blk.call(msg_hash) : msg_hash
257
- end
258
-
259
- =begin rdoc
260
-
261
- === DESCRIPTION:
262
-
263
- Removes all messages from a queue. It does not cancel consumers. Purged messages are deleted
264
- without any formal "undo" mechanism. If an error occurs raises _Bunny_::_ProtocolError_.
265
-
266
- ==== Options:
267
-
268
- * <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
269
-
270
- ==== Returns:
271
-
272
- <tt>:purge_ok</tt> if successful
273
- =end
274
-
275
- def purge(opts = {})
276
- # ignore the :nowait option if passed, otherwise program will hang waiting for a
277
- # response that will not be sent by the server
278
- opts.delete(:nowait)
279
-
280
- opts = { :queue => name, :nowait => false }.merge(opts)
281
-
282
- client.send_frame(Qrack::Protocol::Queue::Purge.new(opts))
283
-
284
- method = client.next_method
285
-
286
- client.check_response(method, Qrack::Protocol::Queue::PurgeOk, "Error purging queue #{name}")
287
-
288
- # return confirmation
289
- :purge_ok
290
- end
291
-
292
- =begin rdoc
293
-
294
- === DESCRIPTION:
295
-
296
- Returns hash {:message_count, :consumer_count}.
297
-
298
- =end
299
-
300
- def status
301
- client.send_frame(Qrack::Protocol::Queue::Declare.new(:queue => name, :passive => true))
302
- method = client.next_method
303
- {:message_count => method.message_count, :consumer_count => method.consumer_count}
304
- end
305
-
306
- def subscribe(opts = {}, &blk)
307
- raise RuntimeError.new("This queue already has default consumer. Please instantiate Bunny::Consumer directly and call its #consume method to register additional consumers.") if @default_consumer && ! opts[:consumer_tag]
308
-
309
- # Create a subscription.
310
- @default_consumer = self.class.consumer_class.new(client, self, opts)
311
- @default_consumer.consume(&blk)
312
- end
313
-
314
- =begin rdoc
315
-
316
- === DESCRIPTION:
317
-
318
- Cancels a consumer. This does not affect already delivered messages, but it does mean
319
- the server will not send any more messages for that consumer.
320
-
321
- ==== OPTIONS:
322
-
323
- * <tt>:consumer_tag => '_tag_'</tt> - Specifies the identifier for the consumer.
324
- * <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
325
-
326
- ==== Returns:
327
-
328
- <tt>:unsubscribe_ok</tt> if successful
329
-
330
- =end
331
-
332
- def unsubscribe(opts = {})
333
- # Default consumer_tag from subscription if not passed in
334
- consumer_tag = @default_consumer ? @default_consumer.consumer_tag : opts[:consumer_tag]
335
-
336
- # Must have consumer tag to tell server what to unsubscribe
337
- raise Bunny::UnsubscribeError,
338
- "No consumer tag received" if !consumer_tag
339
-
340
- # Cancel consumer
341
- client.send_frame(Qrack::Protocol::Basic::Cancel.new(:consumer_tag => consumer_tag,:nowait => false))
342
-
343
- method = client.next_method
344
-
345
- client.check_response(method, Qrack::Protocol::Basic::CancelOk, "Error unsubscribing from queue #{name}")
346
-
347
- # Reset subscription
348
- @default_consumer = nil
349
-
350
- # Return confirmation
351
- :unsubscribe_ok
352
- end
353
-
354
- =begin rdoc
355
-
356
- === DESCRIPTION:
357
-
358
- Removes a queue binding from an exchange. If error occurs, a _Bunny_::_ProtocolError_ is raised.
359
-
360
- ==== OPTIONS:
361
- * <tt>:key => 'routing key'* <tt>:key => 'routing_key'</tt> - Specifies the routing key for
362
- the binding.
363
- * <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
364
-
365
- ==== RETURNS:
366
-
367
- <tt>:unbind_ok</tt> if successful.
368
-
369
- =end
370
-
371
- def unbind(exchange, opts = {})
372
- exchange = exchange.respond_to?(:name) ? exchange.name : exchange
373
-
374
- # ignore the :nowait option if passed, otherwise program will hang waiting for a
375
- # response that will not be sent by the server
376
- opts.delete(:nowait)
377
-
378
- opts = {
379
- :queue => name,
380
- :exchange => exchange,
381
- :routing_key => opts.delete(:key),
382
- :nowait => false
383
- }.merge(opts)
384
-
385
- client.send_frame(Qrack::Protocol::Queue::Unbind.new(opts))
386
-
387
- method = client.next_method
388
-
389
- client.check_response(method, Qrack::Protocol::Queue::UnbindOk, "Error unbinding queue #{name}")
390
-
391
- # return message
392
- :unbind_ok
393
- end
394
-
395
- private
396
-
397
- def exchange
398
- @exchange ||= Bunny::Exchange.new(client, '', {:type => :direct, :key => name})
399
- end
400
-
401
- end
402
-
403
- end
@@ -1,87 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Bunny
4
-
5
- =begin rdoc
6
-
7
- === DESCRIPTION:
8
-
9
- Asks the server to start a "consumer", which is a transient request for messages from a specific
10
- queue. Consumers last as long as the channel they were created on, or until the client cancels them
11
- with an _unsubscribe_. Every time a message reaches the queue it is passed to the _blk_ for
12
- processing. If error occurs, _Bunny_::_ProtocolError_ is raised.
13
-
14
- ==== OPTIONS:
15
- * <tt>:consumer_tag => '_tag_'</tt> - Specifies the identifier for the consumer. The consumer tag is
16
- local to a connection, so two clients can use the same consumer tags. If this option is not
17
- specified a server generated name is used.
18
- * <tt>:ack => false (_default_) or true</tt> - If set to _false_, the server does not expect an
19
- acknowledgement message from the client. If set to _true_, the server expects an acknowledgement
20
- message from the client and will re-queue the message if it does not receive one within a time specified
21
- by the server.
22
- * <tt>:exclusive => true or false (_default_)</tt> - Request exclusive consumer access, meaning
23
- only this consumer can access the queue.
24
- * <tt>:nowait => true or false (_default_)</tt> - Ignored by Bunny, always _false_.
25
- * <tt>:timeout => number of seconds - The subscribe loop will continue to wait for
26
- messages until terminated (Ctrl-C or kill command) or this timeout interval is reached.
27
- * <tt>:message_max => max number messages to process</tt> - When the required number of messages
28
- is processed subscribe loop is exited.
29
-
30
- ==== OPERATION:
31
-
32
- Passes a hash of message information to the block, if one has been supplied. The hash contains
33
- :header, :payload and :delivery_details. The structure of the data is as follows -
34
-
35
- :header has instance variables -
36
- @klass
37
- @size
38
- @weight
39
- @properties is a hash containing -
40
- :content_type
41
- :delivery_mode
42
- :priority
43
-
44
- :payload contains the message contents
45
-
46
- :delivery details is a hash containing -
47
- :consumer_tag
48
- :delivery_tag
49
- :redelivered
50
- :exchange
51
- :routing_key
52
-
53
- If the :timeout option is specified then the subscription will
54
- automatically cease if the given number of seconds passes with no
55
- message arriving.
56
-
57
- ==== EXAMPLES
58
-
59
- my_queue.subscribe(:timeout => 5) {|msg| puts msg[:payload]}
60
-
61
- my_queue.subscribe(:message_max => 10, :ack => true) {|msg| puts msg[:payload]}
62
-
63
- =end
64
-
65
- class Subscription < Bunny::Consumer
66
-
67
- def setup_consumer
68
- subscription_options = {
69
- :queue => queue.name,
70
- :consumer_tag => consumer_tag,
71
- :no_ack => !ack,
72
- :exclusive => exclusive,
73
- :nowait => false
74
- }.merge(@opts)
75
-
76
- client.send_frame(Qrack::Protocol::Basic::Consume.new(subscription_options))
77
-
78
- method = client.next_method
79
-
80
- client.check_response(method, Qrack::Protocol::Basic::ConsumeOk, "Error subscribing to queue #{queue.name}")
81
-
82
- @consumer_tag = method.consumer_tag
83
- end
84
-
85
- end
86
-
87
- end
@@ -1,135 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module Qrack
4
- module Protocol09
5
- #:stopdoc:
6
- class Class::Method
7
- def initialize *args
8
- opts = args.pop if args.last.is_a? Hash
9
- opts ||= {}
10
-
11
- if args.size == 1 and args.first.is_a? Transport09::Buffer
12
- buf = args.shift
13
- else
14
- buf = nil
15
- end
16
-
17
- self.class.arguments.each do |type, name|
18
- val = buf ? buf.read(type) :
19
- args.shift || opts[name] || opts[name.to_s]
20
- instance_variable_set("@#{name}", val)
21
- end
22
- end
23
-
24
- def arguments
25
- self.class.arguments.inject({}) do |hash, (type, name)|
26
- hash.update name => instance_variable_get("@#{name}")
27
- end
28
- end
29
-
30
- def to_binary
31
- buf = Transport09::Buffer.new
32
- buf.write :short, self.class.parent.id
33
- buf.write :short, self.class.id
34
-
35
- bits = []
36
-
37
- self.class.arguments.each do |type, name|
38
- val = instance_variable_get("@#{name}")
39
- if type == :bit
40
- bits << (val || false)
41
- else
42
- unless bits.empty?
43
- buf.write :bit, bits
44
- bits = []
45
- end
46
- buf.write type, val
47
- end
48
- end
49
-
50
- buf.write :bit, bits unless bits.empty?
51
- buf.rewind
52
-
53
- buf
54
- end
55
-
56
- def to_s
57
- to_binary.to_s
58
- end
59
-
60
- def to_frame channel = 0
61
- Transport09::Method.new(self, channel)
62
- end
63
- end
64
-
65
- class Header
66
- def initialize *args
67
- opts = args.pop if args.last.is_a? Hash
68
- opts ||= {}
69
-
70
- first = args.shift
71
-
72
- if first.is_a? ::Class and first.ancestors.include? Protocol09::Class
73
- @klass = first
74
- @size = args.shift || 0
75
- @weight = args.shift || 0
76
- @properties = opts
77
-
78
- elsif first.is_a? Transport09::Buffer or first.is_a? String
79
- buf = first
80
- buf = Transport09::Buffer.new(buf) unless buf.is_a? Transport09::Buffer
81
-
82
- @klass = Protocol09.classes[buf.read(:short)]
83
- @weight = buf.read(:short)
84
- @size = buf.read(:longlong)
85
-
86
- props = buf.read(:properties, *klass.properties.map{|type,_| type })
87
- @properties = Hash[*klass.properties.map{|_,name| name }.zip(props).reject{|k,v| v.nil? }.flatten]
88
-
89
- else
90
- raise ArgumentError, 'Invalid argument'
91
- end
92
-
93
- end
94
- attr_accessor :klass, :size, :weight, :properties
95
-
96
- def to_binary
97
- buf = Transport09::Buffer.new
98
- buf.write :short, klass.id
99
- buf.write :short, weight # XXX rabbitmq only supports weight == 0
100
- buf.write :longlong, size
101
- buf.write :properties, (klass.properties.map do |type, name|
102
- [ type, properties[name] || properties[name.to_s] ]
103
- end)
104
- buf.rewind
105
- buf
106
- end
107
-
108
- def to_s
109
- to_binary.to_s
110
- end
111
-
112
- def to_frame channel = 0
113
- Transport09::Header.new(self, channel)
114
- end
115
-
116
- def == header
117
- [ :klass, :size, :weight, :properties ].inject(true) do |eql, field|
118
- eql and __send__(field) == header.__send__(field)
119
- end
120
- end
121
-
122
- def method_missing meth, *args, &blk
123
- @properties.has_key?(meth) || @klass.properties.find{|_,name| name == meth } ? @properties[meth] :
124
- super
125
- end
126
- end
127
-
128
- def self.parse buf
129
- buf = Transport09::Buffer.new(buf) unless buf.is_a? Transport09::Buffer
130
- class_id, method_id = buf.read(:short, :short)
131
- classes[class_id].methods[method_id].new(buf)
132
- end
133
-
134
- end
135
- end